1184610Salfred/* $FreeBSD$ */ 2184610Salfred/*- 3184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24184610Salfred * SUCH DAMAGE. 25184610Salfred */ 26184610Salfred 27246122Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE 28246122Shselasky#include USB_GLOBAL_INCLUDE_FILE 29246122Shselasky#else 30194677Sthompsa#include <sys/stdint.h> 31194677Sthompsa#include <sys/stddef.h> 32194677Sthompsa#include <sys/param.h> 33194677Sthompsa#include <sys/queue.h> 34194677Sthompsa#include <sys/types.h> 35194677Sthompsa#include <sys/systm.h> 36194677Sthompsa#include <sys/kernel.h> 37194677Sthompsa#include <sys/bus.h> 38194677Sthompsa#include <sys/module.h> 39194677Sthompsa#include <sys/lock.h> 40194677Sthompsa#include <sys/mutex.h> 41194677Sthompsa#include <sys/condvar.h> 42194677Sthompsa#include <sys/sysctl.h> 43194677Sthompsa#include <sys/sx.h> 44194677Sthompsa#include <sys/unistd.h> 45194677Sthompsa#include <sys/callout.h> 46194677Sthompsa#include <sys/malloc.h> 47194677Sthompsa#include <sys/priv.h> 48194677Sthompsa 49188942Sthompsa#include <dev/usb/usb.h> 50194677Sthompsa#include <dev/usb/usbdi.h> 51194677Sthompsa#include <dev/usb/usbdi_util.h> 52184610Salfred 53188942Sthompsa#include <dev/usb/usb_core.h> 54188942Sthompsa#include <dev/usb/usb_util.h> 55188942Sthompsa#include <dev/usb/usb_process.h> 56188942Sthompsa#include <dev/usb/usb_device.h> 57188942Sthompsa#include <dev/usb/usb_request.h> 58188942Sthompsa#include <dev/usb/usb_busdma.h> 59184610Salfred 60188942Sthompsa#include <dev/usb/usb_controller.h> 61188942Sthompsa#include <dev/usb/usb_bus.h> 62246122Shselasky#endif /* USB_GLOBAL_INCLUDE_FILE */ 63184610Salfred 64184610Salfred/*------------------------------------------------------------------------* 65194228Sthompsa * device_set_usb_desc 66184610Salfred * 67184610Salfred * This function can be called at probe or attach to set the USB 68184610Salfred * device supplied textual description for the given device. 69184610Salfred *------------------------------------------------------------------------*/ 70184610Salfredvoid 71194228Sthompsadevice_set_usb_desc(device_t dev) 72184610Salfred{ 73192984Sthompsa struct usb_attach_arg *uaa; 74192984Sthompsa struct usb_device *udev; 75192984Sthompsa struct usb_interface *iface; 76184610Salfred char *temp_p; 77193045Sthompsa usb_error_t err; 78246616Shselasky uint8_t do_unlock; 79184610Salfred 80184610Salfred if (dev == NULL) { 81184610Salfred /* should not happen */ 82184610Salfred return; 83184610Salfred } 84184610Salfred uaa = device_get_ivars(dev); 85184610Salfred if (uaa == NULL) { 86185087Salfred /* can happen if called at the wrong time */ 87184610Salfred return; 88184610Salfred } 89184610Salfred udev = uaa->device; 90184610Salfred iface = uaa->iface; 91184610Salfred 92184610Salfred if ((iface == NULL) || 93184610Salfred (iface->idesc == NULL) || 94184610Salfred (iface->idesc->iInterface == 0)) { 95184610Salfred err = USB_ERR_INVAL; 96184610Salfred } else { 97184610Salfred err = 0; 98184610Salfred } 99184610Salfred 100246616Shselasky /* Protect scratch area */ 101305733Shselasky do_unlock = usbd_ctrl_lock(udev); 102184610Salfred 103246616Shselasky temp_p = (char *)udev->scratch.data; 104246616Shselasky 105246616Shselasky if (err == 0) { 106184610Salfred /* try to get the interface string ! */ 107246616Shselasky err = usbd_req_get_string_any(udev, NULL, temp_p, 108246616Shselasky sizeof(udev->scratch.data), 109246616Shselasky iface->idesc->iInterface); 110184610Salfred } 111246616Shselasky if (err != 0) { 112184610Salfred /* use default description */ 113194228Sthompsa usb_devinfo(udev, temp_p, 114246616Shselasky sizeof(udev->scratch.data)); 115184610Salfred } 116246616Shselasky 117246616Shselasky if (do_unlock) 118305733Shselasky usbd_ctrl_unlock(udev); 119246616Shselasky 120184610Salfred device_set_desc_copy(dev, temp_p); 121184610Salfred device_printf(dev, "<%s> on %s\n", temp_p, 122184610Salfred device_get_nameunit(udev->bus->bdev)); 123184610Salfred} 124184610Salfred 125184610Salfred/*------------------------------------------------------------------------* 126194228Sthompsa * usb_pause_mtx - factored out code 127184610Salfred * 128188411Sthompsa * This function will delay the code by the passed number of system 129188411Sthompsa * ticks. The passed mutex "mtx" will be dropped while waiting, if 130227706Shselasky * "mtx" is different from NULL. 131184610Salfred *------------------------------------------------------------------------*/ 132184610Salfredvoid 133227706Shselaskyusb_pause_mtx(struct mtx *mtx, int timo) 134184610Salfred{ 135188411Sthompsa if (mtx != NULL) 136188411Sthompsa mtx_unlock(mtx); 137188411Sthompsa 138227706Shselasky /* 139227706Shselasky * Add one tick to the timeout so that we don't return too 140227706Shselasky * early! Note that pause() will assert that the passed 141227706Shselasky * timeout is positive and non-zero! 142227706Shselasky */ 143227706Shselasky pause("USBWAIT", timo + 1); 144184610Salfred 145188411Sthompsa if (mtx != NULL) 146188411Sthompsa mtx_lock(mtx); 147184610Salfred} 148184610Salfred 149184610Salfred/*------------------------------------------------------------------------* 150194228Sthompsa * usb_printbcd 151184610Salfred * 152184610Salfred * This function will print the version number "bcd" to the string 153184610Salfred * pointed to by "p" having a maximum length of "p_len" bytes 154184610Salfred * including the terminating zero. 155184610Salfred *------------------------------------------------------------------------*/ 156184610Salfredvoid 157194228Sthompsausb_printbcd(char *p, uint16_t p_len, uint16_t bcd) 158184610Salfred{ 159184610Salfred if (snprintf(p, p_len, "%x.%02x", bcd >> 8, bcd & 0xff)) { 160184610Salfred /* ignore any errors */ 161184610Salfred } 162184610Salfred} 163184610Salfred 164184610Salfred/*------------------------------------------------------------------------* 165194228Sthompsa * usb_trim_spaces 166184610Salfred * 167184610Salfred * This function removes spaces at the beginning and the end of the string 168184610Salfred * pointed to by the "p" argument. 169184610Salfred *------------------------------------------------------------------------*/ 170184610Salfredvoid 171194228Sthompsausb_trim_spaces(char *p) 172184610Salfred{ 173184610Salfred char *q; 174184610Salfred char *e; 175184610Salfred 176184610Salfred if (p == NULL) 177184610Salfred return; 178184610Salfred q = e = p; 179184610Salfred while (*q == ' ') /* skip leading spaces */ 180184610Salfred q++; 181184610Salfred while ((*p = *q++)) /* copy string */ 182184610Salfred if (*p++ != ' ') /* remember last non-space */ 183184610Salfred e = p; 184184610Salfred *e = 0; /* kill trailing spaces */ 185184610Salfred} 186184610Salfred 187184610Salfred/*------------------------------------------------------------------------* 188194228Sthompsa * usb_make_str_desc - convert an ASCII string into a UNICODE string 189184610Salfred *------------------------------------------------------------------------*/ 190184610Salfreduint8_t 191194228Sthompsausb_make_str_desc(void *ptr, uint16_t max_len, const char *s) 192184610Salfred{ 193192984Sthompsa struct usb_string_descriptor *p = ptr; 194184610Salfred uint8_t totlen; 195184610Salfred int j; 196184610Salfred 197184610Salfred if (max_len < 2) { 198184610Salfred /* invalid length */ 199184610Salfred return (0); 200184610Salfred } 201184610Salfred max_len = ((max_len / 2) - 1); 202184610Salfred 203184610Salfred j = strlen(s); 204184610Salfred 205184610Salfred if (j < 0) { 206184610Salfred j = 0; 207184610Salfred } 208184610Salfred if (j > 126) { 209184610Salfred j = 126; 210184610Salfred } 211184610Salfred if (max_len > j) { 212184610Salfred max_len = j; 213184610Salfred } 214184610Salfred totlen = (max_len + 1) * 2; 215184610Salfred 216184610Salfred p->bLength = totlen; 217184610Salfred p->bDescriptorType = UDESC_STRING; 218184610Salfred 219184610Salfred while (max_len--) { 220184610Salfred USETW2(p->bString[max_len], 0, s[max_len]); 221184610Salfred } 222184610Salfred return (totlen); 223184610Salfred} 224