linux驱动开发:平台设备驱动框架
2016-10-30 23:40
507 查看
有一定的mcu51基础或者其他类似芯片基础的人大概都听说过IIC,SPI,IIS,USB,PCIe,CAN等总线。这些都是实实在在存在的总线。上面可以挂接遵循其协议的一个或多个设备。
linux内核自己虚拟地构建了一个称作platform的平台总线,对应的可以在其下面挂载平台设备和平台驱动。这是一条虚拟的总线。
紧接上上一篇的input子系统,我们将上一个例子做成挂载在平台总线下的设备和驱动,以此来简单的了解平台设备驱动框架的实现原理和步骤。
头文件:
平台设备文件:
平台驱动:
1.当驱动,设备没有问题时,会在sys/bus/platform下面的devices和drivers目录下找到我们创建的对应的设备和驱动文件。我们的设备和驱动都叫做p_buttons。
2.安装模块成功后,如果驱动写的没有问题,最后会调用驱动的probe函数.
3.调用测试程序,测试驱动是否动作正常.
4.测试模块的安装,卸载动作是否正常。
整个例子就是这样,下一篇将会大概介绍下整个流程和原理
linux内核自己虚拟地构建了一个称作platform的平台总线,对应的可以在其下面挂载平台设备和平台驱动。这是一条虚拟的总线。
紧接上上一篇的input子系统,我们将上一个例子做成挂载在平台总线下的设备和驱动,以此来简单的了解平台设备驱动框架的实现原理和步骤。
头文件:
#define _HIGH 1 #define _LOW 0 #define _ZERO 0 enum button_event { _EV_UP, _EV_DOWN, }; struct gpio_buttons { int gpio; // gpio num int code; // key code char *desc;//gpio description };
平台设备文件:
#include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <linux/input.h> #include <linux/interrupt.h> #include <linux/platform_device.h> #include <mach/gpio.h> #include <linux/gpio.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/slab.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/irq.h> #include <asm/bitops.h> #include "gpio_buttons.h" void gpio_buttons_release(struct device * dev); /******* void *platform_data; Platform specific data, device ****/ static struct gpio_buttons gpio_buttons_data[] = { { .gpio =S5PV210_GPH2(0), .code =KEY_LEFT, .desc ="LEFT", }, { .gpio =S5PV210_GPH2(1), .code =KEY_RIGHT, .desc ="RIGHT", }, { .gpio =S5PV210_GPH2(2), .code =KEY_UP, .desc ="UP", }, { .gpio =S5PV210_GPH2(3), .code =KEY_DOWN, .desc ="DOWN", }, { .gpio =S5PV210_GPH3(0), .code =KEY_MENU, .desc ="MENU", }, { .gpio =S5PV210_GPH3(1), .code =KEY_ENTER, .desc ="ENTER", }, { .gpio =S5PV210_GPH3(2), .code =KEY_BACKSPACE, .desc ="BACKSPACE", }, { .gpio =S5PV210_GPH3(3), .code =KEY_DELETE, .desc ="DELETE", }, }; /******* struct resource *resource; *****/ static struct resource butttons_resource[] = { { .start =IRQ_EINT(16), .end =IRQ_EINT(16), .flags =IORESOURCE_IRQ,//resource type }, { .start =IRQ_EINT(17), .end =IRQ_EINT(17), .flags =IORESOURCE_IRQ,//resource type }, { .start =IRQ_EINT(18), .end =IRQ_EINT(18), .flags =IORESOURCE_IRQ,//resource type }, { .start =IRQ_EINT(19), .end =IRQ_EINT(19), .flags =IORESOURCE_IRQ,//resource type }, { .start =IRQ_EINT(24), .end =IRQ_EINT(24), .flags =IORESOURCE_IRQ,//resource type }, { .start =IRQ_EINT(25), .end =IRQ_EINT(25), .flags =IORESOURCE_IRQ,//resource type }, { .start =IRQ_EINT(26), .end =IRQ_EINT(26), .flags =IORESOURCE_IRQ,//resource type }, { .start =IRQ_EINT(27), .end =IRQ_EINT(27), .flags =IORESOURCE_IRQ,//resource type }, }; static struct platform_device buttons_dev = { .name ="p_buttons", .resource =butttons_resource, .num_resources =ARRAY_SIZE(butttons_resource), .dev = { .platform_data =gpio_buttons_data, .release =gpio_buttons_release, }, }; /*******func release: void (*release)(struct device *dev)*****/ void gpio_buttons_release(struct device * dev) { printk("enter gpio_buttons_release.\n"); } int __init buttons_dev_init(void) { platform_device_register(&buttons_dev); return 0; } void __exit buttons_dev_exit(void) { platform_device_unregister(&buttons_dev); } module_init(buttons_dev_init); module_exit(buttons_dev_exit); MODULE_LICENSE("GPL");
平台驱动:
#include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <linux/input.h> #include <linux/interrupt.h> #include <linux/platform_device.h> #include <mach/gpio.h> #include <linux/gpio.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/slab.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/irq.h> #include <asm/bitops.h> #include "gpio_buttons.h" /*****irq use****/ volatile static struct gpio_buttons *g_buttons_desc_info = NULL; /*****input device use****/ static struct input_dev *buttons_input_dev =NULL; /*****timer use****/ static struct timer_list buttons_timer; /******button irq******/ static irqreturn_t smart210_buttons_irq(int irq, void* dev_id) { //get whitch key trigger the irq g_buttons_desc_info =(volatile struct gpio_buttons *)dev_id; //Eliminate key jitter,delay 10 ms to get key value mod_timer(&buttons_timer,jiffies + HZ/100); return IRQ_HANDLED; } /******timer del func******/ static void buttons_timer_func(unsigned long data) { int uc_keysta =0; struct gpio_buttons *uc_buttons_desc =(struct gpio_buttons *)g_buttons_desc_info; if(!uc_buttons_desc) { return; } //get the pin level :high /low //pree up 0,pree down 1 if(gpio_get_value(uc_buttons_desc->gpio) == _HIGH) { uc_keysta =_EV_UP; } else { uc_keysta =_EV_DOWN; } input_event(buttons_input_dev,EV_KEY, uc_buttons_desc->code,uc_keysta); input_event(buttons_input_dev,EV_SYN, SYN_REPORT,_ZERO); } /*******int (*probe)(struct platform_device *) *******/ static int buttons_probe(struct platform_device *pdev) { int i=0; int ret =0; struct resource *res =NULL; struct gpio_buttons *button_data = pdev->dev.platform_data; //1.alloc input dev device buttons_input_dev = input_allocate_device(); if (!buttons_input_dev) { ret = -ENOMEM; printk("1.error allocate input device!\n"); goto err_allocate_input_dev; } //2.set up the input dev param,Report event //EV_KEY :key event //EV_SYN: sync event set_bit(EV_KEY,buttons_input_dev->evbit); set_bit(EV_SYN,buttons_input_dev->evbit); set_bit(EV_REP,buttons_input_dev->evbit); //set EV_KEY key code for(i=0; i < pdev->num_resources;i++) { set_bit(button_data[i].code,buttons_input_dev->keybit); } //set input dev name buttons_input_dev->name = "buttons"; //3.register device ret = input_register_device(buttons_input_dev); if(ret) { printk("2.error to register input device!\n"); goto err_register_input_dev; } /******special func user add for different input device*********/ //4.irq request for(i=0; i < pdev->num_resources;i++) { res =platform_get_resource(pdev,IORESOURCE_IRQ,i); ret =request_irq(res->start,smart210_buttons_irq,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, button_data[i].desc,&(button_data[i])); if(ret) { break; } } if(ret) { i--; for(; i >0;i--) { if(!button_data[i].gpio) { continue; } res =platform_get_resource(pdev,IORESOURCE_IRQ,i); disable_irq(res->start); free_irq(res->start,&(button_data[i])); } printk("3.error to request irq !\n"); goto err_request_irq; } //5.timer initial init_timer(&buttons_timer); buttons_timer.function =buttons_timer_func; add_timer(&buttons_timer); printk("4.success driver probe func is ok !\n"); return 0; err_request_irq: input_unregister_device(buttons_input_dev); err_register_input_dev: err_allocate_input_dev: input_free_device(buttons_input_dev); return ret; return 0; } /*******int (*remove)(struct platform_device *)******/ static int buttons_remove(struct platform_device *pdev) { int i; struct resource *res =NULL; struct gpio_buttons *button_data = pdev->dev.platform_data; del_timer(&buttons_timer); for(i=0; i < pdev->num_resources;i++) { res =platform_get_resource(pdev,IORESOURCE_IRQ,i); disable_irq(res->start); free_irq(res->start,&(button_data[i])); } input_unregister_device(buttons_input_dev); input_free_device(buttons_input_dev); printk("5.success driver remove func is ok !\n"); return 0; } static struct platform_driver buttons_drv = { .probe = buttons_probe, .remove = buttons_remove, .driver = { .name = "p_buttons", }, }; int __init buttons_drv_init(void) { platform_driver_register(&buttons_drv); return 0; } void __exit buttons_drv_exit(void) { platform_driver_unregister(&buttons_drv); } module_init(buttons_drv_init); module_exit(buttons_drv_exit); MODULE_LICENSE("GPL");
1.当驱动,设备没有问题时,会在sys/bus/platform下面的devices和drivers目录下找到我们创建的对应的设备和驱动文件。我们的设备和驱动都叫做p_buttons。
2.安装模块成功后,如果驱动写的没有问题,最后会调用驱动的probe函数.
3.调用测试程序,测试驱动是否动作正常.
4.测试模块的安装,卸载动作是否正常。
整个例子就是这样,下一篇将会大概介绍下整个流程和原理
相关文章推荐
- Linux 网络设备驱动开发(三) —— 网络设备驱动基本原理和框架
- USB驱动开发之远程访问USB设备扩展(linux平台USB设备数据采集端)
- Linux下PCI设备驱动程序开发 --- linux 驱动框架(二)
- Linux平台下I2C设备驱动开发和实现
- linux驱动开发之字符设备框架 -调用过程分析
- Linux 网络设备驱动开发(三) —— 网络设备驱动基本原理和框架
- Linux下PCI设备驱动程序开发 --- linux 驱动框架(二)
- 嵌入式linux平台设备驱动(设备驱动模型)开发之linux内核中的设备驱动
- 嵌入式linux平台设备驱动(设备驱动模型)开发之linux内核中bus总线
- linux驱动开发之字符设备框架 - 实例
- Linux 网络设备驱动开发(三) —— 网络设备驱动基本原理和框架
- Linux下的硬件驱动——USB设备(下)(驱动开发部分)
- 嵌入式linux系统开发概述之四----设备驱动(Drivers)
- 设备驱动开发模拟框架
- Linux设备驱动开发概述
- Linux驱动程序开发(4) - 字符设备驱动(3)-LED设备驱动和应用程序
- Linux下的硬件驱动——USB设备(下)(驱动开发部分)
- Linux设备驱动开发详解--笔记3--Linux内核及内核编程
- Linux驱动程序开发 - 设备驱动模型初探
- linux设备驱动开发工具光盘第一版推出