Chinaunix首页 | 论坛 | 博客
  • 博客访问: 35182
  • 博文数量: 5
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 22
  • 用 户 组: 普通用户
  • 注册时间: 2013-04-18 17:08
个人简介

嵌入式工程师

文章分类

全部博文(5)

文章存档

2015年(1)

2013年(4)

分类: LINUX

2013-08-09 09:36:15

下面的文章是基于mini2440的gpio按键来讲解input子系统。

mini2440为例,用该板的bsp文件,进行input子系统的讲解.所用的版本为android4.0.

先来看下板级支持文件都注册了那些资源。

下面是五个按键的资源:

#define KEY_POWER           116  /* SC System Power Down */

#define KEY_F1                   59

#define KEY_F2                   60

#define KEY_F3                   61

#define KEY_F5                   63

struct gpio_keys_button {

       /* Configuration parameters */

       unsigned int code;  /* input event code (KEY_*, SW_*) *///上报事件的code

       int gpio;//所用的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 */

};

static struct gpio_keys_button mini2440_buttons[] = {

       {

              .gpio              = S3C2410_GPG(0),            /* K1 */

              .code             = KEY_F1,

              .desc              = "Button 1",

              .active_low     = 1,

       },

       {

              .gpio              = S3C2410_GPG(3),            /* K2 */

              .code             = KEY_F2,

              .desc              = "Button 2",

              .active_low     = 1,

       },

       {

              .gpio              = S3C2410_GPG(5),            /* K3 */

              .code             = KEY_F3,

              .desc              = "Button 3",

              .active_low     = 1,

       },

       {

              .gpio              = S3C2410_GPG(6),            /* K4 */

              .code             = KEY_POWER,

              .desc              = "Power",

              .active_low     = 1,

       },

       {

              .gpio              = S3C2410_GPG(7),            /* K5 */

              .code             = KEY_F5,

              .desc              = "Button 5",

              .active_low     = 1,

       },

};

 

/*下面是平台数据的声明*/

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 */

};

static struct gpio_keys_platform_data mini2440_button_data = {

       .buttons   = mini2440_buttons,

       .nbuttons = ARRAY_SIZE(mini2440_buttons),

};

 

/*下面是平台设备的声明*/

struct platform_device {

       const char      * name;

       int           id;

       struct device   dev;

       u32         num_resources;

       struct resource       * resource;

 

       const struct platform_device_id    *id_entry;

 

       /* MFD cell pointer */

       struct mfd_cell *mfd_cell;

 

       /* arch specific additions */

       struct pdev_archdata     archdata;

};

static struct platform_device mini2440_button_device = {

       .name             = "gpio-keys",

       .id           = -1,

       .dev        = {

              .platform_data = &mini2440_button_data,

       }

};

 

static struct platform_device *mini2440_devices[] __initdata = {

       ...................

&mini2440_button_device,

       ………

};

 

static void __init mini2440_init(void)

{

       .............................

       platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));

       ……………

}

MACHINE_START(MINI2440, "MINI2440")

       /* Maintainer: Michel Pollet */

       .boot_params  = S3C2410_SDRAM_PA + 0x100,

       .map_io          = mini2440_map_io,

       .init_machine  = mini2440_init,

       .init_irq   = s3c24xx_init_irq,

       .timer             = &s3c24xx_timer,

MACHINE_END

上面是把该设备注册到平台总线上。

 

下面看下平台驱动的注册:

static struct platform_driver gpio_keys_device_driver = {

       .probe            = gpio_keys_probe,

       .remove          = __devexit_p(gpio_keys_remove),

       .driver            = {

              .name      = "gpio-keys",

              .owner    = THIS_MODULE,

       }

};

 

static int __init gpio_keys_init(void)

{

       return platform_driver_register(&gpio_keys_device_driver);

}

 

module_init(gpio_keys_init);

在注册平台驱动时,如果成功匹配平台设备后,会调用平台驱动的probe函数。

下面看下该驱动的probe函数。

static int __devinit gpio_keys_probe(struct platform_device *pdev)

{

       /*取出再bsp文件注册的平台数据*/

       struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;

 

       /*这里出现了一个新的结构体,该结构体定义如下*/

/*struct gpio_keys_drvdata {

       struct input_dev *input;

       struct mutex disable_lock;

       unsigned int n_buttons;

       int (*enable)(struct device *dev);

       void (*disable)(struct device *dev);

       struct gpio_button_data data[0];

};*/

       struct gpio_keys_drvdata *ddata;

       struct device *dev = &pdev->dev;

 

       struct input_dev *input;

 

       /*分配gpio_keys_drvdata结构体内存*/

       ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +

                     pdata->nbuttons * sizeof(struct gpio_button_data),

                     GFP_KERNEL);

 

       /*分配一个input结构体,并初始化部分成员*/

       input = input_allocate_device();

      

       /*ddata的各个成员变量赋值*/

       ddata->input = input;

       ddata->n_buttons = pdata->nbuttons;

       mutex_init(&ddata->disable_lock);

 

       /*ddata设备pdev平台设备的driver data*/

       platform_set_drvdata(pdev, ddata);

      

       /*ddata设备input设备的driver data*/

       input_set_drvdata(input, ddata);

 

       /*设置input设备的各个成员变量*/

       input->phys = "gpio-keys/input0";

       input->dev.parent = &pdev->dev;

       input->open = gpio_keys_open;

       input->close = gpio_keys_close;

 

       input->id.bustype = BUS_HOST;

       input->id.vendor = 0x0001;

       input->id.product = 0x0001;

       input->id.version = 0x0100;

 

       /* 根据pdatarep成员值,设备input子系统的功能*/

       if (pdata->rep)

              __set_bit(EV_REP, input->evbit);

 

       /*取出pdata中得资源进行赋值*/

       for (i = 0; i < pdata->nbuttons; i++) {

              struct gpio_keys_button *button = &pdata->buttons[i];

              struct gpio_button_data *bdata = &ddata->data[i];

 

              /*为三目运算符,相当于button->type ?: button->type:EV_KEY;*/

              unsigned int type = button->type ?: EV_KEY;

 

              bdata->input = input;//

              bdata->button = button;

 

              error = gpio_keys_setup_key(pdev, bdata, button);

             

if (button->wakeup)//该键能否作为唤醒源?

                     wakeup = 1;

 

              input_set_capability(input, type, button->code);

       }

 

       }

 

       error = input_register_device(input);

 

       /* get current state of buttons */

       for (i = 0; i < pdata->nbuttons; i++)

              gpio_keys_report_event(&ddata->data[i]);

       input_sync(input);

 

       device_init_wakeup(&pdev->dev, wakeup);

 

       return 0;

}

下面逐步分解上面标成粉色的函数。

第一个分配一个input dev并进行初始化

struct input_dev *input_allocate_device(void)

{

       struct input_dev *dev;

 

       dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);

       if (dev) {

              dev->dev.type = &input_dev_type;

              dev->dev.class = &input_class;

              device_initialize(&dev->dev);

              mutex_init(&dev->mutex);

              spin_lock_init(&dev->event_lock);

              INIT_LIST_HEAD(&dev->h_list);

              INIT_LIST_HEAD(&dev->node);

       }

       return dev;

}

分析第二个:

static int __devinit gpio_keys_setup_key(struct platform_device *pdev,

                                    struct gpio_button_data *bdata,

                                    struct gpio_keys_button *button)

{

       /*取出按键的描述符*/

       const char *desc = button->desc ? button->desc : "gpio_keys";

       struct device *dev = &pdev->dev;

 

       /*设置该bdata的定时器函数*/

       setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);

      

       /*设置该bdatawork函数*/

       INIT_WORK(&bdata->work, gpio_keys_work_func);

 

       /*申请buttongpio*/

       error = gpio_request(button->gpio, desc);

      

       /*设置gpio的方向*/

       error = gpio_direction_input(button->gpio);

 

       if (button->debounce_interval) { //设置gpio的去抖间隔

              error = gpio_set_debounce(button->gpio,

                                     button->debounce_interval * 1000);

              /* use timer if gpiolib doesn't provide debounce */

              if (error < 0)

                     bdata->timer_debounce = button->debounce_interval;

       }

 

       irq = gpio_to_irq(button->gpio); //gpio引脚对应分配的中断

 

       irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;

       if (!button->can_disable)

              irqflags |= IRQF_SHARED;

 

       /*注册该irq的中断处理函数,并设置标记*/

       error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata);

其中中断处理函数如下:

static irqreturn_t gpio_keys_isr(int irq, void *dev_id)

{

       struct gpio_button_data *bdata = dev_id;

       struct gpio_keys_button *button = bdata->button;

 

       BUG_ON(irq != gpio_to_irq(button->gpio));

 

       if (bdata->timer_debounce)//如果有去抖间隔则修改定时器

              mod_timer(&bdata->timer,

                     jiffies + msecs_to_jiffies(bdata->timer_debounce));

       else

              schedule_work(&bdata->work);//如果没有,直接执行work

       return IRQ_HANDLED;

}

}

如果定时器到期,则执行定时器处理函数:

static void gpio_keys_timer(unsigned long _data)

{

       struct gpio_button_data *data = (struct gpio_button_data *)_data;

       schedule_work(&data->work);//执行相应的work

}

中断处理的结果是执行相应的work。看下work函数

static void gpio_keys_work_func(struct work_struct *work)

{

       struct gpio_button_data *bdata =

              container_of(work, struct gpio_button_data, work);

 

       gpio_keys_report_event(bdata);//input子系统,向上层报事件

}

第三个函数,设置该input dev的能力记录本设备对那些事件感兴趣

void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)

{

       switch (type) {

       case EV_KEY:

              __set_bit(code, dev->keybit);// 比如按键,应该对哪些键值的按键进行处理(对于其它按键不予理睬)

              break;

 

       __set_bit(type, dev->evbit);

}

第四个函数:向input核心注册input设备

int input_register_device(struct input_dev *dev)

{

       static atomic_t input_no = ATOMIC_INIT(0);

       struct input_handler *handler;

       const char *path;

       int error;

 

       /* Every input device generates EV_SYN/SYN_REPORT events. */

       __set_bit(EV_SYN, dev->evbit); //设置支持的能力

 

       /* KEY_RESERVED is not supposed to be transmitted to userspace. */

       __clear_bit(KEY_RESERVED, dev->keybit);//清除该支持的能力

 

       /* Make sure that bitmasks not mentioned in dev->evbit are clean. */

       input_cleanse_bitmasks(dev);//确保在dev->evbit中没有支持的能力被清除掉

 

       if (!dev->hint_events_per_packet)

              dev->hint_events_per_packet = input_estimate_events_per_packet(dev);

 

       /*

        * If delay and period are pre-set by the driver, then autorepeating

        * is handled by the driver itself and we don't do it in input.c.

        */

       init_timer(&dev->timer);

       if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {

              dev->timer.data = (long) dev;

              dev->timer.function = input_repeat_key;

              dev->rep[REP_DELAY] = 250;

              dev->rep[REP_PERIOD] = 33;

       }

 

       /*设置input dev成员变量的处理函数*/

       if (!dev->getkeycode)

              dev->getkeycode = input_default_getkeycode;

 

       if (!dev->setkeycode)

              dev->setkeycode = input_default_setkeycode;

 

       /*设置该dev name*/

       dev_set_name(&dev->dev, "input%ld",

                   (unsigned long) atomic_inc_return(&input_no) - 1);

 

       error = device_add(&dev->dev);//把该设备增加到设备驱动模型中

 

       /*把该dev加入到input_dev_list 链表*/

       list_add_tail(&dev->node, &input_dev_list);

 

       /*遍历input_hander_list链表中得hander,以便匹配input dev*/

       list_for_each_entry(handler, &input_handler_list, node)

              input_attach_handler(dev, handler);

 

       return 0;

}

下面看下匹配函数:

static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)

{

       const struct input_device_id *id;

       id = input_match_device(handler, dev);//返回匹配成功的id

       error = handler->connect(handler, dev, id);//如果匹配成功,则调用handerconnect函数

       return error;

}

下面主要看下match的过程:

static const struct input_device_id *input_match_device(struct input_handler *handler,

                                                 struct input_dev *dev)

{

       const struct input_device_id *id;

 

       for (id = handler->id_table; id->flags || id->driver_info; id++) {

              if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)//如果是匹配bus,则比较id.bus

                     if (id->bustype != dev->id.bustype)

                            continue;

 

if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) //如果是匹配vender则比较id.vender

                     if (id->vendor != dev->id.vendor)

                            continue;

 

//如果是匹配product则比较id.product

              if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)

                     if (id->product != dev->id.product)

                            continue;

 

//如果是匹配versiont则比较id.version

              if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)

                     if (id->version != dev->id.version)

                            continue;

 

/*如果hander支持该能力,则dev也要支持,否则不匹配*/

MATCH_BIT(evbit,  EV_MAX);

              MATCH_BIT(keybit, KEY_MAX);

              MATCH_BIT(relbit, REL_MAX);

              MATCH_BIT(absbit, ABS_MAX);

              MATCH_BIT(mscbit, MSC_MAX);

              MATCH_BIT(ledbit, LED_MAX);

              MATCH_BIT(sndbit, SND_MAX);

              MATCH_BIT(ffbit,  FF_MAX);

              MATCH_BIT(swbit,  SW_MAX);

下面看下这个宏:

#define MATCH_BIT(bit, max) \

              for (i = 0; i < BITS_TO_LONGS(max); i++) \

                     if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \

                            break; \

              if (i != BITS_TO_LONGS(max)) \

                     continue;

 

/*如果handermatch空,则返回该id,或者调用match继续匹配,匹配成员的话也返回id*/

              if (!handler->match || handler->match(handler, dev))

                     return id;

       }

 

       return NULL;

}

上面input dev已经注册完了,下面看看hander的注册.

static const struct input_device_id evdev_ids[] = {

       { .driver_info = 1 },      /* Matches all devices 来则不拒,公交车*/

       { },                /* Terminating zero entry */

};

 

MODULE_DEVICE_TABLE(input, evdev_ids);

 

static struct input_handler evdev_handler = {

       .event             = evdev_event,

       .connect  = evdev_connect,

       .disconnect     = evdev_disconnect,

       .fops              = &evdev_fops,

       .minor            = EVDEV_MINOR_BASE,

       .name             = "evdev",

       .id_table  = evdev_ids,//匹配的列表

};

 

static int __init evdev_init(void)

{

       return input_register_handler(&evdev_handler);

}

module_init(evdev_init);

下面看下hander的注册:

static struct input_handler *input_table[8];

int input_register_handler(struct input_handler *handler)

{

       struct input_dev *dev;

       int retval;

 

       INIT_LIST_HEAD(&handler->h_list);

 

       if (handler->fops != NULL) {

              if (input_table[handler->minor >> 5]) {//判断input_table的相应项是否被占用

                     retval = -EBUSY;

                     goto out;

              }

              input_table[handler->minor >> 5] = handler; // 如果没有占用,则把hander填入

       }

 

/*把要注册的hander加入input_handler_list链表中*/

       list_add_tail(&handler->node, &input_handler_list);

 

       /*遍历input_dev_list链表上得每一个dev,去匹配该hander*/

       list_for_each_entry(dev, &input_dev_list, node)

              input_attach_handler(dev, handler);//开始进行匹配

}

匹配成功后,返回匹配成功的id,然后调用该handlerconnect函数。

static struct evdev *evdev_table[EVDEV_MINORS]; //evdev的容器

static int evdev_connect(struct input_handler *handler, struct input_dev *dev,

                      const struct input_device_id *id)

{

       struct evdev *evdev;

       int minor;

 

       /*在容器中找个空闲的地方*/

       for (minor = 0; minor < EVDEV_MINORS; minor++)

              if (!evdev_table[minor])

                     break;

       /*分配一个evdev变量*/

       evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);

      

       /*初始化该evdev的成员变量*/

       INIT_LIST_HEAD(&evdev->client_list);

       spin_lock_init(&evdev->client_lock);

       mutex_init(&evdev->mutex);

       init_waitqueue_head(&evdev->wait);

       dev_set_name(&evdev->dev, "event%d", minor);

       evdev->exist = true;

       evdev->minor = minor;

      

/*初始化该evdev的成员变量handlehandle相当于是红娘连接input dev和相应的hander*/

       evdev->handle.dev = input_get_device(dev);//增加该dev的引用计数

       evdev->handle.name = dev_name(&evdev->dev);//设置该evdevname

       evdev->handle.handler = handler;

       evdev->handle.private = evdev;//设置hander的私有数据,这个在下面会用到

 

       /*初始化该evdev的成员变量dev*/

       evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);

       evdev->dev.class = &input_class;

       evdev->dev.parent = &dev->dev;

       evdev->dev.release = evdev_free;

       device_initialize(&evdev->dev);

 

       /*注册上面初始化好的handle*/

       error = input_register_handle(&evdev->handle);

      

       /*安装evdev,其实就是放到全局的evdev_table 数组中*/

       error = evdev_install_chrdev(evdev);

该函数如下:

static int evdev_install_chrdev(struct evdev *evdev)

{

       evdev_table[evdev->minor] = evdev;

       return 0;

}

 

/*把该evdev设备增加到设备驱动模型中*/

       error = device_add(&evdev->dev);

 

       return 0;

}

下面主要看input_register_handle干了啥活?

int input_register_handle(struct input_handle *handle)

{

       struct input_handler *handler = handle->handler;

       struct input_dev *dev = handle->dev;

       list_add_tail_rcu(&handle->d_node, &dev->h_list);//加入到dev hist链表的末尾

       list_add_tail_rcu(&handle->h_node, &handler->h_list);//加入到handerhist尾部

       return 0;

注册的过程也就是把该handle加入devhander的链表中

}

上面input devhandler用网上的一个图可以表示:

该图形象的描述了三者的关系.

 

该搭的关系已经搞好啦,下面就是要用啦,用的时候看三者是怎么配合的。

下面看现在中断处理中,是如何用的?

上面有说过,在中断发生后,会调用work,在work中去处理上报键值:上报函数如下:

static void gpio_keys_report_event(struct gpio_button_data *bdata)

{

       struct gpio_keys_button *button = bdata->button;//取出每一个键的结构体

       struct input_dev *input = bdata->input;        //把该键的input设备也取出来

       unsigned int type = button->type ?: EV_KEY;   //类型为key

       int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;

 

       input_event(input, type, button->code, !!state);

       input_sync(input);

}

继续分析:

void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)

{

       if (is_event_supported(type, dev->evbit, EV_MAX)) {//判断该事件是否被支持

              ……….

              input_handle_event(dev, type, code, value);

              ..................

       }

}

下面继续跟踪:

static void input_handle_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)

{

       int disposition = INPUT_IGNORE_EVENT;

 

       switch (type) {

 

       case EV_KEY:

              if (is_event_supported(code, dev->keybit, KEY_MAX) &&  /判断该code是否被支持

                  !!test_bit(code, dev->key) != value) {

 

                     if (value != 2) {

                            __change_bit(code, dev->key);

                            if (value)

                                   input_start_autorepeat(dev, code);

                            else

                                   input_stop_autorepeat(dev);

                     }

 

                     disposition = INPUT_PASS_TO_HANDLERS;

              }

              break;

       }

 

       if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)

              dev->sync = false;

 

       if (disposition & INPUT_PASS_TO_HANDLERS)

              input_pass_event(dev, type, code, value);

}

继续跟踪该函数:

static void input_pass_event(struct input_dev *dev,

                          unsigned int type, unsigned int code, int value)

{

       struct input_handler *handler;

       struct input_handle *handle;

 

              list_for_each_entry_rcu(handle, &dev->h_list, d_node) {

                     if (!handle->open)//如果该handle没有被打开,则找下一个handle

                            continue;

 

                     handler = handle->handler;

                     if (!handler->filter) {

                            handler->event(handle, type, code, value);//调用handlerevent函数

                     }

              }

}

跟踪该函数:

static void evdev_event(struct input_handle *handle,

                     unsigned int type, unsigned int code, int value)

{

       struct evdev *evdev = handle->private;//这个在上面已经设置过

 

       struct evdev_client *client;

       struct input_event event;//要上报的事件结构体变量

       struct timespec ts;

      

       /*填充event,要上报的事件结构体*/

       /*该事件发生的时间*/

       ktime_get_ts(&ts);

       event.time.tv_sec = ts.tv_sec;

       event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;

 

       /*赋值传进来的参数*/

       event.type = type;

       event.code = code;

       event.value = value;

      

       /*遍历evdevclient链表*/

       list_for_each_entry_rcu(client, &evdev->client_list, node)

              evdev_pass_event(client, &event);

}

下面看传递函数:

static void evdev_pass_event(struct evdev_client *client,struct input_event *event)

{

       client->buffer[client->head++] = *event;//把传递的事件赋值给clientbuffer

       client->head &= client->bufsize - 1;//管理循环缓冲区

}

 

*******************************************************************************

下面看下提供给上层的接口

下面看下handerevdev_fops函数操作结构体:

看下具体的实现:

static const struct file_operations evdev_fops = {

       .owner           = THIS_MODULE,

       .read              = evdev_read,

       .write             = evdev_write,

       .poll        = evdev_poll,

       .open             = evdev_open,

       .release    = evdev_release,

       .unlocked_ioctl       = evdev_ioctl,

       .fasync           = evdev_fasync,

       .flush             = evdev_flush,

       .llseek            = no_llseek,

};

下面具体看下open函数:

static int evdev_open(struct inode *inode, struct file *file)

{

       struct evdev *evdev;

       struct evdev_client *client;

       int i = iminor(inode) - EVDEV_MINOR_BASE;

       unsigned int bufsize;

 

       evdev = evdev_table[i];//根据inode的值取出evdev的值

      

       /*client分配缓存*/

       bufsize = evdev_compute_buffer_size(evdev->handle.dev);

 

       /*为每一个打开实例,分配一个client结构体*/

       client = kzalloc(sizeof(struct evdev_client) +

                            bufsize * sizeof(struct input_event),

                      GFP_KERNEL);

 

       /*初始化client的各个成员变量*/

       client->bufsize = bufsize;

       spin_lock_init(&client->buffer_lock);

       snprintf(client->name, sizeof(client->name), "%s-%d",

                     dev_name(&evdev->dev), task_tgid_vnr(current));

       client->evdev = evdev;//和该client关联的evdev

 

    evdev_attach_client(evdev, client); //把该client加入该evdevclient链表中

下面是该函数的实现:

static void evdev_attach_client(struct evdev *evdev,struct evdev_client *client)

{

//把该client加入该evdevclient链表中

list_add_tail_rcu(&client->node, &evdev->client_list);

}

 

       error = evdev_open_device(evdev);

       file->private_data = client;//把该client挂载到file的私有结构体下

       nonseekable_open(inode, file);

 

       return 0;

}

下面接着看evdev_open_device(evdev);函数

static int evdev_open_device(struct evdev *evdev)

{

       int retval;

 

       if (!evdev->exist)//connenct的时候就被设置为true

              retval = -ENODEV;

       else if (!evdev->open++) {

              retval = input_open_device(&evdev->handle);

              if (retval)

                     evdev->open--;

       }

       return retval;

}

看下最后一个函数:

int input_open_device(struct input_handle *handle)

{

       struct input_dev *dev = handle->dev;

       int retval;

 

       handle->open++;//打开的计数器加1

       if (!dev->users++ && dev->open)

              retval = dev->open(dev);//该函数为空

       return retval;

}

下一个目标是分析read函数:

static ssize_t evdev_read(struct file *file, char __user *buffer,

                       size_t count, loff_t *ppos)

{

       struct evdev_client *client = file->private_data;

       struct evdev *evdev = client->evdev;

       struct input_event event;

 

       while (retval + input_event_size() <= count &&evdev_fetch_next_event(client, &event)) {

              if (input_event_to_user(buffer + retval, &event))

                     return -EFAULT;

              retval += input_event_size();

       }

       return retval;

}

看下里面的两个细节

static int evdev_fetch_next_event(struct evdev_client *client,struct input_event *event)

{

       int have_event;

       have_event = client->packet_head != client->tail;

       if (have_event) {

              *event = client->buffer[client->tail++];

              client->tail &= client->bufsize - 1;

       }

       return have_event;

}

/**/

int input_event_to_user(char __user *buffer,const struct input_event *event)

{

       if (copy_to_user(buffer, event, sizeof(struct input_event)))

              return -EFAULT;

       return 0;

}

***************************************************************************

下面再看看input class是咋回事?

static const struct file_operations input_fops = {

       .owner = THIS_MODULE,

       .open = input_open_file,

       .llseek = noop_llseek,

};

 

struct class input_class = {

       .name             = "input",

       .devnode = input_devnode,

};

static int __init input_init(void)

{

       /*注册input class*/

       err = class_register(&input_class);

 

       /*注册input dev字符设备,其中#define INPUT_MAJOR 13*/

       err = register_chrdev(INPUT_MAJOR, "input", &input_fops);

 

       return 0;

}

subsys_initcall(input_init);

***************************************************************************

input_fops 中的input_open_file

static int input_open_file(struct inode *inode, struct file *file)

{

       struct input_handler *handler;

       const struct file_operations *old_fops, *new_fops = NULL;

 

handler = input_table[iminor(inode) >> 5];//根据上层传入的inode结构体,找到对应的handler

       if (handler)//如果handler不为空,则取出该handlerfops指针赋值给新的new_fops

              new_fops = fops_get(handler->fops);

 

       old_fops = file->f_op;//备份老的

       file->f_op = new_fops;//赋值新的,以后的对该设备的操作都会映射到该操作结构体

 

       err = new_fops->open(inode, file);//调用新的open函数

       if (err) {如果出错,则回退

              fops_put(file->f_op);

              file->f_op = fops_get(old_fops);

       }

}

阅读(1822) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~