日期:2014-05-16 浏览次数:20764 次
看了上面的文章,大家也会觉得创建字符设备是一件很复杂的事情,步骤太多,对于初学者要摸好长时间才能慢慢熟悉,然后还要创建设备文件,虽然每一步不难,但是组合到一起就显得有些繁琐了,没办法,开发Linux的都是大牛,更多的精力放到了功能上,而忽略了用户体验与操作的便捷性。
Linux针对像LED这样的操作,有一种设备叫做混杂设备:是一种特殊的字符设备,它的主设备号为10,我们重新启动开发板,然后执行命令:cat /proc/devices ,可以看到:
root@at91sam9260ek:/# cat /proc/devices Character devices: 1 mem 2 pty 3 ttyp 4 /dev/vc/0 4 tty 4 ttyS 5 /dev/tty 5 /dev/console 5 /dev/ptmx 7 vcs 10 misc 13 input 14 sound 90 mtd 116 alsa 128 ptm 136 pts 153 spi 180 usb 189 usb_device 253 usb_endpoint 254 rtc
说明混杂设备早已经存在,是为了给开发者一个叫为简单的操作方式,因为不用再重新申请一个设备号了(misc就是混杂设备的意思),那么它和普通的字符设备有什么不同呢?其实是操作上方便了很多,然我们先看驱动程序,其实改变也不是很大:
#include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/types.h> #include <linux/fs.h> #include <mach/gpio.h> //定义命令 #define LED_ON _IOW('h',0x01,unsigned long) //LED开的命令 #define LED_OFF _IOW('h',0x02,unsigned long) //LED关的命令 int open_state = 0; //1为打开,0为关闭 /*----------------------------------------- 函数名: led_open 参数: struct inode *inode,struct file *filp 返回值: int 描述: open对应的驱动函数 *-----------------------------------------*/ int led_open(struct inode *inode,struct file *filp ) { if(open_state == 0) { open_state = 1; printk("Open file suc!\n"); return 0; } else { printk("The file has opened!\n"); return -1; } } /*----------------------------------------- 函数名: led_release 参数: struct inode *inode,struct file *filp 返回值: int 描述: open对应的驱动函数 *-----------------------------------------*/ int led_release(struct inode *inode,struct file *filp ) { if(open_state == 1) { open_state = 0; printk("close file suc!\n"); return 0; } else { printk("The file has closed!\n"); return -1; } } /*----------------------------------------- 函数名: led_ioctl 参数: struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg 返回值: int 描述: ioctl对应的驱动函数 *-----------------------------------------*/ int led_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg) { switch(cmd) { case LED_ON: printk("ON!\n"); at91_set_gpio_value(AT91_PIN_PC0, 1); //灯亮起来 break; case LED_OFF:printk("OFF\n"); at91_set_gpio_value(AT91_PIN_PC0, 0); //灯灭掉 break; default :printk("Error command!\n"); } return 0; } const struct file_operations led_fop = { .owner = THIS_MODULE, .open = led_open, .ioctl = led_ioctl, .release = led_release, }; struct miscdevice misc = { .minor = 30, .fops = &led_fop, .name = "led3" }; /*----------------------------------------- 函数名: gpio_init 参数: void 返回值: int 描述: 模块初始化函数,在安装模块时候执行 *-----------------------------------------*/ static int __init gpio_init(void) { int ret; printk("------GPIO misc test init-----\n"); /** * 混杂设备主设备号就是10,通过次设备号来区分 */ ret = misc_register(&misc); //向内核注册设备号 if(ret < 0) { printk("Register Error!\n"); return ret; } /** * 初始化字符设备 */ at91_set_gpio_output(AT91_PIN_PC0,1); //设置引脚为输出功能,且为高电平 return 0; } /*----------------------------------------- 函数名: gpio_exit 参数: void 返回值: void 描述: 模块卸载函数,在卸载模块时候执行 *-----------------------------------------*/ static void __exit gpio_exit(void) {