1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 #include <zephyr/device.h>
9 #include <zephyr/sys/byteorder.h>
10 #include <zephyr/devicetree.h>
11 #include <zephyr/init.h>
12 #include <zephyr/sys/iterable_sections.h>
13 
14 #include "usbh_internal.h"
15 #include "usbh_device.h"
16 
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(uhs, CONFIG_USBH_LOG_LEVEL);
19 
20 static K_KERNEL_STACK_DEFINE(usbh_stack, CONFIG_USBH_STACK_SIZE);
21 static struct k_thread usbh_thread_data;
22 
23 K_MSGQ_DEFINE(usbh_msgq, sizeof(struct uhc_event),
24 	      CONFIG_USBH_MAX_UHC_MSG, sizeof(uint32_t));
25 
usbh_event_carrier(const struct device * dev,const struct uhc_event * const event)26 static int usbh_event_carrier(const struct device *dev,
27 			      const struct uhc_event *const event)
28 {
29 	return k_msgq_put(&usbh_msgq, event, K_NO_WAIT);
30 }
31 
discard_ep_request(struct usbh_contex * const ctx,struct uhc_transfer * const xfer)32 static int discard_ep_request(struct usbh_contex *const ctx,
33 			      struct uhc_transfer *const xfer)
34 {
35 	const struct device *dev = ctx->dev;
36 
37 	if (xfer->buf) {
38 		LOG_HEXDUMP_INF(xfer->buf->data, xfer->buf->len, "buf");
39 		uhc_xfer_buf_free(dev, xfer->buf);
40 	}
41 
42 	return uhc_xfer_free(dev, xfer);
43 }
44 
usbh_event_handler(struct usbh_contex * const ctx,struct uhc_event * const event)45 static ALWAYS_INLINE int usbh_event_handler(struct usbh_contex *const ctx,
46 					    struct uhc_event *const event)
47 {
48 	int ret = 0;
49 
50 	if (event->type == UHC_EVT_EP_REQUEST) {
51 		struct usb_device *const udev = event->xfer->udev;
52 		usbh_udev_cb_t cb = event->xfer->cb;
53 
54 		if (event->xfer->cb) {
55 			ret = cb(udev, event->xfer);
56 		} else {
57 			ret = discard_ep_request(ctx, event->xfer);
58 		}
59 		return ret;
60 	}
61 
62 	switch (event->type) {
63 	case UHC_EVT_DEV_CONNECTED_LS:
64 	case UHC_EVT_DEV_CONNECTED_FS:
65 	case UHC_EVT_DEV_CONNECTED_HS:
66 		LOG_DBG("Device connected event");
67 		break;
68 	case UHC_EVT_DEV_REMOVED:
69 		LOG_DBG("Device removed event");
70 		break;
71 	case UHC_EVT_RESETED:
72 		LOG_DBG("Bus reset");
73 		break;
74 	case UHC_EVT_SUSPENDED:
75 		LOG_DBG("Bus suspended");
76 		break;
77 	case UHC_EVT_RESUMED:
78 		LOG_DBG("Bus resumed");
79 		break;
80 	case UHC_EVT_RWUP:
81 		LOG_DBG("RWUP event");
82 		break;
83 	case UHC_EVT_ERROR:
84 		LOG_DBG("Error event %d", event->status);
85 		break;
86 	default:
87 		break;
88 	};
89 
90 	return ret;
91 }
92 
usbh_thread(const struct device * dev)93 static void usbh_thread(const struct device *dev)
94 {
95 	struct uhc_event event;
96 
97 	while (true) {
98 		k_msgq_get(&usbh_msgq, &event, K_FOREVER);
99 
100 		STRUCT_SECTION_FOREACH(usbh_contex, uhs_ctx) {
101 			if (uhs_ctx->dev == event.dev) {
102 				usbh_event_handler(uhs_ctx, &event);
103 			}
104 		}
105 	}
106 }
107 
usbh_init_device_intl(struct usbh_contex * const uhs_ctx)108 int usbh_init_device_intl(struct usbh_contex *const uhs_ctx)
109 {
110 	int ret;
111 
112 	ret = uhc_init(uhs_ctx->dev, usbh_event_carrier);
113 	if (ret != 0) {
114 		LOG_ERR("Failed to init device driver");
115 		return ret;
116 	}
117 
118 	STRUCT_SECTION_FOREACH(usbh_class_data, cdata) {
119 		/*
120 		 * For now, we have not implemented any class drivers,
121 		 * so just keep it as placeholder.
122 		 */
123 		break;
124 	}
125 
126 	return 0;
127 }
128 
uhs_pre_init(void)129 static int uhs_pre_init(void)
130 {
131 	k_thread_create(&usbh_thread_data, usbh_stack,
132 			K_KERNEL_STACK_SIZEOF(usbh_stack),
133 			(k_thread_entry_t)usbh_thread,
134 			NULL, NULL, NULL,
135 			K_PRIO_COOP(9), 0, K_NO_WAIT);
136 
137 	k_thread_name_set(&usbh_thread_data, "usbh");
138 
139 	return 0;
140 }
141 
142 SYS_INIT(uhs_pre_init, POST_KERNEL, CONFIG_USBH_INIT_PRIO);
143