1 /* $FreeBSD: releng/12.2/sys/dev/usb/usb_util.c 326255 2017-11-27 14:52:40Z pfg $ */ 2 /*- 3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 4 * 5 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 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