符合input子系统的设备驱动之按键驱动(二)
作者:Bright-Ho
联系方式:836665637@qq.com
符合input子系统的设备驱动之按键驱动(二)
上一节,我们大概的回顾了裸板按键驱动的方法,这一节,我们继续回顾,不带input子系统的按键字符设备驱动是怎么实现的?
这里直接上流程:
(1)构造file_operstions结构;
static struct file_operations second_drv_fops = {
.owner = THIS_MODULE,
.open = second_drv_open,
.read = second_drv_read,
};
(2)注册设备驱动;
major = register_chrdev(0,"second_drv",&second_drv_fops);
(3)创建类,会在sys/class下生成;
class_create(THIS_MODULE,"seconddrv");
(4)在类下面创建设备;
class_device_create(seconddrv_class,NULL,MKDEV(major,0),NULL,"buttons");
(5)映射寄存器地址
gpfcon = (volatile unsigned long *)ioremap(0x56000050,16); gpfdat = gpfcon + 1;
gpgcon = (volatile unsigned long *)ioremap(0x56000060,16); gpgdat = gpgcon + 1;
(6).open = second_drv_open函数实现什么内容?
static int second_drv_open(struct inode *inode,struct file *file){
printk("second drv open\n");
/*配置GPF0,2为输入引脚*/
*gpfcon &= ~((3<<0) | (3<<4));
/*配置GPG3,11为输入引脚*/
*gpgcon &= ~((3<<6) | (3<<22));
return 0;
}
-
.read = second_drv_read函数实现什么内容?
static ssize_t second_drv_read(struct inode *inode, const char __user *buf, size_t count, loff_t * ppos){
31
32 //printk("second drv write\n");
33
34 /*返回 4个引脚的电平*/
35 unsigned char key_vals[4];
36 int vals;
37
38 if(count != sizeof(key_vals)){
39 return -EINVAL;
40 }
41
42 /*读取GPF0,2*/
43 vals = *gpfdat;
44 key_vals[0] = (vals & (1<<0)) ? 1 : 0;
45 key_vals[1] = (vals & (1<<2)) ? 1 : 0;
46
47 /*读取GPG3,11*/
48 vals = *gpgdat;
49 key_vals[2] = (vals & (1<<3)) ? 1 : 0;
50 key_vals[3] = (vals & (1<<11)) ? 1 : 0;
51
52 copy_to_user(buf,key_vals,sizeof(key_vals)); /*从内核空间把参数传给用户空间*/
54 return 0;
55 }
整体流程来看,就是构造一个file_operations结构,并实现open,read等驱动接口,把该结构注册进内核;然后MDEV机制产生设备节点以备应用程序访问;映射寄存器地址;
在open函数中:设置“控制寄存器”,把按键配置成输入引脚;
在read函数中:通过“数据寄存器”来获得按键值;并通过copy_to_user()函数把按键值传递给用户空间的buf;
这一节有个重要的问题:在内核空间访问寄存器为什么要先ioremap?
这里大概说一下原因,原因是有mmu,地址都重映射了,datesheet中查到的寄存器地址,直接访问是访问不到的.所以需要ioremap !! 在内核中操作的都是虚拟地址,内核访问不到物理地址,只能通过ioremap映射为虚拟地址 内核才能访问此内存空间;
那么至于他是怎么映射的以后有时间我们再深入分析研究!!!
下一节,我们就来实现设备层;