入口函式:
drivers/input/input.c:
input_init > err = register_chrdev(input_major, "input", &input_fops);
static const struct file_operations input_fops = {
.owner = this_module,
.open = input_open_file,
註冊input_handler
1 、放入陣列
input_table[handler->minor >> 5] = handler;
2、放入鍊錶
list_add_tail(&handler->node, &input_handler_list);
3、 對於每個input_dev,呼叫input_attach_handler
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler); // 根據input_handler的id_table判斷能否支援這個input_dev
註冊input_device
1、放入鍊錶
list_add_tail(&dev->node, &input_dev_list);
2、對於每個input_handler,呼叫input_attach_handler
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler); // 根據input_handler的id_table判斷能否支援這個input_dev
input_attach_handler:聯絡input_device和input_handler
1、匹配
id = input_match_device(handler->id_table, dev);
2、連線
error = handler->connect(handler, dev, id);
3、註冊input_dev或input_handler時,會兩兩比較左邊的input_dev和右邊的input_handler,
根據input_handler的id_table判斷input_handler能否支援input_dev,
如果能支援,則呼叫input_handler的connect函式建立"連線"
建立連線handler->connect
1、分配乙個input_handle結構體
2、設定
input_handle.dev = input_dev; // 指向左邊的input_dev
input_handle.handler = input_handler; // 指向右邊的input_handler
3、註冊
input_handler->h_list = &input_handle;
inpu_dev->h_list = &input_handle;
4、例子evdev_connect
// 分配乙個input_handle
evdev = kzalloc(sizeof(struct evdev), gfp_kernel);
// 設定
evdev->handle.dev = dev; // 指向左邊的input_dev
evdev->handle.name = evdev->name;
evdev->handle.handler = handler; // 指向右邊的input_handler
evdev->handle.private = evdev;
// 註冊
error = input_register_handle(&evdev->handle);
讀按鍵過程
1、input_open_file
struct input_handler *handler = input_table[iminor(inode) >> 5];
new_fops = fops_get(handler->fops) // =>&evdev_fops
file->f_op = new_fops;
err = new_fops->open(inode, file);
evdev_read
// 無資料並且是非阻塞方式開啟,則立刻返回
if (client->head == client->tail && evdev->exist && (file->f_flags & o_nonblock))
return -eagain;
// 否則休眠
retval = wait_event_interruptible(evdev->wait,
client->head != client->tail || !evdev->exist);
3、喚醒:evdev_event
wake_up_interruptible(&evdev->wait);
4、誰來呼叫evdev_event:裝置驅動
在裝置的中斷服務程式裡,確定事件是什麼,然後呼叫相應的input_handler的event處理函式。
例子:(/drivers/input/keyboard/gpio_keys.c)
gpio_keys_isr
// 上報事件
input_event(input, type, button->code, !!state);
input_sync(input);
input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
struct input_handle *handle;
list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle, type, code, value);
怎麼寫符合輸入子系統框架的驅動程式?
1. 分配乙個input_dev結構體
2. 設定
3. 註冊
4. 硬體相關的**,比如在中斷服務程式裡上報事件
輸入子系統框架之我見
輸入子系統是linux驅動中很重要的一部分,按鍵 觸控螢幕 滑鼠等等的驅動都可以通過這個框架來構建,下面就來總結下輸入子系統的框架。核心層主要在input.c檔案中,class register input class register chrdev input major,input input ...
linux輸入子系統 5 學習框架
注 本系列 input子系統學習系列文章,是我在實際開發過程中遇到也是必須啃下去的第乙個linux驅動,所以有必要記載下來的。由於剛開始未接觸過input子系統,部分資料還是借鑑網路,本系列文章是本人的學習心得以及集百家所長的產物。input subsystem理論部分 input subsyste...
輸入子系統
驅動函式操作步驟 在初始化函式中 1.分配乙個input dev結構體 struct input dev buttons dev buttons dev input allocate device 2.設定 2.1 能產生哪類事件 set bit ev key,buttons dev evbit s...