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