linux驱动开发:平台设备驱动框架

来源:互联网 发布:python编程 pdf 编辑:程序博客网 时间:2024/06/15 07:53

有一定的mcu51基础或者其他类似芯片基础的人大概都听说过IIC,SPI,IIS,USB,PCIe,CAN等总线。这些都是实实在在存在的总线。上面可以挂接遵循其协议的一个或多个设备。
linux内核自己虚拟地构建了一个称作platform的平台总线,对应的可以在其下面挂载平台设备和平台驱动。这是一条虚拟的总线。
紧接上上一篇的input子系统,我们将上一个例子做成挂载在平台总线下的设备和驱动,以此来简单的了解平台设备驱动框架的实现原理和步骤。

头文件:

#define _HIGH               1#define _LOW                0#define _ZERO                       0enum 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.测试模块的安装,卸载动作是否正常。

整个例子就是这样,下一篇将会大概介绍下整个流程和原理

0 0
原创粉丝点击