


下載本文檔
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、輸入子系統 -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();/ 申請input_dev 結構if (!input)return -ENOMEM; p
2、latform_set_drvdata(pdev, input);/ 把 input_dev 結構放好 (以后方便調用 ) input->evbit0 = BIT(EV_KEY);/ 目前 event 的類型不操作 32,所以你會看到對于 evbit 數組的操作都是對 evbit0 中的位 來進行操作 . 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); /* 根據 用戶所指定的 gpio_keys 來申請中斷和注冊中斷處理函數 */ 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);/ 注冊輸入設備并和對應的 handler 處理函數掛鉤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 結構 ,以下談一下我對于它的理解 :struct input_dev void *private; const char *name;const char *phys;const char *uniq;struct input_id id;/* 根據各種輸入信號的類型來建立類型為 unsigned long 的數組 ,
7、* 數組的每 1bit 代表一種信號類型 , * 內核中會對其進行置位或清位操作來表示時間的發生和 被處理 .*/ 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.*/* 記錄本設備對于哪些事件感興趣 (對其進行處理 )*/ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)switch (type) case EV_KEY:_set_bit(code, dev->keybit);/ 比如按鍵 , 應該對哪 些鍵值的按鍵進行處理 (對于其它按鍵不予
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);/ 感覺和前面重復了(前面一經配置過一次了 )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) / 判斷哪個鍵被按了 ? unsigned int type = button->type ?: EV_KEY;int state = (gpio_get_value(gpio)1 : 0) A button->activeow; 記錄按鍵狀態 input_event(input, type, button->code, !state);/ 匯報輸入事 件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)/ 首先判斷該事件類型是否有 效且為該設備所接受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:/* 這里需要滿足幾個條件 :* 1:鍵值有效 (不超出定義的鍵值的有效范圍 )* 2:鍵值為設備所能接受 (屬于該設備所擁有的鍵值范圍 )* 3: 按鍵狀態改變了*/ if (code > KEY_MAX| !test_bit(code, dev->keybit) | !test_bit(co
17、de, dev->key) = value)dev->key);/ 改變對應按鍵的狀態 /* 如果你 希望按鍵未釋放的時候不斷匯報按鍵事件的話需要以下這 個 (在簡單的 gpio_keys 驅動中不需要這個 ,暫時不去分析 ) */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/* 循環調用所有處理該設備的 handle(event,mouse,ts,joy 等 ),* 如果有進程打開了這些handle(進行讀寫),則調用其對應的event接口向氣匯報該輸入事件*/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 層對于 input 層報告的這個鍵 盤輸入事件是如何來處理的 .# #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 結構(代表些打開evdev的進程(個人理解A_A) */&evdev->client_list, node) /* 填充代表該輸入信號的 struct input_event 結構 (事件 ,類型 ,鍵碼 ,鍵值 ) */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);/ 通知 調用 input_sync 的進程 :輸入事件經已處理完畢 ( 通知底層 ). wake_up_interruptible(&e
25、vdev->wait);/ 喚醒睡眠在 evdev->wait 等待隊列等待輸入信息的進程 (通知上層 ). # #好了 ,至此一個按鍵的輸入事件處理完畢 ,現在再來從上到上 的來看看用戶是如何獲取這個輸入事件的 .# #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 結構到鏈表 evdev->client_list 中 (好讓輸入事件到來的時候填寫該結構 并喚醒進程讀取 ) */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 結構方便以后使用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()對于每次讀取的數據大小是有一定的要
30、 求.return -EINV AL;if(client->head = client->tail && evdev->exist && (file->f_flags &O_NONBLOCK)/ 緩存中沒有數據可讀且設備是存在的 ,如果設置為 NONBLOCK 方式來讀 ,立即返回 .return -EAGAIN;retval =wait_event_interruptible(evdev->wait,client->head !=
31、 client->tail| !evdev->exist);/ 否則等待緩存有數據可讀或設備不存在(被移去 )if (retval)return retval; return -ENODEV;if (!evdev->exist)while(client->head != client->tail && retval + evdev_event_size() <= count) / 下面開始讀取數據 struct input_event *event = (struct input
32、_event *) client->buffer + client->tail;/ 獲取緩存中的讀指針 if (evdev_event_to_user(buffer + retval, event)/ 返回數據給用 戶return -EFAULT;client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1);/ 更新讀指針 retval += evdev_event_size(); return retval;呵呵,看到了吧,應用程序就是這樣獲取輸入事件的A_A#
33、# #本來對于 gpio_keys 這樣的驅動程序 ,只要當發生按鍵事件的 時候向上層應用程序匯報鍵值即可 .不過 ,對于一些帶輸出設 備(例如 led 燈)的輸入設備來說 (例如鍵盤 ),上層應用程序同 樣可以利用 event 層來讀取或改變其狀態 .請看以下代碼 : # #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)/ 從用戶處獲取事件結構return -EFAULT; input_inject_event(&evdev->handle, event.type, event.
35、code, event.value);/ 往底層發送事件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等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 班級活動墻展示活動方案
- 牙科小區活動方案
- 環衛知識進校園活動方案
- 甜品區活動方案
- 愛上幼兒園綜藝活動方案
- 珠寶活動雙十一活動方案
- 生產能手評選活動方案
- 環保校園少先隊活動方案
- 瑜伽攝影活動方案
- 特教六一兒童節活動方案
- 照明組裝生產車間試題帶答案
- 財務部門半年工作復盤
- 江蘇南京金陵中學2024~2025學年高一下冊期末考試數學試題學生卷
- 福建福州第八中學2024~2025學年高一下冊期末數學試題
- 生產工藝流程控制考核試卷
- 交通執法培訓課件新
- l輻射安全管理制度
- 健康評估(第3版)課件6-2 泌尿系統常見癥狀評估
- 麻醉中的人文關懷
- 餐廚廢棄食用油脂管理制度
- 2025年云南省時事政治考試試卷帶解析附完整答案(考點梳理)
評論
0/150
提交評論