1 /*
2 * Copyright (c) 2022 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/usb/usbh.h>
11 #include <zephyr/usb/usb_ch9.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/net/buf.h>
14
15 #include "usbh_device.h"
16
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(usbh_ch9, CONFIG_USBH_LOG_LEVEL);
19
20 /*
21 * For now we set it to the upper limit defined in Chapter
22 * "9.2.6.4 Standard Device Requests"
23 * This will need to be revised and set depending on the request.
24 */
25 #define SETUP_REQ_TIMEOUT 5000U
26
27 K_SEM_DEFINE(ch9_req_sync, 0, 1);
28
ch9_req_cb(struct usb_device * const udev,struct uhc_transfer * const xfer)29 static int ch9_req_cb(struct usb_device *const udev, struct uhc_transfer *const xfer)
30 {
31 LOG_DBG("Request finished %p, err %d", xfer, xfer->err);
32 k_sem_give(&ch9_req_sync);
33
34 return 0;
35 }
36
usbh_req_setup(struct usb_device * const udev,const uint8_t bmRequestType,const uint8_t bRequest,const uint16_t wValue,const uint16_t wIndex,const uint16_t wLength,struct net_buf * const buf)37 int usbh_req_setup(struct usb_device *const udev,
38 const uint8_t bmRequestType,
39 const uint8_t bRequest,
40 const uint16_t wValue,
41 const uint16_t wIndex,
42 const uint16_t wLength,
43 struct net_buf *const buf)
44 {
45 struct usb_setup_packet req = {
46 .bmRequestType = bmRequestType,
47 .bRequest = bRequest,
48 .wValue = sys_cpu_to_le16(wValue),
49 .wIndex = sys_cpu_to_le16(wIndex),
50 .wLength = sys_cpu_to_le16(wLength),
51 };
52 struct uhc_transfer *xfer;
53 uint8_t ep = usb_reqtype_is_to_device(&req) ? 0x00 : 0x80;
54 int ret;
55
56 xfer = usbh_xfer_alloc(udev, ep, 0, 64, SETUP_REQ_TIMEOUT, (void *)ch9_req_cb);
57 if (!xfer) {
58 return -ENOMEM;
59 }
60
61 memcpy(xfer->setup_pkt, &req, sizeof(req));
62
63 __ASSERT((buf != NULL && wLength) || (buf == NULL && !wLength),
64 "Unresolved conditions for data stage");
65 if (wLength) {
66 ret = usbh_xfer_buf_add(udev, xfer, buf);
67 if (ret) {
68 goto buf_alloc_err;
69 }
70 }
71
72 ret = usbh_xfer_enqueue(udev, xfer);
73 if (ret) {
74 goto buf_alloc_err;
75 }
76
77 k_sem_take(&ch9_req_sync, K_MSEC(SETUP_REQ_TIMEOUT));
78 ret = xfer->err;
79
80 buf_alloc_err:
81 usbh_xfer_free(udev, xfer);
82
83 return ret;
84 }
85
usbh_req_desc(struct usb_device * const udev,const uint8_t type,const uint8_t index,const uint16_t id,const uint16_t len,struct net_buf * const buf)86 int usbh_req_desc(struct usb_device *const udev,
87 const uint8_t type, const uint8_t index,
88 const uint16_t id,
89 const uint16_t len,
90 struct net_buf *const buf)
91 {
92 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_HOST << 7;
93 const uint8_t bRequest = USB_SREQ_GET_DESCRIPTOR;
94 const uint16_t wValue = (type << 8) | index;
95
96 return usbh_req_setup(udev,
97 bmRequestType, bRequest, wValue, id, len,
98 buf);
99 }
100
usbh_req_desc_dev(struct usb_device * const udev,struct usb_device_descriptor * const desc)101 int usbh_req_desc_dev(struct usb_device *const udev,
102 struct usb_device_descriptor *const desc)
103 {
104 const uint8_t type = USB_DESC_DEVICE;
105 const uint16_t wLength = sizeof(struct usb_device_descriptor);
106 struct net_buf *buf;
107 int ret;
108
109 buf = usbh_xfer_buf_alloc(udev, wLength);
110 if (!buf) {
111 return -ENOMEM;
112 }
113
114 ret = usbh_req_desc(udev, type, 0, 0, wLength, buf);
115 if (ret == 0 && buf->len == wLength) {
116 memcpy(desc, buf->data, wLength);
117 desc->bcdUSB = sys_le16_to_cpu(desc->bcdUSB);
118 desc->idVendor = sys_le16_to_cpu(desc->idVendor);
119 desc->idProduct = sys_le16_to_cpu(desc->idProduct);
120 desc->bcdDevice = sys_le16_to_cpu(desc->bcdDevice);
121 }
122
123 usbh_xfer_buf_free(udev, buf);
124
125 return ret;
126 }
127
usbh_req_desc_cfg(struct usb_device * const udev,const uint8_t index,const uint16_t len,struct usb_cfg_descriptor * const desc)128 int usbh_req_desc_cfg(struct usb_device *const udev,
129 const uint8_t index,
130 const uint16_t len,
131 struct usb_cfg_descriptor *const desc)
132 {
133 const uint8_t type = USB_DESC_CONFIGURATION;
134 const uint16_t wLength = len;
135 struct net_buf *buf;
136 int ret;
137
138 buf = usbh_xfer_buf_alloc(udev, len);
139 if (!buf) {
140 return -ENOMEM;
141 }
142
143 ret = usbh_req_desc(udev, type, index, 0, wLength, buf);
144 if (ret == 0) {
145 memcpy(desc, buf->data, len);
146 desc->wTotalLength = sys_le16_to_cpu(desc->wTotalLength);
147 }
148
149 usbh_xfer_buf_free(udev, buf);
150
151 return ret;
152 }
153
usbh_req_set_address(struct usb_device * const udev,const uint8_t addr)154 int usbh_req_set_address(struct usb_device *const udev,
155 const uint8_t addr)
156 {
157 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7;
158 const uint8_t bRequest = USB_SREQ_SET_ADDRESS;
159 int ret;
160
161 ret = usbh_req_setup(udev, bmRequestType, bRequest, addr, 0, 0, NULL);
162 if (ret == 0) {
163 udev->addr = addr;
164 if (addr == 0) {
165 udev->state = USB_STATE_DEFAULT;
166 }
167
168 if (addr != 0 && udev->state == USB_STATE_DEFAULT) {
169 udev->state = USB_STATE_ADDRESSED;
170 }
171 }
172
173 return ret;
174 }
175
usbh_req_set_cfg(struct usb_device * const udev,const uint8_t cfg)176 int usbh_req_set_cfg(struct usb_device *const udev,
177 const uint8_t cfg)
178 {
179 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7;
180 const uint8_t bRequest = USB_SREQ_SET_CONFIGURATION;
181 int ret;
182
183 /* Ignore the required state change condition for now. */
184 ret = usbh_req_setup(udev, bmRequestType, bRequest, cfg, 0, 0, NULL);
185 if (ret == 0) {
186 udev->actual_cfg = cfg;
187 if (cfg == 0) {
188 udev->state = USB_STATE_ADDRESSED;
189 }
190
191 if (cfg != 0 && udev->state == USB_STATE_ADDRESSED) {
192 udev->state = USB_STATE_CONFIGURED;
193 }
194 }
195
196 return ret;
197 }
198
usbh_req_get_cfg(struct usb_device * const udev,uint8_t * const cfg)199 int usbh_req_get_cfg(struct usb_device *const udev,
200 uint8_t *const cfg)
201 {
202 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_HOST << 7;
203 const uint8_t bRequest = USB_SREQ_GET_CONFIGURATION;
204 const uint16_t wLength = 1;
205 struct net_buf *buf;
206 int ret;
207
208 buf = usbh_xfer_buf_alloc(udev, wLength);
209 if (!buf) {
210 return -ENOMEM;
211 }
212
213 ret = usbh_req_setup(udev, bmRequestType, bRequest, 0, 0, wLength, buf);
214 if (ret == 0 && buf->len == wLength) {
215 *cfg = buf->data[0];
216 }
217
218 usbh_xfer_buf_free(udev, buf);
219
220 return ret;
221 }
222
usbh_req_set_alt(struct usb_device * const udev,const uint8_t iface,const uint8_t alt)223 int usbh_req_set_alt(struct usb_device *const udev,
224 const uint8_t iface, const uint8_t alt)
225 {
226 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7 |
227 USB_REQTYPE_RECIPIENT_INTERFACE;
228 const uint8_t bRequest = USB_SREQ_SET_INTERFACE;
229 const uint16_t wValue = alt;
230 const uint16_t wIndex = iface;
231
232 return usbh_req_setup(udev,
233 bmRequestType, bRequest, wValue, wIndex, 0,
234 NULL);
235 }
236
usbh_req_set_sfs_rwup(struct usb_device * const udev)237 int usbh_req_set_sfs_rwup(struct usb_device *const udev)
238 {
239 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7;
240 const uint8_t bRequest = USB_SREQ_SET_FEATURE;
241 const uint16_t wValue = USB_SFS_REMOTE_WAKEUP;
242
243 return usbh_req_setup(udev,
244 bmRequestType, bRequest, wValue, 0, 0,
245 NULL);
246 }
247
usbh_req_clear_sfs_rwup(struct usb_device * const udev)248 int usbh_req_clear_sfs_rwup(struct usb_device *const udev)
249 {
250 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7;
251 const uint8_t bRequest = USB_SREQ_CLEAR_FEATURE;
252 const uint16_t wValue = USB_SFS_REMOTE_WAKEUP;
253
254 return usbh_req_setup(udev,
255 bmRequestType, bRequest, wValue, 0, 0,
256 NULL);
257 }
258
usbh_req_set_hcfs_ppwr(struct usb_device * const udev,const uint8_t port)259 int usbh_req_set_hcfs_ppwr(struct usb_device *const udev,
260 const uint8_t port)
261 {
262 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7 |
263 USB_REQTYPE_TYPE_CLASS << 5 |
264 USB_REQTYPE_RECIPIENT_OTHER << 0;
265 const uint8_t bRequest = USB_HCREQ_SET_FEATURE;
266 const uint16_t wValue = USB_HCFS_PORT_POWER;
267 const uint16_t wIndex = port;
268
269 return usbh_req_setup(udev,
270 bmRequestType, bRequest, wValue, wIndex, 0,
271 NULL);
272 }
273
usbh_req_set_hcfs_prst(struct usb_device * const udev,const uint8_t port)274 int usbh_req_set_hcfs_prst(struct usb_device *const udev,
275 const uint8_t port)
276 {
277 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7 |
278 USB_REQTYPE_TYPE_CLASS << 5 |
279 USB_REQTYPE_RECIPIENT_OTHER << 0;
280 const uint8_t bRequest = USB_HCREQ_SET_FEATURE;
281 const uint16_t wValue = USB_HCFS_PORT_RESET;
282 const uint16_t wIndex = port;
283
284 return usbh_req_setup(udev,
285 bmRequestType, bRequest, wValue, wIndex, 0,
286 NULL);
287 }
288