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