usbh_hid.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /**
  2. * @file usbh_hid.c
  3. * @brief
  4. *
  5. * Copyright (c) 2022 sakumisu
  6. *
  7. * Licensed to the Apache Software Foundation (ASF) under one or more
  8. * contributor license agreements. See the NOTICE file distributed with
  9. * this work for additional information regarding copyright ownership. The
  10. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  11. * "License"); you may not use this file except in compliance with the
  12. * License. You may obtain a copy of the License at
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  18. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  19. * License for the specific language governing permissions and limitations
  20. * under the License.
  21. *
  22. */
  23. #include "usbh_core.h"
  24. #include "usbh_hid.h"
  25. #define DEV_FORMAT "/dev/input%d"
  26. static uint32_t g_devinuse = 0;
  27. /****************************************************************************
  28. * Name: usbh_hid_devno_alloc
  29. *
  30. * Description:
  31. * Allocate a unique /dev/input[n] minor number in the range 0-31.
  32. *
  33. ****************************************************************************/
  34. static int usbh_hid_devno_alloc(struct usbh_hid *hid_class)
  35. {
  36. size_t flags;
  37. int devno;
  38. flags = usb_osal_enter_critical_section();
  39. for (devno = 0; devno < 32; devno++) {
  40. uint32_t bitno = 1 << devno;
  41. if ((g_devinuse & bitno) == 0) {
  42. g_devinuse |= bitno;
  43. hid_class->minor = devno;
  44. usb_osal_leave_critical_section(flags);
  45. return 0;
  46. }
  47. }
  48. usb_osal_leave_critical_section(flags);
  49. return -EMFILE;
  50. }
  51. /****************************************************************************
  52. * Name: usbh_hid_devno_free
  53. *
  54. * Description:
  55. * Free a /dev/input[n] minor number so that it can be used.
  56. *
  57. ****************************************************************************/
  58. static void usbh_hid_devno_free(struct usbh_hid *hid_class)
  59. {
  60. int devno = hid_class->minor;
  61. if (devno >= 0 && devno < 32) {
  62. size_t flags = usb_osal_enter_critical_section();
  63. g_devinuse &= ~(1 << devno);
  64. usb_osal_leave_critical_section(flags);
  65. }
  66. }
  67. static int usbh_hid_get_report_descriptor(struct usbh_hid *hid_class, uint8_t *buffer)
  68. {
  69. struct usb_setup_packet *setup = hid_class->hport->setup;
  70. setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
  71. setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
  72. setup->wValue = HID_DESCRIPTOR_TYPE_HID_REPORT << 8;
  73. setup->wIndex = hid_class->intf;
  74. setup->wLength = 128;
  75. return usbh_control_transfer(hid_class->hport->ep0, setup, buffer);
  76. }
  77. int usbh_hid_set_idle(struct usbh_hid *hid_class, uint8_t report_id, uint8_t duration)
  78. {
  79. struct usb_setup_packet *setup = hid_class->hport->setup;
  80. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
  81. setup->bRequest = HID_REQUEST_SET_IDLE;
  82. setup->wValue = report_id;
  83. setup->wIndex = (duration << 8) | hid_class->intf;
  84. setup->wLength = 0;
  85. return usbh_control_transfer(hid_class->hport->ep0, setup, NULL);
  86. }
  87. int usbh_hid_get_idle(struct usbh_hid *hid_class, uint8_t *buffer)
  88. {
  89. struct usb_setup_packet *setup = hid_class->hport->setup;
  90. setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
  91. setup->bRequest = HID_REQUEST_GET_IDLE;
  92. setup->wValue = 0;
  93. setup->wIndex = hid_class->intf;
  94. setup->wLength = 1;
  95. return usbh_control_transfer(hid_class->hport->ep0, setup, buffer);
  96. }
  97. int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
  98. {
  99. struct usbh_endpoint_cfg ep_cfg = { 0 };
  100. struct usb_endpoint_descriptor *ep_desc;
  101. int ret;
  102. struct usbh_hid *hid_class = usb_malloc(sizeof(struct usbh_hid));
  103. if (hid_class == NULL) {
  104. USB_LOG_ERR("Fail to alloc hid_class\r\n");
  105. return -ENOMEM;
  106. }
  107. memset(hid_class, 0, sizeof(struct usbh_hid));
  108. usbh_hid_devno_alloc(hid_class);
  109. hid_class->hport = hport;
  110. hid_class->intf = intf;
  111. hport->config.intf[intf].priv = hid_class;
  112. ret = usbh_hid_set_idle(hid_class, 0, 0);
  113. if (ret < 0) {
  114. return ret;
  115. }
  116. uint8_t *report_buffer = usb_iomalloc(128);
  117. ret = usbh_hid_get_report_descriptor(hid_class, report_buffer);
  118. if (ret < 0) {
  119. usb_iofree(report_buffer);
  120. return ret;
  121. }
  122. usb_iofree(report_buffer);
  123. for (uint8_t i = 0; i < hport->config.intf[intf].intf_desc.bNumEndpoints; i++) {
  124. ep_desc = &hport->config.intf[intf].ep[i].ep_desc;
  125. ep_cfg.ep_addr = ep_desc->bEndpointAddress;
  126. ep_cfg.ep_type = ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
  127. ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
  128. ep_cfg.ep_interval = ep_desc->bInterval;
  129. ep_cfg.hport = hport;
  130. if (ep_desc->bEndpointAddress & 0x80) {
  131. usbh_ep_alloc(&hid_class->intin, &ep_cfg);
  132. } else {
  133. usbh_ep_alloc(&hid_class->intout, &ep_cfg);
  134. }
  135. }
  136. snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, hid_class->minor);
  137. USB_LOG_INFO("Register HID Class:%s\r\n", hport->config.intf[intf].devname);
  138. extern int hid_test();
  139. hid_test();
  140. return 0;
  141. }
  142. int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
  143. {
  144. int ret = 0;
  145. struct usbh_hid *hid_class = (struct usbh_hid *)hport->config.intf[intf].priv;
  146. if (hid_class) {
  147. usbh_hid_devno_free(hid_class);
  148. if (hid_class->intin) {
  149. ret = usb_ep_cancel(hid_class->intin);
  150. if (ret < 0) {
  151. }
  152. usbh_ep_free(hid_class->intin);
  153. }
  154. if (hid_class->intout) {
  155. ret = usb_ep_cancel(hid_class->intout);
  156. if (ret < 0) {
  157. }
  158. usbh_ep_free(hid_class->intout);
  159. }
  160. usb_free(hid_class);
  161. if (hport->config.intf[intf].devname[0] != '\0')
  162. USB_LOG_INFO("Unregister HID Class:%s\r\n", hport->config.intf[intf].devname);
  163. memset(hport->config.intf[intf].devname, 0, CONFIG_USBHOST_DEV_NAMELEN);
  164. hport->config.intf[intf].priv = NULL;
  165. }
  166. return ret;
  167. }
  168. const struct usbh_class_driver hid_class_driver = {
  169. .driver_name = "hid",
  170. .connect = usbh_hid_connect,
  171. .disconnect = usbh_hid_disconnect
  172. };
  173. CLASS_INFO_DEFINE const struct usbh_class_info hid_keyboard_class_info = {
  174. .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
  175. .class = USB_DEVICE_CLASS_HID,
  176. .subclass = HID_SUBCLASS_BOOTIF,
  177. .protocol = HID_PROTOCOL_KEYBOARD,
  178. .vid = 0x00,
  179. .pid = 0x00,
  180. .class_driver = &hid_class_driver
  181. };
  182. CLASS_INFO_DEFINE const struct usbh_class_info hid_mouse_class_info = {
  183. .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
  184. .class = USB_DEVICE_CLASS_HID,
  185. .subclass = HID_SUBCLASS_BOOTIF,
  186. .protocol = HID_PROTOCOL_MOUSE,
  187. .vid = 0x00,
  188. .pid = 0x00,
  189. .class_driver = &hid_class_driver
  190. };