EFM32 Happy Gecko Software Documentation  efm32hg-doc-5.1.2
em_usbdep.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 /*
28  * USBDEP_Ep0Handler() is called each time a packet has been transmitted
29  * or recieved on the default endpoint.
30  * A state machine navigate us through the phases of a control transfer
31  * according to "chapter 9" in the USB spec.
32  */
33 #if !defined( USB_DOEP0INT_STUPPKTRCVD )
34 void USBDEP_Ep0Handler( USBD_Device_TypeDef *device )
35 {
36  int status;
37  USBD_Ep_TypeDef *ep;
38  static bool statusIn;
39  static uint32_t xferred;
40  static USB_XferCompleteCb_TypeDef callback;
41 
42  ep = &device->ep[ 0 ];
43  switch ( ep->state )
44  {
45  case D_EP_IDLE:
46  ep->remaining = 0;
47  ep->zlp = 0;
48  callback = NULL;
49  statusIn = false;
50 
51  status = USBDCH9_SetupCmd( device );
52 
53  if ( status == USB_STATUS_REQ_ERR )
54  {
55  ep->in = true;
56  USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
57  ep->in = false; /* OUT for next SETUP */
58  USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
59  USBDHAL_ReenableEp0Setup( device ); /* Prepare for next SETUP packet*/
60  }
61  else /* ( Status == USB_STATUS_OK ) */
62  {
63  if ( (ep->state == D_EP_RECEIVING) || (ep->state == D_EP_TRANSMITTING) )
64  {
65  callback = ep->xferCompleteCb;
66  }
67 
68  if ( ep->state != D_EP_RECEIVING )
69  {
70  if ( ep->remaining )
71  {
72  /* Data will be sent to host, check if a ZLP must be appended */
73  if ( ( ep->remaining < device->setup->wLength ) &&
74  ( ep->remaining % ep->packetSize == 0 ) )
75  {
76  ep->zlp = 1;
77  }
78  }
79  else
80  {
81  /* Prepare for next SETUP packet*/
82  USBDHAL_ReenableEp0Setup( device );
83 
84  /* No data stage, a ZLP may have been sent. If not, send one */
85 
86  xferred = 0;
87  if ( ep->zlp == 0 )
88  {
89  USBD_Write( 0, NULL, 0, NULL ); /* ACK to host */
90  ep->state = D_EP0_IN_STATUS;
91  }
92  else
93  {
94  ep->state = D_EP_IDLE;
95  ep->in = false; /* OUT for next SETUP */
96  }
97  }
98  }
99  }
100  break;
101 
102  case D_EP_RECEIVING:
103  if ( ep->remaining )
104  {
105  /* There is more data to receive */
106  USBD_ReArmEp0( ep );
107  }
108  else
109  {
110  status = USB_STATUS_OK;
111  if ( callback != NULL )
112  {
113  status = callback( USB_STATUS_OK, ep->xferred, 0 );
114  callback = NULL;
115  }
116 
117  if ( status != USB_STATUS_OK )
118  {
119  ep->in = true;
120  USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
121  ep->in = false; /* OUT for next SETUP */
122  USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
123  USBDHAL_ReenableEp0Setup( device ); /* Prepare for next SETUP pkt. */
124  ep->state = D_EP_IDLE;
125  }
126  else /* Everything OK, send a ZLP (ACK) to host */
127  {
128  USBDHAL_ReenableEp0Setup( device );/* Prepare for next SETUP packet*/
129 
130  ep->state = D_EP_IDLE; /* USBD_Write() sets state back*/
131  /* to EP_TRANSMITTING */
132  USBD_Write( 0, NULL, 0, NULL );
133  ep->state = D_EP0_IN_STATUS;
134  }
135  }
136  break;
137 
138  case D_EP_TRANSMITTING:
139  if ( ep->remaining )
140  {
141  /* There is more data to transmit */
142  USBD_ReArmEp0( ep );
143  }
144  else
145  {
146  /* All data transferred, is a ZLP packet needed ? */
147  if ( ep->zlp == 1 )
148  {
149  xferred = ep->xferred;
150  ep->state = D_EP_IDLE; /* USBD_Write() sets state back */
151  /* to EP_TRANSMITTING */
152  USBD_Write( 0, NULL, 0, NULL ); /* Send ZLP */
153  ep->zlp = 2;
154  }
155  else
156  {
157  if ( ep->zlp == 0 )
158  {
159  xferred = ep->xferred;
160  }
161 
162  ep->state = D_EP_IDLE;
163  USBD_Read( 0, NULL, 0, NULL ); /* Get ZLP packet (ACK) from host */
164  statusIn = true;
165  ep->state = D_EP0_OUT_STATUS;
166  }
167  }
168  break;
169 
170  case D_EP0_IN_STATUS:
171  case D_EP0_OUT_STATUS:
172  if ( statusIn )
173  {
174  USBDHAL_ReenableEp0Setup( device );
175  }
176 
177  if ( callback != NULL )
178  {
179  callback( USB_STATUS_OK, xferred, 0 );
180  }
181 
182  ep->state = D_EP_IDLE;
183  ep->in = false; /* OUT for next SETUP */
184  break;
185 
186  default:
187  EFM_ASSERT( false );
188  break;
189  }
190 }
191 #endif
192 
193 #if defined( USB_DOEP0INT_STUPPKTRCVD )
194 void USBDEP_Ep0Handler( USBD_Device_TypeDef *device )
195 {
196  int status;
197  USBD_Ep_TypeDef *ep;
198  static uint32_t xferred;
199  static USB_XferCompleteCb_TypeDef callback;
200 
201  ep = &device->ep[ 0 ];
202 
203  switch ( ep->state )
204  {
205  case D_EP_IDLE:
206  ep->zlp = 0;
207  ep->remaining = 0;
208  callback = NULL;
209 
210  status = USBDCH9_SetupCmd( device );
211 
212  if ( status == USB_STATUS_REQ_ERR )
213  {
214  ep->in = true;
215  USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
216  ep->in = false; /* OUT for next SETUP */
217  USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
218  USBDHAL_StartEp0Setup( dev ); /* Prepare for next SETUP packet*/
219  }
220  else /* ( Status == USB_STATUS_OK ) */
221  {
222  if ( (ep->state == D_EP_RECEIVING) || (ep->state == D_EP_TRANSMITTING) )
223  {
224  callback = ep->xferCompleteCb;
225  }
226 
227  if ( ep->state != D_EP_RECEIVING )
228  {
229  if ( ep->remaining )
230  {
231  /* Data will be sent to host, check if a ZLP must be appended */
232  if ( ( ep->remaining < device->setup->wLength ) &&
233  ( ep->remaining % ep->packetSize == 0 ) )
234  {
235  ep->zlp = 1;
236  }
237  }
238  else
239  {
240  /* No data stage, a ZLP may have been sent. If not, send one */
241  xferred = 0;
242  if ( ep->zlp == 0 )
243  {
244  ep->state = D_EP_IDLE;
245  USBD_Write( 0, NULL, 0, NULL ); /* ACK to host */
246  ep->state = D_EP0_IN_STATUS;
247  }
248  }
249  }
250  }
251  break;
252 
253  case D_EP_RECEIVING:
254  if ( ep->remaining )
255  {
256  ep->in = false;
257  USBD_ReArmEp0( ep );
258  }
259  else
260  {
261  status = USB_STATUS_OK;
262  if ( callback != NULL )
263  {
264  status = callback( USB_STATUS_OK, ep->xferred, 0 );
265  callback = NULL;
266  }
267 
268  if ( status != USB_STATUS_OK )
269  {
270  ep->in = true;
271  USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
272  ep->in = false; /* OUT for next SETUP */
273  USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
274  USBDHAL_StartEp0Setup( dev ); /* Prepare for next SETUP pkt. */
275  ep->state = D_EP_IDLE;
276  }
277  else
278  {
279 
280  USBDHAL_StartEp0Setup( dev ); /* Prepare for next SETUP packet*/
281  ep->state = D_EP_IDLE; /* USBD_Write() sets state back */
282  /* to EP_TRANSMITTING */
283  USBD_Write( 0, NULL, 0, NULL );
284  ep->state = D_EP0_IN_STATUS;
285  }
286  }
287  break;
288 
289  case D_EP_TRANSMITTING:
290  if ( ep->remaining )
291  {
292  ep->in = true;
293  USBD_ReArmEp0( ep );
294  }
295  else
296  {
297  if ( ep->zlp == 1 )
298  {
299  xferred = ep->xferred;
300  ep->state = D_EP_IDLE; /* USBD_Write() sets state back */
301  /* to EP_TRANSMITTING */
302  USBD_Write( 0, NULL, 0, NULL ); /* Send ZLP */
303  ep->zlp = 2;
304  }
305  else
306  {
307  if ( ep->zlp == 0 )
308  {
309  xferred = ep->xferred;
310  }
311 
312  ep->state = D_EP_IDLE;
313  USBD_Read( 0, NULL, 0, NULL ); /* Get ZLP packet (ACK) from host */
314  ep->state = D_EP0_OUT_STATUS;
315  }
316  }
317  break;
318 
319  case D_EP0_IN_STATUS:
320  if ( ( USB->DOEP0CTL & USB_DOEP0CTL_EPENA ) == 0 )
321  {
322  /* Prepare for more SETUP Packets */
323  USBDHAL_StartEp0Setup( dev );
324  }
325  if ( callback != NULL )
326  {
327  callback( USB_STATUS_OK, xferred, 0 );
328  }
329  ep->state = D_EP_IDLE;
330  ep->in = false; /* OUT for next SETUP */
331  break;
332 
333  case D_EP0_OUT_STATUS:
334  USBDHAL_StartEp0Setup( dev ); /* Prepare for more SETUP Packets */
335  if ( callback != NULL )
336  {
337  callback( USB_STATUS_OK, xferred, 0 );
338  }
339  ep->state = D_EP_IDLE;
340  ep->in = false; /* OUT for next SETUP */
341  break;
342  }
343 }
344 #endif
345 
346 /*
347  * USBDEP_EpHandler() is called each time a packet has been transmitted
348  * or recieved on an endpoint other than the default endpoint.
349  */
350 void USBDEP_EpHandler( uint8_t epAddr )
351 {
353  USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
354 
355  if ( ( ep->state == D_EP_TRANSMITTING ) || ( ep->state == D_EP_RECEIVING ) )
356  {
357  ep->state = D_EP_IDLE;
358  if ( ep->xferCompleteCb )
359  {
360  callback = ep->xferCompleteCb;
361  ep->xferCompleteCb = NULL;
362  callback( USB_STATUS_OK, ep->xferred, ep->remaining );
363  }
364  }
365  else
366  {
367  EFM_ASSERT( false );
368  }
369 }
370 
373 #endif /* defined( USB_DEVICE ) */
374 #endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
USB protocol stack library API for EFM32/EZR32.
#define USB
CMSIS Cortex-M Peripheral Access Layer for Silicon Laboratories microcontroller devices.
int(* USB_XferCompleteCb_TypeDef)(USB_Status_TypeDef status, uint32_t xferred, uint32_t remaining)
USB transfer callback function.
Definition: em_usb.h:663
#define USB_DOEP0CTL_EPENA
Definition: efm32hg_usb.h:1476
USB protocol stack library API for EFM32/EZR32.
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
USB protocol stack library, low level USB peripheral access.
USB protocol stack library, internal type definitions.
int USBD_Read(int epAddr, void *data, int byteCount, USB_XferCompleteCb_TypeDef callback)
Start a read (OUT) transfer on an endpoint.
Definition: em_usbd.c:573