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 if (xfer->err == -ECONNRESET) {
33 LOG_INF("Transfer %p cancelled", (void *)xfer);
34 usbh_xfer_free(udev, xfer);
35
36 return 0;
37 }
38
39 k_sem_give(&ch9_req_sync);
40
41 return 0;
42 }
43
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)44 int usbh_req_setup(struct usb_device *const udev,
45 const uint8_t bmRequestType,
46 const uint8_t bRequest,
47 const uint16_t wValue,
48 const uint16_t wIndex,
49 const uint16_t wLength,
50 struct net_buf *const buf)
51 {
52 struct usb_setup_packet req = {
53 .bmRequestType = bmRequestType,
54 .bRequest = bRequest,
55 .wValue = sys_cpu_to_le16(wValue),
56 .wIndex = sys_cpu_to_le16(wIndex),
57 .wLength = sys_cpu_to_le16(wLength),
58 };
59 struct uhc_transfer *xfer;
60 uint8_t ep = usb_reqtype_is_to_device(&req) ? 0x00 : 0x80;
61 int ret;
62
63 xfer = usbh_xfer_alloc(udev, ep, ch9_req_cb, NULL);
64 if (!xfer) {
65 return -ENOMEM;
66 }
67
68 memcpy(xfer->setup_pkt, &req, sizeof(req));
69
70 __ASSERT((buf != NULL && wLength) || (buf == NULL && !wLength),
71 "Unresolved conditions for data stage");
72 if (wLength) {
73 ret = usbh_xfer_buf_add(udev, xfer, buf);
74 if (ret) {
75 goto buf_alloc_err;
76 }
77 }
78
79 ret = usbh_xfer_enqueue(udev, xfer);
80 if (ret) {
81 goto buf_alloc_err;
82 }
83
84 if (k_sem_take(&ch9_req_sync, K_MSEC(SETUP_REQ_TIMEOUT)) != 0) {
85 ret = usbh_xfer_dequeue(udev, xfer);
86 if (ret != 0) {
87 LOG_ERR("Failed to cancel transfer");
88 return ret;
89 }
90
91 LOG_ERR("Timeout");
92 return -ETIMEDOUT;
93 }
94
95 ret = xfer->err;
96
97 buf_alloc_err:
98 usbh_xfer_free(udev, xfer);
99
100 return ret;
101 }
102
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)103 int usbh_req_desc(struct usb_device *const udev,
104 const uint8_t type, const uint8_t index,
105 const uint16_t id,
106 const uint16_t len,
107 struct net_buf *const buf)
108 {
109 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_HOST << 7;
110 const uint8_t bRequest = USB_SREQ_GET_DESCRIPTOR;
111 const uint16_t wValue = (type << 8) | index;
112
113 return usbh_req_setup(udev,
114 bmRequestType, bRequest, wValue, id, len,
115 buf);
116 }
117
usbh_req_desc_dev(struct usb_device * const udev,const uint16_t len,struct usb_device_descriptor * const desc)118 int usbh_req_desc_dev(struct usb_device *const udev,
119 const uint16_t len,
120 struct usb_device_descriptor *const desc)
121 {
122 const uint8_t type = USB_DESC_DEVICE;
123 const uint16_t wLength = MIN(len, sizeof(struct usb_device_descriptor));
124 struct net_buf *buf;
125 int ret;
126
127 buf = usbh_xfer_buf_alloc(udev, wLength);
128 if (!buf) {
129 return -ENOMEM;
130 }
131
132 ret = usbh_req_desc(udev, type, 0, 0, wLength, buf);
133 if (ret == 0 && buf->len == wLength) {
134 memcpy(desc, buf->data, wLength);
135 desc->bcdUSB = sys_le16_to_cpu(desc->bcdUSB);
136 desc->idVendor = sys_le16_to_cpu(desc->idVendor);
137 desc->idProduct = sys_le16_to_cpu(desc->idProduct);
138 desc->bcdDevice = sys_le16_to_cpu(desc->bcdDevice);
139 }
140
141 usbh_xfer_buf_free(udev, buf);
142
143 return ret;
144 }
145
usbh_req_desc_cfg(struct usb_device * const udev,const uint8_t index,const uint16_t len,struct usb_cfg_descriptor * const desc)146 int usbh_req_desc_cfg(struct usb_device *const udev,
147 const uint8_t index,
148 const uint16_t len,
149 struct usb_cfg_descriptor *const desc)
150 {
151 const uint8_t type = USB_DESC_CONFIGURATION;
152 const uint16_t wLength = len;
153 struct net_buf *buf;
154 int ret;
155
156 buf = usbh_xfer_buf_alloc(udev, len);
157 if (!buf) {
158 return -ENOMEM;
159 }
160
161 ret = usbh_req_desc(udev, type, index, 0, wLength, buf);
162 if (ret == 0) {
163 memcpy(desc, buf->data, len);
164 desc->wTotalLength = sys_le16_to_cpu(desc->wTotalLength);
165 }
166
167 usbh_xfer_buf_free(udev, buf);
168
169 return ret;
170 }
171
usbh_req_set_address(struct usb_device * const udev,const uint8_t addr)172 int usbh_req_set_address(struct usb_device *const udev,
173 const uint8_t addr)
174 {
175 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7;
176 const uint8_t bRequest = USB_SREQ_SET_ADDRESS;
177
178 return usbh_req_setup(udev, bmRequestType, bRequest, addr, 0, 0, NULL);
179 }
180
usbh_req_set_cfg(struct usb_device * const udev,const uint8_t cfg)181 int usbh_req_set_cfg(struct usb_device *const udev,
182 const uint8_t cfg)
183 {
184 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7;
185 const uint8_t bRequest = USB_SREQ_SET_CONFIGURATION;
186
187 return usbh_req_setup(udev, bmRequestType, bRequest, cfg, 0, 0, NULL);
188 }
189
usbh_req_get_cfg(struct usb_device * const udev,uint8_t * const cfg)190 int usbh_req_get_cfg(struct usb_device *const udev,
191 uint8_t *const cfg)
192 {
193 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_HOST << 7;
194 const uint8_t bRequest = USB_SREQ_GET_CONFIGURATION;
195 const uint16_t wLength = 1;
196 struct net_buf *buf;
197 int ret;
198
199 buf = usbh_xfer_buf_alloc(udev, wLength);
200 if (!buf) {
201 return -ENOMEM;
202 }
203
204 ret = usbh_req_setup(udev, bmRequestType, bRequest, 0, 0, wLength, buf);
205 if (ret == 0 && buf->len == wLength) {
206 *cfg = buf->data[0];
207 }
208
209 usbh_xfer_buf_free(udev, buf);
210
211 return ret;
212 }
213
usbh_req_set_alt(struct usb_device * const udev,const uint8_t iface,const uint8_t alt)214 int usbh_req_set_alt(struct usb_device *const udev,
215 const uint8_t iface, const uint8_t alt)
216 {
217 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7 |
218 USB_REQTYPE_RECIPIENT_INTERFACE;
219 const uint8_t bRequest = USB_SREQ_SET_INTERFACE;
220 const uint16_t wValue = alt;
221 const uint16_t wIndex = iface;
222
223 return usbh_req_setup(udev,
224 bmRequestType, bRequest, wValue, wIndex, 0,
225 NULL);
226 }
227
usbh_req_set_sfs_rwup(struct usb_device * const udev)228 int usbh_req_set_sfs_rwup(struct usb_device *const udev)
229 {
230 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7;
231 const uint8_t bRequest = USB_SREQ_SET_FEATURE;
232 const uint16_t wValue = USB_SFS_REMOTE_WAKEUP;
233
234 return usbh_req_setup(udev,
235 bmRequestType, bRequest, wValue, 0, 0,
236 NULL);
237 }
238
usbh_req_clear_sfs_rwup(struct usb_device * const udev)239 int usbh_req_clear_sfs_rwup(struct usb_device *const udev)
240 {
241 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7;
242 const uint8_t bRequest = USB_SREQ_CLEAR_FEATURE;
243 const uint16_t wValue = USB_SFS_REMOTE_WAKEUP;
244
245 return usbh_req_setup(udev,
246 bmRequestType, bRequest, wValue, 0, 0,
247 NULL);
248 }
249
usbh_req_set_hcfs_ppwr(struct usb_device * const udev,const uint8_t port)250 int usbh_req_set_hcfs_ppwr(struct usb_device *const udev,
251 const uint8_t port)
252 {
253 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7 |
254 USB_REQTYPE_TYPE_CLASS << 5 |
255 USB_REQTYPE_RECIPIENT_OTHER << 0;
256 const uint8_t bRequest = USB_HCREQ_SET_FEATURE;
257 const uint16_t wValue = USB_HCFS_PORT_POWER;
258 const uint16_t wIndex = port;
259
260 return usbh_req_setup(udev,
261 bmRequestType, bRequest, wValue, wIndex, 0,
262 NULL);
263 }
264
usbh_req_set_hcfs_prst(struct usb_device * const udev,const uint8_t port)265 int usbh_req_set_hcfs_prst(struct usb_device *const udev,
266 const uint8_t port)
267 {
268 const uint8_t bmRequestType = USB_REQTYPE_DIR_TO_DEVICE << 7 |
269 USB_REQTYPE_TYPE_CLASS << 5 |
270 USB_REQTYPE_RECIPIENT_OTHER << 0;
271 const uint8_t bRequest = USB_HCREQ_SET_FEATURE;
272 const uint16_t wValue = USB_HCFS_PORT_RESET;
273 const uint16_t wIndex = port;
274
275 return usbh_req_setup(udev,
276 bmRequestType, bRequest, wValue, wIndex, 0,
277 NULL);
278 }
279