看了上面的文章,大家也会觉得创建字符设备是一件很复杂的事情,步骤太多,对于初学者要摸好长时间才能慢慢熟悉,然后还要创建设备文件,虽然每一步不难,但是组合到一起就显得有些繁琐了,没办法,开发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)
{
misc_deregister(&misc);
open_state = 0;
printk("GPIO test End\n");
}
module_init(gpio_init);
module_exit(gpio_exit);
MODULE_LICENSE("GPL");
从上面可以看到方便了很多,只需要misc_register注册一下,然后在一定一个结构体的时候直接关联file_operations结构即可,不用再申请设备号。
应用程序和上面一样,就是打开的文件变成了led3,这不是重点,重点是看以下操作和运行结果:
root@at91sam9260ek:/mnt/misc_dev# lsmod
Module Size Used by Not tainted
root@at91sam9260ek:/mnt/misc_dev# ls /dev |grep led
root@at91sam9260ek:/mnt/misc_dev# insmod misc_dev.ko
------GPIO misc test init-----
root@at91sam9260ek:/mnt/misc_dev# ls /dev |grep led
led3
root@at91sam9260ek:/mnt/misc_dev# ./test
Open file suc!
ON!
OFF
ON!
OFF
ON!
OFF
ON!
OFF
ON!
OFF
ON!
OFF
ON!
OFF
ON!
OFF
ON!
close file suc!
Close the file suc!
root@at91sam9260ek:/mnt/misc_dev#
可能已经发现了,它会自动生成设备文件,大大方便了我们的操作!
所以建议大家再使用字符设备驱动驱动led的时候,用混杂设备,比重新申请一个字符设备好用很多。