基于平台总线的按键设备驱动
2018-02-10 00:20
281 查看
平台总线
将设备和驱动分离开来,便于移植,提供设备与驱动的匹配。
设备模块的程序
驱动模块程序
应用程序
运行结果
————————————
2018.02.10
0:20
将设备和驱动分离开来,便于移植,提供设备与驱动的匹配。
设备模块的程序
/*Copyright (c) 2018 Caokaipeng,All rights reserved.*/ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/interrupt.h> //定义key的控制寄存器 #define GPNCON 0x7f008830 //定义资源 struct resource key_resource[] = { [0] = { //基地址->控制寄存器和数据寄存器 .start = GPNCON, .end = GPNCON+4, .flags = IORESOURCE_MEM, }, [1] = { //中断号 .start = IRQ_EINT(0), .end = IRQ_EINT(1), .flags = IORESOURCE_IRQ, }, }; //定义一个平台设备 struct platform_device key_dev ={ .name = "my_key", .id = 0, .num_resources = 2, .resource = key_resource, }; int keydev_init() { //平台设备的注册 platform_device_register(&key_dev); } void keydev_exit() { //平台设备的注销 platform_device_unregister(&key_dev); } MODULE_LICENSE("GPL"); MODULE_AUTHOR("CaoKaipeng"); MODULE_DESCRIPTION("Platform_bus driver"); MODULE_VERSION("V1.0"); module_init(keydev_init); module_exit(keydev_exit);
驱动模块程序
/*Copyright (c) 2018 Caokaipeng,All rights reserved.*/ #include <linux/module.h> #include <linux/init.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/slab.h> //kmalloc函数需要 #include <asm/uaccess.h> //copy_to_user函数需要 #include <linux/sched.h> #include <linux/platform_device.h> //按键编号 unsigned int key_num = 0; //定义下半部工作 struct work_struct *work1; //定义一个定时器 struct timer_list key_timer; //定义一个等待队列 wait_queue_head_t key_wait_queue; //定义一个resource_irq struct resource *res_irq; //定义一个resource_mem struct resource *res_mem; //控制寄存器虚拟地址 unsigned int *key_base; //work1具体执行的函数 void work1_func() { //启动定时器 mod_timer(&key_timer,jiffies + HZ/10); //HZ为1秒 } //定时器的超时函数 void key_timer_func(unsigned long data) { //数据寄存器第0位的读取值 unsigned int key1_val; //数据寄存器第1位的读取值 unsigned int key2_val; //check key1是否仍然按下 key1_val = readl(key_base+1)&0x01; if(0 == key1_val){ //按下为低电平 key_num = 1; } else{ //do nothing } //check key2是否仍然按下 key2_val = readl(key_base+1)&0x02; if(0 == key2_val){ //按下为低电平 key_num = 2; } else{ //do nothing } //唤醒队列中进程 wake_up(&key_wait_queue); } //中断处理函数 irqreturn_t key_interrupt(int irq, void *dev_id) { //1.检测是否发生了按键中断 //->没有采用共享中断,此步骤略 //2.清除已经发生的按键中断 //->处理器级别,cpu会进行清除,此步骤略 //3.提交下半部工作到默认工作队列处理 schedule_work(work1); return IRQ_HANDLED; } //硬件(key)初始化函数 void key_hw_init() { //控制寄存器的读取值 unsigned int data; //读取控制寄存器的值 data = readl(key_base); //打印GPNCON寄存器设定前的值 printk(KERN_WARNING"Set_before,GPNCON = 0x%x.\n",data); //对控制寄存器进行设定,设定GPF0为中断模式 data &= ~0b1111; //寄存器01位设定为00->KEY1对应GPN0,23位设定为00->KEY2对应GPN1 data |= 0b1010; //寄存器01设定为10,23位设定为10 //打印GPNCON寄存器设定后的值 printk(KERN_WARNING"Set_after,GPNCON = 0x%x.\n",data); writel(data,key_base); } //open设备操作 int key_open(struct inode *node, struct file *filp) { return 0; } //read设备操作 ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos) { //判断是否进入等待队列,condition为key_num wait_event(key_wait_queue,key_num); //已经唤醒 printk(KERN_WARNING"in kernel,key_num = %d.\n",key_num); //将数据copy to APP copy_to_user(buf,&key_num,4); //清空数据 key_num = 0; return 4; } //定义并初始化file_operations struct file_operations key_fops = { .open = key_open, .read = key_read, }; //定义并初始化miscdevice结构体 struct miscdevice key_miscdev = { .minor = 200, .name = "key", .fops = &key_fops, }; //定义probe函数 int __devinit key_probe(struct platform_device *pdev) { int ret; int size; //注册miscdevice(混杂设备) ret = misc_register(&key_miscdev); if(ret != 0){ printk(KERN_WARNING"register key_misc fail.\n"); } //获取中断号 res_irq = platform_get_resource(pdev,IORESOURCE_IRQ,0); //注册中断->GPN0对应中断号IRQ_EINT(0) request_irq(res_irq->start,key_interrupt,IRQF_TRIGGER_FALLING,"key",0); //注册中断->GPN1对应中断号IRQ_EINT(1) request_irq(res_irq->end,key_interrupt,IRQF_TRIGGER_FALLING,"key",0); //获取基地址 res_mem = platform_get_resource(pdev,IORESOURCE_MEM,0); size = res_mem->end - res_mem->start +1; key_base = ioremap(res_mem->start,size); //硬件初始化 key_hw_init(); //创建工作1 work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL); //分配空间 INIT_WORK(work1,work1_func); //初始化定时器 init_timer(&key_timer); //设置超时函数 key_timer.function = key_timer_func; //注册定时器 add_timer(&key_timer); //初始化等待队列 init_waitqueue_head(&key_wait_queue); return ret; } //定义remove函数 int __devinit key_remove(struct platform_device *pdev) { //注销miscdevice misc_deregister(&key_miscdev); //注销中断 free_irq(IRQ_EINT(0),0); } //定义一个平台驱动 struct platform_driver key_drv = { .probe =key_probe , .remove = key_remove, .driver = { .name = "my_key", }, }; static int button_init() { //注册平台驱动 return platform_driver_register(&key_drv); } static void button_exit() { //注销平台驱动 platform_driver_unregister(&key_drv); } MODULE_LICENSE("GPL"); MODULE_AUTHOR("CaoKaipeng"); MODULE_DESCRIPTION("Key driver"); MODULE_VERSION("V1.0"); module_init(button_init); module_exit(button_exit);
应用程序
/*Copyright (c) 2018 Caokaipeng. All rights reserved.*/ #include <stdio.h> #include <stdlib.h> int main() { int fd; //文件指针 int key_num; //按键编号 //1.打开设备 fd = open("/dev/6410key",0); if(fd<0){ printf("Open device error!\n"); } //2.读取设备 read(fd,&key_num,4); printf("key_num is %d.\n",key_num); //3.关闭设备 close(fd); }
运行结果
————————————
2018.02.10
0:20
相关文章推荐
- 基于platform总线的中断(按键)字符设备驱动设计
- 基于platform总线的中断(按键)字符设备驱动设计
- 基于platform总线的中断(按键)字符设备驱动设计
- 基于platform总线的中断(按键)字符设备驱动设计
- 平台总线设备驱动模型——代码分析
- 基于ARM9开发板的按键字符设备驱动实现
- linux平台总线驱动设备模型之点亮LED
- android平台按键驱动[基于x210开发板]
- Linux平台总线驱动设备模型
- 设备模型(device-model)之平台总线(bus),驱动(driver),设备(device)
- 基于ARM9开发板的按键字符设备驱动实现(全集)
- linux中LCD设备驱动(4)——基于s3c6410平台
- 总线,设备,驱动(基于2.6.30.4内核的)
- 基于linux的虚拟平台设备驱动 led架构
- (平台)总线 设备 驱动
- 《网蜂A8实战演练》——6.Linux 平台总线驱动设备模型
- 总线设备驱动模型和平台设备模型
- Linux驱动开发———平台总线设备驱动
- SPI NOR 设备介绍(基于i.MX6Q平台,25VF016B型号) + SylixOS SPI总线框架
- Linux平台总线驱动设备模型