blob: aa80edeed8f13c0351dc9d84c7fe536dca6889d2 [file] [log] [blame]
Kévin Redon69b92d92019-01-24 16:39:20 +01001/**
2 * \file
3 *
4 * \brief SAM USB device HAL
5 *
6 * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
7 *
8 * \asf_license_start
9 *
10 * \page License
11 *
12 * Subject to your compliance with these terms, you may use Microchip
13 * software and any derivatives exclusively with Microchip products.
14 * It is your responsibility to comply with third party license terms applicable
15 * to your use of third party software (including open source software) that
16 * may accompany Microchip software.
17 *
18 * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
19 * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
20 * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
21 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
22 * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
23 * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
24 * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
25 * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
26 * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
27 * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
28 * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
29 *
30 * \asf_license_stop
31 *
32 */
33
34#include "hal_usb_device.h"
35#include "hal_atomic.h"
36
37#include <string.h>
38
39#ifdef __cplusplus
40extern "C" {
41#endif
42
43/** USB device HAL driver version. */
44#define USB_D_VERSION 0x00000001u
45
46/**
47 * Endpoint callbacks for data transfer.
48 */
49struct usb_d_ep_callbacks {
50 /** Callback that is invoked when setup packet is received. */
51 usb_d_ep_cb_setup_t req;
52 /** Callback invoked when buffer is done, but last packet is full size
53 * packet without ZLP. Return \c true if new transfer has been submitted.
54 */
55 usb_d_ep_cb_more_t more;
56 /** Callback invoked when transfer is finished/halted/aborted or error
57 * occurs.
58 */
59 usb_d_ep_cb_xfer_t xfer;
60};
61
62/**
63 * Endpoint transfer descriptor header.
64 */
65struct usb_ep_xfer_hdr {
66 /** Transfer type, reuse \ref usb_ep_type. */
67 uint8_t type;
68 /** Endpoint address. */
69 uint8_t ep;
70 /** Endpoint state. */
71 uint8_t state;
72 /** Last status code. */
73 uint8_t status;
74};
75
76/**
77 * Transfer descriptor.
78 */
79struct usb_ep_xfer {
80 /** General transfer descriptor. */
81 struct usb_ep_xfer_hdr hdr;
82 /** Pointer to data buffer. */
83 uint8_t *buf;
84 /** Transfer size. */
85 uint32_t size;
86 /** Control request packet. */
87 uint8_t req[8];
88};
89
90/**
91 * USB device endpoint descriptor.
92 */
93struct usb_d_ep {
94 /** On-going transfer on the endpoint. */
95 struct usb_ep_xfer xfer;
96 /** Endpoint callbacks. */
97 struct usb_d_ep_callbacks callbacks;
98};
99
100/**
101 * USB device HAL driver descriptor.
102 */
103struct usb_d_descriptor {
104 /** USB device endpoints. */
105 struct usb_d_ep ep[CONF_USB_D_NUM_EP_SP];
106};
107
108/** The USB HAL driver descriptor instance. */
109static struct usb_d_descriptor usb_d_inst;
110
111/** \brief Find the endpoint.
112 * \param[in] ep Endpoint address.
113 * \return Index of endpoint descriptor.
114 * \retval >=0 The index.
115 * \retval <0 Not found (endpoint is not initialized).
116 */
117static int8_t _usb_d_find_ep(const uint8_t ep)
118{
119 int8_t i;
120 for (i = 0; i < CONF_USB_D_NUM_EP_SP; i++) {
121 if (usb_d_inst.ep[i].xfer.hdr.ep == ep) {
122 return i;
123 }
124 if (usb_d_inst.ep[i].xfer.hdr.type == USB_EP_XTYPE_CTRL
125 && (ep & USB_EP_N_MASK) == usb_d_inst.ep[i].xfer.hdr.ep) {
126 return i;
127 }
128 }
129 return -1;
130}
131
132/**
133 * \brief Start transactions
134 * \param[in] ep Endpoint address.
135 * \param[in] dir Endpoint transfer direction.
136 * \param[in] buf Pointer to transfer buffer.
137 * \param[in] size Transfer size.
138 * \param[in] zlp Auto append ZLP for IN, or wait ZLP for OUT.
139 */
140static inline int32_t _usb_d_trans(const uint8_t ep, const bool dir, const uint8_t *buf, const uint32_t size,
141 const uint8_t zlp)
142{
143 struct usb_d_transfer trans
144 = {(uint8_t *)buf, size, dir ? (uint8_t)(ep | USB_EP_DIR) : (uint8_t)(ep & USB_EP_N_MASK), zlp};
145
146 return _usb_d_dev_ep_trans(&trans);
147}
148
149/**
150 * \brief Dummy callback that returns false
151 * \param[in] unused0 Unused parameter.
152 * \param[in] unused1 Unused parameter.
153 * \param[in] unused2 Unused parameter.
154 * \return Always \c false.
155 */
156static bool usb_d_dummy_cb_false(uint32_t unused0, uint32_t unused1, uint32_t unused2)
157{
158 (void)unused0;
159 (void)unused1;
160 (void)unused2;
161 return false;
162}
163
164/**
165 * \brief Callback invoked when SETUP packet is ready
166 * \param[in] ep Endpoint number with transfer direction on bit 8.
167 */
168static void usb_d_cb_trans_setup(const uint8_t ep)
169{
170 int8_t ep_index = _usb_d_find_ep(ep);
171 struct usb_d_ep *ept = &usb_d_inst.ep[ep_index];
172 uint8_t * req = ept->xfer.req;
173
174 uint8_t n = _usb_d_dev_ep_read_req(ep, req);
175 if (n != 8) {
176 _usb_d_dev_ep_stall(ep, USB_EP_STALL_SET);
177 _usb_d_dev_ep_stall(ep | USB_EP_DIR, USB_EP_STALL_SET);
178 return;
179 }
180
181 _usb_d_dev_ep_stall(ep, USB_EP_STALL_CLR);
182 _usb_d_dev_ep_stall(ep | USB_EP_DIR, USB_EP_STALL_CLR);
183 ept->xfer.hdr.state = USB_EP_S_IDLE;
184 if (!ept->callbacks.req(ep, req)) {
185 ept->xfer.hdr.state = USB_EP_S_HALTED;
186 _usb_d_dev_ep_stall(ep, USB_EP_STALL_SET);
187 _usb_d_dev_ep_stall(ep | USB_EP_DIR, USB_EP_STALL_SET);
188 }
189}
190
191/**
192 * \brief Callback invoked when request more data
193 * \param[in] ep Endpoint number with transfer direction on bit 8.
194 * \param[in] transfered Number of bytes transfered.
195 */
196static bool usb_d_cb_trans_more(const uint8_t ep, const uint32_t transfered)
197{
198 int8_t ep_index = _usb_d_find_ep(ep);
199 struct usb_d_ep *ept = &usb_d_inst.ep[ep_index];
200 if (ept->xfer.hdr.state == USB_EP_S_X_DATA) {
201 return ept->callbacks.more(ep, transfered);
202 }
203 return false;
204}
205
206/**
207 * \brief Handles the case that control endpoint transactions are done
208 * \param[in,out] ept Pointer to endpoint information.
209 */
210static inline void usb_d_ctrl_trans_done(struct usb_d_ep *ept)
211{
212 uint8_t state = ept->xfer.hdr.state;
213 bool req_dir = USB_GET_bmRequestType(ept->xfer.req) & USB_REQ_TYPE_IN;
214
215 if (state == USB_EP_S_X_DATA) {
216 /* Data stage -> Status stage */
217 bool err = ept->callbacks.xfer(ept->xfer.hdr.ep, USB_XFER_DATA, ept->xfer.req);
218 if (err) {
219 ept->xfer.hdr.state = USB_EP_S_HALTED;
220 ept->xfer.hdr.status = USB_XFER_HALT;
221 _usb_d_dev_ep_stall(req_dir ? ept->xfer.hdr.ep : (ept->xfer.hdr.ep | USB_EP_DIR), USB_EP_STALL_SET);
222 } else {
223 ept->xfer.hdr.state = USB_EP_S_X_STATUS;
224 _usb_d_trans(ept->xfer.hdr.ep, !req_dir, NULL, 0, 1);
225 }
226 } else {
227 /* Status stage done */
228 ept->callbacks.xfer(ept->xfer.hdr.ep, USB_XFER_DONE, ept->xfer.req);
229 ept->xfer.hdr.state = USB_EP_S_X_SETUP;
230 }
231}
232
233/**
234 * Callback when USB transactions are finished.
235 */
236static void _usb_d_cb_trans_done(const uint8_t ep, const int32_t code, const uint32_t transferred)
237{
238 int8_t ep_index = _usb_d_find_ep(ep);
239 struct usb_d_ep *ept = &usb_d_inst.ep[ep_index];
240
241 if (code == USB_TRANS_DONE) {
242 ept->xfer.hdr.status = USB_XFER_DONE;
243 if (ept->xfer.hdr.type == USB_EP_XTYPE_CTRL) {
244 usb_d_ctrl_trans_done(ept);
245 return;
246 }
247 ept->xfer.hdr.state = USB_EP_S_IDLE;
248 } else if (code == USB_TRANS_STALL) {
249 ept->xfer.hdr.status = USB_XFER_HALT;
250 if (ept->xfer.hdr.type == USB_EP_XTYPE_CTRL) {
251 ept->xfer.hdr.state = USB_EP_S_X_SETUP;
252 _usb_d_dev_ep_stall(ep, USB_EP_STALL_CLR);
253 } else {
254 ept->xfer.hdr.state = USB_EP_S_HALTED;
255 }
256 } else if (code == USB_TRANS_ABORT) {
257 ept->xfer.hdr.status = USB_XFER_ABORT;
258 if (ept->xfer.hdr.type == USB_EP_XTYPE_CTRL) {
259 ept->xfer.hdr.state = USB_EP_S_X_SETUP;
260 return;
261 }
262 ept->xfer.hdr.state = USB_EP_S_IDLE;
263 } else if (code == USB_TRANS_RESET) {
264 ept->xfer.hdr.state = USB_EP_S_DISABLED;
265 ept->xfer.hdr.status = USB_XFER_RESET;
266 } else {
267 ept->xfer.hdr.state = USB_EP_S_ERROR;
268 ept->xfer.hdr.status = USB_XFER_ERROR;
269 }
270
271 ept->callbacks.xfer(ep, (enum usb_xfer_code)ept->xfer.hdr.status, (void *)transferred);
272}
273
274int32_t usb_d_init(void)
275{
276 int32_t rc = _usb_d_dev_init();
277 uint8_t i;
278 if (rc < 0) {
279 return rc;
280 }
281 memset(usb_d_inst.ep, 0x00, sizeof(struct usb_d_ep) * CONF_USB_D_NUM_EP_SP);
282 for (i = 0; i < CONF_USB_D_NUM_EP_SP; i++) {
283 usb_d_inst.ep[i].xfer.hdr.ep = 0xFF;
284 usb_d_inst.ep[i].callbacks.req = (usb_d_ep_cb_setup_t)usb_d_dummy_cb_false;
285 usb_d_inst.ep[i].callbacks.more = (usb_d_ep_cb_more_t)usb_d_dummy_cb_false;
286 usb_d_inst.ep[i].callbacks.xfer = (usb_d_ep_cb_xfer_t)usb_d_dummy_cb_false;
287 }
288 /* Handles device driver endpoint callbacks to build transfer. */
289 _usb_d_dev_register_ep_callback(USB_D_DEV_EP_CB_SETUP, (FUNC_PTR)usb_d_cb_trans_setup);
290 _usb_d_dev_register_ep_callback(USB_D_DEV_EP_CB_MORE, (FUNC_PTR)usb_d_cb_trans_more);
291 _usb_d_dev_register_ep_callback(USB_D_DEV_EP_CB_DONE, (FUNC_PTR)_usb_d_cb_trans_done);
292 return ERR_NONE;
293}
294
295void usb_d_deinit(void)
296{
297 _usb_d_dev_deinit();
298}
299
300void usb_d_register_callback(const enum usb_d_cb_type type, const FUNC_PTR func)
301{
302 /* Directly uses device driver callback. */
303 _usb_d_dev_register_callback(type, func);
304}
305
306int32_t usb_d_enable(void)
307{
308 return _usb_d_dev_enable();
309}
310
311void usb_d_disable(void)
312{
313 _usb_d_dev_disable();
314}
315
316void usb_d_attach(void)
317{
318 _usb_d_dev_attach();
319}
320
321void usb_d_detach(void)
322{
323 _usb_d_dev_detach();
324}
325
326enum usb_speed usb_d_get_speed(void)
327{
328 return _usb_d_dev_get_speed();
329}
330
331uint16_t usb_d_get_frame_num(void)
332{
333 return _usb_d_dev_get_frame_n();
334}
335
336uint8_t usb_d_get_uframe_num(void)
337{
338 return _usb_d_dev_get_uframe_n();
339}
340
341void usb_d_set_address(const uint8_t addr)
342{
343 _usb_d_dev_set_address(addr);
344}
345
346void usb_d_send_remotewakeup(void)
347{
348 _usb_d_dev_send_remotewakeup();
349}
350
351int32_t usb_d_ep0_init(const uint8_t max_pkt_size)
352{
353 return usb_d_ep_init(0, USB_EP_XTYPE_CTRL, max_pkt_size);
354}
355
356int32_t usb_d_ep_init(const uint8_t ep, const uint8_t attr, const uint16_t max_pkt_size)
357{
358 int32_t rc;
359 int8_t ep_index = _usb_d_find_ep(ep);
360 struct usb_d_ep *ept = &usb_d_inst.ep[ep_index];
361 if (ep_index >= 0) {
362 return -USB_ERR_REDO;
363 } else {
364 ep_index = _usb_d_find_ep(0xFF);
365 if (ep_index < 0) {
366 return -USB_ERR_ALLOC_FAIL;
367 }
368 ept = &usb_d_inst.ep[ep_index];
369 }
370 rc = _usb_d_dev_ep_init(ep, attr, max_pkt_size);
371 if (rc < 0) {
372 return rc;
373 }
374 ept->xfer.hdr.ep = ep;
375 ept->xfer.hdr.type = attr & USB_EP_XTYPE_MASK;
376 return ERR_NONE;
377}
378
379void usb_d_ep_deinit(const uint8_t ep)
380{
381 int8_t ep_index = _usb_d_find_ep(ep);
382 struct usb_d_ep *ept = &usb_d_inst.ep[ep_index];
383 if (ep_index < 0) {
384 return;
385 }
386 _usb_d_dev_ep_deinit(ep);
387 ept->xfer.hdr.ep = 0xFF;
388}
389
390int32_t usb_d_ep_enable(const uint8_t ep)
391{
392 int8_t ep_index = _usb_d_find_ep(ep);
393 struct usb_d_ep *ept = &usb_d_inst.ep[ep_index];
394 int32_t rc;
395 if (ep_index < 0) {
396 return -USB_ERR_PARAM;
397 }
398 ept->xfer.hdr.state = (ept->xfer.hdr.type == USB_EP_XTYPE_CTRL) ? USB_EP_S_X_SETUP : USB_EP_S_IDLE;
399 rc = _usb_d_dev_ep_enable(ep);
400 if (rc < 0) {
401 ept->xfer.hdr.state = USB_EP_S_DISABLED;
402 }
403 return rc;
404}
405
406void usb_d_ep_disable(const uint8_t ep)
407{
408 int8_t ep_index = _usb_d_find_ep(ep);
409 struct usb_d_ep *ept = &usb_d_inst.ep[ep_index];
410 if (ep_index < 0) {
411 return;
412 }
413 _usb_d_dev_ep_disable(ep);
414 ept->xfer.hdr.state = USB_EP_S_DISABLED;
415}
416
417uint8_t *usb_d_ep_get_req(const uint8_t ep)
418{
419 int8_t ep_index = _usb_d_find_ep(ep);
420 if (ep_index < 0) {
421 return NULL;
422 }
423 return usb_d_inst.ep[ep_index].xfer.req;
424}
425
426int32_t usb_d_ep_transfer(const struct usb_d_transfer *xfer)
427{
428 int8_t ep_index = _usb_d_find_ep(xfer->ep);
429 struct usb_d_ep * ept = &usb_d_inst.ep[ep_index];
430 bool dir = USB_EP_GET_DIR(xfer->ep), zlp = xfer->zlp;
431 uint32_t len = xfer->size;
432 int32_t rc;
433 volatile uint8_t state;
434 volatile hal_atomic_t flags;
435
436 if (ep_index < 0) {
437 return -USB_ERR_PARAM;
438 }
439
440 atomic_enter_critical(&flags);
441 state = ept->xfer.hdr.state;
442 if (state == USB_EP_S_IDLE) {
443 ept->xfer.hdr.state = USB_EP_S_X_DATA;
444 atomic_leave_critical(&flags);
445 } else {
446 atomic_leave_critical(&flags);
447 switch (state) {
448 case USB_EP_S_HALTED:
449 return USB_HALTED;
450 case USB_EP_S_ERROR:
451 return -USB_ERROR;
452 case USB_EP_S_DISABLED:
453 return -USB_ERR_FUNC;
454 default: /* USB_EP_S_X_xxxx */
455 return USB_BUSY;
456 }
457 }
458
459 if (ept->xfer.hdr.type == USB_EP_XTYPE_CTRL) {
460 uint16_t req_len = USB_GET_wLength(ept->xfer.req);
461 /* SETUP without data: ZLP IN as status. */
462 if (req_len == 0) {
463 dir = true;
464 len = 0;
465 zlp = true;
466 ept->xfer.hdr.state = USB_EP_S_X_STATUS;
467 } else {
468 dir = (USB_GET_bmRequestType(ept->xfer.req) & USB_REQ_TYPE_IN);
469 /* Data length not exceed requested. */
470 if (len > req_len) {
471 len = req_len;
472 }
473 if (dir) {
474 /* Setup -> In */
475 zlp = (req_len > len);
476 } else {
477 zlp = false;
478 }
479 }
480 }
481
482 rc = _usb_d_trans(xfer->ep, dir, xfer->buf, len, zlp);
483 return rc;
484}
485
486void usb_d_ep_abort(const uint8_t ep)
487{
488 int8_t ep_index = _usb_d_find_ep(ep);
489 struct usb_d_ep *ept = &usb_d_inst.ep[ep_index];
490 if (ep_index < 0) {
491 return;
492 }
493 _usb_d_dev_ep_abort(ep);
494 ept->xfer.hdr.state = USB_EP_S_IDLE;
495 ept->xfer.hdr.status = USB_XFER_ABORT;
496}
497
498int32_t usb_d_ep_get_status(const uint8_t ep, struct usb_d_ep_status *stat)
499{
500 int8_t ep_index = _usb_d_find_ep(ep);
501 struct usb_d_ep * ept = &usb_d_inst.ep[ep_index];
502 struct usb_d_trans_status tmp;
503 uint8_t state = ept->xfer.hdr.state;
504 if (ep_index < 0) {
505 return -USB_ERR_PARAM;
506 }
507 if (stat) {
508 /* Check transaction status if transferring data. */
509 _usb_d_dev_ep_get_status(ep, &tmp);
510 stat->ep = ep;
511 stat->state = state;
512 stat->code = ept->xfer.hdr.status;
513 stat->count = tmp.count;
514 stat->size = tmp.size;
515 }
516 switch (state) {
517 case USB_EP_S_IDLE:
518 return USB_OK;
519 case USB_EP_S_HALTED:
520 return USB_HALTED;
521 case USB_EP_S_ERROR:
522 return -USB_ERROR;
523 case USB_EP_S_DISABLED:
524 return -USB_ERR_FUNC;
525 default:
526 /* Busy */
527 return USB_BUSY;
528 }
529}
530
531static inline int32_t _usb_d_ep_halt_clr(const uint8_t ep)
532{
533 int8_t ep_index = _usb_d_find_ep(ep);
534 struct usb_d_ep *ept = &usb_d_inst.ep[ep_index];
535 int32_t rc;
536 if (ep_index < 0) {
537 return -USB_ERR_PARAM;
538 }
539 if (_usb_d_dev_ep_stall(ep, USB_EP_STALL_GET)) {
540 rc = _usb_d_dev_ep_stall(ep, USB_EP_STALL_CLR);
541 if (rc < 0) {
542 return rc;
543 }
544 ept->xfer.hdr.state = USB_EP_S_IDLE;
545 ept->xfer.hdr.status = USB_XFER_UNHALT;
546 ept->callbacks.xfer(ep, USB_XFER_UNHALT, NULL);
547 }
548 return ERR_NONE;
549}
550
551int32_t usb_d_ep_halt(const uint8_t ep, const enum usb_ep_halt_ctrl ctrl)
552{
553 if (ctrl == USB_EP_HALT_CLR) {
554 return _usb_d_ep_halt_clr(ep);
555 } else if (ctrl == USB_EP_HALT_SET) {
556 return _usb_d_dev_ep_stall(ep, USB_EP_STALL_SET);
557 } else {
558 return _usb_d_dev_ep_stall(ep, USB_EP_STALL_GET);
559 }
560}
561
562void usb_d_ep_register_callback(const uint8_t ep, const enum usb_d_ep_cb_type type, const FUNC_PTR func)
563{
564 int8_t ep_index = _usb_d_find_ep(ep);
565 struct usb_d_ep *ept = &usb_d_inst.ep[ep_index];
566 FUNC_PTR f = func ? (FUNC_PTR)func : (FUNC_PTR)usb_d_dummy_cb_false;
567 if (ep_index < 0) {
568 return;
569 }
570 switch (type) {
571 case USB_D_EP_CB_SETUP:
572 ept->callbacks.req = (usb_d_ep_cb_setup_t)f;
573 break;
574 case USB_D_EP_CB_MORE:
575 ept->callbacks.more = (usb_d_ep_cb_more_t)f;
576 break;
577 case USB_D_EP_CB_XFER:
578 ept->callbacks.xfer = (usb_d_ep_cb_xfer_t)f;
579 break;
580 default:
581 break;
582 }
583}
584
585uint32_t usb_d_get_version(void)
586{
587 return USB_D_VERSION;
588}
589
590#ifdef __cplusplus
591}
592#endif