日期:2014-05-16  浏览次数:20748 次

Linux设备驱动程序设计(三)----Linux的特殊字符设备:混杂设备,依旧让LED闪烁起来

看了上面的文章,大家也会觉得创建字符设备是一件很复杂的事情,步骤太多,对于初学者要摸好长时间才能慢慢熟悉,然后还要创建设备文件,虽然每一步不难,但是组合到一起就显得有些繁琐了,没办法,开发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)	
{