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