【usb】linux内核USB键盘驱动解析--特殊键值转化及上报

一、概况

以Linux5.10内核中USB键盘驱动为例进行解析:https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.10.tar.gz
文件路径:linux-5.10/drivers/hid/usbhid/usbkbd.c

二、探索

入口

  • 首先我们直接看usb_kbd_probe这个函数的335行usb_fill_int_urb,这里是在填充USB中断传输请求。也就是说在用后面那一大堆参数填充kbd->irq这个变量。然后设置的这个传输的回调函数是usb_kbd_irq,也就是说当有键值报上来的时候,将会用usb_kbd_irq函数处理。

usb_kbd_irq

  • 我们可以看到该函数的参数是一个urb(USB request block),表示本次完成传输的请求。在看117和118行,调用了函数input_report_key向输入子系统上报键值。该函数第一个参数代表设备,第二个参数代表键值,第三个参数代表该键被按下还是释放。
	for (i = 0; i < 8; i++)
		input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
  • 第二个参数usb_kbd_keycode[i + 224],这里的usb_kbd_keycode是一个数组,该数组用来将键盘报上来的键值,转化为输入子系统能够识别的键值。转化的原理就是usb_kbd_keycode的数组下标代表键盘报上来的键值,对应位置的值,代表转化后报给输入子系统的键值。所以这里的意思就是将键盘报上来的i+224这个键值转化为输入子系统对应的键值。

  • 那么这里的i+224又代表哪个键呢?由于i是循环变量,从0开始到7。所以i+224,其实是224~231。所以我们只需要搞清楚,224~231这几个值代表哪几个键。

  • 通过查阅HID Usage Tables的第10节10 Keyboard/Keypad Page (0x07),我们可以知道当键盘报上来04,代表字母a。如下:
    在这里插入图片描述

  • 所以我们继续查阅该表,16进制E0转换成10进制就是224,其代表左侧CTRL键。所以上面的224~231也就是E0~E7,分别代表 LeftControlLeftShift,。。。。。。
    在这里插入图片描述

  • 我们再次回到代码里面,usb_kbd_keycode[i + 224]意思就是将 LeftControlLeftShift,。。。。。。八个键盘报上来的键值转化为输入子系统定义的键值。

  • 上面我们知道了键值转化的原理,那么我们怎么知道这个键有没有被按下呢?我们接着看(kbd->new[0] >> i) & 1,将new[0]元素右移i位,然后在与1。啥意思?通过查阅USB HID协议8.3节,我们可以知道USB会通过一个8位的bitmap来上报CTRL,SHIFT,ALT等键。具体如下:
    在这里插入图片描述

  • 也就是说new[0]这个unsigned char类型的变量里面的每一位代表一个键,如果这个位为0,则表示该位对应的键没有被按下;为1,则该位对应的键被按下了。每个位代表的键如上表。

三、总结

总结一下,117和118行的这个for循环,通过依次查看new[0]元素的各个位,确定该位对应的键是否被按下。并将该键值通过usb_kbd_keycode表转化为输入子系统定义的键值,后上报给输入子系统。

四、参考资料

HID Usage Tables 1.4
USB HID协议

猜你喜欢

转载自blog.csdn.net/C2681595858/article/details/129445755