hid.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2011-12-12 Yi Qiu first version
  9. * 2021-02-23 Leslie Lee update with current usb api
  10. */
  11. #include <rtthread.h>
  12. #include <drivers/usb_host.h>
  13. #include "hid.h"
  14. #ifdef RT_USBH_HID
  15. #define DBG_TAG "usbhost.hid"
  16. #define DBG_LVL DBG_INFO
  17. #include <rtdbg.h>
  18. static struct uclass_driver hid_driver;
  19. static rt_list_t _protocal_list;
  20. /**
  21. * This function will do USB_REQ_SET_IDLE request to set idle period to the usb hid device
  22. *
  23. * @param intf the interface instance.
  24. * @duration the idle period of requesting data.
  25. * @report_id the report id
  26. *
  27. * @return the error code, RT_EOK on successfully.
  28. */
  29. rt_err_t rt_usbh_hid_set_idle(struct uhintf* intf, int duration, int report_id)
  30. {
  31. struct urequest setup;
  32. struct uinstance* device;
  33. int timeout = USB_TIMEOUT_BASIC;
  34. /* parameter check */
  35. RT_ASSERT(intf != RT_NULL);
  36. RT_ASSERT(intf->device != RT_NULL);
  37. device = intf->device;
  38. setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
  39. USB_REQ_TYPE_INTERFACE;
  40. setup.bRequest = USB_REQ_SET_IDLE;
  41. setup.wIndex = 0;
  42. setup.wLength = 0;
  43. setup.wValue = (duration << 8 )| report_id;
  44. if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
  45. if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
  46. return RT_EOK;
  47. return -RT_FALSE;
  48. }
  49. /**
  50. * This function will do USB_REQ_GET_REPORT request to get report from the usb hid device
  51. *
  52. * @param intf the interface instance.
  53. * @buffer the data buffer to save usb report descriptor.
  54. * @param nbytes the size of buffer
  55. *
  56. * @return the error code, RT_EOK on successfully.
  57. */
  58. rt_err_t rt_usbh_hid_get_report(struct uhintf* intf, rt_uint8_t type,
  59. rt_uint8_t id, rt_uint8_t *buffer, rt_size_t size)
  60. {
  61. struct urequest setup;
  62. struct uinstance* device;
  63. int timeout = USB_TIMEOUT_BASIC;
  64. /* parameter check */
  65. RT_ASSERT(intf != RT_NULL);
  66. RT_ASSERT(intf->device != RT_NULL);
  67. device = intf->device;
  68. setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
  69. USB_REQ_TYPE_INTERFACE;
  70. setup.bRequest = USB_REQ_GET_REPORT;
  71. setup.wIndex = intf->intf_desc->bInterfaceNumber;
  72. setup.wLength = size;
  73. setup.wValue = (type << 8 ) + id;
  74. if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
  75. {
  76. if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, size, timeout) == size)
  77. {
  78. if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
  79. {
  80. return RT_EOK;
  81. }
  82. }
  83. }
  84. else
  85. return -RT_FALSE;
  86. return -RT_FALSE;
  87. }
  88. /**
  89. * This function will do USB_REQ_SET_REPORT request to set report to the usb hid device
  90. *
  91. * @param intf the interface instance.
  92. * @buffer the data buffer to save usb report descriptor.
  93. * @param nbytes the size of buffer
  94. *
  95. * @return the error code, RT_EOK on successfully.
  96. */
  97. rt_err_t rt_usbh_hid_set_report(struct uhintf* intf, rt_uint8_t *buffer, rt_size_t size)
  98. {
  99. struct urequest setup;
  100. struct uinstance* device;
  101. int timeout = USB_TIMEOUT_BASIC;
  102. /* parameter check */
  103. RT_ASSERT(intf != RT_NULL);
  104. RT_ASSERT(intf->device != RT_NULL);
  105. device = intf->device;
  106. setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
  107. USB_REQ_TYPE_INTERFACE;
  108. setup.bRequest = USB_REQ_SET_REPORT;
  109. setup.wIndex = intf->intf_desc->bInterfaceNumber;
  110. setup.wLength = size;
  111. setup.wValue = 0x02 << 8;
  112. if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
  113. return RT_EOK;
  114. else
  115. return -RT_FALSE;
  116. }
  117. /**
  118. * This function will do USB_REQ_SET_PROTOCOL request to set protocal to the usb hid device.
  119. *
  120. * @param intf the interface instance.
  121. * @param protocol the protocol id.
  122. *
  123. * @return the error code, RT_EOK on successfully.
  124. */
  125. rt_err_t rt_usbh_hid_set_protocal(struct uhintf* intf, int protocol)
  126. {
  127. struct urequest setup;
  128. struct uinstance* device;
  129. int timeout = USB_TIMEOUT_BASIC;
  130. /* parameter check */
  131. RT_ASSERT(intf != RT_NULL);
  132. RT_ASSERT(intf->device != RT_NULL);
  133. device = intf->device;
  134. setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
  135. USB_REQ_TYPE_INTERFACE;
  136. setup.bRequest = USB_REQ_SET_PROTOCOL;
  137. setup.wIndex = 0;
  138. setup.wLength = 0;
  139. setup.wValue = protocol;
  140. if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
  141. return RT_EOK;
  142. else
  143. return -RT_FALSE;
  144. }
  145. /**
  146. * This function will do USB_REQ_GET_DESCRIPTOR request for the device instance
  147. * to set feature of the hub port.
  148. *
  149. * @param intf the interface instance.
  150. * @buffer the data buffer to save usb report descriptor.
  151. * @param nbytes the size of buffer
  152. *
  153. * @return the error code, RT_EOK on successfully.
  154. */
  155. rt_err_t rt_usbh_hid_get_report_descriptor(struct uhintf* intf,
  156. rt_uint8_t *buffer, rt_size_t size)
  157. {
  158. struct urequest setup;
  159. struct uinstance* device;
  160. int timeout = USB_TIMEOUT_BASIC;
  161. /* parameter check */
  162. RT_ASSERT(intf != RT_NULL);
  163. RT_ASSERT(intf->device != RT_NULL);
  164. device = intf->device;
  165. setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD|
  166. USB_REQ_TYPE_INTERFACE;
  167. setup.bRequest = USB_REQ_GET_DESCRIPTOR;
  168. setup.wIndex = 0;
  169. setup.wLength = size;
  170. setup.wValue = USB_DESC_TYPE_REPORT << 8;
  171. if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
  172. {
  173. if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, size, timeout) == size)
  174. {
  175. if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
  176. {
  177. return RT_EOK;
  178. }
  179. }
  180. }
  181. else
  182. return -RT_FALSE;
  183. return -RT_FALSE;
  184. }
  185. /**
  186. * This function will register specified hid protocal to protocal list
  187. *
  188. * @param protocal the specified protocal.
  189. *
  190. * @return the error code, RT_EOK on successfully.
  191. */
  192. rt_err_t rt_usbh_hid_protocal_register(uprotocal_t protocal)
  193. {
  194. RT_ASSERT(protocal != RT_NULL);
  195. if (protocal == RT_NULL) return -RT_ERROR;
  196. /* insert class driver into driver list */
  197. rt_list_insert_after(&_protocal_list, &(protocal->list));
  198. return RT_EOK;
  199. }
  200. /**
  201. * This function is the callback function of hid's int endpoint, it is invoked when data comes.
  202. *
  203. * @param context the context of the callback function.
  204. *
  205. * @return none.
  206. */
  207. static void rt_usbh_hid_callback(void* context)
  208. {
  209. upipe_t pipe;
  210. struct uhid* hid;
  211. int timeout = USB_TIMEOUT_LONG;
  212. /* parameter check */
  213. RT_ASSERT(context != RT_NULL);
  214. pipe = (upipe_t)context;
  215. hid = (struct uhid*)((struct uhintf*)pipe->inst)->user_data;
  216. /* invoke protocal callback function */
  217. hid->protocal->callback((void*)hid);
  218. /* parameter check */
  219. RT_ASSERT(((struct uhintf*)pipe->inst)->device->hcd != RT_NULL);
  220. rt_usb_hcd_pipe_xfer(((struct uhintf*)pipe->inst)->device->hcd, pipe,
  221. hid->buffer, pipe->ep.wMaxPacketSize, timeout);
  222. }
  223. /**
  224. * This function will find specified hid protocal from protocal list
  225. *
  226. * @param pro_id the protocal id.
  227. *
  228. * @return the found protocal or RT_NULL if there is no this protocal.
  229. */
  230. static uprotocal_t rt_usbh_hid_protocal_find(int pro_id)
  231. {
  232. struct rt_list_node *node;
  233. /* try to find protocal object */
  234. for (node = _protocal_list.next; node != &_protocal_list; node = node->next)
  235. {
  236. uprotocal_t protocal =
  237. (uprotocal_t)rt_list_entry(node, struct uprotocal, list);
  238. if (protocal->pro_id == pro_id) return protocal;
  239. }
  240. /* not found */
  241. return RT_NULL;
  242. }
  243. /**
  244. * This function will run hid class driver when usb device is detected and identified
  245. * as a hid class device, it will continue the enumulate process.
  246. *
  247. * @param arg the argument.
  248. *
  249. * @return the error code, RT_EOK on successfully.
  250. */
  251. static rt_err_t rt_usbh_hid_enable(void* arg)
  252. {
  253. int i = 0, pro_id;
  254. uprotocal_t protocal;
  255. struct uhid* hid;
  256. struct uhintf* intf = (struct uhintf*)arg;
  257. /* parameter check */
  258. if(intf == RT_NULL)
  259. {
  260. rt_kprintf("the interface is not available\n");
  261. return -RT_EIO;
  262. }
  263. pro_id = intf->intf_desc->bInterfaceProtocol;
  264. LOG_D("HID device enable, protocal id %d", pro_id);
  265. protocal = rt_usbh_hid_protocal_find(pro_id);
  266. if(protocal == RT_NULL)
  267. {
  268. rt_kprintf("can't find hid protocal %d\n", pro_id);
  269. intf->user_data = RT_NULL;
  270. return -RT_ERROR;
  271. }
  272. hid = rt_malloc(sizeof(struct uhid));
  273. RT_ASSERT(hid != RT_NULL);
  274. /* initilize the data structure */
  275. rt_memset(hid, 0, sizeof(struct uhid));
  276. intf->user_data = (void*)hid;
  277. hid->protocal = protocal;
  278. for(i=0; i<intf->intf_desc->bNumEndpoints; i++)
  279. {
  280. rt_err_t ret;
  281. uep_desc_t ep_desc;
  282. /* get endpoint descriptor */
  283. rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc);
  284. if(ep_desc == RT_NULL)
  285. {
  286. rt_kprintf("rt_usbh_get_endpoint_descriptor error\n");
  287. return -RT_ERROR;
  288. }
  289. if(USB_EP_ATTR(ep_desc->bmAttributes) != USB_EP_ATTR_INT)
  290. continue;
  291. if(!(ep_desc->bEndpointAddress & USB_DIR_IN)) continue;
  292. ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &hid->pipe_in,
  293. intf->device, ep_desc);
  294. if(ret != RT_EOK) return ret;
  295. }
  296. /* initialize hid protocal */
  297. hid->protocal->init((void*)intf);
  298. return RT_EOK;
  299. }
  300. /**
  301. * This function will be invoked when usb device plug out is detected and it would clean
  302. * and release all hub class related resources.
  303. *
  304. * @param arg the argument.
  305. *
  306. * @return the error code, RT_EOK on successfully.
  307. */
  308. static rt_err_t rt_usbh_hid_disable(void* arg)
  309. {
  310. struct uhid* hid;
  311. struct uhintf* intf = (struct uhintf*)arg;
  312. RT_ASSERT(intf != RT_NULL);
  313. LOG_D("rt_usbh_hid_disable");
  314. hid = (struct uhid*)intf->user_data;
  315. if(hid != RT_NULL)
  316. {
  317. if(hid->pipe_in != RT_NULL)
  318. {
  319. /* free the HID in pipe */
  320. rt_usb_hcd_free_pipe(intf->device->hcd, hid->pipe_in);
  321. }
  322. /* free the hid instance */
  323. rt_free(hid);
  324. }
  325. return RT_EOK;
  326. }
  327. /**
  328. * This function will register hid class driver to the usb class driver manager.
  329. * and it should be invoked in the usb system initialization.
  330. *
  331. * @return the error code, RT_EOK on successfully.
  332. */
  333. ucd_t rt_usbh_class_driver_hid(void)
  334. {
  335. rt_list_init(&_protocal_list);
  336. hid_driver.class_code = USB_CLASS_HID;
  337. hid_driver.enable = rt_usbh_hid_enable;
  338. hid_driver.disable = rt_usbh_hid_disable;
  339. return &hid_driver;
  340. }
  341. #endif