1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2008-2022 Hans Petter Selasky
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include "implementation/global_implementation.h"
29
30 /*------------------------------------------------------------------------*
31 * device_set_usb_desc
32 *
33 * This function can be called at probe or attach to set the USB
34 * device supplied textual description for the given device.
35 *------------------------------------------------------------------------*/
36 void
device_set_usb_desc(device_t dev)37 device_set_usb_desc(device_t dev)
38 {
39 struct usb_attach_arg *uaa;
40 struct usb_device *udev;
41 struct usb_interface *iface;
42 char *temp_p;
43 usb_error_t err;
44 uint8_t do_unlock;
45
46 if (dev == NULL) {
47 /* should not happen */
48 return;
49 }
50 uaa = device_get_ivars(dev);
51 if (uaa == NULL) {
52 /* can happen if called at the wrong time */
53 return;
54 }
55 udev = uaa->device;
56 iface = uaa->iface;
57
58 if ((iface == NULL) ||
59 (iface->idesc == NULL) ||
60 (iface->idesc->iInterface == 0)) {
61 err = USB_ERR_INVAL;
62 } else {
63 err = USB_ERR_NORMAL_COMPLETION;
64 }
65
66 /* Protect scratch area */
67 do_unlock = usbd_ctrl_lock(udev);
68
69 temp_p = (char *)udev->scratch.data;
70
71 if (err == 0) {
72 /* try to get the interface string ! */
73 err = usbd_req_get_string_any(udev, NULL, temp_p,
74 sizeof(udev->scratch.data),
75 iface->idesc->iInterface);
76 }
77 if (err != 0) {
78 /* use default description */
79 usb_devinfo(udev, temp_p,
80 sizeof(udev->scratch.data));
81 }
82
83 if (do_unlock)
84 usbd_ctrl_unlock(udev);
85
86 device_set_desc_copy(dev, temp_p);
87 device_printf(dev, "<%s> on %s\n", temp_p,
88 device_get_nameunit(udev->bus->bdev));
89 }
90
91 /*------------------------------------------------------------------------*
92 * usb_pause_mtx - factored out code
93 *
94 * This function will delay the code by the passed number of system
95 * ticks. The passed mutex "mtx" will be dropped while waiting, if
96 * "mtx" is different from NULL.
97 *------------------------------------------------------------------------*/
98 void
usb_pause_mtx(struct mtx * mtx,int timo)99 usb_pause_mtx(struct mtx *mtx, int timo)
100 {
101 if (mtx != NULL)
102 mtx_unlock(mtx);
103
104 /*
105 * Add one tick to the timeout so that we don't return too
106 * early! Note that pause() will assert that the passed
107 * timeout is positive and non-zero!
108 */
109 pause("USBWAIT", (uint32_t)(timo + 1));
110
111 if (mtx != NULL)
112 mtx_lock(mtx);
113 }
114
115 /*------------------------------------------------------------------------*
116 * usb_printbcd
117 *
118 * This function will print the version number "bcd" to the string
119 * pointed to by "p" having a maximum length of "p_len" bytes
120 * including the terminating zero.
121 *------------------------------------------------------------------------*/
122 void
usb_printbcd(char * p,uint16_t p_len,uint16_t bcd)123 usb_printbcd(char *p, uint16_t p_len, uint16_t bcd)
124 {
125 if (snprintf_s(p, p_len, p_len - 1, "%x.%02x", bcd >> 8, bcd & 0xff)) {
126 /* ignore any errors */
127 }
128 }
129
130 /*------------------------------------------------------------------------*
131 * usb_trim_spaces
132 *
133 * This function removes spaces at the beginning and the end of the string
134 * pointed to by the "p" argument.
135 *------------------------------------------------------------------------*/
136 void
usb_trim_spaces(char * p)137 usb_trim_spaces(char *p)
138 {
139 char *q;
140 char *e;
141
142 if (p == NULL)
143 return;
144 q = e = p;
145 while (*q == ' ') /* skip leading spaces */
146 q++;
147 while ((*p = *q++)) /* copy string */
148 if (*p++ != ' ') /* remember last non-space */
149 e = p;
150 *e = 0; /* kill trailing spaces */
151 }
152
153 /*------------------------------------------------------------------------*
154 * usb_make_str_desc - convert an ASCII string into a UNICODE string
155 *------------------------------------------------------------------------*/
156 uint8_t
usb_make_str_desc(void * ptr,uint16_t max_len,const char * s)157 usb_make_str_desc(void *ptr, uint16_t max_len, const char *s)
158 {
159 struct usb_string_descriptor *p = ptr;
160 uint8_t totlen;
161 int j;
162
163 if (max_len < 2) {
164 /* invalid length */
165 return (0);
166 }
167 max_len = ((max_len / 2) - 1);
168
169 j = strlen(s);
170
171 if (j < 0) {
172 j = 0;
173 }
174 if (j > 126) {
175 j = 126;
176 }
177 if (max_len > j) {
178 max_len = j;
179 }
180 totlen = (max_len + 1) * 2;
181
182 p->bLength = totlen;
183 p->bDescriptorType = UDESC_STRING;
184
185 while (max_len--) {
186 USETW2(p->bString[max_len], 0, s[max_len]);
187 }
188 return (totlen);
189 }
190
191 /*------------------------------------------------------------------------*
192 * usb_check_request - prevent damaging USB requests
193 *
194 * Return values:
195 * 0: Access allowed
196 * Else: No access
197 *------------------------------------------------------------------------*/
198 #if USB_HAVE_UGEN
199 int
usb_check_request(struct usb_device * udev,struct usb_device_request * req)200 usb_check_request(struct usb_device *udev, struct usb_device_request *req)
201 {
202 struct usb_endpoint *ep;
203 int error;
204
205 /*
206 * Avoid requests that would damage the bus integrity:
207 */
208 if (((req->bmRequestType == UT_WRITE_DEVICE) &&
209 (req->bRequest == UR_SET_ADDRESS)) ||
210 ((req->bmRequestType == UT_WRITE_DEVICE) &&
211 (req->bRequest == UR_SET_CONFIG)) ||
212 ((req->bmRequestType == UT_WRITE_INTERFACE) &&
213 (req->bRequest == UR_SET_INTERFACE))) {
214 /*
215 * These requests can be useful for testing USB drivers.
216 */
217 error = priv_check(curthread, PRIV_DRIVER);
218 if (error)
219 return (error);
220 }
221
222 /*
223 * Special case - handle clearing of stall
224 */
225 if (req->bmRequestType == UT_WRITE_ENDPOINT) {
226 ep = usbd_get_ep_by_addr(udev, req->wIndex[0]);
227 if (ep == NULL)
228 return (EINVAL);
229 if ((req->bRequest == UR_CLEAR_FEATURE) &&
230 (UGETW(req->wValue) == UF_ENDPOINT_HALT))
231 usbd_clear_data_toggle(udev, ep);
232 }
233
234 /* TODO: add more checks to verify the interface index */
235
236 return (0);
237 }
238 #endif
239