1 /*
2 * Copyright (c) 2018 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief USB native_posix device driver
10 */
11
12 #include <string.h>
13 #include <stdio.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/sys/byteorder.h>
16 #include <zephyr/drivers/usb/usb_dc.h>
17 #include <zephyr/usb/usb_device.h>
18 #include <zephyr/net/net_ip.h>
19
20 #include "usb_dc_native_posix_adapt.h"
21
22 #define LOG_LEVEL CONFIG_USB_DRIVER_LOG_LEVEL
23 #include <zephyr/logging/log.h>
24 LOG_MODULE_REGISTER(native_posix);
25
26 #define USBIP_IN_EP_NUM 8
27 #define USBIP_OUT_EP_NUM 8
28
29 #ifdef CONFIG_USB_NATIVE_POSIX_HS
30 #define USBIP_MAX_PACKET_SIZE 512
31 #else /* CONFIG_USB_NATIVE_POSIX_HS */
32 #define USBIP_MAX_PACKET_SIZE 64
33 #endif /* !CONFIG_USB_NATIVE_POSIX_HS */
34
35 K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE);
36 static struct k_thread thread;
37
thread_main(void * a,void * b,void * c)38 static void thread_main(void *a, void *b, void *c)
39 {
40 LOG_DBG("");
41
42 usbip_start();
43 }
44
45 /*
46 * USBIP private structures and logic initially copied from
47 * Designware USB driver
48 */
49
50 /*
51 * USB endpoint private structure.
52 */
53 struct usb_ep_ctrl_prv {
54 uint8_t ep_ena;
55 uint16_t mps;
56 usb_dc_ep_callback cb;
57 uint32_t data_len;
58 uint8_t buf[64];
59 uint8_t buf_len;
60 };
61
62 /*
63 * USB controller private structure.
64 */
65 static struct usbip_ctrl_prv {
66 usb_dc_status_callback status_cb;
67 struct usb_ep_ctrl_prv in_ep_ctrl[USBIP_IN_EP_NUM];
68 struct usb_ep_ctrl_prv out_ep_ctrl[USBIP_OUT_EP_NUM];
69 uint8_t attached;
70 } usbip_ctrl;
71
usbip_ep_is_valid(uint8_t ep)72 static uint8_t usbip_ep_is_valid(uint8_t ep)
73 {
74 uint8_t ep_idx = USB_EP_GET_IDX(ep);
75
76 /* Check if ep is valid */
77 if ((USB_EP_DIR_IS_OUT(ep)) &&
78 ep_idx < USBIP_OUT_EP_NUM) {
79 return 1;
80 } else if ((USB_EP_DIR_IS_IN(ep)) &&
81 ep_idx < USBIP_IN_EP_NUM) {
82 return 1;
83 }
84
85 return 0;
86 }
87
usbip_ep_is_enabled(uint8_t ep)88 static uint8_t usbip_ep_is_enabled(uint8_t ep)
89 {
90 uint8_t ep_idx = USB_EP_GET_IDX(ep);
91
92 LOG_DBG("ep %x", ep);
93
94 /* Check if ep enabled */
95 if ((USB_EP_DIR_IS_OUT(ep)) &&
96 usbip_ctrl.out_ep_ctrl[ep_idx].ep_ena) {
97 return 1;
98 } else if ((USB_EP_DIR_IS_IN(ep)) &&
99 usbip_ctrl.in_ep_ctrl[ep_idx].ep_ena) {
100 return 1;
101 }
102
103 return 0;
104 }
105
usb_dc_attach(void)106 int usb_dc_attach(void)
107 {
108 LOG_DBG("");
109
110 if (usbip_ctrl.attached) {
111 LOG_WRN("Already attached");
112 return 0;
113 }
114
115 k_thread_create(&thread, thread_stack,
116 CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE,
117 thread_main, NULL, NULL, NULL,
118 K_PRIO_COOP(2), 0, K_NO_WAIT);
119
120 usbip_ctrl.attached = 1U;
121
122 return 0;
123 }
124
usb_dc_detach(void)125 int usb_dc_detach(void)
126 {
127 LOG_DBG("");
128
129 if (!usbip_ctrl.attached) {
130 return 0;
131 }
132
133 usbip_ctrl.attached = 0U;
134
135 return 0;
136 }
137
usb_dc_reset(void)138 int usb_dc_reset(void)
139 {
140 LOG_DBG("");
141
142 /* Clear private data */
143 memset(&usbip_ctrl, 0, sizeof(usbip_ctrl));
144
145 return 0;
146 }
147
usb_dc_set_address(const uint8_t addr)148 int usb_dc_set_address(const uint8_t addr)
149 {
150 LOG_DBG("");
151
152 return 0;
153 }
154
usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg)155 int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg)
156 {
157 uint8_t ep_idx = USB_EP_GET_IDX(cfg->ep_addr);
158
159 LOG_DBG("ep %x, mps %d, type %d", cfg->ep_addr, cfg->ep_mps,
160 cfg->ep_type);
161
162 if ((cfg->ep_type == USB_DC_EP_CONTROL) && ep_idx) {
163 LOG_ERR("invalid endpoint configuration");
164 return -1;
165 }
166
167 if (cfg->ep_mps > USBIP_MAX_PACKET_SIZE) {
168 LOG_WRN("unsupported packet size");
169 return -1;
170 }
171
172 if ((USB_EP_DIR_IS_OUT(cfg->ep_addr)) &&
173 (ep_idx >= USBIP_OUT_EP_NUM)) {
174 LOG_WRN("OUT endpoint address out of range");
175 return -1;
176 }
177
178 if ((USB_EP_DIR_IS_IN(cfg->ep_addr)) &&
179 (ep_idx >= USBIP_IN_EP_NUM)) {
180 LOG_WRN("IN endpoint address out of range");
181 return -1;
182 }
183
184 return 0;
185 }
186
usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const cfg)187 int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const cfg)
188 {
189 uint16_t ep_mps = cfg->ep_mps;
190 uint8_t ep = cfg->ep_addr;
191 uint8_t ep_idx = USB_EP_GET_IDX(ep);
192
193 if (usb_dc_ep_check_cap(cfg)) {
194 return -EINVAL;
195 }
196
197 if (!usbip_ctrl.attached || !usbip_ep_is_valid(ep)) {
198 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
199 return -EINVAL;
200 }
201
202 if (USB_EP_DIR_IS_OUT(ep)) {
203 usbip_ctrl.out_ep_ctrl[ep_idx].mps = ep_mps;
204 } else {
205 usbip_ctrl.in_ep_ctrl[ep_idx].mps = ep_mps;
206 }
207
208 return 0;
209 }
210
usb_dc_ep_set_stall(const uint8_t ep)211 int usb_dc_ep_set_stall(const uint8_t ep)
212 {
213 LOG_DBG("ep %x", ep);
214
215 if (!usbip_ctrl.attached || !usbip_ep_is_valid(ep)) {
216 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
217 return -EINVAL;
218 }
219
220 /* Use standard reply for now */
221 usb_dc_ep_write(0x80, NULL, 0, NULL);
222
223 return 0;
224 }
225
usb_dc_ep_clear_stall(const uint8_t ep)226 int usb_dc_ep_clear_stall(const uint8_t ep)
227 {
228 uint8_t ep_idx = USB_EP_GET_IDX(ep);
229
230 LOG_DBG("ep %x", ep);
231
232 if (!usbip_ctrl.attached || !usbip_ep_is_valid(ep)) {
233 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
234 return -EINVAL;
235 }
236
237 if (!ep_idx) {
238 /* Not possible to clear stall for EP0 */
239 return -EINVAL;
240 }
241
242 return 0;
243 }
244
usb_dc_ep_halt(const uint8_t ep)245 int usb_dc_ep_halt(const uint8_t ep)
246 {
247 uint8_t ep_idx = USB_EP_GET_IDX(ep);
248
249 LOG_DBG("ep %x", ep);
250
251 if (!usbip_ctrl.attached || !usbip_ep_is_valid(ep)) {
252 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
253 return -EINVAL;
254 }
255
256 if (!ep_idx) {
257 /* Cannot disable EP0, just set stall */
258 usb_dc_ep_set_stall(ep);
259 }
260
261 return 0;
262 }
263
usb_dc_ep_is_stalled(const uint8_t ep,uint8_t * const stalled)264 int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled)
265 {
266 LOG_DBG("ep %x", ep);
267
268 if (!usbip_ctrl.attached || !usbip_ep_is_valid(ep)) {
269 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
270 return -EINVAL;
271 }
272
273 if (!stalled) {
274 return -EINVAL;
275 }
276
277 return 0;
278 }
279
usb_dc_ep_enable(const uint8_t ep)280 int usb_dc_ep_enable(const uint8_t ep)
281 {
282 uint8_t ep_idx = USB_EP_GET_IDX(ep);
283
284 LOG_DBG("ep %x", ep);
285
286 if (!usbip_ctrl.attached || !usbip_ep_is_valid(ep)) {
287 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
288 return -EINVAL;
289 }
290
291 /* Enable Ep */
292 if (USB_EP_DIR_IS_OUT(ep)) {
293 usbip_ctrl.out_ep_ctrl[ep_idx].ep_ena = 1U;
294 } else {
295 usbip_ctrl.in_ep_ctrl[ep_idx].ep_ena = 1U;
296 }
297
298 return 0;
299 }
300
usb_dc_ep_disable(const uint8_t ep)301 int usb_dc_ep_disable(const uint8_t ep)
302 {
303 LOG_DBG("ep %x", ep);
304
305 if (!usbip_ep_is_valid(ep)) {
306 LOG_ERR("Invalid endpoint: EP 0x%x", ep);
307 return -EINVAL;
308 }
309
310 return 0;
311 }
312
usb_dc_ep_flush(const uint8_t ep)313 int usb_dc_ep_flush(const uint8_t ep)
314 {
315 LOG_DBG("ep %x", ep);
316
317 if (!usbip_ctrl.attached || !usbip_ep_is_valid(ep)) {
318 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
319 return -EINVAL;
320 }
321
322 if (USB_EP_DIR_IS_OUT(ep)) {
323 /* RX FIFO is global and cannot be flushed per EP */
324 return -EINVAL;
325 }
326
327 return 0;
328 }
329
usb_dc_ep_write(const uint8_t ep,const uint8_t * const data,const uint32_t data_len,uint32_t * const ret_bytes)330 int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data,
331 const uint32_t data_len, uint32_t * const ret_bytes)
332 {
333 LOG_DBG("ep %x len %u", ep, data_len);
334
335 if (!usbip_ctrl.attached || !usbip_ep_is_valid(ep)) {
336 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
337 return -EINVAL;
338 }
339
340 /* Check if IN ep */
341 if (USB_EP_GET_DIR(ep) != USB_EP_DIR_IN) {
342 return -EINVAL;
343 }
344
345 /* Check if ep enabled */
346 if (!usbip_ep_is_enabled(ep)) {
347 LOG_WRN("ep %x disabled", ep);
348 return -EINVAL;
349 }
350
351 if (USB_EP_GET_IDX(ep) == 0) {
352 if (!usbip_send_common(ep, data_len)) {
353 return -EIO;
354 }
355
356 if (usbip_send(ep, data, data_len) != data_len) {
357 return -EIO;
358 }
359 } else {
360 uint8_t ep_idx = USB_EP_GET_IDX(ep);
361 struct usb_ep_ctrl_prv *ctrl = &usbip_ctrl.in_ep_ctrl[ep_idx];
362
363 if (data_len > ARRAY_SIZE(ctrl->buf)) {
364 return -EINVAL;
365 }
366
367 memcpy(ctrl->buf, data, data_len);
368 ctrl->buf_len = data_len;
369 }
370
371 if (ret_bytes) {
372 *ret_bytes = data_len;
373 }
374
375 return 0;
376 }
377
usb_dc_ep_read_wait(uint8_t ep,uint8_t * data,uint32_t max_data_len,uint32_t * read_bytes)378 int usb_dc_ep_read_wait(uint8_t ep, uint8_t *data, uint32_t max_data_len,
379 uint32_t *read_bytes)
380 {
381 uint8_t ep_idx = USB_EP_GET_IDX(ep);
382 uint32_t to_copy;
383
384 if (!usbip_ctrl.attached || !usbip_ep_is_valid(ep)) {
385 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
386 return -EINVAL;
387 }
388
389 /* Check if OUT ep */
390 if (USB_EP_GET_DIR(ep) != USB_EP_DIR_OUT) {
391 LOG_ERR("Wrong endpoint direction");
392 return -EINVAL;
393 }
394
395 /* Allow to read 0 bytes */
396 if (!data && max_data_len) {
397 LOG_ERR("Wrong arguments");
398 return -EINVAL;
399 }
400
401 /* Check if ep enabled */
402 if (!usbip_ep_is_enabled(ep)) {
403 LOG_ERR("Not enabled endpoint");
404 return -EINVAL;
405 }
406
407 if (data == NULL && max_data_len == 0 && read_bytes != NULL) {
408 /* Return length of the available data in endpoint buffer */
409 *read_bytes = usbip_ctrl.out_ep_ctrl[ep_idx].data_len;
410 return 0;
411 }
412
413 to_copy = MIN(usbip_ctrl.out_ep_ctrl[ep_idx].data_len, max_data_len);
414 LOG_DBG("ep 0x%02x, to_copy %u", ep, to_copy);
415 memcpy(data, usbip_ctrl.out_ep_ctrl[ep_idx].buf, to_copy);
416
417 if (read_bytes) {
418 *read_bytes = to_copy;
419 }
420
421 return 0;
422 }
423
usb_dc_ep_read_continue(uint8_t ep)424 int usb_dc_ep_read_continue(uint8_t ep)
425 {
426 uint8_t ep_idx = USB_EP_GET_IDX(ep);
427
428 if (!usbip_ctrl.attached || !usbip_ep_is_valid(ep)) {
429 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
430 return -EINVAL;
431 }
432
433 /* Check if OUT ep */
434 if (USB_EP_GET_DIR(ep) != USB_EP_DIR_OUT) {
435 LOG_ERR("Wrong endpoint direction");
436 return -EINVAL;
437 }
438
439 if (!usbip_ctrl.out_ep_ctrl[ep_idx].data_len) {
440 /* TODO: continue read */
441 /* usbip_prep_rx(ep_idx, 0); */
442 }
443
444 return 0;
445 }
446
usb_dc_ep_read(const uint8_t ep,uint8_t * const data,const uint32_t max_data_len,uint32_t * const read_bytes)447 int usb_dc_ep_read(const uint8_t ep, uint8_t *const data,
448 const uint32_t max_data_len, uint32_t * const read_bytes)
449 {
450 LOG_DBG("ep %x max_data_len %u", ep, max_data_len);
451
452 if (usb_dc_ep_read_wait(ep, data, max_data_len, read_bytes) != 0) {
453 return -EINVAL;
454 }
455
456 if (!data && !max_data_len) {
457 /* When both buffer and max data to read are zero the above
458 * call would fetch the data len and we simply return.
459 */
460 return 0;
461 }
462
463 if (usb_dc_ep_read_continue(ep) != 0) {
464 return -EINVAL;
465 }
466
467 return 0;
468 }
469
usb_dc_ep_set_callback(const uint8_t ep,const usb_dc_ep_callback cb)470 int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb)
471 {
472 uint8_t ep_idx = USB_EP_GET_IDX(ep);
473
474 LOG_DBG("ep %x callback %p", ep, cb);
475
476 if (!usbip_ctrl.attached || !usbip_ep_is_valid(ep)) {
477 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
478 return -EINVAL;
479 }
480
481 if (USB_EP_DIR_IS_IN(ep)) {
482 usbip_ctrl.in_ep_ctrl[ep_idx].cb = cb;
483 } else {
484 usbip_ctrl.out_ep_ctrl[ep_idx].cb = cb;
485 }
486
487 return 0;
488 }
489
usb_dc_set_status_callback(const usb_dc_status_callback cb)490 void usb_dc_set_status_callback(const usb_dc_status_callback cb)
491 {
492 usbip_ctrl.status_cb = cb;
493 }
494
usb_dc_ep_mps(const uint8_t ep)495 int usb_dc_ep_mps(const uint8_t ep)
496 {
497 uint8_t ep_idx = USB_EP_GET_IDX(ep);
498
499 LOG_DBG("ep %x", ep);
500
501 if (!usbip_ctrl.attached || !usbip_ep_is_valid(ep)) {
502 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
503 return -EINVAL;
504 }
505
506 if (USB_EP_DIR_IS_OUT(ep)) {
507 return usbip_ctrl.out_ep_ctrl[ep_idx].mps;
508 } else {
509 return usbip_ctrl.in_ep_ctrl[ep_idx].mps;
510 }
511 }
512
handle_usb_control(struct usbip_header * hdr)513 int handle_usb_control(struct usbip_header *hdr)
514 {
515 uint8_t ep_idx = USB_EP_GET_IDX(ntohl(hdr->common.ep));
516 struct usb_ep_ctrl_prv *ep_ctrl;
517
518 ep_ctrl = &usbip_ctrl.out_ep_ctrl[ep_idx];
519 if (ep_ctrl->cb == NULL) {
520 LOG_ERR("Control endpoint callback not set");
521 return -EIO;
522 }
523
524 if ((ntohl(hdr->common.direction) == USBIP_DIR_IN) ^
525 USB_REQTYPE_GET_DIR(hdr->u.submit.bmRequestType)) {
526 LOG_ERR("Failed to verify bmRequestType");
527 return -EIO;
528 }
529
530 ep_ctrl->data_len = 8;
531 LOG_DBG("SETUP event ep 0x%02x %u", ep_idx, ep_ctrl->data_len);
532 memcpy(ep_ctrl->buf, &hdr->u.submit.bmRequestType, ep_ctrl->data_len);
533 ep_ctrl->cb(ep_idx, USB_DC_EP_SETUP);
534
535 if (ntohl(hdr->common.direction) == USBIP_DIR_OUT) {
536 uint32_t data_len = ntohl(hdr->u.submit.transfer_buffer_length);
537
538 /* Data OUT stage availably */
539 if (data_len > ARRAY_SIZE(ep_ctrl->buf)) {
540 return -EIO;
541 }
542
543 ep_ctrl->data_len = data_len;
544
545 if (usbip_recv(ep_ctrl->buf, ep_ctrl->data_len) < 0) {
546 return -EIO;
547 }
548
549 LOG_DBG("DATA OUT event ep 0x%02x %u",
550 ep_idx, ep_ctrl->data_len);
551 ep_ctrl->cb(ep_idx, USB_DC_EP_DATA_OUT);
552 }
553
554 return 0;
555 }
556
handle_usb_data(struct usbip_header * hdr)557 int handle_usb_data(struct usbip_header *hdr)
558 {
559 uint8_t ep_idx = ntohl(hdr->common.ep);
560 struct usb_ep_ctrl_prv *ep_ctrl;
561 uint8_t ep;
562
563 if (ntohl(hdr->common.direction) == USBIP_DIR_OUT) {
564 uint32_t data_len;
565
566 if (ep_idx >= USBIP_OUT_EP_NUM) {
567 return -EINVAL;
568 }
569
570 ep_ctrl = &usbip_ctrl.out_ep_ctrl[ep_idx];
571 ep = ep_idx | USB_EP_DIR_OUT;
572 data_len = ntohl(hdr->u.submit.transfer_buffer_length);
573
574 if (data_len > ARRAY_SIZE(ep_ctrl->buf)) {
575 return -EIO;
576 }
577
578 ep_ctrl->data_len = data_len;
579
580 if (usbip_recv(ep_ctrl->buf, ep_ctrl->data_len) < 0) {
581 return -EIO;
582 }
583
584 LOG_DBG("DATA OUT event ep 0x%02x %u", ep, ep_ctrl->data_len);
585 ep_ctrl->cb(ep, USB_DC_EP_DATA_OUT);
586
587 /* Send ACK reply */
588 if (!usbip_send_common(ep, ep_ctrl->data_len)) {
589 return -EIO;
590 }
591 } else {
592 if (ep_idx >= USBIP_IN_EP_NUM) {
593 return -EINVAL;
594 }
595
596 ep_ctrl = &usbip_ctrl.in_ep_ctrl[ep_idx];
597 ep = ep_idx | USB_EP_DIR_IN;
598 LOG_DBG("DATA IN event ep 0x%02x %u", ep, ep_ctrl->buf_len);
599
600 /* Send queued data */
601 if (!usbip_send_common(ep, ep_ctrl->buf_len)) {
602 return -EIO;
603 }
604
605 if (usbip_send(ep, ep_ctrl->buf, ep_ctrl->buf_len) !=
606 ep_ctrl->buf_len) {
607 return -EIO;
608 }
609
610 LOG_HEXDUMP_DBG(ep_ctrl->buf, ep_ctrl->buf_len, ">");
611
612 ep_ctrl->cb(ep, USB_DC_EP_DATA_IN);
613 ep_ctrl->buf_len = 0;
614 }
615
616 return 0;
617 }
618