tinyusb  0.4
Click here to lend your support to tinyusb donation and make a donation at pledgie.com
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
usbd.c
Go to the documentation of this file.
1 /**************************************************************************/
37 /**************************************************************************/
38 
39 #include "tusb_option.h"
40 
41 #if MODE_DEVICE_SUPPORTED
42 
43 #define _TINY_USB_SOURCE_FILE_
44 
45 //--------------------------------------------------------------------+
46 // INCLUDE
47 //--------------------------------------------------------------------+
48 #include "tusb.h"
49 #include "usbd_dcd.h"
50 
51 //--------------------------------------------------------------------+
52 // MACRO CONSTANT TYPEDEF
53 //--------------------------------------------------------------------+
54 usbd_device_info_t usbd_devices[CONTROLLER_DEVICE_NUMBER];
55 TUSB_CFG_ATTR_USBRAM uint8_t usbd_enum_buffer[TUSB_CFG_DEVICE_ENUM_BUFFER_SIZE];
56 
57 static usbd_class_driver_t const usbd_class_drivers[] =
58 {
59  #if DEVICE_CLASS_HID
60  [TUSB_CLASS_HID] =
61  {
62  .init = hidd_init,
63  .open = hidd_open,
64  .control_request_subtask = hidd_control_request_subtask,
65  .xfer_cb = hidd_xfer_cb,
66  .close = hidd_close
67  },
68  #endif
69 
70  #if TUSB_CFG_DEVICE_MSC
71  [TUSB_CLASS_MSC] =
72  {
73  .init = mscd_init,
74  .open = mscd_open,
75  .control_request_subtask = mscd_control_request_subtask,
76  .xfer_cb = mscd_xfer_cb,
77  .close = mscd_close
78  },
79  #endif
80 
81  #if TUSB_CFG_DEVICE_CDC
82  [TUSB_CLASS_CDC] =
83  {
84  .init = cdcd_init,
85  .open = cdcd_open,
86  .control_request_subtask = cdcd_control_request_subtask,
87  .xfer_cb = cdcd_xfer_cb,
88  .close = cdcd_close
89  },
90  #endif
91 
92 };
93 
94 enum { USBD_CLASS_DRIVER_COUNT = sizeof(usbd_class_drivers) / sizeof(usbd_class_driver_t) };
95 
96 //--------------------------------------------------------------------+
97 // INTERNAL OBJECT & FUNCTION DECLARATION
98 //--------------------------------------------------------------------+
99 static tusb_error_t usbd_set_configure_received(uint8_t coreid, uint8_t config_number);
100 static tusb_error_t get_descriptor(uint8_t coreid, tusb_control_request_t const * const p_request, uint8_t const ** pp_buffer, uint16_t * p_length);
101 
102 //--------------------------------------------------------------------+
103 // APPLICATION INTERFACE
104 //--------------------------------------------------------------------+
105 bool tusbd_is_configured(uint8_t coreid)
106 {
107  return usbd_devices[coreid].state == TUSB_DEVICE_STATE_CONFIGURED;
108 }
109 
110 //--------------------------------------------------------------------+
111 // IMPLEMENTATION
112 //--------------------------------------------------------------------+
113 
114 //------------- OSAL Task -------------//
115 enum { USBD_TASK_QUEUE_DEPTH = 8 };
116 
117 typedef enum {
118  USBD_EVENTID_SETUP_RECEIVED = 1,
119  USBD_EVENTID_XFER_DONE
120 }usbd_eventid_t;
121 
122 typedef struct ATTR_ALIGNED(4)
123 {
124  uint8_t coreid;
125  uint8_t event_id;
126  uint8_t sub_event_id;
127  uint8_t reserved;
128 
129  union {
130  tusb_control_request_t setup_received; // USBD_EVENTID_SETUP_RECEIVED
131 
132  struct { // USBD_EVENTID_XFER_DONE
133  endpoint_handle_t edpt_hdl;
134  uint32_t xferred_byte;
135  }xfer_done;
136  };
137 } usbd_task_event_t;
138 
139 STATIC_ASSERT(sizeof(usbd_task_event_t) <= 12, "size is not correct");
140 
141 OSAL_TASK_DEF(usbd_task, 150, TUSB_CFG_OS_TASK_PRIO);
142 OSAL_QUEUE_DEF(usbd_queue_def, USBD_TASK_QUEUE_DEPTH, usbd_task_event_t);
143 OSAL_SEM_DEF(usbd_control_xfer_semaphore_def);
144 
145 static osal_queue_handle_t usbd_queue_hdl;
146 /*static*/ osal_semaphore_handle_t usbd_control_xfer_sem_hdl; // TODO may need to change to static with wrapper function
147 
148 //--------------------------------------------------------------------+
149 // IMPLEMENTATION
150 //--------------------------------------------------------------------+
151 tusb_error_t usbd_control_request_subtask(uint8_t coreid, tusb_control_request_t const * const p_request);
152 static tusb_error_t usbd_body_subtask(void);
153 
154 tusb_error_t usbd_init (void)
155 {
156  ASSERT_STATUS ( dcd_init() );
157 
158  //------------- Task init -------------//
159  usbd_queue_hdl = osal_queue_create( OSAL_QUEUE_REF(usbd_queue_def) );
160  ASSERT_PTR(usbd_queue_hdl, TUSB_ERROR_OSAL_QUEUE_FAILED);
161 
162  usbd_control_xfer_sem_hdl = osal_semaphore_create( OSAL_SEM_REF(usbd_control_xfer_semaphore_def) );
163  ASSERT_PTR(usbd_queue_hdl, TUSB_ERROR_OSAL_SEMAPHORE_FAILED);
164 
165  ASSERT_STATUS( osal_task_create( OSAL_TASK_REF(usbd_task) ));
166 
167  //------------- Descriptor Check -------------//
168  ASSERT(tusbd_descriptor_pointers.p_device != NULL && tusbd_descriptor_pointers.p_configuration != NULL, TUSB_ERROR_DESCRIPTOR_CORRUPTED);
169 
170  //------------- class init -------------//
171  for (uint8_t class_code = TUSB_CLASS_AUDIO; class_code < USBD_CLASS_DRIVER_COUNT; class_code++)
172  {
173  if ( usbd_class_drivers[class_code].init )
174  {
175  usbd_class_drivers[class_code].init();
176  }
177  }
178 
179  return TUSB_ERROR_NONE;
180 }
181 
182 // To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper
183 // and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with
184 // forever loop cannot have any return at all.
185 OSAL_TASK_FUNCTION(usbd_task, p_task_para)
186 {
187  (void) p_task_para; // suppress compiler warnings
188 
189  OSAL_TASK_LOOP_BEGIN
190  usbd_body_subtask();
191  OSAL_TASK_LOOP_END
192 }
193 
194 static tusb_error_t usbd_body_subtask(void)
195 {
196  static usbd_task_event_t event;
197 
198  OSAL_SUBTASK_BEGIN
199 
200  tusb_error_t error;
201  error = TUSB_ERROR_NONE;
202 
203  osal_queue_receive(usbd_queue_hdl, &event, OSAL_TIMEOUT_WAIT_FOREVER, &error);
204  SUBTASK_ASSERT_STATUS(error);
205 
206  if ( USBD_EVENTID_SETUP_RECEIVED == event.event_id )
207  {
208  OSAL_SUBTASK_INVOKED_AND_WAIT( usbd_control_request_subtask(event.coreid, &event.setup_received), error );
209  }else
210  {
211  uint8_t class_index;
212  class_index = std_class_code_to_index( event.xfer_done.edpt_hdl.class_code );
213 
214  if (usbd_class_drivers[class_index].xfer_cb)
215  {
216  usbd_class_drivers[class_index].xfer_cb( event.xfer_done.edpt_hdl, (tusb_event_t) event.sub_event_id, event.xfer_done.xferred_byte);
217  }else
218  {
219  hal_debugger_breakpoint(); // something wrong, no one claims the isr's source
220  }
221  }
222 
223  OSAL_SUBTASK_END
224 }
225 
226 //--------------------------------------------------------------------+
227 // CONTROL REQUEST
228 //--------------------------------------------------------------------+
229 tusb_error_t usbd_control_request_subtask(uint8_t coreid, tusb_control_request_t const * const p_request)
230 {
231  OSAL_SUBTASK_BEGIN
232 
233  tusb_error_t error;
234  error = TUSB_ERROR_NONE;
235 
236  //------------- Standard Control such as those in enumeration -------------//
237  if( TUSB_REQUEST_RECIPIENT_DEVICE == p_request->bmRequestType_bit.recipient &&
238  TUSB_REQUEST_TYPE_STANDARD == p_request->bmRequestType_bit.type )
239  {
240  if ( TUSB_REQUEST_GET_DESCRIPTOR == p_request->bRequest )
241  {
242  uint8_t const * p_buffer = NULL;
243  uint16_t length = 0;
244 
245  error = get_descriptor(coreid, p_request, &p_buffer, &length);
246 
247  if ( TUSB_ERROR_NONE == error )
248  {
249  dcd_pipe_control_xfer(coreid, (tusb_direction_t) p_request->bmRequestType_bit.direction, (uint8_t*) p_buffer, length, false);
250  }
251  }
252  else if ( TUSB_REQUEST_SET_ADDRESS == p_request->bRequest )
253  {
254  dcd_controller_set_address(coreid, (uint8_t) p_request->wValue);
255  usbd_devices[coreid].state = TUSB_DEVICE_STATE_ADDRESSED;
256  }
257  else if ( TUSB_REQUEST_SET_CONFIGURATION == p_request->bRequest )
258  {
259  usbd_set_configure_received(coreid, (uint8_t) p_request->wValue);
260  }else
261  {
262  error = TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
263  }
264  }
265 
266  //------------- Class/Interface Specific Request -------------//
267  else if ( TUSB_REQUEST_RECIPIENT_INTERFACE == p_request->bmRequestType_bit.recipient)
268  {
269  static uint8_t class_code;
270 
271  class_code = usbd_devices[coreid].interface2class[ u16_low_u8(p_request->wIndex) ];
272 
273  // TODO [Custom] TUSB_CLASS_DIAGNOSTIC, vendor etc ...
274  if ( (class_code > 0) && (class_code < USBD_CLASS_DRIVER_COUNT) &&
275  usbd_class_drivers[class_code].control_request_subtask )
276  {
277  OSAL_SUBTASK_INVOKED_AND_WAIT( usbd_class_drivers[class_code].control_request_subtask(coreid, p_request), error );
278  }else
279  {
280  error = TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
281  }
282  }
283 
284  //------------- Endpoint Request -------------//
285  else if ( TUSB_REQUEST_RECIPIENT_ENDPOINT == p_request->bmRequestType_bit.recipient &&
286  TUSB_REQUEST_TYPE_STANDARD == p_request->bmRequestType_bit.type &&
287  TUSB_REQUEST_CLEAR_FEATURE == p_request->bRequest )
288  {
289  dcd_pipe_clear_stall(coreid, u16_low_u8(p_request->wIndex) );
290  } else
291  {
292  error = TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
293  }
294 
295  if(TUSB_ERROR_NONE != error)
296  { // Response with Protocol Stall if request is not supported
297  dcd_pipe_control_stall(coreid);
298  // ASSERT(error == TUSB_ERROR_NONE, VOID_RETURN);
299  }else if (p_request->wLength == 0)
300  {
301  dcd_pipe_control_xfer(coreid, (tusb_direction_t) p_request->bmRequestType_bit.direction, NULL, 0, false); // zero length for non-data
302  }
303 
304  OSAL_SUBTASK_END
305 }
306 
307 // TODO Host (windows) can get HID report descriptor before set configured
308 // may need to open interface before set configured
309 static tusb_error_t usbd_set_configure_received(uint8_t coreid, uint8_t config_number)
310 {
311  dcd_controller_set_configuration(coreid);
312  usbd_devices[coreid].state = TUSB_DEVICE_STATE_CONFIGURED;
313 
314  //------------- parse configuration & open drivers -------------//
315  uint8_t const * p_desc_config = tusbd_descriptor_pointers.p_configuration;
316  uint8_t const * p_desc = p_desc_config + sizeof(tusb_descriptor_configuration_t);
317 
318  uint16_t const config_total_length = ((tusb_descriptor_configuration_t*)p_desc_config)->wTotalLength;
319 
320  while( p_desc < p_desc_config + config_total_length )
321  {
322  if ( TUSB_DESC_TYPE_INTERFACE_ASSOCIATION == p_desc[DESCRIPTOR_OFFSET_TYPE])
323  {
324  p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; // ignore Interface Association
325  }else
326  {
327  ASSERT( TUSB_DESC_TYPE_INTERFACE == p_desc[DESCRIPTOR_OFFSET_TYPE], TUSB_ERROR_NOT_SUPPORTED_YET );
328 
329  uint8_t class_index;
330  tusb_descriptor_interface_t* p_desc_interface = (tusb_descriptor_interface_t*) p_desc;
331 
332  class_index = p_desc_interface->bInterfaceClass;
333 
334  ASSERT( class_index != 0 && class_index < USBD_CLASS_DRIVER_COUNT && usbd_class_drivers[class_index].open != NULL, TUSB_ERROR_NOT_SUPPORTED_YET );
335  ASSERT( 0 == usbd_devices[coreid].interface2class[p_desc_interface->bInterfaceNumber], TUSB_ERROR_FAILED); // duplicate interface number TODO alternate setting
336 
337  usbd_devices[coreid].interface2class[p_desc_interface->bInterfaceNumber] = class_index;
338 
339  uint16_t length=0;
340  ASSERT_STATUS( usbd_class_drivers[class_index].open( coreid, p_desc_interface, &length ) );
341 
342  ASSERT( length >= sizeof(tusb_descriptor_interface_t), TUSB_ERROR_FAILED );
343  p_desc += length;
344  }
345  }
346 
347  return TUSB_ERROR_NONE;
348 }
349 
350 static tusb_error_t get_descriptor(uint8_t coreid, tusb_control_request_t const * const p_request, uint8_t const ** pp_buffer, uint16_t * p_length)
351 {
352  tusb_std_descriptor_type_t const desc_type = (tusb_std_descriptor_type_t) u16_high_u8(p_request->wValue);
353  uint8_t const desc_index = u16_low_u8( p_request->wValue );
354 
355  uint8_t const * p_data = NULL ;
356 
357  switch(desc_type)
358  {
359  case TUSB_DESC_TYPE_DEVICE:
361  (*p_length) = sizeof(tusb_descriptor_device_t);
362  break;
363 
364  case TUSB_DESC_TYPE_CONFIGURATION:
367  break;
368 
369  case TUSB_DESC_TYPE_STRING:
370  if ( !(desc_index < 100) ) return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT; // windows sometimes ask for string at index 238 !!!
371 
372  p_data = tusbd_descriptor_pointers.p_string_arr[desc_index];
373  ASSERT( p_data != NULL, TUSB_ERROR_FAILED);
374 
375  (*p_length) = p_data[0]; // first byte of descriptor is its size
376  break;
377 
378  default: return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
379  }
380 
381  (*p_length) = min16_of(p_request->wLength, (*p_length) ); // cannot return more than hosts requires
382  ASSERT( (*p_length) <= TUSB_CFG_DEVICE_ENUM_BUFFER_SIZE, TUSB_ERROR_NOT_ENOUGH_MEMORY);
383 
384  memcpy(usbd_enum_buffer, p_data, (*p_length));
385  (*pp_buffer) = usbd_enum_buffer;
386 
387  return TUSB_ERROR_NONE;
388 }
389 //--------------------------------------------------------------------+
390 // USBD-CLASS API
391 //--------------------------------------------------------------------+
392 
393 //--------------------------------------------------------------------+
394 // USBD-DCD Callback API
395 //--------------------------------------------------------------------+
396 void usbd_dcd_bus_event_isr(uint8_t coreid, usbd_bus_event_type_t bus_event)
397 {
398  switch(bus_event)
399  {
400  case USBD_BUS_EVENT_RESET :
401  case USBD_BUS_EVENT_UNPLUGGED :
402  memclr_(&usbd_devices[coreid], sizeof(usbd_device_info_t));
403  osal_semaphore_reset(usbd_control_xfer_sem_hdl);
404  for (uint8_t class_code = TUSB_CLASS_AUDIO; class_code < USBD_CLASS_DRIVER_COUNT; class_code++)
405  {
406  if ( usbd_class_drivers[class_code].close ) usbd_class_drivers[class_code].close( coreid );
407  }
408  break;
409 
410  case USBD_BUS_EVENT_SUSPENDED:
411  usbd_devices[coreid].state = TUSB_DEVICE_STATE_SUSPENDED;
412  break;
413 
414  default: break;
415  }
416 }
417 
418 void usbd_setup_received_isr(uint8_t coreid, tusb_control_request_t * p_request)
419 {
420  usbd_task_event_t task_event =
421  {
422  .coreid = coreid,
423  .event_id = USBD_EVENTID_SETUP_RECEIVED,
424  };
425 
426  task_event.setup_received = (*p_request);
427  osal_queue_send(usbd_queue_hdl, &task_event);
428 }
429 
430 void usbd_xfer_isr(endpoint_handle_t edpt_hdl, tusb_event_t event, uint32_t xferred_bytes)
431 {
432  if (edpt_hdl.class_code == 0 ) // Control Transfer
433  {
434  osal_semaphore_post( usbd_control_xfer_sem_hdl );
435  }else
436  {
437  usbd_task_event_t task_event =
438  {
439  .coreid = edpt_hdl.coreid,
440  .event_id = USBD_EVENTID_XFER_DONE,
441  .sub_event_id = event
442  };
443 
444  task_event.xfer_done.xferred_byte = xferred_bytes;
445  task_event.xfer_done.edpt_hdl = edpt_hdl;
446 
447  osal_queue_send(usbd_queue_hdl, &task_event);
448  }
449 }
450 
451 //--------------------------------------------------------------------+
452 // HELPER
453 //--------------------------------------------------------------------+
454 
455 #endif
USB Standard Interface Descriptor (section 9.6.1 table 9-12)
tusbd_descriptor_pointer_t tusbd_descriptor_pointers
uint8_t const ** p_string_arr
a array of pointers to string descriptors
Definition: usbd.h:69
#define TUSB_CFG_ATTR_USBRAM
USB Standard Configuration Descriptor (section 9.6.1 table 9-10) */.
uint8_t const * p_configuration
pointer to the whole configuration descriptor, starting by tusb_descriptor_configuration_t ...
Definition: usbd.h:68
uint8_t bInterfaceNumber
Number of this interface. Zero-based value identifying the index in the array of concurrent interface...
#define TUSB_CFG_OS_TASK_PRIO
If TUSB_CFG_OS is configured to use a real RTOS (other than TUSB_OS_NONE). This determines the priori...
tusb_error_t
Error Code returned.
Definition: tusb_errors.h:100
uint8_t const * p_device
pointer to device descritpor tusb_descriptor_device_t
Definition: usbd.h:67
#define ATTR_ALIGNED(Bytes)
This attribute specifies a minimum alignment for the variable or structure field, measured in bytes...
Definition: compiler_gcc.h:72
tusb_std_descriptor_type_t
USB Descriptor Types (section 9.4 table 9-5)
Definition: tusb_types.h:74
uint8_t bInterfaceClass
Class code (assigned by the USB-IF).
USB Standard Device Descriptor (section 9.6.1, table 9-8)