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