1 /* $FreeBSD$ */ 2 /*- 3 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/stdint.h> 28 #include <sys/param.h> 29 #include <sys/queue.h> 30 #include <sys/types.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/bus.h> 34 #include <sys/module.h> 35 #include <sys/lock.h> 36 #include <sys/mutex.h> 37 #include <sys/condvar.h> 38 #include <sys/sysctl.h> 39 #include <sys/unistd.h> 40 #include <sys/callout.h> 41 #include <sys/malloc.h> 42 #include <sys/priv.h> 43 44 #include <bus/u4b/usb.h> 45 #include <bus/u4b/usbdi.h> 46 #include <bus/u4b/usbdi_util.h> 47 48 #include <bus/u4b/usb_core.h> 49 #include <bus/u4b/usb_util.h> 50 #include <bus/u4b/usb_process.h> 51 #include <bus/u4b/usb_device.h> 52 #include <bus/u4b/usb_request.h> 53 #include <bus/u4b/usb_busdma.h> 54 55 #include <bus/u4b/usb_controller.h> 56 #include <bus/u4b/usb_bus.h> 57 58 /*------------------------------------------------------------------------* 59 * device_set_usb_desc 60 * 61 * This function can be called at probe or attach to set the USB 62 * device supplied textual description for the given device. 63 *------------------------------------------------------------------------*/ 64 void 65 device_set_usb_desc(device_t dev) 66 { 67 struct usb_attach_arg *uaa; 68 struct usb_device *udev; 69 struct usb_interface *iface; 70 char *temp_p; 71 usb_error_t err; 72 73 if (dev == NULL) { 74 /* should not happen */ 75 return; 76 } 77 uaa = device_get_ivars(dev); 78 if (uaa == NULL) { 79 /* can happen if called at the wrong time */ 80 return; 81 } 82 udev = uaa->device; 83 iface = uaa->iface; 84 85 if ((iface == NULL) || 86 (iface->idesc == NULL) || 87 (iface->idesc->iInterface == 0)) { 88 err = USB_ERR_INVAL; 89 } else { 90 err = 0; 91 } 92 93 temp_p = (char *)udev->bus->scratch[0].data; 94 95 if (!err) { 96 /* try to get the interface string ! */ 97 err = usbd_req_get_string_any 98 (udev, NULL, temp_p, 99 sizeof(udev->bus->scratch), iface->idesc->iInterface); 100 } 101 if (err) { 102 /* use default description */ 103 usb_devinfo(udev, temp_p, 104 sizeof(udev->bus->scratch)); 105 } 106 device_set_desc_copy(dev, temp_p); 107 device_printf(dev, "<%s> on %s\n", temp_p, 108 device_get_nameunit(udev->bus->bdev)); 109 } 110 111 /*------------------------------------------------------------------------* 112 * usb_pause_mtx - factored out code 113 * 114 * This function will delay the code by the passed number of system 115 * ticks. The passed mutex "mtx" will be dropped while waiting, if 116 * "mtx" is different from NULL. 117 *------------------------------------------------------------------------*/ 118 void 119 usb_pause_mtx(struct lock *lock, int timo) 120 { 121 /* 122 * Add one tick to the timeout so that we don't return too 123 * early! Note that pause() will assert that the passed 124 * timeout is positive and non-zero! 125 */ 126 if (lock != NULL) { 127 lksleep(&usb_pause_mtx, lock, 0, "USBSLP", timo + 1); 128 } else { 129 KKASSERT(timo + 1 > 0); 130 tsleep(&usb_pause_mtx, 0, "USBSLP", timo + 1); 131 } 132 } 133 134 /*------------------------------------------------------------------------* 135 * usb_printbcd 136 * 137 * This function will print the version number "bcd" to the string 138 * pointed to by "p" having a maximum length of "p_len" bytes 139 * including the terminating zero. 140 *------------------------------------------------------------------------*/ 141 void 142 usb_printbcd(char *p, uint16_t p_len, uint16_t bcd) 143 { 144 if (ksnprintf(p, p_len, "%x.%02x", bcd >> 8, bcd & 0xff)) { 145 /* ignore any errors */ 146 } 147 } 148 149 /*------------------------------------------------------------------------* 150 * usb_trim_spaces 151 * 152 * This function removes spaces at the beginning and the end of the string 153 * pointed to by the "p" argument. 154 *------------------------------------------------------------------------*/ 155 void 156 usb_trim_spaces(char *p) 157 { 158 char *q; 159 char *e; 160 161 if (p == NULL) 162 return; 163 q = e = p; 164 while (*q == ' ') /* skip leading spaces */ 165 q++; 166 while ((*p = *q++)) /* copy string */ 167 if (*p++ != ' ') /* remember last non-space */ 168 e = p; 169 *e = 0; /* kill trailing spaces */ 170 } 171 172 /*------------------------------------------------------------------------* 173 * usb_make_str_desc - convert an ASCII string into a UNICODE string 174 *------------------------------------------------------------------------*/ 175 uint8_t 176 usb_make_str_desc(void *ptr, uint16_t max_len, const char *s) 177 { 178 struct usb_string_descriptor *p = ptr; 179 uint8_t totlen; 180 int j; 181 182 if (max_len < 2) { 183 /* invalid length */ 184 return (0); 185 } 186 max_len = ((max_len / 2) - 1); 187 188 j = strlen(s); 189 190 if (j < 0) { 191 j = 0; 192 } 193 if (j > 126) { 194 j = 126; 195 } 196 if (max_len > j) { 197 max_len = j; 198 } 199 totlen = (max_len + 1) * 2; 200 201 p->bLength = totlen; 202 p->bDescriptorType = UDESC_STRING; 203 204 while (max_len--) { 205 USETW2(p->bString[max_len], 0, s[max_len]); 206 } 207 return (totlen); 208 } 209 210 void 211 usb_callout_timeout_wrapper(void *arg) 212 { 213 struct usb_callout *uco = (struct usb_callout *)arg; 214 215 KKASSERT(uco != NULL); 216 217 /* 218 * Simulate FreeBSD's callout behaviour which allows 219 * a lock to be acquired before the function is called 220 */ 221 222 lockmgr(uco->uco_lock, LK_EXCLUSIVE); 223 uco->uco_func(uco->uco_arg); 224 lockmgr(uco->uco_lock, LK_RELEASE); 225 /* XXX Have to introduce flags and release lock? */ 226 } 227 228 void 229 usb_callout_init_mtx_dfly(struct usb_callout *uco, struct lock *lock, 230 int flags) 231 { 232 callout_init(&uco->co); 233 uco->uco_lock = lock; 234 uco->uco_flags = flags; 235 } 236 237 void 238 usb_callout_reset_dfly(struct usb_callout *uco, int ticks, timeout_t *func, 239 void *arg) 240 { 241 KKASSERT(uco != NULL); 242 uco->uco_func = func; 243 uco->uco_arg = arg; 244 245 callout_reset(&uco->co, ticks, &usb_callout_timeout_wrapper, uco); 246 } 247