ChibiOS/HAL  6.1.0
hal_usb.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 /**
18  * @file hal_usb.c
19  * @brief USB Driver code.
20  *
21  * @addtogroup USB
22  * @{
23  */
24 
25 #include <string.h>
26 
27 #include "hal.h"
28 
29 #if (HAL_USE_USB == TRUE) || defined(__DOXYGEN__)
30 
31 /*===========================================================================*/
32 /* Driver local definitions. */
33 /*===========================================================================*/
34 
35 /*===========================================================================*/
36 /* Driver exported variables. */
37 /*===========================================================================*/
38 
39 /*===========================================================================*/
40 /* Driver local variables and types. */
41 /*===========================================================================*/
42 
43 static const uint8_t zero_status[] = {0x00, 0x00};
44 static const uint8_t active_status[] ={0x00, 0x00};
45 static const uint8_t halted_status[] = {0x01, 0x00};
46 
47 /*===========================================================================*/
48 /* Driver local functions. */
49 /*===========================================================================*/
50 
51 static uint16_t get_hword(uint8_t *p) {
52  uint16_t hw;
53 
54  hw = (uint16_t)*p++;
55  hw |= (uint16_t)*p << 8U;
56  return hw;
57 }
58 
59 /**
60  * @brief SET ADDRESS transaction callback.
61  *
62  * @param[in] usbp pointer to the @p USBDriver object
63  */
64 static void set_address(USBDriver *usbp) {
65 
66  usbp->address = usbp->setup[2];
67  usb_lld_set_address(usbp);
69  usbp->state = USB_SELECTED;
70 }
71 
72 /**
73  * @brief Standard requests handler.
74  * @details This is the standard requests default handler, most standard
75  * requests are handled here, the user can override the standard
76  * handling using the @p requests_hook_cb hook in the
77  * @p USBConfig structure.
78  *
79  * @param[in] usbp pointer to the @p USBDriver object
80  * @return The request handling exit code.
81  * @retval false Request not recognized by the handler or error.
82  * @retval true Request handled.
83  */
84 static bool default_handler(USBDriver *usbp) {
85  const USBDescriptor *dp;
86 
87  /* Decoding the request.*/
88  switch ((((uint32_t)usbp->setup[0] & (USB_RTYPE_RECIPIENT_MASK |
89  USB_RTYPE_TYPE_MASK)) |
90  ((uint32_t)usbp->setup[1] << 8U))) {
91  case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_GET_STATUS << 8):
92  /* Just returns the current status word.*/
93  usbSetupTransfer(usbp, (uint8_t *)&usbp->status, 2, NULL);
94  return true;
95  case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_CLEAR_FEATURE << 8):
96  /* Only the DEVICE_REMOTE_WAKEUP is handled here, any other feature
97  number is handled as an error.*/
98  if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) {
99  usbp->status &= ~2U;
100  usbSetupTransfer(usbp, NULL, 0, NULL);
101  return true;
102  }
103  return false;
104  case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_SET_FEATURE << 8):
105  /* Only the DEVICE_REMOTE_WAKEUP is handled here, any other feature
106  number is handled as an error.*/
107  if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) {
108  usbp->status |= 2U;
109  usbSetupTransfer(usbp, NULL, 0, NULL);
110  return true;
111  }
112  return false;
113  case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_SET_ADDRESS << 8):
114  /* The SET_ADDRESS handling can be performed here or postponed after
115  the status packed depending on the USB_SET_ADDRESS_MODE low
116  driver setting.*/
117 #if USB_SET_ADDRESS_MODE == USB_EARLY_SET_ADDRESS
118  if ((usbp->setup[0] == USB_RTYPE_RECIPIENT_DEVICE) &&
119  (usbp->setup[1] == USB_REQ_SET_ADDRESS)) {
120  set_address(usbp);
121  }
122  usbSetupTransfer(usbp, NULL, 0, NULL);
123 #else
124  usbSetupTransfer(usbp, NULL, 0, set_address);
125 #endif
126  return true;
127  case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_GET_DESCRIPTOR << 8):
128  case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_GET_DESCRIPTOR << 8):
129  /* Handling descriptor requests from the host.*/
130  dp = usbp->config->get_descriptor_cb(usbp, usbp->setup[3],
131  usbp->setup[2],
132  get_hword(&usbp->setup[4]));
133  if (dp == NULL) {
134  return false;
135  }
136  /*lint -save -e9005 [11.8] Removing const is fine.*/
137  usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size, NULL);
138  /*lint -restore*/
139  return true;
140  case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_GET_CONFIGURATION << 8):
141  /* Returning the last selected configuration.*/
142  usbSetupTransfer(usbp, &usbp->configuration, 1, NULL);
143  return true;
144  case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_SET_CONFIGURATION << 8):
145 #if defined(USB_SET_CONFIGURATION_OLD_BEHAVIOR)
146  /* Handling configuration selection from the host only if it is different
147  from the current configuration.*/
148  if (usbp->configuration != usbp->setup[2])
149 #endif
150  {
151  /* If the USB device is already active then we have to perform the clear
152  procedure on the current configuration.*/
153  if (usbp->state == USB_ACTIVE) {
154  /* Current configuration cleared.*/
156  usbDisableEndpointsI(usbp);
158  usbp->configuration = 0U;
159  usbp->state = USB_SELECTED;
161  }
162  if (usbp->setup[2] != 0U) {
163  /* New configuration.*/
164  usbp->configuration = usbp->setup[2];
165  usbp->state = USB_ACTIVE;
167  }
168  }
169  usbSetupTransfer(usbp, NULL, 0, NULL);
170  return true;
171  case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_GET_STATUS << 8):
172  case (uint32_t)USB_RTYPE_RECIPIENT_ENDPOINT | ((uint32_t)USB_REQ_SYNCH_FRAME << 8):
173  /* Just sending two zero bytes, the application can change the behavior
174  using a hook..*/
175  /*lint -save -e9005 [11.8] Removing const is fine.*/
176  usbSetupTransfer(usbp, (uint8_t *)zero_status, 2, NULL);
177  /*lint -restore*/
178  return true;
179  case (uint32_t)USB_RTYPE_RECIPIENT_ENDPOINT | ((uint32_t)USB_REQ_GET_STATUS << 8):
180  /* Sending the EP status.*/
181  if ((usbp->setup[4] & 0x80U) != 0U) {
182  switch (usb_lld_get_status_in(usbp, usbp->setup[4] & 0x0FU)) {
183  case EP_STATUS_STALLED:
184  /*lint -save -e9005 [11.8] Removing const is fine.*/
185  usbSetupTransfer(usbp, (uint8_t *)halted_status, 2, NULL);
186  /*lint -restore*/
187  return true;
188  case EP_STATUS_ACTIVE:
189  /*lint -save -e9005 [11.8] Removing const is fine.*/
190  usbSetupTransfer(usbp, (uint8_t *)active_status, 2, NULL);
191  /*lint -restore*/
192  return true;
193  case EP_STATUS_DISABLED:
194  default:
195  return false;
196  }
197  }
198  else {
199  switch (usb_lld_get_status_out(usbp, usbp->setup[4] & 0x0FU)) {
200  case EP_STATUS_STALLED:
201  /*lint -save -e9005 [11.8] Removing const is fine.*/
202  usbSetupTransfer(usbp, (uint8_t *)halted_status, 2, NULL);
203  /*lint -restore*/
204  return true;
205  case EP_STATUS_ACTIVE:
206  /*lint -save -e9005 [11.8] Removing const is fine.*/
207  usbSetupTransfer(usbp, (uint8_t *)active_status, 2, NULL);
208  /*lint -restore*/
209  return true;
210  case EP_STATUS_DISABLED:
211  default:
212  return false;
213  }
214  }
215  case (uint32_t)USB_RTYPE_RECIPIENT_ENDPOINT | ((uint32_t)USB_REQ_CLEAR_FEATURE << 8):
216  /* Only ENDPOINT_HALT is handled as feature.*/
217  if (usbp->setup[2] != USB_FEATURE_ENDPOINT_HALT) {
218  return false;
219  }
220  /* Clearing the EP status, not valid for EP0, it is ignored in that case.*/
221  if ((usbp->setup[4] & 0x0FU) != 0U) {
222  if ((usbp->setup[4] & 0x80U) != 0U) {
223  usb_lld_clear_in(usbp, usbp->setup[4] & 0x0FU);
224  }
225  else {
226  usb_lld_clear_out(usbp, usbp->setup[4] & 0x0FU);
227  }
228  }
229  usbSetupTransfer(usbp, NULL, 0, NULL);
230  return true;
231  case (uint32_t)USB_RTYPE_RECIPIENT_ENDPOINT | ((uint32_t)USB_REQ_SET_FEATURE << 8):
232  /* Only ENDPOINT_HALT is handled as feature.*/
233  if (usbp->setup[2] != USB_FEATURE_ENDPOINT_HALT) {
234  return false;
235  }
236  /* Stalling the EP, not valid for EP0, it is ignored in that case.*/
237  if ((usbp->setup[4] & 0x0FU) != 0U) {
238  if ((usbp->setup[4] & 0x80U) != 0U) {
239  usb_lld_stall_in(usbp, usbp->setup[4] & 0x0FU);
240  }
241  else {
242  usb_lld_stall_out(usbp, usbp->setup[4] & 0x0FU);
243  }
244  }
245  usbSetupTransfer(usbp, NULL, 0, NULL);
246  return true;
247  case (uint32_t)USB_RTYPE_RECIPIENT_DEVICE | ((uint32_t)USB_REQ_SET_DESCRIPTOR << 8):
248  case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_CLEAR_FEATURE << 8):
249  case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_SET_FEATURE << 8):
250  case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_GET_INTERFACE << 8):
251  case (uint32_t)USB_RTYPE_RECIPIENT_INTERFACE | ((uint32_t)USB_REQ_SET_INTERFACE << 8):
252  /* All the above requests are not handled here, if you need them then
253  use the hook mechanism and provide handling.*/
254  default:
255  return false;
256  }
257 }
258 
259 /*===========================================================================*/
260 /* Driver exported functions. */
261 /*===========================================================================*/
262 
263 /**
264  * @brief USB Driver initialization.
265  * @note This function is implicitly invoked by @p halInit(), there is
266  * no need to explicitly initialize the driver.
267  *
268  * @init
269  */
270 void usbInit(void) {
271 
272  usb_lld_init();
273 }
274 
275 /**
276  * @brief Initializes the standard part of a @p USBDriver structure.
277  *
278  * @param[out] usbp pointer to the @p USBDriver object
279  *
280  * @init
281  */
283  unsigned i;
284 
285  usbp->state = USB_STOP;
286  usbp->config = NULL;
287  for (i = 0; i < (unsigned)USB_MAX_ENDPOINTS; i++) {
288  usbp->in_params[i] = NULL;
289  usbp->out_params[i] = NULL;
290  }
291  usbp->transmitting = 0;
292  usbp->receiving = 0;
293 }
294 
295 /**
296  * @brief Configures and activates the USB peripheral.
297  *
298  * @param[in] usbp pointer to the @p USBDriver object
299  * @param[in] config pointer to the @p USBConfig object
300  *
301  * @api
302  */
303 void usbStart(USBDriver *usbp, const USBConfig *config) {
304  unsigned i;
305 
306  osalDbgCheck((usbp != NULL) && (config != NULL));
307 
308  osalSysLock();
309  osalDbgAssert((usbp->state == USB_STOP) || (usbp->state == USB_READY),
310  "invalid state");
311  usbp->config = config;
312  for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) {
313  usbp->epc[i] = NULL;
314  }
315  usb_lld_start(usbp);
316  usbp->state = USB_READY;
317  osalSysUnlock();
318 }
319 
320 /**
321  * @brief Deactivates the USB peripheral.
322  *
323  * @param[in] usbp pointer to the @p USBDriver object
324  *
325  * @api
326  */
327 void usbStop(USBDriver *usbp) {
328  unsigned i;
329 
330  osalDbgCheck(usbp != NULL);
331 
332  osalSysLock();
333 
334  osalDbgAssert((usbp->state == USB_STOP) || (usbp->state == USB_READY) ||
335  (usbp->state == USB_SELECTED) || (usbp->state == USB_ACTIVE) ||
336  (usbp->state == USB_SUSPENDED),
337  "invalid state");
338 
339  usb_lld_stop(usbp);
340  usbp->config = NULL;
341  usbp->state = USB_STOP;
342 
343  /* Resetting all ongoing synchronous operations.*/
344  for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) {
345 #if USB_USE_WAIT == TRUE
346  if (usbp->epc[i] != NULL) {
347  if (usbp->epc[i]->in_state != NULL) {
348  osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET);
349  }
350  if (usbp->epc[i]->out_state != NULL) {
351  osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET);
352  }
353  }
354 #endif
355  usbp->epc[i] = NULL;
356  }
358 
359  osalSysUnlock();
360 }
361 
362 /**
363  * @brief Enables an endpoint.
364  * @details This function enables an endpoint, both IN and/or OUT directions
365  * depending on the configuration structure.
366  * @note This function must be invoked in response of a SET_CONFIGURATION
367  * or SET_INTERFACE message.
368  *
369  * @param[in] usbp pointer to the @p USBDriver object
370  * @param[in] ep endpoint number
371  * @param[in] epcp the endpoint configuration
372  *
373  * @iclass
374  */
376  const USBEndpointConfig *epcp) {
377 
379  osalDbgCheck((usbp != NULL) && (epcp != NULL));
380  osalDbgAssert(usbp->state == USB_ACTIVE,
381  "invalid state");
382  osalDbgAssert(usbp->epc[ep] == NULL, "already initialized");
383 
384  /* Logically enabling the endpoint in the USBDriver structure.*/
385  usbp->epc[ep] = epcp;
386 
387  /* Clearing the state structures, custom fields as well.*/
388  if (epcp->in_state != NULL) {
389  memset(epcp->in_state, 0, sizeof(USBInEndpointState));
390  }
391  if (epcp->out_state != NULL) {
392  memset(epcp->out_state, 0, sizeof(USBOutEndpointState));
393  }
394 
395  /* Low level endpoint activation.*/
396  usb_lld_init_endpoint(usbp, ep);
397 }
398 
399 /**
400  * @brief Disables all the active endpoints.
401  * @details This function disables all the active endpoints except the
402  * endpoint zero.
403  * @note This function must be invoked in response of a SET_CONFIGURATION
404  * message with configuration number zero.
405  *
406  * @param[in] usbp pointer to the @p USBDriver object
407  *
408  * @iclass
409  */
411  unsigned i;
412 
414  osalDbgCheck(usbp != NULL);
415  osalDbgAssert(usbp->state == USB_ACTIVE, "invalid state");
416 
417  usbp->transmitting &= 1U;
418  usbp->receiving &= 1U;
419 
420  for (i = 1; i <= (unsigned)USB_MAX_ENDPOINTS; i++) {
421 #if USB_USE_WAIT == TRUE
422  /* Signaling the event to threads waiting on endpoints.*/
423  if (usbp->epc[i] != NULL) {
424  if (usbp->epc[i]->in_state != NULL) {
425  osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET);
426  }
427  if (usbp->epc[i]->out_state != NULL) {
428  osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET);
429  }
430  }
431 #endif
432  usbp->epc[i] = NULL;
433  }
434 
435  /* Low level endpoints deactivation.*/
437 }
438 
439 /**
440  * @brief Starts a receive transaction on an OUT endpoint.
441  * @note This function is meant to be called from ISR context outside
442  * critical zones because there is a potentially slow operation
443  * inside.
444  *
445  * @param[in] usbp pointer to the @p USBDriver object
446  * @param[in] ep endpoint number
447  * @param[out] buf buffer where to copy the received data
448  * @param[in] n transaction size. It is recommended a multiple of
449  * the packet size because the excess is discarded.
450  *
451  * @iclass
452  */
454  uint8_t *buf, size_t n) {
455  USBOutEndpointState *osp;
456 
458  osalDbgCheck((usbp != NULL) && (ep <= (usbep_t)USB_MAX_ENDPOINTS));
459  osalDbgAssert(!usbGetReceiveStatusI(usbp, ep), "already receiving");
460 
461  /* Marking the endpoint as active.*/
462  usbp->receiving |= (uint16_t)((unsigned)1U << (unsigned)ep);
463 
464  /* Setting up the transfer.*/
465  /*lint -save -e661 [18.1] pclint is confused by the check on ep.*/
466  osp = usbp->epc[ep]->out_state;
467  /*lint -restore*/
468  osp->rxbuf = buf;
469  osp->rxsize = n;
470  osp->rxcnt = 0;
471 #if USB_USE_WAIT == TRUE
472  osp->thread = NULL;
473 #endif
474 
475  /* Starting transfer.*/
476  usb_lld_start_out(usbp, ep);
477 }
478 
479 /**
480  * @brief Starts a transmit transaction on an IN endpoint.
481  * @note This function is meant to be called from ISR context outside
482  * critical zones because there is a potentially slow operation
483  * inside.
484  *
485  * @param[in] usbp pointer to the @p USBDriver object
486  * @param[in] ep endpoint number
487  * @param[in] buf buffer where to fetch the data to be transmitted
488  * @param[in] n transaction size
489  *
490  * @iclass
491  */
493  const uint8_t *buf, size_t n) {
494  USBInEndpointState *isp;
495 
497  osalDbgCheck((usbp != NULL) && (ep <= (usbep_t)USB_MAX_ENDPOINTS));
498  osalDbgAssert(!usbGetTransmitStatusI(usbp, ep), "already transmitting");
499 
500  /* Marking the endpoint as active.*/
501  usbp->transmitting |= (uint16_t)((unsigned)1U << (unsigned)ep);
502 
503  /* Setting up the transfer.*/
504  /*lint -save -e661 [18.1] pclint is confused by the check on ep.*/
505  isp = usbp->epc[ep]->in_state;
506  /*lint -restore*/
507  isp->txbuf = buf;
508  isp->txsize = n;
509  isp->txcnt = 0;
510 #if USB_USE_WAIT == TRUE
511  isp->thread = NULL;
512 #endif
513 
514  /* Starting transfer.*/
515  usb_lld_start_in(usbp, ep);
516 }
517 
518 #if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__)
519 /**
520  * @brief Performs a receive transaction on an OUT endpoint.
521  *
522  * @param[in] usbp pointer to the @p USBDriver object
523  * @param[in] ep endpoint number
524  * @param[out] buf buffer where to copy the received data
525  * @param[in] n transaction size. It is recommended a multiple of
526  * the packet size because the excess is discarded.
527  *
528  * @return The received effective data size, it can be less than
529  * the amount specified.
530  * @retval MSG_RESET driver not in @p USB_ACTIVE state or the operation
531  * has been aborted by an USB reset or a transition to
532  * the @p USB_SUSPENDED state.
533  *
534  * @api
535  */
536 msg_t usbReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) {
537  msg_t msg;
538 
539  osalSysLock();
540 
541  if (usbGetDriverStateI(usbp) != USB_ACTIVE) {
542  osalSysUnlock();
543  return MSG_RESET;
544  }
545 
546  usbStartReceiveI(usbp, ep, buf, n);
547  msg = osalThreadSuspendS(&usbp->epc[ep]->out_state->thread);
548  osalSysUnlock();
549 
550  return msg;
551 }
552 
553 /**
554  * @brief Performs a transmit transaction on an IN endpoint.
555  *
556  * @param[in] usbp pointer to the @p USBDriver object
557  * @param[in] ep endpoint number
558  * @param[in] buf buffer where to fetch the data to be transmitted
559  * @param[in] n transaction size
560  *
561  * @return The operation status.
562  * @retval MSG_OK operation performed successfully.
563  * @retval MSG_RESET driver not in @p USB_ACTIVE state or the operation
564  * has been aborted by an USB reset or a transition to
565  * the @p USB_SUSPENDED state.
566  *
567  * @api
568  */
569 msg_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n) {
570  msg_t msg;
571 
572  osalSysLock();
573 
574  if (usbGetDriverStateI(usbp) != USB_ACTIVE) {
575  osalSysUnlock();
576  return MSG_RESET;
577  }
578 
579  usbStartTransmitI(usbp, ep, buf, n);
580  msg = osalThreadSuspendS(&usbp->epc[ep]->in_state->thread);
581  osalSysUnlock();
582 
583  return msg;
584 }
585 #endif /* USB_USE_WAIT == TRUE */
586 
587 /**
588  * @brief Stalls an OUT endpoint.
589  *
590  * @param[in] usbp pointer to the @p USBDriver object
591  * @param[in] ep endpoint number
592  *
593  * @return The operation status.
594  * @retval false Endpoint stalled.
595  * @retval true Endpoint busy, not stalled.
596  *
597  * @iclass
598  */
600 
602  osalDbgCheck(usbp != NULL);
603 
604  if (usbGetReceiveStatusI(usbp, ep)) {
605  return true;
606  }
607 
608  usb_lld_stall_out(usbp, ep);
609  return false;
610 }
611 
612 /**
613  * @brief Stalls an IN endpoint.
614  *
615  * @param[in] usbp pointer to the @p USBDriver object
616  * @param[in] ep endpoint number
617  *
618  * @return The operation status.
619  * @retval false Endpoint stalled.
620  * @retval true Endpoint busy, not stalled.
621  *
622  * @iclass
623  */
625 
627  osalDbgCheck(usbp != NULL);
628 
629  if (usbGetTransmitStatusI(usbp, ep)) {
630  return true;
631  }
632 
633  usb_lld_stall_in(usbp, ep);
634  return false;
635 }
636 
637 /**
638  * @brief Host wake-up procedure.
639  * @note It is silently ignored if the USB device is not in the
640  * @p USB_SUSPENDED state.
641  *
642  * @param[in] usbp pointer to the @p USBDriver object
643  *
644  * @api
645  */
647 
648  if (usbp->state == USB_SUSPENDED) {
649  /* Starting host wakeup procedure.*/
650  usb_lld_wakeup_host(usbp);
651  }
652 }
653 
654 /**
655  * @brief USB reset routine.
656  * @details This function must be invoked when an USB bus reset condition is
657  * detected.
658  *
659  * @param[in] usbp pointer to the @p USBDriver object
660  *
661  * @notapi
662  */
663 void _usb_reset(USBDriver *usbp) {
664  unsigned i;
665 
666  /* State transition.*/
667  usbp->state = USB_READY;
668 
669  /* Resetting internal state.*/
670  usbp->status = 0;
671  usbp->address = 0;
672  usbp->configuration = 0;
673  usbp->transmitting = 0;
674  usbp->receiving = 0;
675 
676  /* Invalidates all endpoints into the USBDriver structure.*/
677  for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) {
678 #if USB_USE_WAIT == TRUE
679  /* Signaling the event to threads waiting on endpoints.*/
680  if (usbp->epc[i] != NULL) {
682  if (usbp->epc[i]->in_state != NULL) {
683  osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET);
684  }
685  if (usbp->epc[i]->out_state != NULL) {
686  osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET);
687  }
689  }
690 #endif
691  usbp->epc[i] = NULL;
692  }
693 
694  /* EP0 state machine initialization.*/
696 
697  /* Low level reset.*/
698  usb_lld_reset(usbp);
699 
700  /* Notification of reset event.*/
702 }
703 
704 /**
705  * @brief USB suspend routine.
706  * @details This function must be invoked when an USB bus suspend condition is
707  * detected.
708  *
709  * @param[in] usbp pointer to the @p USBDriver object
710  *
711  * @notapi
712  */
713 void _usb_suspend(USBDriver *usbp) {
714  /* No state change, suspend always returns to previous state. */
715 
716  /* State transition.*/
717  usbp->saved_state = usbp->state;
718  usbp->state = USB_SUSPENDED;
719 
720  /* Notification of suspend event.*/
722 
723  /* Signaling the event to threads waiting on endpoints.*/
724 #if USB_USE_WAIT == TRUE
725  {
726  unsigned i;
727 
728  for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) {
729  if (usbp->epc[i] != NULL) {
731  if (usbp->epc[i]->in_state != NULL) {
732  osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET);
733  }
734  if (usbp->epc[i]->out_state != NULL) {
735  osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET);
736  }
738  }
739  }
740  }
741 #endif
742 }
743 
744 /**
745  * @brief USB wake-up routine.
746  * @details This function must be invoked when an USB bus wake-up condition is
747  * detected.
748  *
749  * @param[in] usbp pointer to the @p USBDriver object
750  *
751  * @notapi
752  */
753 void _usb_wakeup(USBDriver *usbp) {
754 
755  /* State transition, returning to the previous state.*/
756  usbp->state = usbp->saved_state;
757 
758  /* Notification of suspend event.*/
760 }
761 
762 /**
763  * @brief Default EP0 SETUP callback.
764  * @details This function is used by the low level driver as default handler
765  * for EP0 SETUP events.
766  *
767  * @param[in] usbp pointer to the @p USBDriver object
768  * @param[in] ep endpoint number, always zero
769  *
770  * @notapi
771  */
772 void _usb_ep0setup(USBDriver *usbp, usbep_t ep) {
773  size_t max;
774 
775  /* Is the EP0 state machine in the correct state for handling setup
776  packets?*/
777  if (usbp->ep0state != USB_EP0_STP_WAITING) {
778  /* This is unexpected could require handling with a warning event.*/
779  /* TODO: handling here.*/
780 
781  /* Resetting the EP0 state machine and going ahead.*/
783  }
784 
785  /* Reading the setup data into the driver buffer.*/
786  usbReadSetup(usbp, ep, usbp->setup);
787 
788  /* First verify if the application has an handler installed for this
789  request.*/
790  /*lint -save -e9007 [13.5] No side effects, it is intentional.*/
791  if ((usbp->config->requests_hook_cb == NULL) ||
792  !(usbp->config->requests_hook_cb(usbp))) {
793  /*lint -restore*/
794  /* Invoking the default handler, if this fails then stalls the
795  endpoint zero as error.*/
796  /*lint -save -e9007 [13.5] No side effects, it is intentional.*/
797  if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) != USB_RTYPE_TYPE_STD) ||
798  !default_handler(usbp)) {
799  /*lint -restore*/
800  /* Error response, the state machine goes into an error state, the low
801  level layer will have to reset it to USB_EP0_WAITING_SETUP after
802  receiving a SETUP packet.*/
803  usb_lld_stall_in(usbp, 0);
804  usb_lld_stall_out(usbp, 0);
806  usbp->ep0state = USB_EP0_ERROR;
807  return;
808  }
809  }
810 #if (USB_SET_ADDRESS_ACK_HANDLING == USB_SET_ADDRESS_ACK_HW)
811  if (usbp->setup[1] == USB_REQ_SET_ADDRESS) {
812  /* Zero-length packet sent by hardware */
813  return;
814  }
815 #endif
816  /* Transfer preparation. The request handler must have populated
817  correctly the fields ep0next, ep0n and ep0endcb using the macro
818  usbSetupTransfer().*/
819  max = (size_t)get_hword(&usbp->setup[6]);
820  /* The transfer size cannot exceed the specified amount.*/
821  if (usbp->ep0n > max) {
822  usbp->ep0n = max;
823  }
824  if ((usbp->setup[0] & USB_RTYPE_DIR_MASK) == USB_RTYPE_DIR_DEV2HOST) {
825  /* IN phase.*/
826  if (usbp->ep0n != 0U) {
827  /* Starts the transmit phase.*/
828  usbp->ep0state = USB_EP0_IN_TX;
830  usbStartTransmitI(usbp, 0, usbp->ep0next, usbp->ep0n);
832  }
833  else {
834  /* No transmission phase, directly receiving the zero sized status
835  packet.*/
837 #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW)
839  usbStartReceiveI(usbp, 0, NULL, 0);
841 #else
842  usb_lld_end_setup(usbp, ep);
843 #endif
844  }
845  }
846  else {
847  /* OUT phase.*/
848  if (usbp->ep0n != 0U) {
849  /* Starts the receive phase.*/
850  usbp->ep0state = USB_EP0_OUT_RX;
852  usbStartReceiveI(usbp, 0, (uint8_t *)usbp->ep0next, usbp->ep0n);
854  }
855  else {
856  /* No receive phase, directly sending the zero sized status
857  packet.*/
859 #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW)
861  usbStartTransmitI(usbp, 0, NULL, 0);
863 #else
864  usb_lld_end_setup(usbp, ep);
865 #endif
866  }
867  }
868 }
869 
870 /**
871  * @brief Default EP0 IN callback.
872  * @details This function is used by the low level driver as default handler
873  * for EP0 IN events.
874  *
875  * @param[in] usbp pointer to the @p USBDriver object
876  * @param[in] ep endpoint number, always zero
877  *
878  * @notapi
879  */
880 void _usb_ep0in(USBDriver *usbp, usbep_t ep) {
881  size_t max;
882 
883  (void)ep;
884  switch (usbp->ep0state) {
885  case USB_EP0_IN_TX:
886  max = (size_t)get_hword(&usbp->setup[6]);
887  /* If the transmitted size is less than the requested size and it is a
888  multiple of the maximum packet size then a zero size packet must be
889  transmitted.*/
890  if ((usbp->ep0n < max) &&
891  ((usbp->ep0n % usbp->epc[0]->in_maxsize) == 0U)) {
893  usbStartTransmitI(usbp, 0, NULL, 0);
896  return;
897  }
898  /* Falls through.*/
900  /* Transmit phase over, receiving the zero sized status packet.*/
902 #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW)
904  usbStartReceiveI(usbp, 0, NULL, 0);
906 #else
907  usb_lld_end_setup(usbp, ep);
908 #endif
909  return;
911  /* Status packet sent, invoking the callback if defined.*/
912  if (usbp->ep0endcb != NULL) {
913  usbp->ep0endcb(usbp);
914  }
916  return;
917  case USB_EP0_STP_WAITING:
919  case USB_EP0_OUT_RX:
920  /* All the above are invalid states in the IN phase.*/
921  osalDbgAssert(false, "EP0 state machine error");
922  /* Falls through.*/
923  case USB_EP0_ERROR:
924  /* Error response, the state machine goes into an error state, the low
925  level layer will have to reset it to USB_EP0_WAITING_SETUP after
926  receiving a SETUP packet.*/
927  usb_lld_stall_in(usbp, 0);
928  usb_lld_stall_out(usbp, 0);
930  usbp->ep0state = USB_EP0_ERROR;
931  return;
932  default:
933  osalDbgAssert(false, "EP0 state machine invalid state");
934  }
935 }
936 
937 /**
938  * @brief Default EP0 OUT callback.
939  * @details This function is used by the low level driver as default handler
940  * for EP0 OUT events.
941  *
942  * @param[in] usbp pointer to the @p USBDriver object
943  * @param[in] ep endpoint number, always zero
944  *
945  * @notapi
946  */
947 void _usb_ep0out(USBDriver *usbp, usbep_t ep) {
948 
949  (void)ep;
950  switch (usbp->ep0state) {
951  case USB_EP0_OUT_RX:
952  /* Receive phase over, sending the zero sized status packet.*/
954 #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW)
956  usbStartTransmitI(usbp, 0, NULL, 0);
958 #else
959  usb_lld_end_setup(usbp, ep);
960 #endif
961  return;
963  /* Status packet received, it must be zero sized, invoking the callback
964  if defined.*/
965 #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW)
966  if (usbGetReceiveTransactionSizeX(usbp, 0) != 0U) {
967  break;
968  }
969 #endif
970  if (usbp->ep0endcb != NULL) {
971  usbp->ep0endcb(usbp);
972  }
974  return;
975  case USB_EP0_STP_WAITING:
976  case USB_EP0_IN_TX:
979  /* All the above are invalid states in the IN phase.*/
980  osalDbgAssert(false, "EP0 state machine error");
981  /* Falls through.*/
982  case USB_EP0_ERROR:
983  /* Error response, the state machine goes into an error state, the low
984  level layer will have to reset it to USB_EP0_WAITING_SETUP after
985  receiving a SETUP packet.*/
986  usb_lld_stall_in(usbp, 0);
987  usb_lld_stall_out(usbp, 0);
989  usbp->ep0state = USB_EP0_ERROR;
990  return;
991  default:
992  osalDbgAssert(false, "EP0 state machine invalid state");
993  }
994 }
995 
996 #endif /* HAL_USE_USB == TRUE */
997 
998 /** @} */
USBOutEndpointState * out_state
USBEndpointState associated to the OUT endpoint.
Definition: hal_usb_lld.h:183
static void set_address(USBDriver *usbp)
SET ADDRESS transaction callback.
Definition: hal_usb.c:64
uint16_t in_maxsize
IN endpoint maximum packet size.
Definition: hal_usb_lld.h:167
void usbDisableEndpointsI(USBDriver *usbp)
Disables all the active endpoints.
Definition: hal_usb.c:410
void _usb_suspend(USBDriver *usbp)
USB suspend routine.
Definition: hal_usb.c:713
void _usb_ep0setup(USBDriver *usbp, usbep_t ep)
Default EP0 SETUP callback.
Definition: hal_usb.c:772
Type of an OUT endpoint state structure.
Definition: hal_usb_lld.h:108
msg_t osalThreadSuspendS(thread_reference_t *trp)
Sends the current thread sleeping and sets a reference variable.
Definition: osal.c:185
void usbWakeupHost(USBDriver *usbp)
Host wake-up procedure.
Definition: hal_usb.c:646
void usb_lld_init(void)
Low level USB driver initialization.
Definition: hal_usb_lld.c:99
usbstate_t state
Driver state.
Definition: hal_usb_lld.h:221
size_t rxcnt
Received bytes so far.
Definition: hal_usb_lld.h:116
const USBEndpointConfig * epc[USB_MAX_ENDPOINTS+1]
Active endpoints configurations.
Definition: hal_usb_lld.h:237
uint8_t setup[8]
Setup packet buffer.
Definition: hal_usb_lld.h:271
void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep)
Enables an endpoint.
Definition: hal_usb_lld.c:186
void usb_lld_clear_out(USBDriver *usbp, usbep_t ep)
Brings an OUT endpoint in the active state.
Definition: hal_usb_lld.c:366
size_t txsize
Requested transmit transfer size.
Definition: hal_usb_lld.h:87
#define usb_lld_wakeup_host(usbp)
Start of host wake-up procedure.
Definition: hal_usb_lld.h:344
size_t ud_size
Descriptor size in unicode characters.
Definition: hal_usb.h:320
void usb_lld_clear_in(USBDriver *usbp, usbep_t ep)
Brings an IN endpoint in the active state.
Definition: hal_usb_lld.c:381
#define usbGetReceiveStatusI(usbp, ep)
Returns the status of an OUT endpoint.
Definition: hal_usb.h:446
void usb_lld_start(USBDriver *usbp)
Configures and activates the USB peripheral.
Definition: hal_usb_lld.c:114
HAL subsystem header.
#define osalDbgCheckClassI()
I-Class state check.
Definition: osal.h:292
void usb_lld_disable_endpoints(USBDriver *usbp)
Disables all the active endpoints except the endpoint zero.
Definition: hal_usb_lld.c:200
void usb_lld_start_out(USBDriver *usbp, usbep_t ep)
Starts a receive operation on an OUT endpoint.
Definition: hal_usb_lld.c:306
static void osalSysLockFromISR(void)
Enters a critical zone from ISR context.
Definition: osal.h:550
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition: osal.h:540
void usb_lld_stall_in(USBDriver *usbp, usbep_t ep)
Brings an IN endpoint in the stalled state.
Definition: hal_usb_lld.c:351
void osalOsRescheduleS(void)
Checks if a reschedule is required and performs it.
Definition: osal.c:119
uint8_t configuration
Current USB device configuration.
Definition: hal_usb_lld.h:283
void usb_lld_start_in(USBDriver *usbp, usbep_t ep)
Starts a transmit operation on an IN endpoint.
Definition: hal_usb_lld.c:321
const USBConfig * config
Current configuration data.
Definition: hal_usb_lld.h:225
Structure representing an USB driver.
Definition: hal_usb_lld.h:217
uint8_t address
Assigned USB address.
Definition: hal_usb_lld.h:279
void * out_params[USB_MAX_ENDPOINTS]
Fields available to user, it can be used to associate an application-defined handler to an OUT endpoi...
Definition: hal_usb_lld.h:251
size_t ep0n
Number of bytes yet to be transferred through endpoint 0.
Definition: hal_usb_lld.h:263
int32_t msg_t
Type of a message.
Definition: osal.h:160
void usb_lld_stall_out(USBDriver *usbp, usbep_t ep)
Brings an OUT endpoint in the stalled state.
Definition: hal_usb_lld.c:336
uint16_t receiving
Bit map of the receiving OUT endpoints.
Definition: hal_usb_lld.h:233
#define usbGetDriverStateI(usbp)
Returns the driver state.
Definition: hal_usb.h:391
msg_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n)
Performs a transmit transaction on an IN endpoint.
Definition: hal_usb.c:569
thread_reference_t thread
Waiting thread.
Definition: hal_usb_lld.h:100
const uint8_t * txbuf
Pointer to the transmission linear buffer.
Definition: hal_usb_lld.h:95
#define usbGetTransmitStatusI(usbp, ep)
Returns the status of an IN endpoint.
Definition: hal_usb.h:432
void usbInit(void)
USB Driver initialization.
Definition: hal_usb.c:270
usbreqhandler_t requests_hook_cb
Requests hook callback.
Definition: hal_usb_lld.h:206
uint8_t * rxbuf
Pointer to the receive linear buffer.
Definition: hal_usb_lld.h:120
void usbStartReceiveI(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n)
Starts a receive transaction on an OUT endpoint.
Definition: hal_usb.c:453
#define _usb_isr_invoke_event_cb(usbp, evt)
Common ISR code, usb event callback.
Definition: hal_usb.h:511
void _usb_ep0in(USBDriver *usbp, usbep_t ep)
Default EP0 IN callback.
Definition: hal_usb.c:880
size_t txcnt
Transmitted bytes so far.
Definition: hal_usb_lld.h:91
void _usb_wakeup(USBDriver *usbp)
USB wake-up routine.
Definition: hal_usb.c:753
#define osalDbgCheck(c)
Function parameters check.
Definition: osal.h:278
void usb_lld_reset(USBDriver *usbp)
USB low level reset routine.
Definition: hal_usb_lld.c:156
size_t rxsize
Requested receive transfer size.
Definition: hal_usb_lld.h:112
static void osalSysUnlockFromISR(void)
Leaves a critical zone from ISR context.
Definition: osal.h:560
void _usb_ep0out(USBDriver *usbp, usbep_t ep)
Default EP0 OUT callback.
Definition: hal_usb.c:947
uint16_t transmitting
Bit map of the transmitting IN endpoints.
Definition: hal_usb_lld.h:229
void usbStop(USBDriver *usbp)
Deactivates the USB peripheral.
Definition: hal_usb.c:327
const uint8_t * ud_string
Pointer to the descriptor.
Definition: hal_usb.h:324
bool usbStallTransmitI(USBDriver *usbp, usbep_t ep)
Stalls an IN endpoint.
Definition: hal_usb.c:624
void usbInitEndpointI(USBDriver *usbp, usbep_t ep, const USBEndpointConfig *epcp)
Enables an endpoint.
Definition: hal_usb.c:375
usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep)
Returns the status of an OUT endpoint.
Definition: hal_usb_lld.c:218
void * in_params[USB_MAX_ENDPOINTS]
Fields available to user, it can be used to associate an application-defined handler to an IN endpoin...
Definition: hal_usb_lld.h:244
uint16_t status
Current USB device status.
Definition: hal_usb_lld.h:275
#define usbReadSetup(usbp, ep, buf)
Reads a setup packet from the dedicated packet buffer.
Definition: hal_usb.h:496
void _usb_reset(USBDriver *usbp)
USB reset routine.
Definition: hal_usb.c:663
void usbStart(USBDriver *usbp, const USBConfig *config)
Configures and activates the USB peripheral.
Definition: hal_usb.c:303
Type of an IN endpoint state structure.
Definition: hal_usb_lld.h:83
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition: osal.h:530
static bool default_handler(USBDriver *usbp)
Standard requests handler.
Definition: hal_usb.c:84
uint8_t * ep0next
Next position in the buffer to be transferred through endpoint 0.
Definition: hal_usb_lld.h:259
usbgetdescriptor_t get_descriptor_cb
Device GET_DESCRIPTOR request callback.
Definition: hal_usb_lld.h:200
usbcallback_t ep0endcb
Endpoint 0 end transaction callback.
Definition: hal_usb_lld.h:267
usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep)
Returns the status of an IN endpoint.
Definition: hal_usb_lld.c:238
bool usbStallReceiveI(USBDriver *usbp, usbep_t ep)
Stalls an OUT endpoint.
Definition: hal_usb.c:599
#define osalDbgAssert(c, remark)
Condition assertion.
Definition: osal.h:258
Type of an USB descriptor.
Definition: hal_usb.h:316
uint8_t usbep_t
Type of an endpoint identifier.
Definition: hal_usb.h:264
Type of an USB driver configuration structure.
Definition: hal_usb_lld.h:190
void osalThreadResumeI(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition: osal.c:230
void usbStartTransmitI(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n)
Starts a transmit transaction on an IN endpoint.
Definition: hal_usb.c:492
void usb_lld_stop(USBDriver *usbp)
Deactivates the USB peripheral.
Definition: hal_usb_lld.c:135
msg_t usbReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n)
Performs a receive transaction on an OUT endpoint.
Definition: hal_usb.c:536
Type of an USB endpoint configuration structure.
Definition: hal_usb_lld.h:134
void usbObjectInit(USBDriver *usbp)
Initializes the standard part of a USBDriver structure.
Definition: hal_usb.c:282
#define usbSetupTransfer(usbp, buf, n, endcb)
Request transfer setup.
Definition: hal_usb.h:476
usbstate_t saved_state
State of the driver when a suspend happened.
Definition: hal_usb_lld.h:287
USBInEndpointState * in_state
USBEndpointState associated to the IN endpoint.
Definition: hal_usb_lld.h:178
thread_reference_t thread
Waiting thread.
Definition: hal_usb_lld.h:125
void usb_lld_set_address(USBDriver *usbp)
Sets the USB address.
Definition: hal_usb_lld.c:172
usbep0state_t ep0state
Endpoint 0 state.
Definition: hal_usb_lld.h:255
#define usbGetReceiveTransactionSizeX(usbp, ep)
Returns the exact size of a receive transaction.
Definition: hal_usb.h:461
#define USB_MAX_ENDPOINTS
Maximum endpoint address.
Definition: hal_usb_lld.h:37