usbd.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /**************************************************************************/
  2. /*!
  3. @file usbd.c
  4. @author hathach (tinyusb.org)
  5. @section LICENSE
  6. Software License Agreement (BSD License)
  7. Copyright (c) 2013, hathach (tinyusb.org)
  8. All rights reserved.
  9. Redistribution and use in source and binary forms, with or without
  10. modification, are permitted provided that the following conditions are met:
  11. 1. Redistributions of source code must retain the above copyright
  12. notice, this list of conditions and the following disclaimer.
  13. 2. Redistributions in binary form must reproduce the above copyright
  14. notice, this list of conditions and the following disclaimer in the
  15. documentation and/or other materials provided with the distribution.
  16. 3. Neither the name of the copyright holders nor the
  17. names of its contributors may be used to endorse or promote products
  18. derived from this software without specific prior written permission.
  19. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
  20. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
  23. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  26. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. This file is part of the tinyusb stack.
  30. */
  31. /**************************************************************************/
  32. #include "tusb_option.h"
  33. #if MODE_DEVICE_SUPPORTED
  34. #define _TINY_USB_SOURCE_FILE_
  35. //--------------------------------------------------------------------+
  36. // INCLUDE
  37. //--------------------------------------------------------------------+
  38. #include "tusb.h"
  39. #include "usbd.h"
  40. //--------------------------------------------------------------------+
  41. // MACRO CONSTANT TYPEDEF
  42. //--------------------------------------------------------------------+
  43. usbd_device_info_t usbd_devices[CONTROLLER_DEVICE_NUMBER];
  44. TUSB_CFG_ATTR_USBRAM uint8_t usbd_enum_buffer[TUSB_CFG_DEVICE_ENUM_BUFFER_SIZE];
  45. static usbd_class_driver_t const usbd_class_drivers[] =
  46. {
  47. #if DEVICE_CLASS_HID
  48. [TUSB_CLASS_HID] =
  49. {
  50. .init = hidd_init,
  51. .open = hidd_open,
  52. .control_request_subtask = hidd_control_request_subtask,
  53. .xfer_cb = hidd_xfer_cb,
  54. // .routine = NULL,
  55. .sof = NULL,
  56. .close = hidd_close
  57. },
  58. #endif
  59. #if TUSB_CFG_DEVICE_MSC
  60. [TUSB_CLASS_MSC] =
  61. {
  62. .init = mscd_init,
  63. .open = mscd_open,
  64. .control_request_subtask = mscd_control_request_subtask,
  65. .xfer_cb = mscd_xfer_cb,
  66. // .routine = NULL,
  67. .sof = NULL,
  68. .close = mscd_close
  69. },
  70. #endif
  71. #if TUSB_CFG_DEVICE_CDC
  72. [TUSB_CLASS_CDC] =
  73. {
  74. .init = cdcd_init,
  75. .open = cdcd_open,
  76. .control_request_subtask = cdcd_control_request_subtask,
  77. .xfer_cb = cdcd_xfer_cb,
  78. // .routine = NULL,
  79. .sof = cdcd_sof,
  80. .close = cdcd_close
  81. },
  82. #endif
  83. };
  84. enum { USBD_CLASS_DRIVER_COUNT = sizeof(usbd_class_drivers) / sizeof(usbd_class_driver_t) };
  85. //--------------------------------------------------------------------+
  86. // INTERNAL OBJECT & FUNCTION DECLARATION
  87. //--------------------------------------------------------------------+
  88. static tusb_error_t usbd_set_configure_received(uint8_t port, uint8_t config_number);
  89. static tusb_error_t get_descriptor(uint8_t port, tusb_control_request_t const * const p_request, uint8_t const ** pp_buffer, uint16_t * p_length);
  90. //--------------------------------------------------------------------+
  91. // APPLICATION INTERFACE
  92. //--------------------------------------------------------------------+
  93. bool tud_n_mounted(uint8_t port)
  94. {
  95. return usbd_devices[port].state == TUSB_DEVICE_STATE_CONFIGURED;
  96. }
  97. //--------------------------------------------------------------------+
  98. // IMPLEMENTATION
  99. //--------------------------------------------------------------------+
  100. //------------- OSAL Task -------------//
  101. enum { USBD_TASK_QUEUE_DEPTH = 16 };
  102. typedef enum
  103. {
  104. USBD_EVENTID_SETUP_RECEIVED = 1,
  105. USBD_EVENTID_XFER_DONE,
  106. USBD_EVENTID_SOF
  107. }usbd_eventid_t;
  108. typedef struct ATTR_ALIGNED(4)
  109. {
  110. uint8_t port;
  111. uint8_t event_id;
  112. uint8_t sub_event_id;
  113. uint8_t reserved;
  114. union {
  115. tusb_control_request_t setup_received;
  116. struct { // USBD_EVENTID_XFER_DONE
  117. uint8_t edpt_addr;
  118. uint32_t xferred_byte;
  119. }xfer_done;
  120. };
  121. } usbd_task_event_t;
  122. STATIC_ASSERT(sizeof(usbd_task_event_t) <= 12, "size is not correct");
  123. #ifndef TUC_DEVICE_STACKSIZE
  124. #define TUC_DEVICE_STACKSIZE 150
  125. #endif
  126. #ifndef TUSB_CFG_OS_TASK_PRIO
  127. #define TUSB_CFG_OS_TASK_PRIO 0
  128. #endif
  129. static osal_queue_t usbd_queue_hdl;
  130. /*static*/ osal_semaphore_t usbd_control_xfer_sem_hdl; // TODO may need to change to static with wrapper function
  131. //--------------------------------------------------------------------+
  132. // IMPLEMENTATION
  133. //--------------------------------------------------------------------+
  134. tusb_error_t usbd_control_request_subtask(uint8_t port, tusb_control_request_t const * const p_request);
  135. static tusb_error_t usbd_body_subtask(void);
  136. tusb_error_t usbd_init (void)
  137. {
  138. #if (TUSB_CFG_CONTROLLER_0_MODE & TUSB_MODE_DEVICE)
  139. tusb_dcd_init(0);
  140. #endif
  141. #if (TUSB_CFG_CONTROLLER_1_MODE & TUSB_MODE_DEVICE)
  142. tusb_dcd_init(1);
  143. #endif
  144. //------------- Task init -------------//
  145. usbd_queue_hdl = osal_queue_create(USBD_TASK_QUEUE_DEPTH, sizeof(usbd_task_event_t));
  146. VERIFY(usbd_queue_hdl, TUSB_ERROR_OSAL_QUEUE_FAILED);
  147. usbd_control_xfer_sem_hdl = osal_semaphore_create(1, 0);
  148. VERIFY(usbd_queue_hdl, TUSB_ERROR_OSAL_SEMAPHORE_FAILED);
  149. osal_task_create(usbd_task, "usbd", TUC_DEVICE_STACKSIZE, NULL, TUSB_CFG_OS_TASK_PRIO);
  150. //------------- Descriptor Check -------------//
  151. ASSERT(tusbd_descriptor_pointers.p_device != NULL && tusbd_descriptor_pointers.p_configuration != NULL, TUSB_ERROR_DESCRIPTOR_CORRUPTED);
  152. //------------- class init -------------//
  153. for (uint8_t class_code = TUSB_CLASS_AUDIO; class_code < USBD_CLASS_DRIVER_COUNT; class_code++)
  154. {
  155. if ( usbd_class_drivers[class_code].init )
  156. {
  157. usbd_class_drivers[class_code].init();
  158. }
  159. }
  160. return TUSB_ERROR_NONE;
  161. }
  162. // To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper
  163. // and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with
  164. // forever loop cannot have any return at all.
  165. void usbd_task( void* param)
  166. {
  167. (void) param;
  168. OSAL_TASK_BEGIN
  169. usbd_body_subtask();
  170. OSAL_TASK_END
  171. }
  172. static tusb_error_t usbd_body_subtask(void)
  173. {
  174. static usbd_task_event_t event;
  175. OSAL_SUBTASK_BEGIN
  176. tusb_error_t error;
  177. error = TUSB_ERROR_NONE;
  178. memclr_(&event, sizeof(usbd_task_event_t));
  179. #if 1
  180. osal_queue_receive(usbd_queue_hdl, &event, OSAL_TIMEOUT_WAIT_FOREVER, &error);
  181. SUBTASK_ASSERT_STATUS(error);
  182. #else
  183. enum { ROUTINE_INTERVAL_MS = 10 };
  184. osal_queue_receive(usbd_queue_hdl, &event, ROUTINE_INTERVAL_MS, &error);
  185. if ( error != TUSB_ERROR_NONE )
  186. {
  187. // time out, run class routine then
  188. if ( error == TUSB_ERROR_OSAL_TIMEOUT)
  189. {
  190. for (uint8_t class_code = TUSB_CLASS_AUDIO; class_code < USBD_CLASS_DRIVER_COUNT; class_code++)
  191. {
  192. if ( usbd_class_drivers[class_code].routine ) usbd_class_drivers[class_code].routine();
  193. }
  194. }
  195. SUBTASK_RETURN(error);
  196. }
  197. #endif
  198. if ( USBD_EVENTID_SETUP_RECEIVED == event.event_id )
  199. {
  200. OSAL_SUBTASK_INVOKED_AND_WAIT( usbd_control_request_subtask(event.port, &event.setup_received), error );
  201. }else if (USBD_EVENTID_XFER_DONE == event.event_id)
  202. {
  203. // Call class handling function, Class that endpoint not belong to should check and return
  204. for (uint8_t class_code = TUSB_CLASS_AUDIO; class_code < USBD_CLASS_DRIVER_COUNT; class_code++)
  205. {
  206. if ( usbd_class_drivers[class_code].xfer_cb )
  207. {
  208. usbd_class_drivers[class_code].xfer_cb( event.port, event.xfer_done.edpt_addr, (tusb_event_t) event.sub_event_id, event.xfer_done.xferred_byte);
  209. }
  210. }
  211. }else if (USBD_EVENTID_SOF == event.event_id)
  212. {
  213. for (uint8_t class_code = TUSB_CLASS_AUDIO; class_code < USBD_CLASS_DRIVER_COUNT; class_code++)
  214. {
  215. if ( usbd_class_drivers[class_code].sof )
  216. {
  217. usbd_class_drivers[class_code].sof( event.port );
  218. }
  219. }
  220. }
  221. else
  222. {
  223. SUBTASK_ASSERT(false);
  224. }
  225. OSAL_SUBTASK_END
  226. }
  227. //--------------------------------------------------------------------+
  228. // CONTROL REQUEST
  229. //--------------------------------------------------------------------+
  230. tusb_error_t usbd_control_request_subtask(uint8_t port, tusb_control_request_t const * const p_request)
  231. {
  232. OSAL_SUBTASK_BEGIN
  233. tusb_error_t error;
  234. error = TUSB_ERROR_NONE;
  235. //------------- Standard Control e.g in enumeration -------------//
  236. if( TUSB_REQ_RCPT_DEVICE == p_request->bmRequestType_bit.recipient &&
  237. TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type )
  238. {
  239. if ( TUSB_REQUEST_GET_DESCRIPTOR == p_request->bRequest )
  240. {
  241. uint8_t const * p_buffer = NULL;
  242. uint16_t length = 0;
  243. error = get_descriptor(port, p_request, &p_buffer, &length);
  244. if ( TUSB_ERROR_NONE == error )
  245. {
  246. tusb_dcd_control_xfer(port, (tusb_dir_t) p_request->bmRequestType_bit.direction, (uint8_t*) p_buffer, length, false);
  247. }
  248. }
  249. else if ( TUSB_REQUEST_SET_ADDRESS == p_request->bRequest )
  250. {
  251. tusb_dcd_set_address(port, (uint8_t) p_request->wValue);
  252. usbd_devices[port].state = TUSB_DEVICE_STATE_ADDRESSED;
  253. }
  254. else if ( TUSB_REQUEST_SET_CONFIGURATION == p_request->bRequest )
  255. {
  256. usbd_set_configure_received(port, (uint8_t) p_request->wValue);
  257. }else
  258. {
  259. error = TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
  260. }
  261. }
  262. //------------- Class/Interface Specific Request -------------//
  263. else if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient)
  264. {
  265. static uint8_t class_code;
  266. class_code = usbd_devices[port].interface2class[ u16_low_u8(p_request->wIndex) ];
  267. // TODO [Custom] TUSB_CLASS_DIAGNOSTIC, vendor etc ...
  268. if ( (class_code > 0) && (class_code < USBD_CLASS_DRIVER_COUNT) &&
  269. usbd_class_drivers[class_code].control_request_subtask )
  270. {
  271. OSAL_SUBTASK_INVOKED_AND_WAIT( usbd_class_drivers[class_code].control_request_subtask(port, p_request), error );
  272. }else
  273. {
  274. error = TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
  275. }
  276. }
  277. //------------- Endpoint Request -------------//
  278. else if ( TUSB_REQ_RCPT_ENDPOINT == p_request->bmRequestType_bit.recipient &&
  279. TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type &&
  280. TUSB_REQUEST_CLEAR_FEATURE == p_request->bRequest )
  281. {
  282. tusb_dcd_edpt_clear_stall(port, u16_low_u8(p_request->wIndex) );
  283. } else
  284. {
  285. error = TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
  286. }
  287. if(TUSB_ERROR_NONE != error)
  288. { // Response with Protocol Stall if request is not supported
  289. tusb_dcd_control_stall(port);
  290. // ASSERT(error == TUSB_ERROR_NONE, VOID_RETURN);
  291. }else if (p_request->wLength == 0)
  292. {
  293. tusb_dcd_control_xfer(port, (tusb_dir_t) p_request->bmRequestType_bit.direction, NULL, 0, false); // zero length for non-data
  294. }
  295. OSAL_SUBTASK_END
  296. }
  297. // TODO Host (windows) can get HID report descriptor before set configured
  298. // may need to open interface before set configured
  299. static tusb_error_t usbd_set_configure_received(uint8_t port, uint8_t config_number)
  300. {
  301. tusb_dcd_set_config(port, config_number);
  302. usbd_devices[port].state = TUSB_DEVICE_STATE_CONFIGURED;
  303. //------------- parse configuration & open drivers -------------//
  304. uint8_t const * p_desc_config = tusbd_descriptor_pointers.p_configuration;
  305. uint8_t const * p_desc = p_desc_config + sizeof(tusb_descriptor_configuration_t);
  306. uint16_t const config_total_length = ((tusb_descriptor_configuration_t*)p_desc_config)->wTotalLength;
  307. while( p_desc < p_desc_config + config_total_length )
  308. {
  309. if ( TUSB_DESC_INTERFACE_ASSOCIATION == p_desc[DESCRIPTOR_OFFSET_TYPE])
  310. {
  311. p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; // ignore Interface Association
  312. }else
  313. {
  314. ASSERT( TUSB_DESC_INTERFACE == p_desc[DESCRIPTOR_OFFSET_TYPE], TUSB_ERROR_NOT_SUPPORTED_YET );
  315. uint8_t class_index;
  316. tusb_descriptor_interface_t* p_desc_interface = (tusb_descriptor_interface_t*) p_desc;
  317. class_index = p_desc_interface->bInterfaceClass;
  318. ASSERT( class_index != 0 && class_index < USBD_CLASS_DRIVER_COUNT && usbd_class_drivers[class_index].open != NULL, TUSB_ERROR_NOT_SUPPORTED_YET );
  319. ASSERT( 0 == usbd_devices[port].interface2class[p_desc_interface->bInterfaceNumber], TUSB_ERROR_FAILED); // duplicate interface number TODO alternate setting
  320. usbd_devices[port].interface2class[p_desc_interface->bInterfaceNumber] = class_index;
  321. uint16_t length=0;
  322. ASSERT_STATUS( usbd_class_drivers[class_index].open( port, p_desc_interface, &length ) );
  323. ASSERT( length >= sizeof(tusb_descriptor_interface_t), TUSB_ERROR_FAILED );
  324. p_desc += length;
  325. }
  326. }
  327. // invoke callback
  328. tud_mount_cb(port);
  329. return TUSB_ERROR_NONE;
  330. }
  331. static tusb_error_t get_descriptor(uint8_t port, tusb_control_request_t const * const p_request, uint8_t const ** pp_buffer, uint16_t * p_length)
  332. {
  333. tusb_desc_type_t const desc_type = (tusb_desc_type_t) u16_high_u8(p_request->wValue);
  334. uint8_t const desc_index = u16_low_u8( p_request->wValue );
  335. uint8_t const * p_data = NULL ;
  336. switch(desc_type)
  337. {
  338. case TUSB_DESC_DEVICE:
  339. p_data = tusbd_descriptor_pointers.p_device;
  340. (*p_length) = sizeof(tusb_descriptor_device_t);
  341. break;
  342. case TUSB_DESC_CONFIGURATION:
  343. p_data = tusbd_descriptor_pointers.p_configuration;
  344. (*p_length) = ((tusb_descriptor_configuration_t*)tusbd_descriptor_pointers.p_configuration)->wTotalLength;
  345. break;
  346. case TUSB_DESC_STRING:
  347. if ( !(desc_index < 100) ) return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT; // windows sometimes ask for string at index 238 !!!
  348. p_data = tusbd_descriptor_pointers.p_string_arr[desc_index];
  349. ASSERT( p_data != NULL, TUSB_ERROR_FAILED);
  350. (*p_length) = p_data[0]; // first byte of descriptor is its size
  351. break;
  352. // TODO Report Descriptor (HID Generic)
  353. // TODO HID Descriptor
  354. default: return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
  355. }
  356. (*p_length) = min16_of(p_request->wLength, (*p_length) ); // cannot return more than hosts requires
  357. ASSERT( (*p_length) <= TUSB_CFG_DEVICE_ENUM_BUFFER_SIZE, TUSB_ERROR_NOT_ENOUGH_MEMORY);
  358. memcpy(usbd_enum_buffer, p_data, (*p_length));
  359. (*pp_buffer) = usbd_enum_buffer;
  360. return TUSB_ERROR_NONE;
  361. }
  362. //--------------------------------------------------------------------+
  363. // USBD-CLASS API
  364. //--------------------------------------------------------------------+
  365. //--------------------------------------------------------------------+
  366. // USBD-DCD Callback API
  367. //--------------------------------------------------------------------+
  368. void tusb_dcd_bus_event(uint8_t port, usbd_bus_event_type_t bus_event)
  369. {
  370. switch(bus_event)
  371. {
  372. case USBD_BUS_EVENT_RESET :
  373. memclr_(&usbd_devices[port], sizeof(usbd_device_info_t));
  374. osal_queue_flush(usbd_queue_hdl);
  375. osal_semaphore_reset(usbd_control_xfer_sem_hdl);
  376. for (uint8_t class_code = TUSB_CLASS_AUDIO; class_code < USBD_CLASS_DRIVER_COUNT; class_code++)
  377. {
  378. if ( usbd_class_drivers[class_code].close ) usbd_class_drivers[class_code].close( port );
  379. }
  380. // invoke callback
  381. tud_umount_cb(port);
  382. break;
  383. case USBD_BUS_EVENT_SOF:
  384. {
  385. usbd_task_event_t task_event =
  386. {
  387. .port = port,
  388. .event_id = USBD_EVENTID_SOF,
  389. };
  390. osal_queue_send(usbd_queue_hdl, &task_event);
  391. }
  392. break;
  393. case USBD_BUS_EVENT_UNPLUGGED : break;
  394. case USBD_BUS_EVENT_SUSPENDED:
  395. usbd_devices[port].state = TUSB_DEVICE_STATE_SUSPENDED;
  396. break;
  397. default: break;
  398. }
  399. }
  400. void tusb_dcd_setup_received(uint8_t port, uint8_t const* p_request)
  401. {
  402. usbd_task_event_t task_event =
  403. {
  404. .port = port,
  405. .event_id = USBD_EVENTID_SETUP_RECEIVED,
  406. };
  407. memcpy(&task_event.setup_received, p_request, sizeof(tusb_control_request_t));
  408. osal_queue_send(usbd_queue_hdl, &task_event);
  409. }
  410. void tusb_dcd_xfer_complete(uint8_t port, uint8_t edpt_addr, uint32_t xferred_bytes, bool succeeded)
  411. {
  412. if (edpt_addr == 0 )
  413. {
  414. // Control Transfer
  415. osal_semaphore_post( usbd_control_xfer_sem_hdl );
  416. }else
  417. {
  418. usbd_task_event_t task_event =
  419. {
  420. .port = port,
  421. .event_id = USBD_EVENTID_XFER_DONE,
  422. .sub_event_id = succeeded ? TUSB_EVENT_XFER_COMPLETE : TUSB_EVENT_XFER_ERROR
  423. };
  424. task_event.xfer_done.edpt_addr = edpt_addr;
  425. task_event.xfer_done.xferred_byte = xferred_bytes;
  426. osal_queue_send(usbd_queue_hdl, &task_event);
  427. }
  428. }
  429. //--------------------------------------------------------------------+
  430. // HELPER
  431. //--------------------------------------------------------------------+
  432. #endif