Linux--核心Uevent事件機制 與 Input子系統
阿新 • • 發佈:2019-01-25
1. 輸入子系統由驅動層、輸入子系統核心、事件處理層三部分組成:
一個輸入事件,如滑鼠移動、鍵盤按下等通過Driver->Inputcore->Event handler->userspace的順序到達使用者控制元件的應用程式。
2. input子系統仍然是字元裝置驅動程式,但是程式碼量減少很多,input子系統只需要完成兩個工作:初始化和事件報告。
3. (1)上報的大致過程:裝置驅動層->核心層->事件處理層->應用層
(2)具體呼叫的函式(以evdev為例):
input_event()->input_handle_event() ->input_pass_event() ->handle->handler->event(handle,type, code, value)
->evdev_event() ->evdev_pass_event() ,
然後通過client->buffer[client->head++]= *event賦值給上層client(是struct evdev_client)
//2. Input 子系統之一--框架結構(初始化)
1. 第一層
===============================================================================
使用者空間訪問 <User space> 裝置節點訪問(略)
@@@@@@xx_test.c
2. 第二層
===============================================================================
事件處理層<Event Handler>
/*主要是和使用者空間互動。
(Linux中在使用者空間將所有的裝置都當初檔案來處理,由於在一般的驅動程式中都有提供fops介面,以及在/dev下生成相應的裝置檔案nod,這些操作在輸入子系統中由事件處理層完成)*/
@@@@@@evdev.c等。(以evdev_handler為例)
(1)===>>module_init(evdev_init); module_exit(evdev_exit);
(2)===>>static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);///
/*static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops, ////evdev的檔案操作方法
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,*/
};
}
(3)===>>int input_register_handler(struct input_handler *handler)//註冊一個新的event handler
{
struct input_dev *dev;
list_add_tail(&handler->node, &input_handler_list);
list_for_each_entry(dev, &input_dev_list, node);
input_attach_handler(dev, handler);////將這個新的event handler 與其相容的input dev繫結在一起
}
(4)===>>static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
id = input_match_device(handler, dev);//匹配規則:Input_dev和input_handler匹配後呼叫input_handler的connect。
error = handler->connect(handler, dev, id);//
}
(5)===>>建立新的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++)//尋找未使用的minor
if (!evdev_table[minor])
break;
dev_set_name(&evdev->dev, "event%d", minor);
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);//建立字元裝置節點event%d
}
3. 第三層
===============================================================================
核心層<Input Core>
/*承上啟下。為驅動層提供輸入設備註冊與操作介面,如:input_register_device;通知事件處理層對事件進行處理;在/Proc下產生相應的裝置資訊*/
@@@@@@input.c
(1)===>>subsys_initcall(input_init); module_exit(input_exit);
(2)===>>static int __init input_init(void)
{
//建立 sysfs 系統檔案/proc/bus/input:devices && handlers
err = class_register(&input_class);/// struct class input_class = {
.name = "input",
.devnode = input_devnode,//kasprintf(GFP_KERNEL, "input/%s", dev_name(dev));
};
//建立proc系統檔案/proc/bus/input:devices && handlers
err = input_proc_init();
if (err)
goto fail1;
//註冊字元裝置的檔案操作input_fops
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,///
.llseek = noop_llseek,}
}
(3)===>>static int input_open_file(struct inode *inode, struct file *file)
{
struct input_handler *handler;
/* No load-on-demand here? */
handler = input_table[iminor(inode) >> 5];
if (handler)
new_fops = fops_get(handler->fops);
file->f_op = new_fops;/////根據傳入的inode節點(即:event handler),設定相應的檔案操作方法
err = new_fops->open(inode, file);////開啟檔案操作方法
}
4. 第四層
===============================================================================
裝置驅動層<Input driver>(略)
/*將底層的硬體輸入轉化為統一事件形式,想輸入核心(Input Core)彙報。*/
/*實現裝置驅動核心工作是:向系統報告按鍵、觸控式螢幕等輸入事件(event,通過input_event結構描述),不再需要關心檔案操作介面。
驅動報告事件經過inputCore和Eventhandler到達使用者空間。*/
@@@@@@mtk_tpd.c && ft5206_driver.c
===============================================================================
一個輸入事件,如滑鼠移動、鍵盤按下等通過Driver->Inputcore->Event handler->userspace的順序到達使用者控制元件的應用程式。
2. input子系統仍然是字元裝置驅動程式,但是程式碼量減少很多,input子系統只需要完成兩個工作:初始化和事件報告。
3. (1)上報的大致過程:裝置驅動層->核心層->事件處理層->應用層
(2)具體呼叫的函式(以evdev為例):
input_event()->input_handle_event() ->input_pass_event() ->handle->handler->event(handle,type, code, value)
->evdev_event() ->evdev_pass_event() ,
然後通過client->buffer[client->head++]= *event賦值給上層client(是struct evdev_client)
1. 第一層
===============================================================================
使用者空間訪問 <User space> 裝置節點訪問(略)
@@@@@@xx_test.c
2. 第二層
===============================================================================
事件處理層<Event Handler>
/*主要是和使用者空間互動。
(Linux中在使用者空間將所有的裝置都當初檔案來處理,由於在一般的驅動程式中都有提供fops介面,以及在/dev下生成相應的裝置檔案nod,這些操作在輸入子系統中由事件處理層完成)*/
@@@@@@evdev.c等。(以evdev_handler為例)
(1)===>>module_init(evdev_init); module_exit(evdev_exit);
(2)===>>static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);///
/*static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops, ////evdev的檔案操作方法
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,*/
};
}
(3)===>>int input_register_handler(struct input_handler *handler)//註冊一個新的event handler
{
struct input_dev *dev;
list_add_tail(&handler->node, &input_handler_list);
list_for_each_entry(dev, &input_dev_list, node);
input_attach_handler(dev, handler);////將這個新的event handler 與其相容的input dev繫結在一起
}
(4)===>>static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
id = input_match_device(handler, dev);//匹配規則:Input_dev和input_handler匹配後呼叫input_handler的connect。
error = handler->connect(handler, dev, id);//
}
(5)===>>建立新的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++)//尋找未使用的minor
if (!evdev_table[minor])
break;
dev_set_name(&evdev->dev, "event%d", minor);
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);//建立字元裝置節點event%d
}
3. 第三層
===============================================================================
核心層<Input Core>
/*承上啟下。為驅動層提供輸入設備註冊與操作介面,如:input_register_device;通知事件處理層對事件進行處理;在/Proc下產生相應的裝置資訊*/
@@@@@@input.c
(1)===>>subsys_initcall(input_init); module_exit(input_exit);
(2)===>>static int __init input_init(void)
{
//建立 sysfs 系統檔案/proc/bus/input:devices && handlers
err = class_register(&input_class);/// struct class input_class = {
.name = "input",
.devnode = input_devnode,//kasprintf(GFP_KERNEL, "input/%s", dev_name(dev));
};
//建立proc系統檔案/proc/bus/input:devices && handlers
err = input_proc_init();
if (err)
goto fail1;
//註冊字元裝置的檔案操作input_fops
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,///
.llseek = noop_llseek,}
}
(3)===>>static int input_open_file(struct inode *inode, struct file *file)
{
struct input_handler *handler;
/* No load-on-demand here? */
handler = input_table[iminor(inode) >> 5];
if (handler)
new_fops = fops_get(handler->fops);
file->f_op = new_fops;/////根據傳入的inode節點(即:event handler),設定相應的檔案操作方法
err = new_fops->open(inode, file);////開啟檔案操作方法
}
4. 第四層
===============================================================================
裝置驅動層<Input driver>(略)
/*將底層的硬體輸入轉化為統一事件形式,想輸入核心(Input Core)彙報。*/
/*實現裝置驅動核心工作是:向系統報告按鍵、觸控式螢幕等輸入事件(event,通過input_event結構描述),不再需要關心檔案操作介面。
驅動報告事件經過inputCore和Eventhandler到達使用者空間。*/
@@@@@@mtk_tpd.c && ft5206_driver.c
===============================================================================