misc杂散类设备驱动2:驱动代码的分析

misc杂散类设备虽然单独的归为杂散类这个类中,但其实也是字符设备驱动的一种,很多的代码的实现都与字符设备驱动如出一辙,这里以一个比较简单的蜂鸣器buzzer设备为例,以实际的代码分析misc杂散类设备的注册过程:

1.驱动的入口:

module_init(dev_init);
static int __init dev_init(void)
{
	int ret;

	init_MUTEX(&lock);
	ret = misc_register(&misc);
	
	/* GPD0_2 (PWMTOUT2) */
	ret = gpio_request(S5PV210_GPD0(2), "GPD0");
	if(ret)
		printk("buzzer-x210: request gpio GPD0(2) fail");
		
	s3c_gpio_setpull(S5PV210_GPD0(2), S3C_GPIO_PULL_UP);
	s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(1));
	gpio_set_value(S5PV210_GPD0(2), 0);

	printk ("x210 "DEVICE_NAME" initialized\n");
    	return ret;
}

(1)利用信号量,使得buzzer设备不会被多个进程同时操作,

init_MUTEX(&lock);

这里使用了信号量,但是经过分析,实际信号量只能计数一次,也就是以信号量的形式实现了一个互斥锁,使得对于该buzzer设备的操作,不能同时被多次执行。对于这里的信号量后面会再做介绍。

(2)核心注册杂散设备:misc_register

ret = misc_register(&misc);

(3)注册是核心是misc_register()函数的传参,对misc分析:

static struct miscdevice misc = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEVICE_NAME,
	.fops = &dev_fops,
};

指定次设备号为255,让系统帮我们动态分配次设备号,指定了次设备号的名字,以及最重要file_operations.

(4)file_operations结构体变量dev_fops:

static struct file_operations dev_fops = {
    .owner   =   THIS_MODULE,
    .open    =   x210_pwm_open,
    .release =   x210_pwm_close, 
    .ioctl   =   x210_pwm_ioctl,
};

open、release函数的实现比较普通,较为简单,在这里不做分析,对ioctl函数的实现做一个简单的分析:

(5) .ioctl   =   x210_pwm_ioctl分析:
 

static int x210_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	switch (cmd) 
	{
		case PWM_IOCTL_SET_FREQ:
			printk("PWM_IOCTL_SET_FREQ:\r\n");
			if (arg == 0)
				return -EINVAL;
			PWM_Set_Freq(arg);
			break;

		case PWM_IOCTL_STOP:
		default:
			printk("PWM_IOCTL_STOP:\r\n");
			PWM_Stop();
			break;
	}

	return 0;
}

首先说一下x210_pwm_ioctl()函数如何使用:

打开:x210_pwm_ioctl(fd,"/dev/buzzer",PWM_IOCTL_SET_FREQ,xxx),xxx是你欲设置的输出频率;

关闭:x210_pwm_ioctl(fd,"/dev/buzzer",PWM_IOCTL_STOP)。

ioctl函数在驱动中实现之后会提供给应用开发者使用,那么为了减少应用开发者的麻烦,驱动这里将对ioctl函数中原本控制设备工作、静止的数字变量宏定义为一个直观的变量:

#define PWM_IOCTL_SET_FREQ		1
#define PWM_IOCTL_STOP			0

这样应用开发者就可以更清楚这个函数如何操作硬件。

而根据函数的使用方法,由结果,我们接着对代码的实现进行分析:

首先比较我们输入的参数,然后如果是PWM_IOCTL_SET_FREQ 则表示打开,然后调用PWM_Set_Freq(arg)将频率设置为我们设定的参数,如果是PWM_IOCTL_STOP或者一个无效的参数,则将设备进行关闭。

回到入口函数dev_init()中继续分析

 

(6)设置buzzer的硬件相关的输出模式:

ret = gpio_request(S5PV210_GPD0(2), "GPD0");
	if(ret)
		printk("buzzer-x210: request gpio GPD0(2) fail");
		
	s3c_gpio_setpull(S5PV210_GPD0(2), S3C_GPIO_PULL_UP);
	s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(1));
	gpio_set_value(S5PV210_GPD0(2), 0);

先向gpiolib申请gpio口,然后将其设置为上拉模式,输出模式,输出值为0,也就是一开始将其设置为静止。

到这里buzzer设备驱动的分析基本完成,下面对一开始说的信号量进行一个分析:

 

(7)对信号量的使用进行分析:

init_MUTEX(&lock);
static struct semaphore lock;
struct semaphore {
	spinlock_t		lock;
	unsigned int		count;
	struct list_head	wait_list;
};

lock表示信号,count表示信号量的计数次数,wait_list表示如果信号量阻塞等待时将其放在一个链表中。

以上是对信号量定义的一个追踪,而真正对信号量的使用是在几个open、release函数中间接使用:

①对信号量进行申请,也就是上锁。

extern void down(struct semaphore *sem);

②释放信号量,也就是解锁。

extern void up(struct semaphore *sem);

 

值得注意的是:这两个函数的返回值都是void类型的,因为down、up操作肯定是是成功才能返回的,所以不需要再用返回值来标识情况,而其余的几个操作的函数返回值都是int类型的,不同的返回值代表不同的执行情况。

③阻塞等待申请信号量时可以被其他的信号量打断:

extern int __must_check down_interruptible(struct semaphore *sem);

④阻塞等待申请信号量,过程中可以被杀死:

extern int __must_check down_killable(struct semaphore *sem);

⑤非阻塞形式实现阻塞等待,当申请时如果申请不到,则返回错误,这也是此设备open时使用的方法:

extern int __must_check down_trylock(struct semaphore *sem);
static int x210_pwm_open(struct inode *inode, struct file *file)
{
	if (!down_trylock(&lock))
		return 0;
	else
		return -EBUSY;
	
}

这也保证了设备不会被重复打开,重复使用。

⑥超时机制的阻塞等待,在规定的时间内进行阻塞等待,超时不再等待:

extern int __must_check down_timeout(struct semaphore *sem, long jiffies);

 

2.驱动的出口:

static void __exit dev_exit(void)
{
	misc_deregister(&misc);
}

驱动的出口很是简单,只是调用一个misc_deregister(&misc);函数,而函数的内部替我们完成了很多的回收,销毁工作。

 

写在最后:驱动的分析不能从头到尾进行分析,此篇博文的分析过程是一个比较合适、正确的分析流程,大家可以借鉴参考。

End。。。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值