輸入子系統(tǒng)--event層分析_第1頁
輸入子系統(tǒng)--event層分析_第2頁
輸入子系統(tǒng)--event層分析_第3頁
已閱讀5頁,還剩16頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、輸入子系統(tǒng) -event 層分析drivers/input/keyboard/gpio_keys.c:static int _devinit gpio_keys_probe(struct platform_device *pdev)struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;struct input_dev *input;int i, error;input = input_allocate_device();/ 申請(qǐng)input_dev 結(jié)構(gòu)if (!input)return -ENOMEM; p

2、latform_set_drvdata(pdev, input);/ 把 input_dev 結(jié)構(gòu)放好 (以后方便調(diào)用 ) input->evbit0 = BIT(EV_KEY);/ 目前 event 的類型不操作 32,所以你會(huì)看到對(duì)于 evbit 數(shù)組的操作都是對(duì) evbit0 中的位 來進(jìn)行操作 . input->name = pdev->name;input->phys = "gpio-keys/input0" input->dev.parent = &pdev->d

3、ev;input->id.bustype = BUS_HOST; input->id.vendor = 0x0001; input->duct = 0x0001;input->id.version = 0x0100; for (i = 0; i <pdata->nbuttons; i+) struct gpio_keys_button *button =&pdata->buttonsi;int irq = gpio_to_irq(button->gpio)

4、;unsigned int type = button->type ?: EV_KEY;set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); /* 根據(jù) 用戶所指定的 gpio_keys 來申請(qǐng)中斷和注冊(cè)中斷處理函數(shù) */ error = request_irq(irq, gpio_keys_isr,IRQF_SAMPLE_RANDOM,button->desc ? button->desc :"gpio_keys",pdev);if (error) printk(KERN_ERR "gpio-ke

5、ys: unable to claimirq %d; error %dn",irq, error);goto fail; input_set_capability(input, type, button->code);error = input_register_device(input);/ 注冊(cè)輸入設(shè)備并和對(duì)應(yīng)的 handler 處理函數(shù)掛鉤if (error) printk(KERN_ERR "Unable to register gpio-keys input devicen");goto fail; return 0; fail:for (

6、i = i - 1; i >= 0; i-)free_irq(gpio_to_irq(pdata->buttonsi.gpio), pdev); input_free_device(input); return error;提到 input_dev 結(jié)構(gòu) ,以下談一下我對(duì)于它的理解 :struct input_dev void *private; const char *name;const char *phys;const char *uniq;struct input_id id;/* 根據(jù)各種輸入信號(hào)的類型來建立類型為 unsigned long 的數(shù)組 ,

7、* 數(shù)組的每 1bit 代表一種信號(hào)類型 , * 內(nèi)核中會(huì)對(duì)其進(jìn)行置位或清位操作來表示時(shí)間的發(fā)生和 被處理 .*/ unsigned long evbitNBITS(EV_MAX);unsigned long keybitNBITS(KEY_MAX);unsigned long relbitNBITS(REL_MAX);unsigned long absbitNBITS(ABS_MAX);unsigned long mscbitNBITS(MSC_MAX);unsigned long ledbitNBITS(LED_MAX);unsigned long sndbitNBITS(SND_MAX)

8、; unsigned long ffbitNBITS(FF_MAX);unsigned long swbitNBITS(SW_MAX); ;/* input_set_capability - mark device as capable of a certain event* dev: device that is capable of emitting or accepting event* type: type of the event (EV_KEY , EV_REL, etc.)* code: event code* In addition to setting up correspo

9、nding bit in appropriate capability* bitmap the function also adjusts dev->evbit.*/* 記錄本設(shè)備對(duì)于哪些事件感興趣 (對(duì)其進(jìn)行處理 )*/ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)switch (type) case EV_KEY:_set_bit(code, dev->keybit);/ 比如按鍵 , 應(yīng)該對(duì)哪 些鍵值的按鍵進(jìn)行處理 (對(duì)于其它按鍵不予

10、理睬 )break; case EV_REL:_set_bit(code, dev->relbit);break; case EV_ABS:_set_bit(code, dev->absbit);break; case EV_MSC:_set_bit(code, dev->mscbit);break; case EV_SW:_set_bit(code, dev->swbit);break; case EV_LED:_set_bit(code, dev->ledbit);break; case EV_SND:_set_bit(

11、code, dev->sndbit);break; case EV_FF:_set_bit(code, dev->ffbit);break; default:printk(KERN_ERR"input_set_capability: unknown type %u(code %u)n",type, code);dump_stack();return;_set_bit(type, dev->evbit);/ 感覺和前面重復(fù)了(前面一經(jīng)配置過一次了 )EXPORT_SYMBOL(input_set_capability);static

12、irqreturn_t gpio_keys_isr(int irq, void *dev_id)int i;struct platform_device *pdev = dev_id;struct gpio_keys_platform_data *pdata =pdev->dev.platform_data;struct input_dev *input = platform_get_drvdata(pdev);for (i = 0; i < pdata->nbuttons; i+) struct gpio_keys_button *button =&

13、amp;amp;pdata->buttonsi;int gpio = button->gpio;if (irq = gpio_to_irq(gpio) / 判斷哪個(gè)鍵被按了 ? unsigned int type = button->type ?: EV_KEY;int state = (gpio_get_value(gpio)1 : 0) A button->activeow; 記錄按鍵狀態(tài) input_event(input, type, button->code, !state);/ 匯報(bào)輸入事 件input_sync

14、(input);/ 等待輸入事件處理完成 return IRQ_HANDLED;/* input_event() - report new input event* dev: device that generated the event* type: type of the event* code: event code* value: value of the event* This function should be used by drivers implementing various input devices* See also input_inject_event()*/vo

15、id input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)struct input_handle *handle; if (type > EV_MAX| !test_bit(type, dev->evbit)/ 首先判斷該事件類型是否有 效且為該設(shè)備所接受return; add_input_randomness(type, code, value); switch (code) case SYN_CONFIG:if (dev->event)

16、dev->event(dev, type, code, value);break; caseSYN_REPORT:if (dev->sync)return;dev->sync = 1;break;break; case EV_KEY:/* 這里需要滿足幾個(gè)條件 :* 1:鍵值有效 (不超出定義的鍵值的有效范圍 )* 2:鍵值為設(shè)備所能接受 (屬于該設(shè)備所擁有的鍵值范圍 )* 3: 按鍵狀態(tài)改變了*/ if (code > KEY_MAX| !test_bit(code, dev->keybit) | !test_bit(co

17、de, dev->key) = value)dev->key);/ 改變對(duì)應(yīng)按鍵的狀態(tài) /* 如果你 希望按鍵未釋放的時(shí)候不斷匯報(bào)按鍵事件的話需要以下這 個(gè) (在簡單的 gpio_keys 驅(qū)動(dòng)中不需要這個(gè) ,暫時(shí)不去分析 ) */if (test_bit(EV_REP, dev->evbit) && dev->repREP_PERIOD && dev->repREP_DELAY && dev->timer.data

18、 && value) dev->repeat_key = code; mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->repREP_DELAY); break; if (type != EV_SYN) dev->sync = 0; if (dev->grab) dev->grab->handler->event(dev->grab, type, code, va

19、lue);else/* 循環(huán)調(diào)用所有處理該設(shè)備的 handle(event,mouse,ts,joy 等 ),* 如果有進(jìn)程打開了這些handle(進(jìn)行讀寫),則調(diào)用其對(duì)應(yīng)的event接口向氣匯報(bào)該輸入事件*/list_for_each_entry(handle, &dev->h_list,d_node)if (handle->open)handle->handler->event(handle, type,code, value);EXPORT_SYMBOL(input_event);# # 好了 ,下面再來研究一下 e

20、vent 層對(duì)于 input 層報(bào)告的這個(gè)鍵 盤輸入事件是如何來處理的 .# #drivers/input/evdev.c: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 void evdev_event(str

21、uct input_handle *handle, unsignedint type, unsigned int code, int value)struct evdev *evdev = handle->private;struct evdev_client *client; if(evdev->grab) client = evdev->grab;do_gettimeofday(&client->bufferclient->head.time );client->bufferclient-&

22、amp;gt;head.type = type;client->bufferclient->head.code = code;client->bufferclient->head.value = value;client->head = (client->head + 1)& (EVDEV_BUFFER_SIZE - 1); kill_fasync(&client->fasync, SIGIO, POLL_IN); else/* 遍厲 client_list 鏈表中

23、的 client 結(jié)構(gòu)(代表些打開evdev的進(jìn)程(個(gè)人理解A_A) */&evdev->client_list, node) /* 填充代表該輸入信號(hào)的 struct input_event 結(jié)構(gòu) (事件 ,類型 ,鍵碼 ,鍵值 ) */do_gettimeofday(&client->bufferclient->head.time );client->bufferclient->head.type = type;client->bufferclient->hea

24、d.code = code;client->bufferclient->head.value = value;/* 更新寫指針 */ client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);kill_fasync(&client->fasync, SIGIO, POLL_IN);/ 通知 調(diào)用 input_sync 的進(jìn)程 :輸入事件經(jīng)已處理完畢 ( 通知底層 ). wake_up_interruptible(&e

25、vdev->wait);/ 喚醒睡眠在 evdev->wait 等待隊(duì)列等待輸入信息的進(jìn)程 (通知上層 ). # #好了 ,至此一個(gè)按鍵的輸入事件處理完畢 ,現(xiàn)在再來從上到上 的來看看用戶是如何獲取這個(gè)輸入事件的 .# #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,.unlocke

26、d_ioctlevdev_ioctl,#ifdef CONFIG_COMPAT.compat_ioctl = evdev_ioctl_compat,#endif.fasync =evdev_fasync,.flush =evdev_flush;static int evdev_open(struct inode *inode, struct file *file) struct evdev_client *client;struct evdev *evdev;int i = iminor(inode) - EVDEV_MINOR_BASE;int error;if (i >= E

27、VDEV_MINORS)return -ENODEV;evdev =evdev_tablei;if (!evdev | !evdev->exist)return -ENODEV;client =kzalloc(sizeof(struct evdev_client), GFP_KERNEL);if (!client)return -ENOMEM;client->evdev = evdev;/* 添加 evdev_client 結(jié)構(gòu)到鏈表 evdev->client_list 中 (好讓輸入事件到來的時(shí)候填寫該結(jié)構(gòu) 并喚醒進(jìn)程讀取 ) */list_add

28、_tail(&client->node, &evdev->client_list); if (!evdev->open+ && evdev->exist) error = input_open_device(&evdev->handle);if (error) list_del(&client->node);kfree(client);return error;file->private_data =

29、client;/ 存放好 evdev_client 結(jié)構(gòu)方便以后使用return 0;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;int retval; if (count <evdev_event_size()對(duì)于每次讀取的數(shù)據(jù)大小是有一定的要

30、 求.return -EINV AL;if(client->head = client->tail && evdev->exist && (file->f_flags &O_NONBLOCK)/ 緩存中沒有數(shù)據(jù)可讀且設(shè)備是存在的 ,如果設(shè)置為 NONBLOCK 方式來讀 ,立即返回 .return -EAGAIN;retval =wait_event_interruptible(evdev->wait,client->head !=

31、 client->tail| !evdev->exist);/ 否則等待緩存有數(shù)據(jù)可讀或設(shè)備不存在(被移去 )if (retval)return retval; return -ENODEV;if (!evdev->exist)while(client->head != client->tail && retval + evdev_event_size() <= count) / 下面開始讀取數(shù)據(jù) struct input_event *event = (struct input

32、_event *) client->buffer + client->tail;/ 獲取緩存中的讀指針 if (evdev_event_to_user(buffer + retval, event)/ 返回?cái)?shù)據(jù)給用 戶return -EFAULT;client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1);/ 更新讀指針 retval += evdev_event_size(); return retval;呵呵,看到了吧,應(yīng)用程序就是這樣獲取輸入事件的A_A#

33、# #本來對(duì)于 gpio_keys 這樣的驅(qū)動(dòng)程序 ,只要當(dāng)發(fā)生按鍵事件的 時(shí)候向上層應(yīng)用程序匯報(bào)鍵值即可 .不過 ,對(duì)于一些帶輸出設(shè) 備(例如 led 燈)的輸入設(shè)備來說 (例如鍵盤 ),上層應(yīng)用程序同 樣可以利用 event 層來讀取或改變其狀態(tài) .請(qǐng)看以下代碼 : # #static ssize_t evdev_write(struct file *file, const char _user *buffer, size_t count, loff_t *ppos)struct evdev_client *client = file->private_data;struct

34、 evdev *evdev = client->evdev;struct input_event event;int retval = 0;if (!evdev->exist)return -ENODEV;while (retval <count) if (evdev_event_from_user(buffer + retval, &event)/ 從用戶處獲取事件結(jié)構(gòu)return -EFAULT; input_inject_event(&evdev->handle, event.type, event.

35、code, event.value);/ 往底層發(fā)送事件retval += evdev_event_size(); return retval;/* input_inject_event() - send input event from input handler* handle: input handle to send event through* type: type of the event* code: event codevalue: value of the event* Similar to input_event() but will ignore event if dev

36、ice is "grabbed" and handle* injecting event is not the one that owns the device.*/void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)if (!handle->dev->grab | handle->dev->grab = handle) input_event(handle-&g

37、t;dev, type, code, value); EXPORT_SYMBOL(input_inject_event);/* input_event() - report new input event* dev: device that generated the event* type: type of the event* code: event code* value: value of the eventThis function should be used by drivers implementingvarious input devices* See also input_inject_event()*/void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)struct input_handle *handle; if (type > EV

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論