USB驱动——键盘驱动(控制传输)

USB驱动——键盘驱动(控制传输)

http://blog.csdn.net/lizuobin2/ https://blog.csdn.net/lizuobin2/article/details/51971393

    本文以 usbkbd.c 为例,分析 usb 键盘驱动程序。

 
  1. static int __init usb_kbd_init(void)

  2. {

  3. int result = usb_register(&usb_kbd_driver);

  4. if (result == 0)

  5. printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"

  6. DRIVER_DESC "\n");

  7. return result;

  8. }

 
  1. static struct usb_driver usb_kbd_driver = {

  2. .name = "usbkbd",

  3. .probe = usb_kbd_probe,

  4. .disconnect = usb_kbd_disconnect,

  5. .id_table = usb_kbd_id_table,

  6. };

    还是来看一下 id_table ,与鼠标相比,仅仅是协议不一样。

 
  1. static struct usb_device_id usb_kbd_id_table [] = {

  2. { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,

  3. USB_INTERFACE_PROTOCOL_KEYBOARD) },

  4. { } /* Terminating entry */

  5. };

    下面来看probe函数

 
  1. static int usb_kbd_probe(struct usb_interface *iface,

  2. const struct usb_device_id *id)

  3. {

  4. /* 获得usb_device */

  5. struct usb_device *dev = interface_to_usbdev(iface);

  6.  
  7. /* 接口的设置 */

  8. struct usb_host_interface *interface;

  9.  
  10. /* 端点描述符 */

  11. struct usb_endpoint_descriptor *endpoint;

  12.  
  13. /* 键盘结构体 */

  14. struct usb_kbd *kbd;

  15.  
  16. /* 输入设备 */

  17. struct input_dev *input_dev;

  18.  
  19. int i, pipe, maxp;

  20. int error = -ENOMEM;

  21.  
  22. /* 获取该接口当前的设置 */

  23. interface = iface->cur_altsetting;

  24.  
  25. /* 如果当前设置的端点数量不是1,那么错误,返回 */

  26. if (interface->desc.bNumEndpoints != 1)

  27. return -ENODEV;

  28.  
  29. /* 如果当前设置第一个端点的类型不是中断端点,错误,返回 */

  30. endpoint = &interface->endpoint[0].desc;

  31. if (!usb_endpoint_is_int_in(endpoint))

  32. return -ENODEV;

  33.  
  34. /* 第一个端点的管道 */

  35. pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);

  36.  
  37. /* 最大传输包大小 */

  38. maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));

  39.  
  40. /* 为键盘结构体分配空间 */

  41. kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);

  42.  
  43. /* 分配一个输入设备 */

  44. input_dev = input_allocate_device();

  45.  
  46. /*

  47. kbd->irq = usb_alloc_urb(0, GFP_KERNEL)

  48. kbd->led = usb_alloc_urb(0, GFP_KERNEL)

  49. kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma)

  50. kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma)

  51. kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC, &kbd->leds_dma)

  52. */

  53. if (usb_kbd_alloc_mem(dev, kbd))

  54. goto fail2;

  55.  
  56. /* 填充键盘结构体。以及一些字符串 */

  57. kbd->usbdev = dev;

  58. kbd->dev = input_dev;

  59.  
  60. if (dev->manufacturer)

  61. strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));

  62.  
  63. if (dev->product) {

  64. if (dev->manufacturer)

  65. strlcat(kbd->name, " ", sizeof(kbd->name));

  66. strlcat(kbd->name, dev->product, sizeof(kbd->name));

  67. }

  68.  
  69. if (!strlen(kbd->name))

  70. snprintf(kbd->name, sizeof(kbd->name),

  71. "USB HIDBP Keyboard %04x:%04x",

  72. le16_to_cpu(dev->descriptor.idVendor),

  73. le16_to_cpu(dev->descriptor.idProduct));

  74.  
  75. usb_make_path(dev, kbd->phys, sizeof(kbd->phys));

  76. strlcpy(kbd->phys, "/input0", sizeof(kbd->phys));

  77.  
  78. /* 填充输入设备 */

  79. input_dev->name = kbd->name;

  80. input_dev->phys = kbd->phys;

  81. usb_to_input_id(dev, &input_dev->id);

  82. input_dev->dev.parent = &iface->dev;

  83.  
  84. input_set_drvdata(input_dev, kbd);

  85.  
  86. /* 设置它支持的事件类型和具体事件 1、按键类事件 2、LED灯(大小写灯等)3、重复上报*/

  87. input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |

  88. BIT_MASK(EV_REP);

  89. input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |

  90. BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) |

  91. BIT_MASK(LED_KANA);

  92.  
  93. for (i = 0; i < 255; i++)

  94. set_bit(usb_kbd_keycode[i], input_dev->keybit);

  95. clear_bit(0, input_dev->keybit);

  96.  
  97. /* 对于LED类型的事件,首先会调用到dev->event 然后再调用事件处理层的event */

  98. input_dev->event = usb_kbd_event;

  99. input_dev->open = usb_kbd_open;

  100. input_dev->close = usb_kbd_close;

  101.  
  102. /* 填充中断类型Urb */

  103. usb_fill_int_urb(kbd->irq, dev, pipe,

  104. kbd->new, (maxp > 8 ? 8 : maxp),

  105. usb_kbd_irq, kbd, endpoint->bInterval);

  106. kbd->irq->transfer_dma = kbd->new_dma;

  107. kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

  108.  
  109. /*

  110. * bit7 控制传输 data 阶段的方向 0 主机到设备 1设备到主机, 这里 0 主机到设备

  111. * bit5-6 表示 request 类型,是标准的还是厂家定义的, 这里为hid class定义

  112. * bit0-4 表示这个请求针对的是设备、接口还是端点 , 这里是接口

  113. */

  114. kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; // 0x01 << 5 |

  115.  
  116. /*

  117. #define USB_REQ_GET_STATUS 0x00

  118. #define USB_REQ_CLEAR_FEATURE 0x01

  119. #define USB_REQ_SET_FEATURE 0x03

  120. #define USB_REQ_SET_ADDRESS 0x05

  121. #define USB_REQ_GET_DESCRIPTOR 0x06

  122. #define USB_REQ_SET_DESCRIPTOR 0x07

  123. #define USB_REQ_GET_CONFIGURATION 0x08

  124. #define USB_REQ_SET_CONFIGURATION 0x09

  125. #define USB_REQ_GET_INTERFACE 0x0A

  126. #define USB_REQ_SET_INTERFACE 0x0B

  127. #define USB_REQ_SYNCH_FRAME 0x0C

  128. */

  129. kbd->cr->bRequest = USB_REQ_SET_CONFIGURATION;

  130.  
  131. /* request 的参数 */

  132. kbd->cr->wValue = cpu_to_le16(0x200);

  133.  
  134. /* bRequestType 中,针对接口、端点时,它表示那个接口或端点 */

  135. kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);

  136.  
  137. /* data阶段数据长度 */

  138. kbd->cr->wLength = cpu_to_le16(1);

  139.  
  140. /*

  141. static inline void usb_fill_control_urb(

  142. struct urb *urb,

  143. struct usb_device *dev,

  144. unsigned int pipe,

  145. unsigned char *setup_packet,

  146. void *transfer_buffer,

  147. int buffer_length,

  148. usb_complete_t complete_fn,

  149. void *context)

  150. */

  151. /* 这里使用的是默认端点0 */

  152. usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),(void *) kbd->cr, kbd->leds, 1, usb_kbd_led, kbd);

  153. kbd->led->setup_dma = kbd->cr_dma;

  154. kbd->led->transfer_dma = kbd->leds_dma;

  155. kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);

  156.  
  157. error = input_register_device(kbd->dev);

  158.  
  159. usb_set_intfdata(iface, kbd);

  160. return 0;

  161. }

    这里与鼠标驱动程序相比,多了一个控制传输过程,而且,这个控制传输的 bRequestType 中说明了这个传输不是标准的请求,而是Class,我们的键盘是HID类型,因此还要看USB HID协议中,关于这个请求是如何定义的,才能知道wValue 、wIndex等是什么意思(参考:http://blog.csdn.net/leo_wonty/article/details/6721214),这就是就将knd->leds 内的一字节数据发送给从设备。在鼠标驱动程序中,中断 urb 是在open函数中提交的,这里也不例外。

 
  1. static int usb_kbd_open(struct input_dev *dev)

  2. {

  3. struct usb_kbd *kbd = input_get_drvdata(dev);

  4.  
  5. kbd->irq->dev = kbd->usbdev;

  6. if (usb_submit_urb(kbd->irq, GFP_KERNEL))

  7. return -EIO;

  8.  
  9. return 0;

  10. }

    中断传输完成之后会调用完成函数,usb_kbd_irq

 
  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. //报告usb_kbd_keycode[224..231]8按键状态

  18. //KEY_LEFTCTRL,KEY_LEFTSHIFT,KEY_LEFTALT,KEY_LEFTMETA,

  19. //KEY_RIGHTCTRL,KEY_RIGHTSHIFT,KEY_RIGHTALT,KEY_RIGHTMETA

  20. for (i = 0; i < 8; i++)

  21. input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);

  22. //若同时只按下1个按键则在第[2]个字节,若同时有两个按键则第二个在第[3]字节,类推最多可有6个按键同时按下

  23. for (i = 2; i < 8; i++) {

  24. //获取键盘离开的中断

  25. //同时没有该KEY的按下状态

  26. if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {

  27. if (usb_kbd_keycode[kbd->old[i]])

  28. input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);

  29. else

  30. hid_info(urb->dev,

  31. "Unknown key (scancode %#x) released.\n",

  32. kbd->old[i]);

  33. }

  34. //获取键盘按下的中断

  35. //同时没有该KEY的离开状态

  36. if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {

  37. if (usb_kbd_keycode[kbd->new[i]])

  38. input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);

  39. else

  40. hid_info(urb->dev,

  41. "Unknown key (scancode %#x) released.\n",

  42. kbd->new[i]);

  43. }

  44. }

  45.  
  46. input_sync(kbd->dev); //同步设备,告知事件的接收者驱动已经发出了一个完整的报告

  47.  
  48. memcpy(kbd->old, kbd->new, 8); //防止未松开时被当成新的按键处理

  49.  
  50. resubmit:

  51. i = usb_submit_urb (urb, GFP_ATOMIC);

  52. if (i)

  53. hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",

  54. kbd->usbdev->bus->bus_name,

  55. kbd->usbdev->devpath, i);

  56. }

    这里,都是上报的按键类事件,我们在前边的Probe函数中,设置了输入设备支持按键类事件,还有一个LED类事件,但是搜遍代码也没有找到,LED类事件是在哪里上报的。还有,probe函数中定义了一个dev->event函数,在浏览资料时发现,有些人说在input_event时,调用事件处理层的event函数的同时会调用dev->event,我认为这种说法是不正确的,看过input_event代码的同学应该不难发现,只有上报LED类等事件的时候才会触发dev->event,我们这里单纯上报的按键类事件并不会触发dev->event 。那么,probe 函数里定义的 dev->event 函数岂不是成了摆设么?确实,我暂时没发现它有什么用。手头没有usb键盘,这个后边实验证实。

 
  1. static int usb_kbd_event(struct input_dev *dev, unsigned int type,

  2. unsigned int code, int value)

  3. {

  4. struct usb_kbd *kbd = input_get_drvdata(dev);

  5.  
  6. if (type != EV_LED)

  7. return -1;

  8.  
  9. kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |

  10. (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |

  11. (!!test_bit(LED_NUML, dev->led));

  12.  
  13. if (kbd->led->status == -EINPROGRESS)

  14. return 0;

  15.  
  16. if (*(kbd->leds) == kbd->newleds)

  17. return 0;

  18.  
  19. *(kbd->leds) = kbd->newleds;

  20. kbd->led->dev = kbd->usbdev;

  21. if (usb_submit_urb(kbd->led, GFP_ATOMIC))

  22. err_hid("usb_submit_urb(leds) failed");

  23.  
  24. return 0;

  25. }

    这里的 dev->led 记录的是led的状态,比如,我们上报一个LED事件时,input_event 中会将对应的事件记录在 dev->led 中。这里检测LED事件是否发生,然后通过控制传输将1字节数据传送给usb键盘,Usb键盘的灯相应做出改变。但是,说到底,代码里没有上报过LED类事件,一切都是白扯。

 
  1. static void usb_kbd_led(struct urb *urb)

  2. {

  3. struct usb_kbd *kbd = urb->context;

  4.  
  5. if (urb->status)

  6. dev_warn(&urb->dev->dev, "led urb status %d received\n",

  7. urb->status);

  8.  
  9. if (*(kbd->leds) == kbd->newleds)

  10. return;

  11.  
  12. *(kbd->leds) = kbd->newleds;

  13. kbd->led->dev = kbd->usbdev;

  14. if (usb_submit_urb(kbd->led, GFP_ATOMIC))

  15. err_hid("usb_submit_urb(leds) failed");

  16. }

    这里的控制传输完成函数也是个累赘?每次有LED事件上报的话,那么控制传输urb就自动提交了。那么,*(kbd->leds)== kbd->newleds 必然是相等的,除非又有新的事件上报了,但是新事件上报时,在usb_kbd_event 函数里urb不就自动提交了么? 会出现不相等的情况?

猜你喜欢

转载自blog.csdn.net/yangming2466/article/details/83218746