linux驱动之input子系统及分层/分离设计实例按键驱动

之前介绍过linux驱动的分层/分离思想,这里写个简单的例子。

 

按键处理在linux内核中有做好的驱动,可以利用输入子系统模块,所以驱动只需写硬件相关的就行,比如中断向量号、IO口、管脚数量等等即可;

 

本代码使用input子系统,另外采用platform总线,将硬件相关的驱动分成两部分,一部分是platformdevice相关的,另一部分是platformdriver相关的部分,其实整个驱动也就是写这两部分,至于驱动接收到按键中断怎么处理这个事件,只需往input子系统发送事件即可,事件处理/解析完全有子系统做;

具体的流程是:

    1、在platformdevice里面设置好io口中断号等信息,然后注册;

    2、在platformdriver里面注册platformdriver结构体

    3、初始化probe函数,分配inputdevice结构

    4、填充需要实现的事件类型及事件信息

    5、注册inputdevice

    6、处理按键中断,编制中断服务程序

    7、在中断服务里面发送事件信息

platform_device 结构体内包含一个struct device结构体,在这个结构体中,主要是硬件相关的数据,期中有一项比较有意思,它是void类型的指针!说明可以自由转换成任意数据类型,比如自定义的结构体!这个在扩展驱动的时候很重要!

void        *platform_data;    /* Platform specific data, device

在系统自带的输入子系统里面,按键相关的事件处理,可以参考gpio_keys.h文件,在该文件内定义了一个gpio_keys_platform_data的结构体,这个结构体我们就可以赋值给上面那个万能的platform_data,然后再注册platformdevice的时候把这个数据传递给platformdriver那边进行处理;

简单的来看看gpio_keys_platform_data结构体:

struct gpio_keys_platform_data {
    struct gpio_keys_button *buttons;
    int nbuttons;
    unsigned int poll_interval;    /* polling interval in msecs -
                       for polling driver only */
    unsigned int rep:1;        /* enable input subsystem auto repeat */
    int (*enable)(struct device *dev);
    void (*disable)(struct device *dev);
    const char *name;        /* input device name */
};

可以看到,该结构体中还包含了一个专门为button定义的结构体,看看里面有什么信息

struct gpio_keys_button {
    /* Configuration parameters */
    unsigned int code;    /* input event code (KEY_*, SW_*) */
    int gpio;        /* -1 if this key does not support gpio */
    int active_low;
    const char *desc;
    unsigned int type;    /* input event type (EV_KEY, EV_SW, EV_ABS) */
    int wakeup;        /* configure the button as a wake-up source */
    int debounce_interval;    /* debounce ticks interval in msecs */
    bool can_disable;
    int value;        /* axis value for EV_ABS */
    unsigned int irq;    /* Irq number in case of interrupt keys */
};

粗劣看看可以知道包括引脚信息、中断号、名字描述、触发方式等等,我们写自己的按键程序的时候完全可以借用这个结构体,不需要自己另外定义一个结构体。

 

以下看看具体的代码:

本代码采用内核为3.4.2,编译链为4.3.2,主机为ubuntu12.04,开发板是JZ2440.

platformdevice:

#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/gpio_keys.h>

#include <asm/gpio.h>
#include <asm/io.h>




static buttondev_release ( struct device *dev );

static struct gpio_keys_button buttonkey[] =
{
    {
        .gpio             = S3C2410_GPF ( 0 ),
        .code             = KEY_L,
        .desc             = "s1",
        .active_low        = 1,
        .irq             = IRQ_EINT0,
    },

    {
        .gpio             = S3C2410_GPF ( 2 ),
        .code             = KEY_S,
        .desc             = "s2",
        .active_low     = 1,
        .irq             = IRQ_EINT2,
    },
    {
        .gpio             = S3C2410_GPG ( 3 ),
        .code             = KEY_ENTER,
        .desc             = "s3",
        .active_low     = 1,
        .irq             = IRQ_EINT11,
    },
    {
        .gpio             = S3C2410_GPG ( 11 ),
        .code             = KEY_LEFTSHIFT,
        .desc             = "s4",
        .active_low     = 1,
        .irq             = IRQ_EINT19,
    },

};
static struct gpio_keys_platform_data buttonkeydata =
{
    .buttons = buttonkey,
    .nbuttons = ARRAY_SIZE ( buttonkey ),
};

struct platform_device buttondev =
{
    .name         = "mybuttons",
    .id     = -1,

    .dev = {
        .release = buttondev_release,
        .platform_data = &buttonkeydata,
    },

};

static buttondev_release ( struct device *dev )
{

}

static int button_init ( void )
{
    printk("button dev init function running\n");
    platform_device_register ( &buttondev );
    return 0;
}

static void button_exit ( void )
{
    platform_device_unregister ( &buttondev );
}

module_init ( button_init );
module_exit ( button_exit );
MODULE_LICENSE ( "GPL" );

platformdriver:

#include <linux/module.h>
#include <linux/version.h>

#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/gpio_keys.h>

#include <asm/gpio.h>
#include <asm/io.h>



static int button_probe ( struct platform_device *dev );
static int button_remove ( struct platform_device *pdev );


static struct input_dev *iputdev;
static struct timer_list buttons_timer;
struct gpio_keys_button *irq_pd;

struct platform_driver buttondrv =
{
    .probe = button_probe,
    .remove = button_remove,
    .driver =
    {
        .name = "mybuttons",
        .owner = THIS_MODULE,
    },

};

static irqreturn_t buttons_irqhandler ( int irq, void *irqdev )
{
    irq_pd = ( struct gpio_keys_button * ) irqdev;
    mod_timer ( &buttons_timer, jiffies + HZ / 100 );
    return IRQ_RETVAL ( IRQ_HANDLED );
}
static void buttons_timer_function ( unsigned long data )
{
    struct gpio_keys_button *buttonkey = ( struct gpio_keys_button * ) irq_pd;

    u32 pinval;
    pinval = s3c2410_gpio_getpin ( buttonkey->gpio );

    if ( pinval )    
    {
        input_event ( iputdev, EV_KEY, buttonkey->code, 0 );
        input_sync ( iputdev );
    }
    else    
    {
        input_event ( iputdev, EV_KEY, buttonkey->code, 1 );
        input_sync ( iputdev );
    }
}

static int __devinit button_probe ( struct platform_device *dev )
{

    int i;
    struct gpio_keys_platform_data *platdata = ( struct gpio_keys_platform_data * ) dev->dev.platform_data;
    iputdev = input_allocate_device();
    iputdev->name = "mybutton";
    set_bit ( EV_KEY, iputdev->evbit );
    set_bit ( EV_REP, iputdev->evbit );
    set_bit ( KEY_L, iputdev->keybit );
    set_bit ( KEY_S, iputdev->keybit );
    set_bit ( KEY_ENTER, iputdev->keybit );

    input_register_device ( iputdev );
    init_timer ( &buttons_timer );
    buttons_timer.function = buttons_timer_function;
    add_timer ( &buttons_timer );

    for ( i = 0; i < platdata->nbuttons; i++ )
    {
        request_irq ( platdata->buttons[i].irq, buttons_irqhandler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, platdata->buttons[i].desc, &platdata->buttons[i] );
    }

    return 0;
}

static int button_remove ( struct platform_device *pdev )
{
    int i;
    struct gpio_keys_platform_data *platdata = pdev->dev.platform_data;

    for ( i = 0; i < platdata->nbuttons; i++ )
    {
        free_irq ( platdata->buttons[i].irq, &platdata->buttons[i] );
    }
    del_timer(&buttons_timer);
    input_unregister_device ( iputdev );
    input_free_device ( iputdev );
}

static int button_init ( void )
{
    platform_driver_register ( &buttondrv );

    return 0;
}


void button_exit ( void )
{
    platform_driver_unregister ( &buttondrv );

}

module_init ( button_init );
module_exit ( button_exit );
MODULE_LICENSE ( "GPL" );

 

posted @ 2017-08-25 22:03  迷途小菜鸟  阅读(723)  评论(0编辑  收藏  举报