在工业控制中,GPIO口用作DO,DI的情况非常多,所以常常不|厌其烦的改写DO,DI的字符设备驱动。虽然改起来很快,但是感觉很多时候都是重复的工作。
最近把它整理成了一个模板,最后在我所使用的这种厂家的ARM体系架构下的芯片只需要填写一个数组就OK,想想这些也是没有办法更简单了。
由于以前的GPIO口相关的驱动,我都是采用的Platform 平台的。driver ,device分开的思想还是很不错的,但是对GPIO这种简单的驱动来说,就整得有点复
杂了。我想这也是MISC 设备驱动模型存在的原因,以前有简单分析过MISC 驱动模型,如下链接:
http://blog.chinaunix.net/uid-20768928-id-3423500.html
整理过程我最后还是选择采用MISC模型,因为能在一个文件中搞定,这样改起来也方便。
MISC 的优点就是设备节点创建简单,主次设备号申请简单,driver与device在同一个文件中就可以搞定。
整理后的GPIO ,DODI驱动源码demo如下:linux_dodi_misc_model.rar
-
#include <linux/gpio.h>
-
#include <linux/io.h>
-
#include <linux/ioport.h>
-
#include <linux/module.h>
-
#include <linux/slab.h>
-
#include <linux/delay.h>
-
#include <linux/fcntl.h>
-
#include <linux/cdev.h>
-
#include <asm/uaccess.h>
-
#include <asm/system.h>
-
#include <asm/io.h>
-
#include <linux/kernel.h>
-
#include <linux/fs.h>
-
#include <linux/init.h>
-
#include <linux/device.h>
-
#include <linux/platform_device.h>
-
#include <linux/ioctl.h>
-
-
#include <linux/miscdevice.h>
-
#include <asm/uaccess.h>
-
-
-
/*********************************************/
-
#include <mach/pinctrl.h>
-
#include "mach/mx28_pins.h"
-
/*********************************************/
-
-
-
//#define xxx_DEBUG
-
#undef PDEBUG /* undef it, just in case */
-
#ifdef xxx_DEBUG
-
#ifdef __KERNEL__
-
/* This one if debugging is on, and kernel space */
-
#define PDEBUG(fmt, args...) printk( KERN_EMERG "xxx: " fmt, ## args)
-
#else
-
/* This one for user space */
-
#define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
-
#endif
-
#else
-
#define PDEBUG(fmt, args...) /* not debugging: nothing */
-
#endif
-
-
-
#define MCU_DIDO_IOC_MAGIC 'd'
-
-
#define IO_GPIO_SET_OUTPUT _IO(MCU_DIDO_IOC_MAGIC,0)
-
#define IO_GPIO_RSEET_OUTPUT _IO(MCU_DIDO_IOC_MAGIC,1)
-
#define IO_GPIO_GET_INPUT _IOR(MCU_DIDO_IOC_MAGIC,2,int)
-
-
#define PINID_PCM_SYNC MXS_PIN_ENCODE(3,21)
-
#define PINID_PCM_DOUT MXS_PIN_ENCODE(3,26)
-
#define PINID_PCM_DIN MXS_PIN_ENCODE(3,23)
-
#define PINID_PCM_CLK MXS_PIN_ENCODE(3,22)
-
-
#define PINID_LCD_08 MXS_PIN_ENCODE(1,8)
-
-
-
#define DI_GPIO_0 MXS_PIN_TO_GPIO(PINID_PCM_SYNC)
-
#define DI_GPIO_1 MXS_PIN_TO_GPIO(PINID_PCM_CLK)
-
#define DI_GPIO_2 MXS_PIN_TO_GPIO(PINID_PCM_DIN)
-
#define DI_GPIO_3 MXS_PIN_TO_GPIO(PINID_PCM_DOUT)
-
-
#define DO_GPIO_0 MXS_PIN_TO_GPIO(PINID_LCD_08) //以上为体系结构相关的部分
-
-
//do 不超过256 , di 不超过32
-
static unsigned int uI_Input[] = {DI_GPIO_0,DI_GPIO_1,DI_GPIO_2,DI_GPIO_3};
-
static unsigned int uI_Output[] = {DO_GPIO_0};
-
unsigned char ucOutputNum = 0;
-
unsigned char ucInputNum = 0 ;
-
-
static int xxx_open(struct inode *inode,struct file *filp)
-
{
-
PDEBUG("---> %s \n",__FUNCTION__);
-
return 0;
-
}
-
-
static int xxx_close(struct inode *inode,struct file *filp)
-
{
-
PDEBUG("---> %s \n",__FUNCTION__);
-
return 0;
-
}
-
-
static int xxx_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
-
{
-
int err = 0;
-
PDEBUG("---> %s \n",__FUNCTION__);
-
return err;
-
}
-
-
-
static int xxx_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
-
{
-
int ret = 0;
-
unsigned char i ;
-
unsigned int temp = 0 ;
-
unsigned int input_value = 0 ;
-
PDEBUG("---> %s, cmd=%d,arg=%ld \n",__FUNCTION__,cmd,arg);
-
switch(cmd)
-
{
-
case IO_GPIO_SET_OUTPUT:
-
PDEBUG("%s: case xxx_ON \n",__FUNCTION__);
-
if(arg >= ucOutputNum)
-
return -EINVAL;
-
gpio_direction_output(uI_Output[arg],1);
-
break;
-
case IO_GPIO_RSEET_OUTPUT:
-
PDEBUG("%s: case xxx_OFF \n",__FUNCTION__);
-
if(arg >= ucOutputNum)
-
return -EINVAL;
-
gpio_direction_output(uI_Output[arg],0);
-
break;
-
case IO_GPIO_GET_INPUT:
-
for(i = 0 ; i < ucInputNum ; i++)
-
{
-
temp = gpio_get_value(uI_Input[i]);
-
if(temp)
-
input_value |= (1<<i);
-
}
-
PDEBUG("%s: %d \n",__FUNCTION__,input_value);
-
-
copy_to_user((void *)arg,&input_value,4);
-
break;
-
default :
-
return -EINVAL;
-
}
-
-
return ret;
-
}
-
-
-
static int xxx_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos)
-
{
-
PDEBUG("---> %s \n",__FUNCTION__);
-
return 0;
-
}
-
-
/************************************************************
-
important struct
-
************************************************************/
-
static struct file_operations xxx_fops=
-
{
-
.owner = THIS_MODULE,
-
.open = xxx_open,
-
.release =xxx_close,
-
.read = xxx_read,
-
.ioctl = xxx_ioctl,
-
.write = xxx_write
-
};
-
-
-
-
static int __devinit xxx_probe(void)
-
{
-
int ret ;
-
char i = 0 ;
-
-
-
ucOutputNum = sizeof(uI_Output) / sizeof(unsigned int); //输出数量
-
ucInputNum = sizeof(uI_Input) / sizeof(unsigned int); // 输入数量
-
-
for(i = 0 ; i < ucInputNum ; i++)
-
{
-
ret = gpio_request(uI_Input[i],"input_di");
-
if (ret)
-
{
-
goto err_free_inputs;
-
}
-
}
-
-
for(i = 0 ; i < ucOutputNum ; i++)
-
{
-
ret = gpio_request(uI_Output[i],"output_do");
-
if (ret)
-
{
-
goto err_free_outputs;
-
}
-
}
-
-
// gpio_direction_output(uI_Output[0],1);
-
// gpio_direction_input(uI_Input[0]);
-
-
printk(KERN_INFO "xxx driver probe OK \n");
-
return 0;
-
-
err_free_outputs:
-
i = ucOutputNum;
-
while(--i >= 0)
-
gpio_free(uI_Output[i]);
-
-
err_free_inputs:
-
i = ucInputNum;
-
while(--i >= 0)
-
gpio_free(uI_Input[i]);
-
-
return ret;
-
}
-
-
-
static struct miscdevice xxx = {
-
.minor = MISC_DYNAMIC_MINOR,
-
.name = "xxx",
-
.fops = &xxx_fops,
-
};
-
-
-
-
static int __init xxx_init(void)
-
{
-
int ret = 0;
-
int i;
-
ret = xxx_probe();
-
if(ret)
-
{
-
printk("xxx gpio reques fail \n");
-
return ret ;
-
}
-
ret = misc_register(&xxx);
-
if(ret<0)
-
{
-
printk("xxx misc devices register fail \n");
-
}
-
-
return ret;
-
}
-
-
static int __exit xxx_exit(void)
-
{
-
char i ;
-
misc_deregister(&xxx);
-
-
i = ucInputNum;
-
while(--i >= 0)
-
gpio_free(uI_Input[i]);
-
-
i = ucOutputNum;
-
while(--i >= 0)
-
gpio_free(uI_Output[i]);
-
-
return 0;
-
}
-
-
-
module_init(xxx_init);
-
module_exit(xxx_exit);
xxx是设备名,全部替换就OK了。
uI_Input 是输入GPIO数组。有就填写,没有可以留空数组。
uI_Output 是输出GPIO数组。有就填写,没有可以留空数组。
在这种体系结构下,需要换GPIO口,只需要更换uI_Input , uI_Output 两个数组。然后用你想要的设备名替换xxx。
misc 的次设备采用MISC_DYNAMIC_MINOR动态分配。
阅读(717) | 评论(0) | 转发(0) |