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