![輸入子系統(tǒng)--event層分析_第1頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/13/9e5c4659-a417-487f-bf90-11c304d7e4ea/9e5c4659-a417-487f-bf90-11c304d7e4ea1.gif)
![輸入子系統(tǒng)--event層分析_第2頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/13/9e5c4659-a417-487f-bf90-11c304d7e4ea/9e5c4659-a417-487f-bf90-11c304d7e4ea2.gif)
![輸入子系統(tǒng)--event層分析_第3頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/13/9e5c4659-a417-487f-bf90-11c304d7e4ea/9e5c4659-a417-487f-bf90-11c304d7e4ea3.gif)
版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 塑料制品液堿物流合同
- 健身房專用鮮奶供應(yīng)合同
- 光伏設(shè)備運(yùn)輸安裝合同
- 實(shí)驗(yàn)室改造工程監(jiān)管合同
- 新津道路工程施工方案
- 輸電線路防腐施工方案
- 許昌戶外雕塑噴泉施工方案
- 青島地下管網(wǎng)施工方案
- 國企技術(shù)入股合同范例
- 項(xiàng)目包裝調(diào)研方案
- 2024年長沙衛(wèi)生職業(yè)學(xué)院高職單招職業(yè)技能測驗(yàn)歷年參考題庫(頻考版)含答案解析
- 河北省滄州市五縣聯(lián)考2024-2025學(xué)年高一上學(xué)期期末英語試卷(含答案含含聽力原文無音頻)
- 福建省泉州市南安市2024-2025學(xué)年九年級(jí)上學(xué)期期末考試語文試題(無答案)
- 腫瘤護(hù)士培訓(xùn)課件
- 新課標(biāo)體育與健康水平二教案合集
- 2025屆高考語文一輪復(fù)習(xí)知識(shí)清單:古代詩歌鑒賞
- 醫(yī)療器材申請(qǐng)物價(jià)流程
- 我的消防文員職業(yè)規(guī)劃
- 2025年公司品質(zhì)部部門工作計(jì)劃
- 2024年世界職業(yè)院校技能大賽高職組“市政管線(道)數(shù)字化施工組”賽項(xiàng)考試題庫
- 華為研發(fā)部門績效考核制度及方案
評(píng)論
0/150
提交評(píng)論