函数中完成了对evdev_client对象的构造以及初始化,每一个打开input设备节点的用户都在内核中维护了一个evdev_client对象,这些evdev_client对象通过evdev_attach_client 接下来我们具体分析evdev_open()函数: static int evdev_open(struct inode *inode, struct file *file) { struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev); // 1.计算环形缓冲区大小bufsize以及evdev_client对象大小 注册到内核链表 evdev_attach_client(evdev, client); error = evdev_open_device(evdev); if (error) (evdev, client); kvfree(client); return error; } 在evdev_open()函数中,我们看到了evdev_client对象从构造到注册到内核链表的过程
测试时使用 xinput 设置 Evdev Axis Calibration 属性。 如若都不行切换到 evdev 驱动,即安装 xserver-xorg-input-evdev 然后添加 99-touchscreen-evdev.conf 到 /etc/X11/xorg.conf.d " [ 7221.421] (II) Loading /usr/lib/xorg/modules/input/evdev_drv.so [ 7221.421] (II) Module evdev: ' for 'SYNA2393:00 06CB:19AC' ---- evdev 执行命令 xinput set-prop 11 Evdev Axis Calibration 2 3021 -7 2015 参考文档 man 4 evdev : 需要安装 xserver-xorg-input-evdev man 4 libinput : 需要安装 xserver-xorg-input-libinput
这里以evdev.c为例。 = { .event = evdev_event, .events = evdev_events, .connect = evdev_connect, .disconnect = evdev_disconnect (&evdev->dev); evdev->handle.handler = handler; evdev->handle.private = evdev; /* 将handle作为字符驱动注册到内核 (&evdev->cdev, &evdev_fops); evdev->cdev.kobj.parent = &evdev->dev.kobj; error = cdev_add(&evdev->cdev = { .event = evdev_event, .events = evdev_events, .connect = evdev_connect, .disconnect = evdev_disconnect
事件驱动层 内核在事件驱动层中实现了一个输入设备通用的事件驱动,即evdev,其实现在driver/input/evdev.c中。无论是按键、触摸屏还是鼠标,都会通过evdev进行输入事件的处理。 { .event = evdev_event, .connect = evdev_connect, .disconnect = evdev_disconnect, 为例,回到evdev.c中,进入到evdev_event函数中 client = rcu_dereference(evdev->grab); if (client) evdev_pass_event ;(其中evdev是struct evdev的实例对象,是对一个完整的evdev事件驱动的抽象描述,其中struct evdev_client *grab成员管理该事件驱动下的所有client;client evdev_open函数主要做的是根据次设备号减去基地址得到索引,从evdev_table中取出evdev对象,然后实例化出一个client对象,将clinet对象绑定到evdev对象中。
(&evdev_handler); //注册 } 6我们来看看这个evdev_handler变量是什么结构体,: 1 static struct input_handler evdev_handler 8.1 evdev_handler的.connect函数是evdev_connect(),代码如下: 1 static int evdev_connect(struct input_handler * && evdev_table[minor]; minor++); //查找驱动设备的子设备号 5 if (minor == EVDEV_MINORS) { // EVDEV_MINORS= 驱动设备 13 evdev->handle.name = evdev->name; 14 evdev->handle.handler = handler; //指向参数 input_handler wake_up_interruptible(&evdev->wait); //有事件触发,便唤醒等待中断 } 其中evdev_event()是evdev.c(事件驱动) 的evdev_handler
<linux/input.h> #include "tslib.h" int evdev_root_x; int evdev_root_y; int evdev_button; struct tsdev ts) { perror("ts_setup"); exit(1); } evdev_root_x = 0; evdev_root_y = 0; evdev_button evdev_root_y = samp.y ; } if(0 == samp.pressure) evdev_button = LV_INDEV_STATE_REL ; else evdev_button = LV_INDEV_STATE_PR ; //将变量注册到LVGL输入设备接口的环境中 data->point.x = evdev_root_x ; data-> point.y = evdev_root_y ; data->state = evdev_button ; //坐标限幅 if(data->point.x < 0) data->point.x
用户使用了 evdev 和 pyudev 包来实现此功能。脚本大部分都可以正常工作,包括键盘和鼠标事件检测以及插件检测。然而,每当用户拔出鼠标时,都会发生许多奇怪的事情,导致脚本无法正常工作。 /mouseX 拔下事件会首先发生,但我在 evdev 中没有使用它,这会导致脚本失败,因为 ./eventX(脚本中读取数据的位置)也会同时拔下,但我只能在下一轮中检测到 ./eventX。 /usr/bin/env pythonimport pyudevfrom evdev import InputDevice, list_devices, categorizefrom select import 设备,而 mouseX 是“传统”设备(例如,不支持各种 evdev ioctl)。 initially, so that if# there is a plugin after we evdev.list_devices() we'll pick it upmonitor.start
分配一个evdev结构 evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); //2. 初始化evdev->handle中的dev // 初始化evdev->handle中的hanler。 这样以来,input_handle就成handler与dev之间连接的桥梁了。 evdev->handle.dev = input_get_device(dev); evdev->handle.name = dev_name(&evdev->dev); evdev->handle.handler = handler; evdev->handle.private = evdev; } //3. 行,我们假设我们用的evdev这个事件处理handler /*分析evdev_read函数 */ static ssize_t evdev_read(struct file *file, char _
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); // 分配一个input_handle // 设置 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) evdev_read // 无数据并且是非阻塞方式打开,则立刻返回 if (client->head == client->tail && evdev->exist && (file- evdev->exist); 谁来唤醒? evdev_event wake_up_interruptible(&evdev->wait); evdev_event被谁调用?
442 # define USE_EVDEV 1 443 #endif 444 445 #ifndef USE_BSD_EVDEV 446 # define USE_BSD_EVDEV 0 447 #endif 448 449 #if USE_EVDEV || USE_BSD_EVDEV 450 # define EVDEV_NAME "/dev/input/event0 456 # define EVDEV_HOR_MIN 0 /*to invert axis swap EVDEV_XXX_MIN by EVDEV_XXX_MAX calibraion values>*/ 458 # define EVDEV_VER_MIN 0 459 # define EVDEV_VER_MAX 4096 460 # endif /*EVDEV_CALIBRATE*/ 461 #endif /*USE_EVDEV*/ 其它的地方暂时不用修改,然后按ESC退出编辑模式,输入:wq保存退出。
Evdev 如果希望底层控制键盘,可以使用Evdev模块直接访问/dev/input/event设备 Evdev模块需要安装Linux头文件,比较复杂,且只支持Linux系统,适合有一定基础的用户使用
通过键盘驱动的read函数,若有按键按下,就会上传按键数据给用户层hexdump 因为键盘驱动的input_handler 是:evdev_handler 所以键盘驱动的read函数是: evdev_handler ->evdev_fops->evdev_read 进入evdev_read()函数,如下图所示: ? evdev_event_to_user()这个函数从字面上来看,显然就是用来上传给用户层的函数,其中buffer是函数参数,指向用户层, 所以数据就是event.
自定义画布lv_canvas暂未对接g2d缩放功能 evdev 触摸我们用的是lvgl官方的evdev 代码位置如下: lichee/rtos-components/thirdparty/littlevgl -8/lv_drivers/indev/evdev.c lvgl 使用触控功能,需在应用lv_drv_conf.h 文件中配置: # define USE_EVDEV 1 应用lv_drv_conf.h 中的EVDEV_NAME 要与所使用的触摸屏驱动对应,例如 lv_examples 的配置文件: lichee/rtos-components/thirdparty/littlevgl-8/lv_examples LVGL 开启触控功能 lvgl 使用触控功能,需在应用 lv_drv_conf.h 文件中使能宏 USE_EVDEV。 前提要确认好触摸屏驱动模块能够正常加载使用,并且使 lv_drv_conf.h 中的 EVDEV_NAME 与所使用的触摸屏驱动对应: # define USE_EVDEV 1 # define EVDEV_NAME
gracefully */ exit(signum); } } } 漏洞利用思路 利用do_beep()中的write函数,则console_type必须为BEEP_TYPE_EVDEV = -1) console_type = BEEP_TYPE_EVDEV; else console_type = BEEP_TYPE_CONSOLE; /* Beep */ 在这个间隔里,console_type为BEEP_TYPE_EVDEV,而console_fd为目标文件,就可以对任意文件进行写操作。 但是由于一启动beep程序,console_device就不能改变了,我们可以一开始指向有效的设备,使console_type为BEEP_TYPE_EVDEV,绕过验证,之后再通过软链接来指向目标文件, = -1) + console_type = BEEP_TYPE_EVDEV; + else + console_type = BEEP_TYPE_CONSOLE; + /* this
图3-2 《四》 这里我们以evdev.c(事件设备)来讲解如何注册handler?? 在evdev.c中入口函数中(图4-1)通过input_register_handler()函数,注册了一个结构体evdev_handler(图4-2). ① fops:注册了file_operations ② minor:子设备号(evdev:64),用于上面说到input_table[]数组中。 ③ id_table:用来和input_dev匹配(图4-4),从注释上可以获知,支持所有的输入设备。 在《四》中,我们以evdev.c(事件设备)。在图4-4中,我们可以看到input_device_id只注册了driver_info,所以我们前面四个if可以不解读。 《七》 图7-1所示为evdev.c(事件设备)的connect()函数实体。dev和handler通过一个中间件hande连接起来。通过devfs_mk_cdev()函数创建设备文件。
#include "lvgl/lvgl.h" #include "lv_drivers/display/sunxifb.h" #include "lv_drivers/indev/evdev.h" #include disp_drv.rotated = rotated; disp_drv.screen_transp = 0; lv_disp_drv_register(&disp_drv); evdev_init initialization*/ indev_drv.type = LV_INDEV_TYPE_POINTER; /*See below.*/ indev_drv.read_cb = evdev_read stdio.h> #include "lvgl/lvgl.h" #include "lv_drivers/display/sunxifb.h" #include "lv_drivers/indev/evdev.h initialization*/ indev_drv.type = LV_INDEV_TYPE_POINTER; /*See below.*/ indev_drv.read_cb = evdev_read
dev/fb0"); /* 如添加如下两行,对应前面屏幕适配后的设备节点 /dev/input/event2 */ lv_indev_t * touch; touch = lv_evdev_create while(1) { lv_timer_handler(); usleep(5000); } return 0; } [ 再修改 lv_conf.h,启用evdev ,以便使用触摸功能 /*Driver for evdev input devices*/ #define LV_USE_EVDEV 1 [ 经过上面的处理,移植代码就准备好了。
" #include "lvgl/demos/lv_demos.h" #include "lv_drivers/display/fbdev.h" #include "lv_drivers/indev/evdev.h fbdev_flush; disp_drv.hor_res = 480; disp_drv.ver_res = 800; lv_disp_drv_register(&disp_drv); evdev_init lv_indev_drv_init(&indev_drv_1); indev_drv_1.type = LV_INDEV_TYPE_POINTER; indev_drv_1.read_cb = evdev_read
= "retropie" ;then sudo apt-get install xserver-xorg-input-evdev sudo cp -rf /usr/share/X11/xorg.conf.d /10-evdev.conf /usr/share/X11/xorg.conf.d/45-evdev.conf fi if test "$j" = "retropie" ;then sudo cp -
1、Linux内核修改 在Kernel目录下搜索:USB_VIDEO_CLASS_INPUT_EVDEV: 然后按以下的方式进行配置: 2、配置UVC成功的验证方法 配置以后重新编译SDK,然后插入