驱动之路之platform按键驱动

 一 、重要知识点:

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

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

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

在 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)

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

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

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

sta     ti   c 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;

sta  TI c 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;

}

sta  TI c 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");

#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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;}sta  TI c 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

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

sta  TI c 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_W     AI   T_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,     mi   n(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 platf     rom   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");

//platform driver#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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;elsewait_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

#include

#include

#include

#include

#include

#include

#include

#include

#include

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;

}

/** Buttons Example for Matrix V** Copyright (C) 2004 capbily - friendly-arm*capbily@hotmail.com*/#include #include #include #include #include #include #include #include #include #include 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;}

 驱动之路之platform按键驱动_设计制作_RF/无线

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



84
5
0
47

相关资讯

  1. 1、《小小军团合战三国》新春有礼虎符在手得天下673
  2. 2、30级剧情任务《新葵花宝典》新手的进阶之路2008
  3. 3、《剑与魔法》跨服3V3竞技赛巅峰决战将要一触即发3936
  4. 4、《螺旋境界线》1.7版本上线男主大变脸567
  5. 5、小宇宙爆发《不服小天王》宝宝七大技曝光4822
  6. 6、《三生萌唐录》深不可测无底洞门派介绍321
  7. 7、春风拂槛露华浓《熹妃Q传》时装制作功能介绍3979
  8. 8、《百万曹操传》曹操也结义安卓公测版本揭秘499
  9. 9、《无尽大冒险》潮人奶爸来袭以弱打强有秘诀2339
  10. 10、人靠衣装马靠鞍《北凉悍刀行》装备系统介绍3793
全部评论(0)
我也有话说
0
收藏
点赞
顶部