一、原理分析
1. 首先通过打印usb_buf[i]中的8字节数据,看一下按键按下之后会接收到什么。
1)通过按完所有键盘按键打印的结果可知,有8个按键会打印在usb_buf[0]里,即:
ctrl左键----0x01----00000001
shift左键----0x02----00000010
alt左键----0x04------00000100
win左键----0x08-----00001000
ctrl右键----0x10------00010000
shift右键----0x20------00100000
alt右键----0x40--------01000000
win右键----0x80-------10000000
2)usb_buf[2]--usb_buf[7]为A B C D 1 2 3 4 F2 F4等普通的按键;
根据上节内容可知,按键的KEY_L等值得宏定义在input.h中,即:
从打印的usb_buf[i]数组可知,字符A为0x04,但alt左键也是0x04,该怎样在程序里区分呢?
。。。。。。。。。。
在键盘的源码程序/drivers/hid/usbhid/usbkbd.c中,使用过数组一一对应的:
static unsigned char usb_kbd_keycode[256] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, 150,158,159,128,136,177,178,176,142,152,173,140 };
1)对于字符A的0x04就对应数组中的0x30;这里usb_buf[2-7]的0x04等数值,就对应usb_kbd_keycode[256]中的位置,确定每个按键的input码。
2)对于8个特殊按键,其位置为usb_buf[0]-1+ 224, input码为:usb_kbd_keycode[usb_buf[0]-1+ 224](数组从0开始)。例如:ctrl左键在usb_buf[0]为0x01,对应的input码为:usb_kbd_keycode[0+ 224]=29。正好和input.h中的宏定义的值相同。
同时,也可以有源码程序推理出:
1 for (i = 0; i < 8; i++) 2 input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
程序中用于判断这8个按键的数据kbd->new[0](usb_buf[0])是否为1,然后通过input_report_key函数上传按键事件。
例如:alt左键----0x04------00000100按下后,判断(0x04 >> 2) & 1=1,则上报。
二、源码分析
1.中断函数
1 static void usb_kbd_irq(struct urb *urb) 2 { 3 struct usb_kbd *kbd = urb->context; 4 int i; 5 6 switch (urb->status) { 7 case 0: /* success */ 8 break; 9 case -ECONNRESET: /* unlink */ 10 case -ENOENT: 11 case -ESHUTDOWN: 12 return; 13 /* -EPIPE: should clear the halt */ 14 default: /* error */ 15 goto resubmit; 16 } 17 //特殊的8个按键检测是否按下 18 for (i = 0; i < 8; i++) 19 input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); 20 //检测普通按键 数组下表为2-7 21 for (i = 2; i < 8; i++) { 22 //usb_kbd_keycode数组中跳过前面3个0,从3开始;
//上一次的按键kbd->old[i]非0数值 与 kbd->new + 2开始的6个字节的kbd->new[i]数组数值是否有相同的,若无,则按键已经松开 23 if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
24 if (usb_kbd_keycode[kbd->old[i]]) //判断非零值 25 input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); //上传松开事件 26 else 27 info("Unknown key (scancode %#x) released.", kbd->old[i]); 28 } 29 //当前状态的按键kbd->new[i]非0数值 与 上一次的按键kbd->old[i]+ 2开始的6个字节的是否有相同的,若无,则按键已经按下 30 if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { 31 if (usb_kbd_keycode[kbd->new[i]]) 32 input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); 33 else 34 info("Unknown key (scancode %#x) pressed.", kbd->new[i]); 35 } 36 } 37 38 input_sync(kbd->dev); 39 40 memcpy(kbd->old, kbd->new, 8); //拷贝当前按键的8个字节到kbd->old,进行下一次的判断 41 42 resubmit: 43 i = usb_submit_urb (urb, GFP_ATOMIC); 44 if (i) 45 err ("can't resubmit intr, %s-%s/input0, status %d", 46 kbd->usbdev->bus->bus_name, 47 kbd->usbdev->devpath, i); 48 }
2. 修改id_table(用于驱动和设备匹配的)
1 static struct usb_device_id usb_keyboardid_table [] = { 2 { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, 3 USB_INTERFACE_PROTOCOL_KEYBOARD) },//USB协议:键盘协议 4 5 };
三、自己编写的程序
1 #include <linux/kernel.h> 2 #include <linux/slab.h> 3 #include <linux/module.h> 4 #include <linux/init.h> 5 #include <linux/usb/input.h> 6 #include <linux/hid.h> 7 8 static struct input_dev *myusb_kbd_dev; 9 static char *usb_buf; 10 static dma_addr_t usb_buf_phys; 11 static int len; 12 static struct urb *myusb_kbd_urb; 13 14 //键盘码表共有252个数据 15 static const unsigned char usb_kbd_keycode[252] = { 16 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 17 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, 18 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, 19 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 20 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, 21 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 22 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, 23 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, 24 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, 25 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, 31 150,158,159,128,136,177,178,176,142,152,173,140 32 }; 33 34 static struct usb_device_id usb_keyboardid_table [] = { 35 { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, 36 USB_INTERFACE_PROTOCOL_KEYBOARD) },//USB协议:键盘协议 37 38 }; 39 40 void my_memcpy(unsigned char *dest,unsigned char *src,int len) //复制缓存 41 { 42 while(len--) 43 { 44 *dest++= *src++; 45 } 46 } 47 48 static void usb_keyboardirq(struct urb *urb) 49 { 50 static unsigned char pre_val[8]={0,0,0,0,0,0,0,0}; 51 int i; 52 53 //8个特殊按键,对比上一次的按键值pre_val[0]和当前usb_buf[0],如果不相等有按键按下,则上报 54 for (i = 0; i < 8; i++) 55 if(((pre_val[0]>>i)&1)!=((usb_buf[0]>>i)&1)) 56 { 57 input_report_key(myusb_kbd_dev, usb_kbd_keycode[i + 224], (usb_buf[0]>> i) & 1); 58 input_sync(myusb_kbd_dev); //上传同步事件 59 } 60 61 62 /*上传普通按键*/ 63 for(i=2;i<8;i++) 64 if(pre_val[i]!=usb_buf[i]) //上一次和本次按键值不同,说明有按键按下 65 { 66 if(usb_buf[i]) //非0,按下事件上报 67 input_report_key(myusb_kbd_dev,usb_kbd_keycode[usb_buf[i]], 1); 68 else if(pre_val[i]) //上一次非零,本次为0,松开事件 69 input_report_key(myusb_kbd_dev,usb_kbd_keycode[pre_val[i]], 0); 70 input_sync(myusb_kbd_dev); //上传同步事件 71 } 72 73 my_memcpy(pre_val, usb_buf, 8); //更新数据 74 75 /* 重新提交urb */ 76 usb_submit_urb(myusb_kbd_urb, GFP_KERNEL); 77 } 78 79 static int usb_keyboardprobe(struct usb_interface *intf, const struct usb_device_id *id) 80 { 81 volatile unsigned char i; 82 struct usb_device *dev = interface_to_usbdev(intf); //设备,通过usb_ interface接口获取usb_device设备,为后面设置USB数据传输用 83 struct usb_host_interface *interface; // 当前接口 84 struct usb_endpoint_descriptor *endpoint; 85 int pipe; //端点管道 86 87 interface = intf->cur_altsetting; 88 endpoint = &interface->endpoint[0].desc; //当前接口下的端点描述符 89 90 printk("VID=%x,PID=%x\n",dev->descriptor.idVendor,dev->descriptor.idProduct); 91 92 /* a. 分配一个input_dev */ 93 myusb_kbd_dev = input_allocate_device(); 94 95 /* b. 设置 */ 96 /* b.1 能产生哪类事件 */ 97 set_bit(EV_KEY, myusb_kbd_dev->evbit); 98 set_bit(EV_REP, myusb_kbd_dev->evbit); 99 100 /* b.2 添加所有按键 */ 101 for (i = 0; i < 252; i++) 102 set_bit(usb_kbd_keycode[i], myusb_kbd_dev->keybit); 103 clear_bit(0, myusb_kbd_dev->keybit); 104 105 106 /* c. 注册 */ 107 input_register_device(myusb_kbd_dev); 108 109 /* d. 硬件相关操作 */ 110 /* 数据传输3要素: 源,目的,长度 */ 111 /* 源: USB设备的某个端点 */ 112 pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); 113 114 /* 长度: */ 115 len = endpoint->wMaxPacketSize; 116 117 /* 目的: */ 118 usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys); 119 120 /* 使用"3要素" */ 121 /* 分配usb request block */ 122 myusb_kbd_urb = usb_alloc_urb(0, GFP_KERNEL);//usb传输素具的urb结构体 123 /* 使用"3要素设置urb" */ 124 usb_fill_int_urb(myusb_kbd_urb, dev, pipe, usb_buf, len, usb_keyboardirq, NULL, endpoint->bInterval); 125 myusb_kbd_urb->transfer_dma = usb_buf_phys; 126 myusb_kbd_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 127 128 /* 使用URB */ 129 usb_submit_urb(myusb_kbd_urb, GFP_KERNEL); 130 131 return 0; 132 } 133 134 static void usb_keyboarddisconnect(struct usb_interface *intf) 135 { 136 struct usb_device *dev = interface_to_usbdev(intf); 137 138 //printk("disconnect usbmouse!\n"); 139 usb_kill_urb(myusb_kbd_urb); 140 usb_free_urb(myusb_kbd_urb); 141 142 usb_buffer_free(dev, len, usb_buf, usb_buf_phys); 143 input_unregister_device(myusb_kbd_dev); 144 input_free_device(myusb_kbd_dev); 145 } 146 147 /* 1. 分配/设置usb_driver */ 148 static struct usb_driver usb_keyboarddriver = { 149 .name = "usb_keyboard", 150 .probe = usb_keyboardprobe, 151 .disconnect = usb_keyboarddisconnect, 152 .id_table = usb_keyboardid_table, 153 }; 154 155 156 static int usb_keyboardinit(void) 157 { 158 /* 2. 注册 */ 159 usb_register(&usb_keyboarddriver); 160 return 0; 161 } 162 163 static void usb_keyboardexit(void) 164 { 165 usb_deregister(&usb_keyboarddriver); 166 } 167 168 module_init(usb_keyboardinit); 169 module_exit(usb_keyboardexit); 170 171 MODULE_LICENSE("GPL");
四、测试
1. 烧写内核,编译/加载驱动模块。
2. # cat /dev/tty1
3. # exec 0</dev/tty1 (直接可以用键盘操作开发板的控制台)
标签:USB,urb,dev,键盘,kbd,编写,buf,myusb,usb From: https://www.cnblogs.com/kn-zheng/p/17086946.html