博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(转载)驱动之路-platform按键驱动
阅读量:4982 次
发布时间:2019-06-12

本文共 9761 字,大约阅读时间需要 32 分钟。

一 、重要知识点:

1.platform设备模型

    从Linux 2.6起引入了一套新的驱动管理和注册机制,platform_device和platform_driver,Linux中大部分的设备驱动都可以使用这套机制。platform是一条虚拟的总线。设备用platform_device表示,驱动用platform_driver进行注册,Linux platform driver机制和传统的device driver机制(通过driver_register进行注册)相比,一个明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动中使用这些资源时通过platform device提供的标准结构进行申请并使用。这样提高了驱动和资源的独立性,并且具有较好的可移植性和安全性(这些标准接口是安全的)。

    pltform机制本身使用并不复杂,由两部分组成:platform_device和platform_driver。通过platform机制开发底层驱动的大致流程为:定义platform_deive->注册platform_device->定义platform_driver->注册platform_driver。

    首先要确认的就是设备的资源信息,例如设备的地址,中断号等。

1)platform_device

在 2.6 内核中 platform 设备用结构体 platform_device 来描述,该结构体定义在 kernel/include/linux/platform_device.h 中,

structplatform_device {

const char * name;

u32  id;

struct device dev;

u32  num_resources;

struct resource * resource;

};

该结构一个重要的元素是resource ,该元素存入了最为重要的设备资源信息,定义在kernel/include/linux/ioport.h 中,

structresource {

const char *name;//资源的名称

unsigned long start, end;//资源起始的和结束的物理地址

unsigned long flags;//资源的类型,比如MEM,IO,IRQ类型

struct resource *parent, *sibling, *child;//资源链表的指针

};

structplatform_device的分配使用

structplatform_device *platform_device_alloc(const char *name, int id)

name是设备名,id,设备id,一般为-1,如果是-1,表示同样名字的设备只有一个

举个简单的例子,name/id是“serial/1”则它的bus_id就是serial.1  如果name/id是“serial/0”则它的bus_id就是serial.0 ,如果它的name/id是“serial/-1”则它的bus_id就是serial。

注册平台设备,使用函数

intplatform_device_add(struct platform_device *pdev)

注销使用

voidplatform_device_unregister(struct platform_device *pdev)

2)platform_driver

在平台设备驱动中获取平台设备资源使用

structresource *platform_get_resource(struct platform_device *dev, unsigned int type,unsigned int num)

该函数用于获取dev设备的第num个类型为type的资源,如果获取失败,则返回NULL。例如 platform_get_resource(pdev,IORESOURCE_IRQ, 0)。

平台驱动描述使用

structplatform_driver {

int (*probe)(struct platform_device *);

int (*remove)(struct platform_device *);

void (*shutdown)(struct platform_device *);

int (*suspend)(struct platform_device *, pm_message_t state);

int (*suspend_late)(struct platform_device *, pm_message_t state);

int (*resume_early)(struct platform_device *);

int (*resume)(struct platform_device *);

struct device_driver driver;

};

Probe()函数必须验证指定设备的硬件是否真的存在,probe()可以使用设备的资源,包括时钟,platform_data等,Platform driver可以通过下面的函数完成对驱动的注册:

int platform_driver_register(structplatform_driver *drv);一般来说设备是不能被热插拔的,所以可以将probe()函数放在init段里面来节省driver运行时候的内存开销:

int platform_driver_probe(struct platform_driver *drv, int (*probe)(structplatform_device *));

注销使用void platform_driver_unregister(struct platform_driver *drv)

2.中断处理

在Linux驱动程序中,为设备实现一个中断包含 两个步骤1.向内核注册(申请中断)中断 2.实现中断处理函数

request_irq用于实现中断的注册

intrequest_irq(unsigned in irq, void(*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void*dev_id)

向内核申请中断号为irq,中断处理函数为handler指针指向的函数,中断标志为flag,设备名为devname的中断。成功返回0,或者返回一个错误码。

当request_irq不用于共享中断时,dev_id可以为NULL,或者指向驱动程序自己的私有数据。但用于共享中断时dev_id必须唯一。因为free_irq时也需要dev_id做参数,这样free_irq才知道要卸载共享中断上哪个中断服务处理函数。共享中断会在后面讲到。

在flag参数中,可以选以下参数

IRQF_DISABLED(SA_INTERRUPT)

如果设置该位,表示是一个“快速”中断处理程序,如果没有,那么就是一个“慢速”中断处理程序。

IRQF_SHARED(SA_SHITQ)

该位表示中断可以在设备间共享。

快速/慢速中断

这两种类型的中断处理程序的主要区别在于:快速中断保证中断处理的原子性(不被打断),而慢速中断则不保证。换句话说,也就是开启中断标志位在运行快速中断处理程序时

关闭的,因此在服务该中断时,不会被其他类型的中断打断;而调用慢速中断处理时,其他类型中断扔可以得到服务。

    共享中断

共享中断就是将不同的设备挂到同一个中断信号线上。linux对共享的支持主要是位PCI设备服务。

释放中断

voidfree_irq(unsigned int irq)

当设备不再需要使用中断时(通常是设备关闭和驱动卸载时),应该使用该函数把他们返回给内核使用。

禁用中断

voiddisable_irq(int irq)

当一些代码中不能使用中断时(如支持自旋锁的上下文中)使用该函数禁用中断。

启用中断

voidenable_irq(int irq)

当禁止后可以使用该函数重新启用。

 

 

二、驱动代码

 

  该驱动实现能够读取按键按下的键值,比如说如果是第一个键按下读取的键值就为1。

   platform平台设备

 

  • #include <linux/device.h> 
  • #include <linux/string.h> 
  • #include <linux/platform_device.h> 
  • #include <linux/module.h> 
  • #include <linux/kernel.h> 
  • #include <linux/fs.h> 
  • #include <linux/init.h> 
  • #include <linux/delay.h> 
  • #include <linux/poll.h> 
  • #include <linux/irq.h> 
  • #include <asm/irq.h> 
  • #include <linux/interrupt.h> 
  • #include <asm/uaccess.h> 
  • #include <mach/regs-gpio.h> 
  • #include <mach/hardware.h> 
  • #include <linux/cdev.h> 
  • #include <linux/miscdevice.h> 
  • #include <linux/sched.h> 
  • #include <linux/gpio.h> 
  •  
  • static struct resource key_resource[]= 
  • {    
  •     [0] = { 
  •         .start = IRQ_EINT8
  •         .end = IRQ_EINT8
  •         .flags = IORESOURCE_IRQ
  •     }, 
  •     [1] = { 
  •         .start = IRQ_EINT11
  •         .end = IRQ_EINT11
  •         .flags = IORESOURCE_IRQ
  •     }, 
  •     [2]= { 
  •         .start = IRQ_EINT13
  •         .end = IRQ_EINT13
  •         .flags = IORESOURCE_IRQ
  •     }, 
  •     [3] = { 
  •         .start = IRQ_EINT14
  •         .end = IRQ_EINT14
  •         .flags = IORESOURCE_IRQ
  •     }, 
  •     [4] = { 
  •         .start = IRQ_EINT15
  •         .end = IRQ_EINT15
  •         .flags = IORESOURCE_IRQ
  •     }, 
  •     [5] = { 
  •         .start = IRQ_EINT19
  •         .end = IRQ_EINT19
  •         .flags = IORESOURCE_IRQ
  •     }, 
  • }; 
  •  
  • struct platform_device *my_buttons_dev; 
  •  
  • static int __init platform_dev_init(void) 
  •     int ret; 
  •      
  •     my_buttons_dev = platform_device_alloc("my_buttons", -1); 
  •      
  •     platform_device_add_resources(my_buttons_dev,key_resource,6);//添加资源一定要用该函数,不能使用对platform_device->resource幅值 
  •                                                                 //否则会导致platform_device_unregister调用失败,内核异常。 
  •      
  •     ret = platform_device_add(my_buttons_dev); 
  •      
  •     if(ret) 
  •         platform_device_put(my_buttons_dev); 
  •      
  •     return ret; 
  •  
  • static void __exit platform_dev_exit(void) 
  •     platform_device_unregister(my_buttons_dev); 
  •  
  • module_init(platform_dev_init); 
  • module_exit(platform_dev_exit); 
  •  
  • MODULE_AUTHOR("Y-Kee"); 
  • MODULE_LICENSE("GPL"); 

 

 

platform平台驱动

  • //platform driver 
  • #include <linux/module.h> 
  • #include <linux/types.h> 
  • #include <linux/miscdevice.h> 
  • #include <linux/fs.h> 
  • #include <linux/init.h> 
  • #include <linux/platform_device.h> 
  • #include <linux/interrupt.h> 
  • #include <linux/clk.h> 
  • #include <linux/uaccess.h> 
  • #include <linux/io.h> 
  • #include <mach/map.h> 
  • #include <mach/regs-gpio.h> 
  • #include <linux/poll.h> 
  • #include <linux/irq.h> 
  • #include <asm/unistd.h> 
  • #include <linux/device.h> 
  •  
  •  
  • static int buttons_irq[6]; 
  •  
  • struct irq_des 
  •     int *buttons_irq; 
  •     char *name[6]; 
  • }; 
  •  
  •  
  • struct irq_des button_irqs = {  
  •     .buttons_irq = buttons_irq, 
  •     .name = {"KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5"}, 
  • }; 
  •  
  • static volatile int key_values; 
  •  
  •  
  • static DECLARE_WAIT_QUEUE_HEAD(button_waitq); 
  •  
  •  
  • static volatile int ev_press = 0
  •  
  •  
  • static irqreturn_t buttons_interrupt(int irq, void *dev_id) 
  •     int i; 
  •     for(i=0; i<6; i++){ 
  •         if(irq == buttons_irq[i]){ 
  •             key_values = i
  •             ev_press = 1
  •             wake_up_interruptible(&button_waitq);    
  •         } 
  •     } 
  •      
  •     return IRQ_RETVAL(IRQ_HANDLED); 
  •  
  •  
  • static int s3c24xx_buttons_open(struct inode *inode, struct file *file) 
  •     int i; 
  •     int err = 0
  •      
  •     for (i = 0; i <6; i++) { 
  •         err = request_irq(button_irqs.buttons_irq[i], buttons_interrupt, IRQ_TYPE_EDGE_BOTH,  
  •                           button_irqs.name[i], (void *)&button_irqs.buttons_irq[i]); 
  •         if (err) 
  •             break; 
  •     } 
  •  
  •     if (err) { 
  •         i--; 
  •         for (; i >= 0; i--) { 
  •         if (button_irqs.buttons_irq[i] <0) { 
  •         continue; 
  •         } 
  •         disable_irq(button_irqs.buttons_irq[i]); 
  •             free_irq(button_irqs.buttons_irq[i], (void *)&button_irqs.buttons_irq[i]); 
  •         } 
  •         return -EBUSY; 
  •     } 
  •      
  •     return 0; 
  •  
  •  
  • static int s3c24xx_buttons_close(struct inode *inode, struct file *file) 
  •     int i; 
  •      
  •     for (i = 0; i <6; i++) { 
  •     free_irq(button_irqs.buttons_irq[i], (void *)&button_irqs.buttons_irq[i]); 
  •     } 
  •  
  •     return 0; 
  •  
  •  
  • static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) 
  •     unsigned long err; 
  •  
  •     if (!ev_press) { 
  •     if (filp->f_flags & O_NONBLOCK) 
  •         return -EAGAIN; 
  •     else 
  •         wait_event_interruptible(button_waitq, ev_press); 
  •     } 
  •      
  •     ev_press = 0
  •  
  •     err = copy_to_user(buff, (const void *)&key_values, min(sizeof(key_values), count)); 
  •  
  •     return err ? -EFAULT : min(sizeof(key_values), count); 
  •  
  • static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait) 
  •     unsigned int mask = 0
  •     poll_wait(file, &button_waitq, wait); 
  •     if (ev_press) 
  •         mask |= POLLIN | POLLRDNORM; 
  •     return mask; 
  •  
  •  
  • static struct file_operations dev_fops = { 
  •     .owner   =   THIS_MODULE
  •     .open    =   s3c24xx_buttons_open
  •     .release =   s3c24xx_buttons_close,  
  •     .read    =   s3c24xx_buttons_read
  •     .poll    =   s3c24xx_buttons_poll
  • }; 
  •  
  • static struct miscdevice misc = { 
  •     .minor = MISC_DYNAMIC_MINOR
  •     .name = "my_buttons"
  •     .fops = &dev_fops, 
  • }; 
  •  
  •  
  • static int my_plat_probe(struct platform_device *dev) 
  •     int ret,i; 
  •     struct resource *plat_resource; 
  •     struct platform_device *pdev = dev; 
  •      
  •     printk("my platform dirver find my platfrom device.\n"); 
  •  
  •     for(i=0; i<6; i++){ 
  •         plat_resource = platform_get_resource(pdev,IORESOURCE_IRQ,i); 
  •         if(plat_resource == NULL) 
  •             return -ENOENT;  
  •         buttons_irq[i] = plat_resource->start; 
  •     } 
  •  
  •     ret = misc_register(&misc); 
  •     if(ret) 
  •         return ret; 
  •  
  •      
  •     return 0; 
  •  
  • static int my_plat_remove(struct platform_device *dev) 
  •     printk("my platfrom device has removed.\n"); 
  •     misc_deregister(&misc); 
  •     return 0; 
  •  
  • struct platform_driver my_buttons_drv = {  
  •     .probe = my_plat_probe
  •     .remove = my_plat_remove
  •     .driver = {  
  •         .owner = THIS_MODULE
  •         .name = "my_buttons"
  •     }, 
  • }; 
  •  
  • static int __init platform_drv_init(void) 
  •     int ret; 
  •  
  •     ret = platform_driver_register(&my_buttons_drv); 
  •      
  •     return ret; 
  •  
  • static void __exit platform_drv_exit(void) 
  •     platform_driver_unregister(&my_buttons_drv); 
  •  
  • module_init(platform_drv_init); 
  • module_exit(platform_drv_exit); 
  •  
  • MODULE_AUTHOR("Y-Kee"); 
  • MODULE_LICENSE("GPL"); 

测试代码

  • /* 
  • *      Buttons Example for Matrix V 
  • *      Copyright (C) 2004 capbily - friendly-arm 
  • *  capbily@hotmail.com 
  • */ 
  • #include <stdio.h> 
  • #include <stdlib.h> 
  • #include <unistd.h> 
  • #include <sys/ioctl.h> 
  • #include <sys/types.h> 
  • #include <sys/stat.h> 
  • #include <fcntl.h> 
  • #include <sys/select.h> 
  • #include <sys/time.h> 
  • #include <errno.h> 
  •  
  • int main(void) 
  •     int buttons_fd; 
  •     int key_value; 
  •  
  •     buttons_fd = open("/dev/buttons", 0); 
  •     if (buttons_fd <0) { 
  •         perror("open device buttons"); 
  •         exit(1); 
  •     } 
  •  
  •     for (;;) { 
  •         fd_set rds; 
  •         int ret; 
  •  
  •         FD_ZERO(&rds); 
  •         FD_SET(buttons_fd, &rds); 
  •  
  •         ret = select(buttons_fd + 1, &rds, NULL, NULL, NULL); 
  •         if (ret <0) { 
  •             perror("select"); 
  •             exit(1); 
  •         } 
  •         if (ret == 0) { 
  •             printf("Timeout.\n"); 
  •         } else if (FD_ISSET(buttons_fd, &rds)) { 
  •             int ret = read(buttons_fd, &key_value, sizeof key_value); 
  •             if (ret != sizeof key_value) { 
  •                 if (errno != EAGAIN) 
  •                     perror("read buttons\n"); 
  •                 continue; 
  •             } else { 
  •                 printf("buttons_value: %d\n", key_value+1); 
  •             } 
  •                  
  •         } 
  •     } 
  •  
  •     close(buttons_fd); 
  •     return 0; 

测试结果:

运行测试程序后按下第二个键,中断上打印了多次按键的键值,产生原因是因为按键抖动。导致按一下按键,产生多次中断。

转载于:https://www.cnblogs.com/hello2mhb/articles/3319519.html

你可能感兴趣的文章
es6-module
查看>>
(一)MapReduce篇之InputFormat,InputSplit,RecordReader(转)
查看>>
HTTP之Response状态码
查看>>
Mac如何使用git以及github
查看>>
mysql如何利用Navicat 导出和导入数据库
查看>>
Java正则表达式(一)、抓取网页email地址实例
查看>>
网络_01 基本配置
查看>>
【原创】关于oracle11G空表无法导出问题的解决方法
查看>>
16进制的简单运算
查看>>
速读《Javascript模式》(一)(简介、var的变量提升以及es6新规范的let)
查看>>
DM8168集成图像算法
查看>>
GDI编程小结
查看>>
nalply/crtmpserver
查看>>
jquery 遍历节点
查看>>
工具选择
查看>>
(转)C#实现RSA非对称加密解密
查看>>
迅为iTOP-4412开发板-Android4.4-固定MAC
查看>>
centos下,安装MySQL以及配置远程连接等
查看>>
获取硬盘和CPU的序列号
查看>>
Python全栈开发 day2 - 数据类型详解
查看>>