Android 輸入系統架構 筆記4

下面看下Linux 下 input 驅動的架構,以具體例子分析下:

下面的文章是基於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 <[email protected]> */ 
       .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; 
  
       /* 根據pdata的rep成員值設備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); 
        
       /*設置該bdata的work函數*/ 
       INIT_WORK(&bdata->work, gpio_keys_work_func); 
  
       /*申請button的gpio*/ 
       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);//如果匹配成功則調用hander的connect函數 
       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; 
					 /*如果hander的match空則返回該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然後調用該handler的connect函數。 
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的成員變量handlehandle相當於是紅娘連接input dev和相應的hander*/ 
       evdev->handle.dev = input_get_device(dev);//增加該dev的引用計數 
       evdev->handle.name = dev_name(&evdev->dev);//設置該evdev的name 
       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);//加入到hander的hist尾部 
       return 0; 
註冊的過程也就是把該handle加入dev和hander的鏈表中 
} 

上面input dev和handler用網上的一個圖可以表示 
 
該圖形象的描述了三者的關係. 



該搭的關係已經搞好啦下面就是要用啦,用的時候看三者是怎麼配合的。下面看現在中斷處理中是如何用的上面有說過在中斷髮生後會調用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);//調用handler的event函數 
                     } 
              } 
} 

跟蹤該函數
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; 
        
       /*遍歷evdev的client鏈表*/ 
       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;//把傳遞的事件賦值給client的buffer中 
       client->head &= client->bufsize - 1;//管理循環緩衝區 
} 
  

******************************************************************************* 
下面看下提供給上層的接口,下面看下hander的evdev_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加入該evdev的client鏈表中 
下面是該函數的實現 
static void evdev_attach_client(struct evdev *evdev,struct evdev_client *client) 
{ 
//把該client加入該evdev的client鏈表中 
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不爲空則取出該handler的fops指針賦值給新的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); 
       } 
} 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章