EFM32 Happy Gecko Software Documentation  efm32hg-doc-5.1.2
em_usbdch9.c
Go to the documentation of this file.
1 /**************************************************************************/
16 #include "em_device.h"
17 #if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
18 #include "em_usb.h"
19 #if defined( USB_DEVICE )
20 
21 #include "em_usbtypes.h"
22 #include "em_usbhal.h"
23 #include "em_usbd.h"
24 
27 static int ClearFeature ( USBD_Device_TypeDef *pDev );
28 static int GetConfiguration ( USBD_Device_TypeDef *pDev );
29 static int GetDescriptor ( USBD_Device_TypeDef *pDev );
30 static int GetInterface ( USBD_Device_TypeDef *pDev );
31 static int GetStatus ( USBD_Device_TypeDef *pDev );
32 static int SetAddress ( USBD_Device_TypeDef *pDev );
33 static int SetConfiguration ( USBD_Device_TypeDef *pDev );
34 static int SetFeature ( USBD_Device_TypeDef *pDev );
35 static int SetInterface ( USBD_Device_TypeDef *pDev );
36 
37 static uint32_t txBuf;
38 
39 int USBDCH9_SetupCmd( USBD_Device_TypeDef *device )
40 {
41  int status;
42  USB_Setup_TypeDef *p = device->setup;
43 
44  /* Vendor unique, Class or Standard setup commands override ? */
45  if ( device->callbacks->setupCmd )
46  {
47  status = device->callbacks->setupCmd( p );
48 
49  if ( status != USB_STATUS_REQ_UNHANDLED )
50  {
51  return status;
52  }
53  }
54 
55  status = USB_STATUS_REQ_ERR;
56 
57  if ( p->Type == USB_SETUP_TYPE_STANDARD )
58  {
59  switch ( p->bRequest )
60  {
61  case GET_STATUS:
62  status = GetStatus( device );
63  break;
64 
65  case CLEAR_FEATURE:
66  status = ClearFeature( device );
67  break;
68 
69  case SET_FEATURE:
70  status = SetFeature( device );
71  break;
72 
73  case SET_ADDRESS:
74  status = SetAddress( device );
75  break;
76 
77  case GET_DESCRIPTOR:
78  status = GetDescriptor( device );
79  break;
80 
81  case GET_CONFIGURATION:
82  status = GetConfiguration( device );
83  break;
84 
85  case SET_CONFIGURATION:
86  status = SetConfiguration( device );
87  break;
88 
89  case GET_INTERFACE:
90  status = GetInterface( device );
91  break;
92 
93  case SET_INTERFACE:
94  status = SetInterface( device );
95  break;
96 
97  case SYNCH_FRAME: /* Synch frame is for isochronous endpoints */
98  case SET_DESCRIPTOR: /* Set descriptor is optional */
99  default:
100  break;
101  }
102  }
103 
104  return status;
105 }
106 
107 static int ClearFeature( USBD_Device_TypeDef *pDev )
108 {
109  USBD_Ep_TypeDef *ep;
110  int retVal = USB_STATUS_REQ_ERR;
111  USB_Setup_TypeDef *p = pDev->setup;
112 
113  if ( p->wLength != 0 )
114  {
115  return USB_STATUS_REQ_ERR;
116  }
117 
118  switch ( p->Recipient )
119  {
121  if ( ( p->wIndex == 0 ) &&
123  ( ( pDev->state == USBD_STATE_ADDRESSED ) ||
124  ( pDev->state == USBD_STATE_CONFIGURED ) ) )
125  {
126  /* Remote wakeup feature clear */
127  if ( pDev->configDescriptor->bmAttributes & CONFIG_DESC_BM_REMOTEWAKEUP )
128  {
129  /* The device is capable of signalling remote wakeup */
130  pDev->remoteWakeupEnabled = false;
131  retVal = USB_STATUS_OK;
132  }
133  }
134  break;
135 
137  ep = USBD_GetEpFromAddr( p->wIndex & 0xFF );
138  if ( ep )
139  {
140  if ( ( ep->num > 0 ) &&
141  ( p->wValue == USB_FEATURE_ENDPOINT_HALT ) &&
142  ( pDev->state == USBD_STATE_CONFIGURED ) )
143  {
144  retVal = USBDHAL_UnStallEp( ep );
145  }
146  }
147  }
148 
149  return retVal;
150 }
151 
152 static int GetConfiguration( USBD_Device_TypeDef *pDev )
153 {
154  int retVal = USB_STATUS_REQ_ERR;
155  USB_Setup_TypeDef *p = pDev->setup;
156  uint8_t *pConfigValue = (uint8_t*)&txBuf;
157 
158  if ( ( p->wIndex != 0 ) ||
159  ( p->wLength != 1 ) ||
160  ( p->wValue != 0 ) ||
161  ( p->Direction != USB_SETUP_DIR_IN ) ||
163  {
164  return USB_STATUS_REQ_ERR;
165  }
166 
167  if ( pDev->state == USBD_STATE_ADDRESSED )
168  {
169  *pConfigValue = 0;
170  retVal = USBD_Write( 0, pConfigValue, 1, NULL );
171  }
172 
173  else if ( pDev->state == USBD_STATE_CONFIGURED )
174  {
175  retVal = USBD_Write( 0, &pDev->configurationValue, 1, NULL );
176  }
177 
178  return retVal;
179 }
180 
181 static int GetDescriptor( USBD_Device_TypeDef *pDev )
182 {
183  int index;
184  uint16_t length = 0;
185  const void *data = NULL;
186  int retVal = USB_STATUS_REQ_ERR;
187  USB_Setup_TypeDef *p = pDev->setup;
188 
189  if ( ( p->Recipient != USB_SETUP_RECIPIENT_DEVICE ) ||
190  ( p->Direction != USB_SETUP_DIR_IN ) )
191  {
192  return USB_STATUS_REQ_ERR;
193  }
194 
195  index = p->wValue & 0xFF;
196  switch ( p->wValue >> 8 )
197  {
198  case USB_DEVICE_DESCRIPTOR :
199  if ( index != 0 )
200  {
201  break;
202  }
203  data = pDev->deviceDescriptor;
204  length = pDev->deviceDescriptor->bLength;
205  break;
206 
207  case USB_CONFIG_DESCRIPTOR :
208  if ( index != 0 )
209  {
210  break;
211  }
212  data = pDev->configDescriptor;
213  length = pDev->configDescriptor->wTotalLength;
214  break;
215 
216  case USB_STRING_DESCRIPTOR :
217  if ( index < pDev->numberOfStrings )
218  {
220  s = ((USB_StringDescriptor_TypeDef**)pDev->stringDescriptors)[index];
221 
222  data = s;
223  length = s->len;
224  }
225  break;
226  }
227 
228  if ( length )
229  {
230  retVal = USBD_Write( 0, (void*)data, SL_MIN(length, p->wLength), NULL );
231  }
232 
233  return retVal;
234 }
235 
236 static int GetInterface( USBD_Device_TypeDef *pDev )
237 {
238  int retVal = USB_STATUS_REQ_ERR;
239  USB_Setup_TypeDef *p = pDev->setup;
240  uint8_t *pAlternateSetting = (uint8_t*)&txBuf;
241 
242  /* There is currently no support for alternate interface settings. */
243 
244  if ( ( p->wIndex >= pDev->numberOfInterfaces ) ||
245  ( p->wLength != 1 ) ||
246  ( p->wValue != 0 ) ||
247  ( p->Direction != USB_SETUP_DIR_IN ) ||
249  {
250  return USB_STATUS_REQ_ERR;
251  }
252 
253  if ( pDev->state == USBD_STATE_CONFIGURED )
254  {
255  *pAlternateSetting = 0;
256  retVal = USBD_Write( 0, pAlternateSetting, 1, NULL );
257  }
258 
259  return retVal;
260 }
261 
262 static int GetStatus( USBD_Device_TypeDef *pDev )
263 {
264  USBD_Ep_TypeDef *ep;
265  int retVal = USB_STATUS_REQ_ERR;
266  USB_Setup_TypeDef *p = pDev->setup;
267  uint16_t *pStatus = (uint16_t*)&txBuf;
268 
269  if ( ( p->wValue != 0 ) ||
270  ( p->wLength != 2 ) ||
271  ( p->Direction != USB_SETUP_DIR_IN ) )
272  {
273  return USB_STATUS_REQ_ERR;
274  }
275 
276  switch ( p->Recipient )
277  {
279  if ( ( p->wIndex == 0 ) &&
280  ( ( pDev->state == USBD_STATE_ADDRESSED ) ||
281  ( pDev->state == USBD_STATE_CONFIGURED ) ) )
282  {
283  *pStatus = 0;
284 
285  /* Remote wakeup feature status */
286  if ( pDev->remoteWakeupEnabled )
287  *pStatus |= REMOTE_WAKEUP_ENABLED;
288 
289  /* Current self/bus power status */
290  if ( pDev->callbacks->isSelfPowered != NULL )
291  {
292  if ( pDev->callbacks->isSelfPowered() )
293  {
294  *pStatus |= DEVICE_IS_SELFPOWERED;
295  }
296  }
297  else
298  {
299  if ( pDev->configDescriptor->bmAttributes & CONFIG_DESC_BM_SELFPOWERED )
300  {
301  *pStatus |= DEVICE_IS_SELFPOWERED;
302  }
303  }
304 
305  retVal = USBD_Write( 0, pStatus, 2, NULL );
306  }
307  break;
308 
310  if ( ( ( pDev->state == USBD_STATE_ADDRESSED ) &&
311  ( p->wIndex == 0 ) ) ||
312  ( ( pDev->state == USBD_STATE_CONFIGURED ) &&
313  ( p->wIndex < pDev->numberOfInterfaces ) ) )
314  {
315  *pStatus = 0;
316  retVal = USBD_Write( 0, pStatus, 2, NULL );
317  }
318  break;
319 
321  ep = USBD_GetEpFromAddr( p->wIndex & 0xFF );
322  if ( ep )
323  {
324  if ( ( ( pDev->state == USBD_STATE_ADDRESSED ) &&
325  ( ep->num == 0 ) ) ||
326  ( pDev->state == USBD_STATE_CONFIGURED ) )
327  {
328  /* Send 2 bytes w/halt status for endpoint */
329  retVal = USBDHAL_GetStallStatusEp( ep, pStatus );
330  if ( retVal == USB_STATUS_OK )
331  {
332  retVal = USBD_Write( 0, pStatus, 2, NULL );
333  }
334  }
335  }
336  break;
337  }
338 
339  return retVal;
340 }
341 
342 static int SetAddress( USBD_Device_TypeDef *pDev )
343 {
344  int retVal = USB_STATUS_REQ_ERR;
345  USB_Setup_TypeDef *p = pDev->setup;
346 
347  if ( ( p->wIndex != 0 ) ||
348  ( p->wLength != 0 ) ||
349  ( p->wValue > 127 ) ||
351  {
352  return USB_STATUS_REQ_ERR;
353  }
354 
355  if ( pDev->state == USBD_STATE_DEFAULT )
356  {
357  if ( p->wValue != 0 )
358  {
359  USBD_SetUsbState( USBD_STATE_ADDRESSED );
360  }
361  USBDHAL_SetAddr( p->wValue );
362  retVal = USB_STATUS_OK;
363  }
364 
365  else if ( pDev->state == USBD_STATE_ADDRESSED )
366  {
367  if ( p->wValue == 0 )
368  {
369  USBD_SetUsbState( USBD_STATE_DEFAULT );
370  }
371  USBDHAL_SetAddr( p->wValue );
372  retVal = USB_STATUS_OK;
373  }
374 
375  return retVal;
376 }
377 
378 static int SetConfiguration( USBD_Device_TypeDef *pDev )
379 {
380  int retVal = USB_STATUS_REQ_ERR;
381  USB_Setup_TypeDef *p = pDev->setup;
382 
383  if ( ( p->wIndex != 0 ) ||
384  ( p->wLength != 0 ) ||
385  ( (p->wValue>>8) != 0 ) ||
387  {
388  return USB_STATUS_REQ_ERR;
389  }
390 
391  if ( pDev->state == USBD_STATE_ADDRESSED )
392  {
393  if ( ( p->wValue == 0 ) ||
394  ( p->wValue == pDev->configDescriptor->bConfigurationValue ) )
395  {
396  pDev->configurationValue = p->wValue;
397  if ( p->wValue == pDev->configDescriptor->bConfigurationValue )
398  {
399  USBD_ActivateAllEps( true );
400  USBD_SetUsbState( USBD_STATE_CONFIGURED );
401  }
402  retVal = USB_STATUS_OK;
403  }
404  }
405 
406  else if ( pDev->state == USBD_STATE_CONFIGURED )
407  {
408  if ( ( p->wValue == 0 ) ||
409  ( p->wValue == pDev->configDescriptor->bConfigurationValue ) )
410  {
411  pDev->configurationValue = p->wValue;
412  if ( p->wValue == 0 )
413  {
414  USBD_SetUsbState( USBD_STATE_ADDRESSED );
415  USBD_DeactivateAllEps( USB_STATUS_DEVICE_UNCONFIGURED );
416  }
417  else
418  {
419  /* Reenable device endpoints, will reset data toggles */
420  USBD_ActivateAllEps( false );
421  }
422  retVal = USB_STATUS_OK;
423  }
424  }
425 
426  return retVal;
427 }
428 
429 static int SetFeature( USBD_Device_TypeDef *pDev )
430 {
431  USBD_Ep_TypeDef *ep;
432  int retVal = USB_STATUS_REQ_ERR;
434  USB_Setup_TypeDef *p = pDev->setup;
435 
436  if ( p->wLength != 0 )
437  {
438  return USB_STATUS_REQ_ERR;
439  }
440 
441  switch ( p->Recipient )
442  {
444  if ( ( p->wIndex == 0 ) &&
446  ( pDev->state == USBD_STATE_CONFIGURED ) )
447  {
448  /* Remote wakeup feature set */
449  if ( pDev->configDescriptor->bmAttributes & CONFIG_DESC_BM_REMOTEWAKEUP )
450  {
451  /* The device is capable of signalling remote wakeup */
452  pDev->remoteWakeupEnabled = true;
453  retVal = USB_STATUS_OK;
454  }
455  }
456  break;
457 
459  ep = USBD_GetEpFromAddr( p->wIndex & 0xFF );
460  if ( ep )
461  {
462  if ( ( ep->num > 0 ) &&
463  ( p->wValue == USB_FEATURE_ENDPOINT_HALT ) &&
464  ( pDev->state == USBD_STATE_CONFIGURED ) )
465  {
466  retVal = USBDHAL_StallEp( ep );
467 
468  ep->state = D_EP_IDLE;
469  /* Call end of transfer callback for endpoint */
470  if ( ( retVal == USB_STATUS_OK ) &&
471  ( ep->state != D_EP_IDLE ) &&
472  ( ep->xferCompleteCb ) )
473  {
474  callback = ep->xferCompleteCb;
475  ep->xferCompleteCb = NULL;
476  DEBUG_USB_API_PUTS( "\nEP cb(), EP stalled" );
477  callback( USB_STATUS_EP_STALLED, ep->xferred, ep->remaining);
478  }
479  }
480  }
481  }
482 
483  return retVal;
484 }
485 
486 static int SetInterface( USBD_Device_TypeDef *pDev )
487 {
488  int retVal = USB_STATUS_REQ_ERR;
489  USB_Setup_TypeDef *p = pDev->setup;
490 
491  /* There is currently no support for alternate interface settings. */
492 
493  if ( ( p->wIndex < pDev->numberOfInterfaces ) &&
494  ( p->wLength == 0 ) &&
495  ( p->wValue == 0 ) &&
496  ( pDev->state == USBD_STATE_CONFIGURED ) &&
498  {
499  /* Reset data toggles on EP's */
500  USBD_ActivateAllEps( false );
501  return USB_STATUS_OK;
502  }
503  return retVal;
504 }
505 
508 #endif /* defined( USB_DEVICE ) */
509 #endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
USB protocol stack library API for EFM32/EZR32.
#define SET_INTERFACE
Definition: em_usb.h:96
#define SET_DESCRIPTOR
Definition: em_usb.h:92
#define SET_CONFIGURATION
Definition: em_usb.h:94
#define GET_STATUS
Definition: em_usb.h:87
#define USB_STRING_DESCRIPTOR
Definition: em_usb.h:126
uint16_t wValue
Definition: em_usb.h:394
#define USB_SETUP_RECIPIENT_ENDPOINT
Definition: em_usb.h:83
CMSIS Cortex-M Peripheral Access Layer for Silicon Laboratories microcontroller devices.
#define DEVICE_IS_SELFPOWERED
Definition: em_usb.h:197
uint8_t Direction
Definition: em_usb.h:389
#define CONFIG_DESC_BM_REMOTEWAKEUP
Definition: em_usb.h:191
#define GET_CONFIGURATION
Definition: em_usb.h:93
USB Setup request package.
Definition: em_usb.h:377
#define USB_SETUP_DIR_IN
Definition: em_usb.h:67
int(* USB_XferCompleteCb_TypeDef)(USB_Status_TypeDef status, uint32_t xferred, uint32_t remaining)
USB transfer callback function.
Definition: em_usb.h:663
uint16_t wIndex
Definition: em_usb.h:395
#define USB_DEVICE_DESCRIPTOR
Definition: em_usb.h:124
#define SET_ADDRESS
Definition: em_usb.h:90
uint8_t Type
Definition: em_usb.h:388
#define SYNCH_FRAME
Definition: em_usb.h:97
USB protocol stack library API for EFM32/EZR32.
#define REMOTE_WAKEUP_ENABLED
Definition: em_usb.h:198
#define USB_SETUP_RECIPIENT_DEVICE
Definition: em_usb.h:81
#define USB_SETUP_RECIPIENT_INTERFACE
Definition: em_usb.h:82
#define CLEAR_FEATURE
Definition: em_usb.h:88
#define USB_SETUP_TYPE_STANDARD
Definition: em_usb.h:73
uint16_t wLength
Definition: em_usb.h:396
#define SET_FEATURE
Definition: em_usb.h:89
int USBD_Write(int epAddr, void *data, int byteCount, USB_XferCompleteCb_TypeDef callback)
Start a write (IN) transfer on an endpoint.
Definition: em_usbd.c:851
#define CONFIG_DESC_BM_SELFPOWERED
Definition: em_usb.h:192
#define GET_DESCRIPTOR
Definition: em_usb.h:91
#define USB_FEATURE_ENDPOINT_HALT
Definition: em_usb.h:199
USB protocol stack library, low level USB peripheral access.
#define SL_MIN(a, b)
Macro for getting minimum value. No sideeffects, a and b are evaluated once only. ...
Definition: em_common.h:137
#define USB_CONFIG_DESCRIPTOR
Definition: em_usb.h:125
#define GET_INTERFACE
Definition: em_usb.h:95
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP
Definition: em_usb.h:200
USB protocol stack library, internal type definitions.
uint8_t bRequest
Definition: em_usb.h:393
USB String Descriptor.
Definition: em_usb.h:514
uint8_t Recipient
Definition: em_usb.h:387