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> 52250204Shselasky 53250204Shselasky#define USB_DEBUG_VAR usb_debug 54250204Shselasky 55250204Shselasky#include <dev/usb/usb_core.h> 56250204Shselasky#include <dev/usb/usb_debug.h> 57246122Shselasky#endif /* USB_GLOBAL_INCLUDE_FILE */ 58184610Salfred 59184610Salfred/*------------------------------------------------------------------------* 60194228Sthompsa * usb_desc_foreach 61184610Salfred * 62184610Salfred * This function is the safe way to iterate across the USB config 63184610Salfred * descriptor. It contains several checks against invalid 64184610Salfred * descriptors. If the "desc" argument passed to this function is 65184610Salfred * "NULL" the first descriptor, if any, will be returned. 66184610Salfred * 67184610Salfred * Return values: 68184610Salfred * NULL: End of descriptors 69184610Salfred * Else: Next descriptor after "desc" 70184610Salfred *------------------------------------------------------------------------*/ 71192984Sthompsastruct usb_descriptor * 72194228Sthompsausb_desc_foreach(struct usb_config_descriptor *cd, 73192984Sthompsa struct usb_descriptor *_desc) 74184610Salfred{ 75187178Sthompsa uint8_t *desc_next; 76187178Sthompsa uint8_t *start; 77187178Sthompsa uint8_t *end; 78187178Sthompsa uint8_t *desc; 79184610Salfred 80187178Sthompsa /* be NULL safe */ 81187178Sthompsa if (cd == NULL) 82184610Salfred return (NULL); 83184610Salfred 84187178Sthompsa /* We assume that the "wTotalLength" has been checked. */ 85187178Sthompsa start = (uint8_t *)cd; 86187178Sthompsa end = start + UGETW(cd->wTotalLength); 87187178Sthompsa desc = (uint8_t *)_desc; 88187178Sthompsa 89187178Sthompsa /* Get start of next USB descriptor. */ 90187178Sthompsa if (desc == NULL) 91187178Sthompsa desc = start; 92187178Sthompsa else 93187178Sthompsa desc = desc + desc[0]; 94187178Sthompsa 95187178Sthompsa /* Check that the next USB descriptor is within the range. */ 96187178Sthompsa if ((desc < start) || (desc >= end)) 97187178Sthompsa return (NULL); /* out of range, or EOD */ 98187178Sthompsa 99187178Sthompsa /* Check that the second next USB descriptor is within range. */ 100187178Sthompsa desc_next = desc + desc[0]; 101187178Sthompsa if ((desc_next < start) || (desc_next > end)) 102187178Sthompsa return (NULL); /* out of range */ 103187178Sthompsa 104187178Sthompsa /* Check minimum descriptor length. */ 105187178Sthompsa if (desc[0] < 3) 106187178Sthompsa return (NULL); /* too short descriptor */ 107187178Sthompsa 108187178Sthompsa /* Return start of next descriptor. */ 109192984Sthompsa return ((struct usb_descriptor *)desc); 110184610Salfred} 111184610Salfred 112184610Salfred/*------------------------------------------------------------------------* 113194228Sthompsa * usb_idesc_foreach 114184610Salfred * 115190730Sthompsa * This function will iterate the interface descriptors in the config 116190730Sthompsa * descriptor. The parse state structure should be zeroed before 117190730Sthompsa * calling this function the first time. 118184610Salfred * 119184610Salfred * Return values: 120184610Salfred * NULL: End of descriptors 121184610Salfred * Else: A valid interface descriptor 122184610Salfred *------------------------------------------------------------------------*/ 123192984Sthompsastruct usb_interface_descriptor * 124194228Sthompsausb_idesc_foreach(struct usb_config_descriptor *cd, 125192984Sthompsa struct usb_idesc_parse_state *ps) 126184610Salfred{ 127192984Sthompsa struct usb_interface_descriptor *id; 128190730Sthompsa uint8_t new_iface; 129184610Salfred 130190730Sthompsa /* retrieve current descriptor */ 131192984Sthompsa id = (struct usb_interface_descriptor *)ps->desc; 132190730Sthompsa /* default is to start a new interface */ 133190730Sthompsa new_iface = 1; 134184610Salfred 135190730Sthompsa while (1) { 136192984Sthompsa id = (struct usb_interface_descriptor *) 137194228Sthompsa usb_desc_foreach(cd, (struct usb_descriptor *)id); 138190730Sthompsa if (id == NULL) 139190730Sthompsa break; 140190730Sthompsa if ((id->bDescriptorType == UDESC_INTERFACE) && 141190730Sthompsa (id->bLength >= sizeof(*id))) { 142190730Sthompsa if (ps->iface_no_last == id->bInterfaceNumber) 143190730Sthompsa new_iface = 0; 144190730Sthompsa ps->iface_no_last = id->bInterfaceNumber; 145190730Sthompsa break; 146190730Sthompsa } 147190730Sthompsa } 148184610Salfred 149190730Sthompsa if (ps->desc == NULL) { 150250204Shselasky /* first time or zero descriptors */ 151190730Sthompsa } else if (new_iface) { 152190730Sthompsa /* new interface */ 153190730Sthompsa ps->iface_index ++; 154190730Sthompsa ps->iface_index_alt = 0; 155190730Sthompsa } else { 156190730Sthompsa /* new alternate interface */ 157190730Sthompsa ps->iface_index_alt ++; 158190730Sthompsa } 159250204Shselasky#if (USB_IFACE_MAX <= 0) 160250204Shselasky#error "USB_IFACE_MAX must be defined greater than zero" 161250204Shselasky#endif 162250204Shselasky /* check for too many interfaces */ 163250204Shselasky if (ps->iface_index >= USB_IFACE_MAX) { 164250204Shselasky DPRINTF("Interface limit reached\n"); 165250204Shselasky id = NULL; 166250204Shselasky } 167184610Salfred 168190730Sthompsa /* store and return current descriptor */ 169192984Sthompsa ps->desc = (struct usb_descriptor *)id; 170190730Sthompsa return (id); 171184610Salfred} 172184610Salfred 173184610Salfred/*------------------------------------------------------------------------* 174194228Sthompsa * usb_edesc_foreach 175184610Salfred * 176190730Sthompsa * This function will iterate all the endpoint descriptors within an 177190730Sthompsa * interface descriptor. Starting value for the "ped" argument should 178190730Sthompsa * be a valid interface descriptor. 179184610Salfred * 180184610Salfred * Return values: 181184610Salfred * NULL: End of descriptors 182184610Salfred * Else: A valid endpoint descriptor 183184610Salfred *------------------------------------------------------------------------*/ 184192984Sthompsastruct usb_endpoint_descriptor * 185194228Sthompsausb_edesc_foreach(struct usb_config_descriptor *cd, 186192984Sthompsa struct usb_endpoint_descriptor *ped) 187184610Salfred{ 188192984Sthompsa struct usb_descriptor *desc; 189184610Salfred 190192984Sthompsa desc = ((struct usb_descriptor *)ped); 191184610Salfred 192194228Sthompsa while ((desc = usb_desc_foreach(cd, desc))) { 193184610Salfred if (desc->bDescriptorType == UDESC_INTERFACE) { 194184610Salfred break; 195184610Salfred } 196184610Salfred if (desc->bDescriptorType == UDESC_ENDPOINT) { 197190730Sthompsa if (desc->bLength < sizeof(*ped)) { 198213435Shselasky /* endpoint descriptor is invalid */ 199190730Sthompsa break; 200184610Salfred } 201192984Sthompsa return ((struct usb_endpoint_descriptor *)desc); 202184610Salfred } 203184610Salfred } 204184610Salfred return (NULL); 205184610Salfred} 206184610Salfred 207184610Salfred/*------------------------------------------------------------------------* 208213435Shselasky * usb_ed_comp_foreach 209213435Shselasky * 210213435Shselasky * This function will iterate all the endpoint companion descriptors 211213435Shselasky * within an endpoint descriptor in an interface descriptor. Starting 212213435Shselasky * value for the "ped" argument should be a valid endpoint companion 213213435Shselasky * descriptor. 214213435Shselasky * 215213435Shselasky * Return values: 216213435Shselasky * NULL: End of descriptors 217213435Shselasky * Else: A valid endpoint companion descriptor 218213435Shselasky *------------------------------------------------------------------------*/ 219213435Shselaskystruct usb_endpoint_ss_comp_descriptor * 220213435Shselaskyusb_ed_comp_foreach(struct usb_config_descriptor *cd, 221213435Shselasky struct usb_endpoint_ss_comp_descriptor *ped) 222213435Shselasky{ 223213435Shselasky struct usb_descriptor *desc; 224213435Shselasky 225213435Shselasky desc = ((struct usb_descriptor *)ped); 226213435Shselasky 227213435Shselasky while ((desc = usb_desc_foreach(cd, desc))) { 228213435Shselasky if (desc->bDescriptorType == UDESC_INTERFACE) 229213435Shselasky break; 230213435Shselasky if (desc->bDescriptorType == UDESC_ENDPOINT) 231213435Shselasky break; 232213435Shselasky if (desc->bDescriptorType == UDESC_ENDPOINT_SS_COMP) { 233213435Shselasky if (desc->bLength < sizeof(*ped)) { 234213435Shselasky /* endpoint companion descriptor is invalid */ 235213435Shselasky break; 236213435Shselasky } 237213435Shselasky return ((struct usb_endpoint_ss_comp_descriptor *)desc); 238213435Shselasky } 239213435Shselasky } 240213435Shselasky return (NULL); 241213435Shselasky} 242213435Shselasky 243213435Shselasky/*------------------------------------------------------------------------* 244194228Sthompsa * usbd_get_no_descriptors 245184610Salfred * 246190730Sthompsa * This function will count the total number of descriptors in the 247190730Sthompsa * configuration descriptor of type "type". 248184610Salfred *------------------------------------------------------------------------*/ 249190730Sthompsauint8_t 250194228Sthompsausbd_get_no_descriptors(struct usb_config_descriptor *cd, uint8_t type) 251184610Salfred{ 252192984Sthompsa struct usb_descriptor *desc = NULL; 253190730Sthompsa uint8_t count = 0; 254184610Salfred 255194228Sthompsa while ((desc = usb_desc_foreach(cd, desc))) { 256190730Sthompsa if (desc->bDescriptorType == type) { 257184610Salfred count++; 258190730Sthompsa if (count == 0xFF) 259190730Sthompsa break; /* crazy */ 260184610Salfred } 261184610Salfred } 262184610Salfred return (count); 263184610Salfred} 264184610Salfred 265184610Salfred/*------------------------------------------------------------------------* 266194228Sthompsa * usbd_get_no_alts 267184610Salfred * 268184610Salfred * Return value: 269195963Salfred * Number of alternate settings for the given interface descriptor 270195963Salfred * pointer. If the USB descriptor is corrupt, the returned value can 271195963Salfred * be greater than the actual number of alternate settings. 272184610Salfred *------------------------------------------------------------------------*/ 273190730Sthompsauint8_t 274194228Sthompsausbd_get_no_alts(struct usb_config_descriptor *cd, 275192984Sthompsa struct usb_interface_descriptor *id) 276184610Salfred{ 277192984Sthompsa struct usb_descriptor *desc; 278195963Salfred uint8_t n; 279190730Sthompsa uint8_t ifaceno; 280184610Salfred 281195963Salfred /* Reset interface count */ 282195963Salfred 283195963Salfred n = 0; 284195963Salfred 285195963Salfred /* Get the interface number */ 286195963Salfred 287190730Sthompsa ifaceno = id->bInterfaceNumber; 288190730Sthompsa 289195963Salfred /* Iterate all the USB descriptors */ 290190730Sthompsa 291195963Salfred desc = NULL; 292194228Sthompsa while ((desc = usb_desc_foreach(cd, desc))) { 293184610Salfred if ((desc->bDescriptorType == UDESC_INTERFACE) && 294184610Salfred (desc->bLength >= sizeof(*id))) { 295192984Sthompsa id = (struct usb_interface_descriptor *)desc; 296184610Salfred if (id->bInterfaceNumber == ifaceno) { 297184610Salfred n++; 298190730Sthompsa if (n == 0xFF) 299190730Sthompsa break; /* crazy */ 300195963Salfred } 301184610Salfred } 302184610Salfred } 303184610Salfred return (n); 304184610Salfred} 305