driver_分层分离机制

作者:杏彩彩票app下载

至于关于驱动装置模型相关概念请参见《Linux Device Drivers》等连锁书籍,和水源源码目录...Documentationdriver-model

分开分层机制

试验现象:在调控台打字与印刷开关值,而且经过开关调节相应的LED亮灭。

Linux Device Drivers [PDF] 下载见 http://www.linuxidc.com/Linux/2011-06/37778.htm

              app  

1.代码

归纳的话总线(bus),驱动(driver),设备(device)那三者之间的关联正是:驱动开垦者可以透过总线(bus)来将使得(driver)和配备(device)实行隔断,那样的裨益正是开荒者可以将相对平稳不改变的驱动(driver)独立起来,能够透过总线(bus)来桥接与之相配的装置(device)。设备(device)只供给提供与硬件相关的尾部硬件的配备,如io,中断等。


input_subsys_drv.c

platform.c 提供了三个平台总线(platform_bus),和挂号平台设备(platform_device)和平台驱动(platform_driver)的连锁接口,在这之中平台总线(platform_bus)已经编进内核,开拓者只须要提供平台设备(platform_device)和平台驱动(platform_driver)的有关代码就行了。

                input.c

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

在linux源码目录driversinputkeyboard下,提供了一个gpio_keys.c的阳台驱动(platform_driver),这几个正是一个简约地开关驱动,检查测验到开关状态,上报给输入子系统。

      (向应用层提供联合的接口)                 |      

#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>

所以,开辟者需求做的正是提供三个平台设备(platform_device),以向平台驱动(platform_driver)提供相关的硬件配置,如开关IO,中断号,开关码等等。

   |                        |                      |分层      

#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>

gpio_keys.c (不用别样改换)

buttons.c   --分离--      evdev.c             |   

struct pin_desc{
    int irq;
    char *name;
    unsigned int pin;
    unsigned int key_val;
};

/*
 * Driver for keys on GPIO lines capable of generating interrupts.
 *
 * Copyright 2005 Phil Blundell
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

(硬件相关)                  (纯软件)           |

struct pin_desc pins_desc[4] = {
    {IRQ_EINT0,  "S2", S3C2410_GPF0,  KEY_L},
    {IRQ_EINT2,  "S3", S3C2410_GPF2,  KEY_S},
    {IRQ_EINT11, "S4", S3C2410_GPG3,  KEY_ENTER},
    {IRQ_EINT19, "S5",  S3C2410_GPG11, KEY_LEFTSHIFT},
};

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

 

static struct input_dev *input_subsys_dev;
static struct pin_desc *irq_pd;
static struct timer_list buttons_timer;

#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>

分别:把“硬件相关”和“纯软件”分离开;

static irqreturn_t buttons_irq(int irq, void *dev_id)
{
    /* [cgw]: 按钮IO发生边沿中断时再度设置按期间隔
    * 用于按钮消抖
    */
    irq_pd = (struct pin_desc *)dev_id;
    buttons_timer.data = irq_pd->pin;
    mod_timer(&buttons_timer, jiffies+HZ/100);
    return IRQ_RETVAL(IRQ_HANDLED);
}

#include <asm/gpio.h>

支行:“硬件相关”和“纯软件”分别提升注册(input.c),提供联合的接口;每一层潜心于本人的政工;

static void buttons_timer_function(unsigned long data)
{
    struct pin_desc * pindesc = irq_pd;
    unsigned int pinval;

static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
{
    int i;
    /* [cgw]: 在gpio_keys_probe()中调用了request_irq(..., pdev),
    * 因此dev_id指向了platform_device *pdev,通过dev_id直接传递
    * platform_device *指针
    */
    struct platform_device *pdev = dev_id;
    /* [cgw]: 当platform_device 和 platform_driver匹配时,会通过
    * probe()传递platform_device进来。在注册platform_device时,
    * platform_device.dev.platform_data必需指向gpio_keys_platform_data *
    */
    struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
    /* [cgw]: probe()中已分配了一个struct input_dev,并通过platform_set_drvdata()
    * 设置platform_device->dev->driver_data = input;
    */
    struct input_dev *input = platform_get_drvdata(pdev);

 

    if (!pindesc)
        return;
       
    /* [cgw]: 获取开关IO状态 */
    pinval = s3c2410_gpio_getpin((unsigned int)data);

    /* [cgw]: 轮询pdata->nbuttons个按键 */
    for (i = 0; i < pdata->nbuttons; i++) {
        struct gpio_keys_button *button = &pdata->buttons[i];
        int gpio = button->gpio;
       
        /* [cgw]: 某些gpio爆发了中断 */
        if (irq == gpio_to_irq(gpio)) {
            /* [cgw]: 得到开关类型 */
            unsigned int type = button->type ?: EV_KEY;
            /* [cgw]: 获取开关状态 */
            int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low;
            /* [cgw]: 发送按钮事件 */
            input_event(input, type, button->code, !!state);
            /* [cgw]: 发送同步事件 */
            input_sync(input);
        }
    }

1.看一个例子linux-2.6.22.6/drivers/input/keyboard/gpio_keys.c

    /* [cgw]: 依照开关IO状态汇报按钮事件 */
    if (pinval)
    {
        /* [cgw]: 上报开关弹起 */
        input_report_key(input_subsys_dev, pindesc->key_val, 0);
        //input_sync(input_subsys_dev);
    }
    else
    {
        /* [cgw]: 上报开关按下 */
        input_report_key(input_subsys_dev, pindesc->key_val, 1);
        //input_sync(input_subsys_dev);
    }

    return IRQ_HANDLED;
}

 gpio_keys_init 入口函数里面注册一个平台驱动结构体;

    //printk("timer occur!n");
}

static int __devinit gpio_keys_probe(struct platform_device *pdev)
{
    /* [cgw]: 在gpio_keys_probe()中调用了request_irq(..., pdev),
    * 因此dev_id指向了platform_device *pdev,通过dev_id直接传递
    * platform_device *指针
    */
    struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
    struct input_dev *input;
    int i, error;

 static int __init gpio_keys_init(void)    {        

static int led_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
    printk("led event!n");
    printk("value: 0x%xn", value);

    /* [cgw]: 分配三个输入设备 */
    input = input_allocate_device();
    /* [cgw]: 分配战败 */
    if (!input)
        return -ENOMEM;

  return platform_driver_register(&gpio_keys_device_driver);//注册二个阳台驱动结构体;    

    /* [cgw]: 依照管用程序下发的LED调节事件
    * 亮灭LED
    */
    //if (code == SND_BELL) {
    if (code == LED_MUTE) {
        if (value == 0xAA) {
            /* [cgw]: 点亮 */
            s3c2410_gpio_setpin(S3C2410_GPF4, 0);
        } else if (value == 0xEE) {
            /* [cgw]: 熄灭 */
            s3c2410_gpio_setpin(S3C2410_GPF4, 1);
        }
       
        return 0;
    }

    /* [cgw]: 设置platform_device->dev->driver_data = input */
    platform_set_drvdata(pdev, input);

}

    return -1;
}

    /* [cgw]: 设置evdev.c帮助的风云类型 */
    input->evbit[0] = BIT(EV_KEY);
    /* [cgw]: 设置输入设备名,同platform_device的名字 */
    input->name = pdev->name;
    /* [cgw]:  */
    input->phys = "gpio-keys/input0";
    /* [cgw]: 设置输入设备dev的父节点为platform_device->dev */
    input->dev.parent = &pdev->dev;
   
    /* [cgw]: 设置输入设备总线类型,中间商,产品,版本 */
    input->id.bustype = BUS_HOST;
    input->id.vendor = 0x0001;
    input->id.product = 0x0001;
    input->id.version = 0x0100;

 

int input_subsys_open(struct input_dev *dev)
{
    int i, retval;

    /* [cgw]: 为pdata->nbuttons个按钮申请中断 */
    for (i = 0; i < pdata->nbuttons; i++) {
        struct gpio_keys_button *button = &pdata->buttons[i];
        /* [cgw]: 得到gpio对应的行车制动器踏板号 */
        int irq = gpio_to_irq(button->gpio);
        /* [cgw]: 获得开关类型 */
        unsigned int type = button->type ?: EV_KEY;

进入gpio_keys_device_driver:    

    /* [cgw]: 设置按钮IO为中断输入 */
    s3c2410_gpio_cfgpin(S3C2410_GPF0, S3C2410_GPF0_EINT0);
    s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
    s3c2410_gpio_cfgpin(S3C2410_GPG3, S3C2410_GPG3_EINT11);
    s3c2410_gpio_cfgpin(S3C2410_GPG11, S3C2410_GPG11_EINT19);

        /* [cgw]: 设置中断类型为一侧中断 */
        set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
        /* [cgw]: 申请中断,设置中断服务程序 */
        error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM,
                    button->desc ? button->desc : "gpio_keys",
                    pdev);
        if (error) {
            printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %dn",
                irq, error);
            goto fail;
        }

  struct platform_driver gpio_keys_device_driver = {      

    /* [cgw]: 设置LED IO为出口,起初为熄灭LED */
    s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);
    s3c2410_gpio_setpin(S3C2410_GPF4, 1);

        /* [cgw]: 设置evdev.c援助的开关码 */
        input_set_capability(input, type, button->code);
    }

    .probe      = gpio_keys_probe,      

    s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
    s3c2410_gpio_setpin(S3C2410_GPF5, 1);

    /* [cgw]: 注册一个输入设备 */
    error = input_register_device(input);
    /* [cgw]: 注册战败 */
    if (error) {
        printk(KERN_ERR "Unable to register gpio-keys input devicen");
        goto fail;
    }

    .remove     = __devexit_p(gpio_keys_remove),      

    s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
    s3c2410_gpio_setpin(S3C2410_GPF5, 1);

    return 0;

    .driver     = {              

    /* [cgw]: 为开关IO分配中断线 */
    for (i = 0; i < 4; i++)
    {
        retval = request_irq(pins_desc[i].irq, buttons_irq, IRQT_BOTHEDGE, pins_desc[i].name, &pins_desc[i]);
    }

 fail:
    /* [cgw]: 释放中断 */
    for (i = i - 1; i >= 0; i--)
        free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);
    /* [cgw]: 释放输入设备占用的内部存款和储蓄器 */
    input_free_device(input);

            .name   = "gpio-keys",      

    printk("input subsys open!n");

    return error;
}

    }    

    return 0;
}

static int __devexit gpio_keys_remove(struct platform_device *pdev)
{
    /* [cgw]: 在gpio_keys_probe()中调用了request_irq(..., pdev),
    * 因此dev_id指向了platform_device *pdev,通过dev_id直接传递
    * platform_device *指针
    */
    struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
    /* [cgw]: probe()中已分配了三个struct input_dev,并通过platform_set_drvdata()
    * 设置platform_device->dev->driver_data = input;
    */
    struct input_dev *input = platform_get_drvdata(pdev);
    int i;

  };

 

    /* [cgw]: 释放中断 */
    for (i = 0; i < pdata->nbuttons; i++) {
        int irq = gpio_to_irq(pdata->buttons[i].gpio);
        free_irq(irq, pdev);
    }

 关心gpio_keys_probe函数:       

static int input_subsys_init(void)
{
    /* [cgw]: 分配二个输入设备 */
    input_subsys_dev = input_allocate_device();
    input_subsys_dev->name = "input_subsys_dev";

    /* [cgw]: 注销输入设备 */
    input_unregister_device(input);

  input = input_allocate_device();//分配多少个input_dev结构 

    /* [cgw]: 设置协理的事件类型 */
    set_bit(EV_KEY, input_subsys_dev->evbit);
    //set_bit(EV_REP, input_subsys_dev->evbit);
   
    set_bit(EV_LED, input_subsys_dev->evbit);
    //set_bit(EV_SND, input_subsys_dev->evbit);

    return 0;
}

 

    /* [cgw]: 设置扶助的事件码 */
    set_bit(KEY_L, input_subsys_dev->keybit);
    set_bit(KEY_S, input_subsys_dev->keybit);
    set_bit(KEY_ENTER, input_subsys_dev->keybit);
    set_bit(KEY_LEFTSHIFT, input_subsys_dev->keybit);

struct platform_driver gpio_keys_device_driver = {
    .probe        = gpio_keys_probe,
    .remove        = __devexit_p(gpio_keys_remove),
    .driver        = {
        .name    = "gpio-keys",
    }
};

  1. 通过platform_driver_register函数,引入此外一个定义: bus_drv_dev模型(总线驱动装置模型)     

    set_bit(LED_MUTE, input_subsys_dev->ledbit);
    //set_bit(SND_BELL, input_subsys_dev->sndbit);

static int __init gpio_keys_init(void)
{
    /* [cgw]: 注册gpio_keys_device_driver平台驱动 */
    return platform_driver_register(&gpio_keys_device_driver);
}

  (1)bus总线也是三个结构体,里面满含:drv链表,dev链表,.match函数     

    /* [cgw]: 分配输入设备的open方法,顾客操作open(/dev/xxx, ...)时调用 */
    input_subsys_dev->open = input_subsys_open;
    /* [cgw]: 分配输入设备的event方法,客户在应用程序write()时 */
    input_subsys_dev->event = led_event;

static void __exit gpio_keys_exit(void)
{
    /* [cgw]: 注销gpio_keys_device_driver平台驱动 */
    platform_driver_unregister(&gpio_keys_device_driver);
}

  (2)device结构体(硬件相关):通过device_add函数把device归入bus总线的dev链表;然后从bus的drv链表中抽取各个driver结构体,用bus

    /* [cgw]: 注册输入设备 */
    input_register_device(input_subsys_dev);

module_init(gpio_keys_init);
module_exit(gpio_keys_exit);

的.match函数判别drv能或不可能支持dev,若援救则调用driver结构体的probe函数(probe是比较稳固的代码);     

    /* [cgw]: 开首化沙漏,用于按钮消抖 */
    init_timer(&buttons_timer);
    buttons_timer.function = buttons_timer_function;
    add_timer(&buttons_timer);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");

  (3)driver结构体:通过driver_register函数把driver结构体放入bus总线的drv链表;然后从bus总线的dev链表中抽取每贰个dev,通过.match函

    printk("input subsys init!n");
   
    return 0;
}

阳台设备(platform_device):
keys_dev.c

数一一比较判别dev是还是不是帮助drv,若帮助则调用driver结构体的probe函数(probe是比较稳固的代码);

static void input_subsys_exit(void)
{
    int i;

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

 上边3点,只不过是bus_drv_dev模型的一种体制;probe函数里面能够打字与印刷一句话可能注册三个字符设备大概注册input_dev结构体,完全由友好决

    /* [cgw]: 释放开关IO中断 */
    for (i = 0; i < 4; i++)
    {
        free_irq(pins_desc[i].irq, &pins_desc[i]);
    }

#include <linux/init.h>

定;这里只不过是一种体制,强制的分成了左右两侧,能够放在别的地点;大家修改硬件的时候,只修改硬件部分device,driver部分保持安澜;    

    /* [cgw]: 删除放大计时器 */
    del_timer(&buttons_timer);
    /* [cgw]: 注销输入设备 */
    input_unregister_device(input_subsys_dev);
    /* [cgw]: 释放输入设备内部存款和储蓄器空间 */
    input_free_device(input_subsys_dev);   
}

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/irq.h>

    3.目的:

module_init(input_subsys_init);

#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>

  采纳分离分层的思量编写本驱动程序,首要分为七个部分,与硬件操作相关的led_dev和对峙安静的led_drv;led_dev首要担当分配,设置,注册叁个阳台设

module_exit(input_subsys_exit);

/* [cgw]: 设置两个开关的键码,按钮io,激活状态,开关名,按钮类型 */
static struct gpio_keys_button keys_buff[4] = {
    {
        KEY_A,
        S3C2410_GPF0,
        1,
        "A",
        EV_KEY
    },
   
    {
        KEY_B,
        S3C2410_GPF2,
        1,
        "B",
        EV_KEY
    },

备结构体(platform_device),本程序的目标是想点亮一个led灯,就算调控其他四个led灯,只要求修改此驱动程序就可以兑现内需的意义;led_drv首要承担

MODULE_LICENSE("GPL");

    {
        KEY_C,
        S3C2410_GPG3,
        1,
        "C",
        EV_KEY
    },

分配,设置,注册叁个阳台驱动结构体(platform_drvier),首要承担挂号三个字符设备驱动程序,获取平台设备传来的财富音讯

input_subsys_test.c

    {
        KEY_D,
        S3C2410_GPG11,
        1,
        "D",
        EV_KEY
    },
};

 

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

static struct gpio_keys_platform_data keys_dev = {
    .buttons = &keys_buff[0],
    .nbuttons = ARRAY_SIZE(keys_buff)
};

代码:

#include <linux/input.h>

static void keys_dev_release(struct device * dev)
{
    printk("keys_dev_release! n");
}

led_dev.c

 

/* [cgw]: 分配贰个阳台设备 */
static struct platform_device keys_platform_dev = {
    .name        = "gpio-keys",
    .id          = -1,
    .dev = {
        .release = keys_dev_release,
        .platform_data = (void *)&keys_dev,
    },
};

/*----------------------------------------------*/

int fd;

static int keys_dev_init(void)
{
    /* [cgw]: 注册keys_platform_dev平台设备 */
    platform_device_register(&keys_platform_dev);
    return 0;
}

#include <linux/module.h>

void my_signal_fun(int signum)
{
    struct input_event buttons_event, leds_event;

static void keys_dev_exit(void)
{
    /* [cgw]: 注销keys_platform_dev平台设备 */
    platform_device_unregister(&keys_platform_dev);
}

#include <linux/version.h>

    /* [cgw]: 异步布告发出时重临的数据 */
    read(fd, &buttons_event, sizeof(struct input_event));

module_init(keys_dev_init);
module_exit(keys_dev_exit);

#include <linux/kernel.h>

    /* [cgw]: 打字与印刷事件类型,事件码,事件值 */
    printf("type: 0x%x code: 0x%x value: 0x%xn",
          buttons_event.type,
          buttons_event.code, 
          buttons_event.value);

MODULE_LICENSE("GPL");

#include <linux/types.h>

    /* [cgw]: 重返的是KEY_L或KEY_S值 */
    if (buttons_event.code == KEY_L || buttons_event.code == KEY_S) {
        /* [cgw]: 按钮弹起 */
        if (buttons_event.value == 0) {

行使测量试验程序:

#include <linux/interrupt.h>

            /* [cgw]: 构造一个EV_LED事件 */
           
            //leds_event.type = EV_SND;
            leds_event.type = EV_LED;
            //leds_event.code = SND_BELL;
            leds_event.code = LED_MUTE;

platform_test.c

#include <linux/list.h>

            /* [cgw]: KEY_L和KEY_S控制LED的亮灭 */
            if (buttons_event.code == KEY_L) {
                leds_event.value = 0xAA;
            } else if (buttons_event.code == KEY_S) {
                leds_event.value = 0xEE;   
            }

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

#include <linux/timer.h>

            /* [cgw]: 发送LED调整事件 */
            write(fd, &leds_event, sizeof(struct input_event));
           
            printf("led write!n");
        }
    }
}

#include <linux/input.h>

#include <linux/init.h>

int main(int argc, char **argv)
{
    int Oflags;

 

#include <linux/serial_core.h>

    /* [cgw]: 设置要求管理的连续信号SIGIO,即输入文件会呈请三个SIGIO
    * 实信号,当有新数据光临这么些时限信号会发给filp->f_owner进程
    */
    signal(SIGIO, my_signal_fun);
   
    fd = open("/dev/event1", O_RDWR | O_NONBLOCK);
   
    //printf("fd = 0x%xn", fd);
   
    if (fd < 0)
    {
        printf("can't open!n");
    }

int fd;

#include <linux/platform_device.h>

    /* [cgw]: 依照文件标志符fd,设置能够获取那些文件的长河(owner)
    * getpid()得到当前经过ID
    */
    fcntl(fd, F_SETOWN, getpid());

void my_signal_fun(int signum)
{
    struct input_event buttons_event;

 

    /* [cgw]: 获得file->f_flags标志 */
    Oflags = fcntl(fd, F_GETFL);
   
    /* [cgw]: 置位FASYNC使能异步通告 */
    fcntl(fd, F_SETFL, Oflags | FASYNC);

    /* [cgw]: 异步公告发出时回来的数据 */
    read(fd, &buttons_event, sizeof(struct input_event));

/*分配/设置/注册一个platform_device平台*/

    while (1)
    {
        /* [cgw]: 休眠 */
        sleep(1000);
    }
   
    return 0;
}

    /* [cgw]: 打字与印刷事件类型,事件码,事件值 */
    printf("type: 0x%x code: 0x%x value: 0x%xn",
          buttons_event.type,
          buttons_event.code, 
          buttons_event.value);
}

//该组织体存入了最为关键的设施能源音信,驱动程序通过相配后能够赢得硬件的能源

makefile

int main(int argc, char **argv)
{
    int ret, arg;
    struct pollfd fds[1];
    unsigned long ver = 0;

static struct resource led_resource[] = {

KERN_DIR = /work/system/linux-2.6.22.6

    fd = open("/dev/event1", O_RDWR | O_NONBLOCK);
   
    if (fd < 0)
    {
        printf("can't open!n");
    }

//寄存器最早地址,要是要换硬件存放器,只须求在此处修改就能够

all:
    make -C $(KERN_DIR) M=`pwd` modules

    ioctl(fd, EVIOCGVERSION, &ver);
    printf("Ver:0x%x n", ver);

  [0] = {          

clean:
    make -C $(KERN_DIR) M=`pwd` modules clean
    rm -rf modules.order

    /* [cgw]: 设置文件标记符 */
    fds[0].fd    = fd;
    /* [cgw]: 设置应用程序要响应的平地风波 */
    fds[0].events = POLLIN;

      .start = 0x56000050,            

obj-m    += input_subsys_drv.o

    while (1)
    {
        /* [cgw]: 休眠5S */
        ret = poll(fds, 1, 5000);
       
        /* [cgw]: 唤醒或超时 */
        //printf("wake up!n");
        if (ret == 0)
        {
            printf("time outn");
        }
        else
        {
            my_signal_fun(arg);
        }
    }

      .end   = 0x5五千050 + 8 - 1,//截至地址           

  1. 实验

    close(fd);
   
    return 0;
}

      .flags = IORESOURCE_MEM,//表示哪一类能源       

2.1

阳台设备(platform_device) keys_platform_dev 是什么样找到与之相配的阳台驱动(platform_driver) gpio_keys_device_driver的呢?

 },

安装驱动程序:

因为他们都注册到了平台总线(platform_bus)上。平台驱动(platform_driver)和平台设备(platform_device)会互相查找互相是还是不是相称,相称的条件就是,

  //哪根引脚,若是要换一个led亮,只要求修改上边包车型客车数字就可以  

insmod input_subsys_drv.ko

1 static int platform_match(struct device * dev, struct device_driver * drv)
2 {
3     struct platform_device *pdev = container_of(dev, struct platform_device, dev);
4 
5     return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
6 }

  [1] = {           

1 # insmod input_subsys_drv.ko
2 input: input_subsys_dev as /class/input/input1
3 input subsys open!
4 input subsys init!

platform_device->name == platform_driver->driver->name 即他们的名字正是:“gpio-keys”

       .start = 4,           

运维应用程序

假定相配,就能够调用

       .end   = 4,           

./input_subsys_test

static int platform_drv_probe(struct device *_dev)
{
    struct platform_driver *drv = to_platform_driver(_dev->driver);
    struct platform_device *dev = to_platform_device(_dev);

       .flags = IORESOURCE_I奥德赛Q,//描述的是暂停能源消息。设备驱动会基于flags来收获相应的财富新闻。       

# ./input_subsys_test
type: 0x1 code: 0x26 value: 0x1
type: 0x1 code: 0x26 value: 0x0
led event!
value: 0xaa
led write!
type: 0x11 code: 0x7 value: 0xaa
type: 0x1 code: 0x1f value: 0x1
type: 0x1 code: 0x1f value: 0x0
led event!
value: 0xee
led write!
type: 0x11 code: 0x7 value: 0xee

    return drv->probe(dev);
}

 }

  1. 气象剖判

drv->probe() = platform_driver->probe() = gpio_keys_probe()

};

按一下按钮KEY_L,终端输出:

这么平台驱动(platform_driver)就能够收获平台设备(platform_device)的 struct platform_device结构的多少了,即keys_platform_dev,从这一个结构就足以博得相关配置,以使能平台驱动(platform_driver) gpio_keys.c中相应的IO和制动踏板。

 

type: 0x1 code: 0x26 value: 0x1  //按键按下
type: 0x1 code: 0x26 value: 0x0  //按键弹起
led event!                       //应用程序操作write, 发送LED控制事件,调用led_event()
value: 0xaa                      //读到的LED亮的命令
led write!                       //返回应用程序继执行
type: 0x11 code: 0x7 value: 0xaa //因为应用程序发送了事件给驱动程序,驱动把这个事件作为一个输入事件(相当于按键输入事件),同样通过异步通知反馈到应用程序

试验现象:

static void led_release(struct device *dev){

 

# insmod gpio_keys.ko                     //安装平台驱动(platform_driver)
# insmod keys_dev.ko                      //安装平台设备(platform_device)
input: gpio-keys as /class/input/input1
# ./platform_test                         //运行应用测试程序
Ver:0x10000                               //用ioctl获取输入子系统的版本号
type: 0x1 code: 0x2e value: 0x1           //按下"C"键
type: 0x0 code: 0x0 value: 0x0            //因为调用了input_sync()
type: 0x1 code: 0x2e value: 0x0           //松开(弹起)"C"键
type: 0x0 code: 0x0 value: 0x0            //因为调用了input_sync()
type: 0x1 code: 0x30 value: 0x1           //... ...
type: 0x0 code: 0x0 value: 0x0
type: 0x1 code: 0x30 value: 0x0
type: 0x0 code: 0x0 value: 0x0
type: 0x1 code: 0x1e value: 0x1
type: 0x0 code: 0x0 value: 0x0
type: 0x1 code: 0x1e value: 0x0
type: 0x0 code: 0x0 value: 0x0
type: 0x1 code: 0x20 value: 0x1
type: 0x0 code: 0x0 value: 0x0
type: 0x1 code: 0x20 value: 0x0
type: 0x0 code: 0x0 value: 0x0
time out
time out
time out

 

图片 1

本文永恒更新链接地址:http://www.linuxidc.com/Linux/2016-10/136247.htm

}

The end!

图片 2

 

本文永恒更新链接地址:http://www.linuxidc.com/Linux/2016-10/136248.htm

static struct platform_device led_dev = {    

图片 3

  .name    = "myled",/*以此名字要和led_drv.c中的一样,设备name,通过此来相称platform_driver*/    

  .id     = -1,    

  .num_resources  = ARRAY_SIZE(led_resource),    

  .resource   = led_resource,    

  .dev    = {               

  .release = led_release,/*假若不提供此函数,在卸载模块时会报错*/        

      },

};

 

static int led_dev_init(void){

//platform_device_register→platform_device_add→device_add即把设备归入平台总线里的道具链表中去

//即加载lsmod led_dev.ko后,会调用driver的probe函数。   

 platform_device_register(&led_dev);

    return 0;

}

static void led_dev_exit(void){

/*    

 *    rmmod  led_dev模块后,调用此函数,而此函数会从bus总线的dev链表中寻找此设施,然后    

 *    去掉并根据match函数找到呼应的drv,然后调用里面(drv结构体)的remove函数做些    

 *     清理专门的工作  

 */

本文由杏彩发布,转载请注明来源

关键词: