usb_template.c revision 218475
1184610Salfred/* $FreeBSD: head/sys/dev/usb/template/usb_template.c 218475 2011-02-09 08:01:45Z hselasky $ */ 2184610Salfred/*- 3184610Salfred * Copyright (c) 2007 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 27184610Salfred/* 28184610Salfred * This file contains sub-routines to build up USB descriptors from 29184610Salfred * USB templates. 30184610Salfred */ 31184610Salfred 32194677Sthompsa#include <sys/stdint.h> 33194677Sthompsa#include <sys/stddef.h> 34194677Sthompsa#include <sys/param.h> 35194677Sthompsa#include <sys/queue.h> 36194677Sthompsa#include <sys/types.h> 37194677Sthompsa#include <sys/systm.h> 38194677Sthompsa#include <sys/kernel.h> 39194677Sthompsa#include <sys/bus.h> 40194677Sthompsa#include <sys/module.h> 41194677Sthompsa#include <sys/lock.h> 42194677Sthompsa#include <sys/mutex.h> 43194677Sthompsa#include <sys/condvar.h> 44194677Sthompsa#include <sys/sysctl.h> 45194677Sthompsa#include <sys/sx.h> 46194677Sthompsa#include <sys/unistd.h> 47194677Sthompsa#include <sys/callout.h> 48194677Sthompsa#include <sys/malloc.h> 49194677Sthompsa#include <sys/priv.h> 50194677Sthompsa 51188942Sthompsa#include <dev/usb/usb.h> 52194677Sthompsa#include <dev/usb/usbdi.h> 53194677Sthompsa#include <dev/usb/usbdi_util.h> 54194677Sthompsa#include "usbdevs.h" 55194677Sthompsa 56188942Sthompsa#include <dev/usb/usb_cdc.h> 57188942Sthompsa#include <dev/usb/usb_core.h> 58194677Sthompsa#include <dev/usb/usb_dynamic.h> 59188942Sthompsa#include <dev/usb/usb_busdma.h> 60188942Sthompsa#include <dev/usb/usb_process.h> 61188942Sthompsa#include <dev/usb/usb_device.h> 62184610Salfred 63194677Sthompsa#define USB_DEBUG_VAR usb_debug 64194677Sthompsa#include <dev/usb/usb_debug.h> 65194677Sthompsa 66188942Sthompsa#include <dev/usb/usb_controller.h> 67188942Sthompsa#include <dev/usb/usb_bus.h> 68188942Sthompsa#include <dev/usb/template/usb_template.h> 69184610Salfred 70188942SthompsaMODULE_DEPEND(usb_template, usb, 1, 1, 1); 71188942SthompsaMODULE_VERSION(usb_template, 1); 72184610Salfred 73184610Salfred/* function prototypes */ 74184610Salfred 75194228Sthompsastatic void usb_make_raw_desc(struct usb_temp_setup *, const uint8_t *); 76194228Sthompsastatic void usb_make_endpoint_desc(struct usb_temp_setup *, 77192984Sthompsa const struct usb_temp_endpoint_desc *); 78194228Sthompsastatic void usb_make_interface_desc(struct usb_temp_setup *, 79192984Sthompsa const struct usb_temp_interface_desc *); 80194228Sthompsastatic void usb_make_config_desc(struct usb_temp_setup *, 81192984Sthompsa const struct usb_temp_config_desc *); 82194228Sthompsastatic void usb_make_device_desc(struct usb_temp_setup *, 83192984Sthompsa const struct usb_temp_device_desc *); 84194228Sthompsastatic uint8_t usb_hw_ep_match(const struct usb_hw_ep_profile *, uint8_t, 85185948Sthompsa uint8_t); 86194228Sthompsastatic uint8_t usb_hw_ep_find_match(struct usb_hw_ep_scratch *, 87192984Sthompsa struct usb_hw_ep_scratch_sub *, uint8_t); 88194228Sthompsastatic uint8_t usb_hw_ep_get_needs(struct usb_hw_ep_scratch *, uint8_t, 89185948Sthompsa uint8_t); 90194228Sthompsastatic usb_error_t usb_hw_ep_resolve(struct usb_device *, 91192984Sthompsa struct usb_descriptor *); 92194228Sthompsastatic const struct usb_temp_device_desc *usb_temp_get_tdd(struct usb_device *); 93194228Sthompsastatic void *usb_temp_get_device_desc(struct usb_device *); 94194228Sthompsastatic void *usb_temp_get_qualifier_desc(struct usb_device *); 95194228Sthompsastatic void *usb_temp_get_config_desc(struct usb_device *, uint16_t *, 96185948Sthompsa uint8_t); 97194228Sthompsastatic const void *usb_temp_get_string_desc(struct usb_device *, uint16_t, 98185948Sthompsa uint8_t); 99194228Sthompsastatic const void *usb_temp_get_vendor_desc(struct usb_device *, 100205030Sthompsa const struct usb_device_request *, uint16_t *plen); 101194228Sthompsastatic const void *usb_temp_get_hub_desc(struct usb_device *); 102194228Sthompsastatic usb_error_t usb_temp_get_desc(struct usb_device *, 103192984Sthompsa struct usb_device_request *, const void **, uint16_t *); 104194228Sthompsastatic usb_error_t usb_temp_setup_by_index(struct usb_device *, 105185948Sthompsa uint16_t index); 106194228Sthompsastatic void usb_temp_init(void *); 107184610Salfred 108184610Salfred/*------------------------------------------------------------------------* 109194228Sthompsa * usb_make_raw_desc 110184610Salfred * 111184610Salfred * This function will insert a raw USB descriptor into the generated 112184610Salfred * USB configuration. 113184610Salfred *------------------------------------------------------------------------*/ 114184610Salfredstatic void 115194228Sthompsausb_make_raw_desc(struct usb_temp_setup *temp, 116184610Salfred const uint8_t *raw) 117184610Salfred{ 118184610Salfred void *dst; 119184610Salfred uint8_t len; 120184610Salfred 121184610Salfred /* 122184610Salfred * The first byte of any USB descriptor gives the length. 123184610Salfred */ 124184610Salfred if (raw) { 125184610Salfred len = raw[0]; 126184610Salfred if (temp->buf) { 127184610Salfred dst = USB_ADD_BYTES(temp->buf, temp->size); 128218475Shselasky memcpy(dst, raw, len); 129184610Salfred 130184610Salfred /* check if we have got a CDC union descriptor */ 131184610Salfred 132192984Sthompsa if ((raw[0] >= sizeof(struct usb_cdc_union_descriptor)) && 133184610Salfred (raw[1] == UDESC_CS_INTERFACE) && 134184610Salfred (raw[2] == UDESCSUB_CDC_UNION)) { 135192984Sthompsa struct usb_cdc_union_descriptor *ud = (void *)dst; 136184610Salfred 137184610Salfred /* update the interface numbers */ 138184610Salfred 139184610Salfred ud->bMasterInterface += 140184610Salfred temp->bInterfaceNumber; 141184610Salfred ud->bSlaveInterface[0] += 142184610Salfred temp->bInterfaceNumber; 143184610Salfred } 144184610Salfred } 145184610Salfred temp->size += len; 146184610Salfred } 147184610Salfred} 148184610Salfred 149184610Salfred/*------------------------------------------------------------------------* 150194228Sthompsa * usb_make_endpoint_desc 151184610Salfred * 152184610Salfred * This function will generate an USB endpoint descriptor from the 153184610Salfred * given USB template endpoint descriptor, which will be inserted into 154184610Salfred * the USB configuration. 155184610Salfred *------------------------------------------------------------------------*/ 156184610Salfredstatic void 157194228Sthompsausb_make_endpoint_desc(struct usb_temp_setup *temp, 158192984Sthompsa const struct usb_temp_endpoint_desc *ted) 159184610Salfred{ 160192984Sthompsa struct usb_endpoint_descriptor *ed; 161184610Salfred const void **rd; 162184610Salfred uint16_t old_size; 163184610Salfred uint16_t mps; 164205033Sthompsa uint8_t ea; /* Endpoint Address */ 165205033Sthompsa uint8_t et; /* Endpiont Type */ 166184610Salfred 167184610Salfred /* Reserve memory */ 168184610Salfred old_size = temp->size; 169184610Salfred 170205033Sthompsa ea = (ted->bEndpointAddress & (UE_ADDR | UE_DIR_IN | UE_DIR_OUT)); 171205033Sthompsa et = (ted->bmAttributes & UE_XFERTYPE); 172205033Sthompsa 173205033Sthompsa if (et == UE_ISOCHRONOUS) { 174205033Sthompsa /* account for extra byte fields */ 175205033Sthompsa temp->size += sizeof(*ed) + 2; 176205033Sthompsa } else { 177205033Sthompsa temp->size += sizeof(*ed); 178205033Sthompsa } 179205033Sthompsa 180184610Salfred /* Scan all Raw Descriptors first */ 181184610Salfred rd = ted->ppRawDesc; 182184610Salfred if (rd) { 183184610Salfred while (*rd) { 184194228Sthompsa usb_make_raw_desc(temp, *rd); 185184610Salfred rd++; 186184610Salfred } 187184610Salfred } 188184610Salfred if (ted->pPacketSize == NULL) { 189184610Salfred /* not initialized */ 190184610Salfred temp->err = USB_ERR_INVAL; 191184610Salfred return; 192184610Salfred } 193192500Sthompsa mps = ted->pPacketSize->mps[temp->usb_speed]; 194184610Salfred if (mps == 0) { 195184610Salfred /* not initialized */ 196184610Salfred temp->err = USB_ERR_INVAL; 197184610Salfred return; 198184610Salfred } else if (mps == UE_ZERO_MPS) { 199184610Salfred /* escape for Zero Max Packet Size */ 200184610Salfred mps = 0; 201184610Salfred } 202184610Salfred 203184610Salfred /* 204184610Salfred * Fill out the real USB endpoint descriptor 205184610Salfred * in case there is a buffer present: 206184610Salfred */ 207184610Salfred if (temp->buf) { 208184610Salfred ed = USB_ADD_BYTES(temp->buf, old_size); 209205033Sthompsa if (et == UE_ISOCHRONOUS) 210205033Sthompsa ed->bLength = sizeof(*ed) + 2; 211205033Sthompsa else 212205033Sthompsa ed->bLength = sizeof(*ed); 213184610Salfred ed->bDescriptorType = UDESC_ENDPOINT; 214184610Salfred ed->bEndpointAddress = ea; 215184610Salfred ed->bmAttributes = ted->bmAttributes; 216184610Salfred USETW(ed->wMaxPacketSize, mps); 217184610Salfred 218184610Salfred /* setup bInterval parameter */ 219184610Salfred 220184610Salfred if (ted->pIntervals && 221192500Sthompsa ted->pIntervals->bInterval[temp->usb_speed]) { 222184610Salfred ed->bInterval = 223192500Sthompsa ted->pIntervals->bInterval[temp->usb_speed]; 224184610Salfred } else { 225184610Salfred switch (et) { 226184610Salfred case UE_BULK: 227184610Salfred case UE_CONTROL: 228184610Salfred ed->bInterval = 0; /* not used */ 229184610Salfred break; 230184610Salfred case UE_INTERRUPT: 231192500Sthompsa switch (temp->usb_speed) { 232184610Salfred case USB_SPEED_LOW: 233184610Salfred case USB_SPEED_FULL: 234184610Salfred ed->bInterval = 1; /* 1 ms */ 235184610Salfred break; 236184610Salfred default: 237184610Salfred ed->bInterval = 8; /* 8*125 us */ 238184610Salfred break; 239184610Salfred } 240184610Salfred break; 241184610Salfred default: /* UE_ISOCHRONOUS */ 242192500Sthompsa switch (temp->usb_speed) { 243184610Salfred case USB_SPEED_LOW: 244184610Salfred case USB_SPEED_FULL: 245184610Salfred ed->bInterval = 1; /* 1 ms */ 246184610Salfred break; 247184610Salfred default: 248184610Salfred ed->bInterval = 1; /* 125 us */ 249184610Salfred break; 250184610Salfred } 251184610Salfred break; 252184610Salfred } 253184610Salfred } 254184610Salfred } 255184610Salfred temp->bNumEndpoints++; 256184610Salfred} 257184610Salfred 258184610Salfred/*------------------------------------------------------------------------* 259194228Sthompsa * usb_make_interface_desc 260184610Salfred * 261184610Salfred * This function will generate an USB interface descriptor from the 262184610Salfred * given USB template interface descriptor, which will be inserted 263184610Salfred * into the USB configuration. 264184610Salfred *------------------------------------------------------------------------*/ 265184610Salfredstatic void 266194228Sthompsausb_make_interface_desc(struct usb_temp_setup *temp, 267192984Sthompsa const struct usb_temp_interface_desc *tid) 268184610Salfred{ 269192984Sthompsa struct usb_interface_descriptor *id; 270192984Sthompsa const struct usb_temp_endpoint_desc **ted; 271184610Salfred const void **rd; 272184610Salfred uint16_t old_size; 273184610Salfred 274184610Salfred /* Reserve memory */ 275184610Salfred 276184610Salfred old_size = temp->size; 277184610Salfred temp->size += sizeof(*id); 278184610Salfred 279184610Salfred /* Update interface and alternate interface numbers */ 280184610Salfred 281184610Salfred if (tid->isAltInterface == 0) { 282184610Salfred temp->bAlternateSetting = 0; 283184610Salfred temp->bInterfaceNumber++; 284184610Salfred } else { 285184610Salfred temp->bAlternateSetting++; 286184610Salfred } 287184610Salfred 288184610Salfred /* Scan all Raw Descriptors first */ 289184610Salfred 290184610Salfred rd = tid->ppRawDesc; 291184610Salfred 292184610Salfred if (rd) { 293184610Salfred while (*rd) { 294194228Sthompsa usb_make_raw_desc(temp, *rd); 295184610Salfred rd++; 296184610Salfred } 297184610Salfred } 298184610Salfred /* Reset some counters */ 299184610Salfred 300184610Salfred temp->bNumEndpoints = 0; 301184610Salfred 302184610Salfred /* Scan all Endpoint Descriptors second */ 303184610Salfred 304184610Salfred ted = tid->ppEndpoints; 305184610Salfred if (ted) { 306184610Salfred while (*ted) { 307194228Sthompsa usb_make_endpoint_desc(temp, *ted); 308184610Salfred ted++; 309184610Salfred } 310184610Salfred } 311184610Salfred /* 312184610Salfred * Fill out the real USB interface descriptor 313184610Salfred * in case there is a buffer present: 314184610Salfred */ 315184610Salfred if (temp->buf) { 316184610Salfred id = USB_ADD_BYTES(temp->buf, old_size); 317184610Salfred id->bLength = sizeof(*id); 318184610Salfred id->bDescriptorType = UDESC_INTERFACE; 319184610Salfred id->bInterfaceNumber = temp->bInterfaceNumber; 320184610Salfred id->bAlternateSetting = temp->bAlternateSetting; 321184610Salfred id->bNumEndpoints = temp->bNumEndpoints; 322184610Salfred id->bInterfaceClass = tid->bInterfaceClass; 323184610Salfred id->bInterfaceSubClass = tid->bInterfaceSubClass; 324184610Salfred id->bInterfaceProtocol = tid->bInterfaceProtocol; 325184610Salfred id->iInterface = tid->iInterface; 326184610Salfred } 327184610Salfred} 328184610Salfred 329184610Salfred/*------------------------------------------------------------------------* 330194228Sthompsa * usb_make_config_desc 331184610Salfred * 332184610Salfred * This function will generate an USB config descriptor from the given 333184610Salfred * USB template config descriptor, which will be inserted into the USB 334184610Salfred * configuration. 335184610Salfred *------------------------------------------------------------------------*/ 336184610Salfredstatic void 337194228Sthompsausb_make_config_desc(struct usb_temp_setup *temp, 338192984Sthompsa const struct usb_temp_config_desc *tcd) 339184610Salfred{ 340192984Sthompsa struct usb_config_descriptor *cd; 341192984Sthompsa const struct usb_temp_interface_desc **tid; 342184610Salfred uint16_t old_size; 343184610Salfred 344184610Salfred /* Reserve memory */ 345184610Salfred 346184610Salfred old_size = temp->size; 347184610Salfred temp->size += sizeof(*cd); 348184610Salfred 349184610Salfred /* Reset some counters */ 350184610Salfred 351184610Salfred temp->bInterfaceNumber = 0 - 1; 352184610Salfred temp->bAlternateSetting = 0; 353184610Salfred 354184610Salfred /* Scan all the USB interfaces */ 355184610Salfred 356184610Salfred tid = tcd->ppIfaceDesc; 357184610Salfred if (tid) { 358184610Salfred while (*tid) { 359194228Sthompsa usb_make_interface_desc(temp, *tid); 360184610Salfred tid++; 361184610Salfred } 362184610Salfred } 363184610Salfred /* 364184610Salfred * Fill out the real USB config descriptor 365184610Salfred * in case there is a buffer present: 366184610Salfred */ 367184610Salfred if (temp->buf) { 368184610Salfred cd = USB_ADD_BYTES(temp->buf, old_size); 369184610Salfred 370184610Salfred /* compute total size */ 371184610Salfred old_size = temp->size - old_size; 372184610Salfred 373184610Salfred cd->bLength = sizeof(*cd); 374184610Salfred cd->bDescriptorType = UDESC_CONFIG; 375184610Salfred USETW(cd->wTotalLength, old_size); 376184610Salfred cd->bNumInterface = temp->bInterfaceNumber + 1; 377184610Salfred cd->bConfigurationValue = temp->bConfigurationValue; 378184610Salfred cd->iConfiguration = tcd->iConfiguration; 379184610Salfred cd->bmAttributes = tcd->bmAttributes; 380184610Salfred cd->bMaxPower = tcd->bMaxPower; 381184610Salfred cd->bmAttributes |= (UC_REMOTE_WAKEUP | UC_BUS_POWERED); 382184610Salfred 383184610Salfred if (temp->self_powered) { 384184610Salfred cd->bmAttributes |= UC_SELF_POWERED; 385184610Salfred } else { 386184610Salfred cd->bmAttributes &= ~UC_SELF_POWERED; 387184610Salfred } 388184610Salfred } 389184610Salfred} 390184610Salfred 391184610Salfred/*------------------------------------------------------------------------* 392194228Sthompsa * usb_make_device_desc 393184610Salfred * 394184610Salfred * This function will generate an USB device descriptor from the 395184610Salfred * given USB template device descriptor. 396184610Salfred *------------------------------------------------------------------------*/ 397184610Salfredstatic void 398194228Sthompsausb_make_device_desc(struct usb_temp_setup *temp, 399192984Sthompsa const struct usb_temp_device_desc *tdd) 400184610Salfred{ 401192984Sthompsa struct usb_temp_data *utd; 402192984Sthompsa const struct usb_temp_config_desc **tcd; 403184610Salfred uint16_t old_size; 404184610Salfred 405184610Salfred /* Reserve memory */ 406184610Salfred 407184610Salfred old_size = temp->size; 408184610Salfred temp->size += sizeof(*utd); 409184610Salfred 410184610Salfred /* Scan all the USB configs */ 411184610Salfred 412184610Salfred temp->bConfigurationValue = 1; 413184610Salfred tcd = tdd->ppConfigDesc; 414184610Salfred if (tcd) { 415184610Salfred while (*tcd) { 416194228Sthompsa usb_make_config_desc(temp, *tcd); 417184610Salfred temp->bConfigurationValue++; 418184610Salfred tcd++; 419184610Salfred } 420184610Salfred } 421184610Salfred /* 422184610Salfred * Fill out the real USB device descriptor 423184610Salfred * in case there is a buffer present: 424184610Salfred */ 425184610Salfred 426184610Salfred if (temp->buf) { 427184610Salfred utd = USB_ADD_BYTES(temp->buf, old_size); 428184610Salfred 429184610Salfred /* Store a pointer to our template device descriptor */ 430184610Salfred utd->tdd = tdd; 431184610Salfred 432184610Salfred /* Fill out USB device descriptor */ 433184610Salfred utd->udd.bLength = sizeof(utd->udd); 434184610Salfred utd->udd.bDescriptorType = UDESC_DEVICE; 435184610Salfred utd->udd.bDeviceClass = tdd->bDeviceClass; 436184610Salfred utd->udd.bDeviceSubClass = tdd->bDeviceSubClass; 437184610Salfred utd->udd.bDeviceProtocol = tdd->bDeviceProtocol; 438184610Salfred USETW(utd->udd.idVendor, tdd->idVendor); 439184610Salfred USETW(utd->udd.idProduct, tdd->idProduct); 440184610Salfred USETW(utd->udd.bcdDevice, tdd->bcdDevice); 441184610Salfred utd->udd.iManufacturer = tdd->iManufacturer; 442184610Salfred utd->udd.iProduct = tdd->iProduct; 443184610Salfred utd->udd.iSerialNumber = tdd->iSerialNumber; 444184610Salfred utd->udd.bNumConfigurations = temp->bConfigurationValue - 1; 445184610Salfred 446184610Salfred /* 447184610Salfred * Fill out the USB device qualifier. Pretend that we 448184610Salfred * don't support any other speeds by setting 449184610Salfred * "bNumConfigurations" equal to zero. That saves us 450184610Salfred * generating an extra set of configuration 451184610Salfred * descriptors. 452184610Salfred */ 453184610Salfred utd->udq.bLength = sizeof(utd->udq); 454184610Salfred utd->udq.bDescriptorType = UDESC_DEVICE_QUALIFIER; 455184610Salfred utd->udq.bDeviceClass = tdd->bDeviceClass; 456184610Salfred utd->udq.bDeviceSubClass = tdd->bDeviceSubClass; 457184610Salfred utd->udq.bDeviceProtocol = tdd->bDeviceProtocol; 458184610Salfred utd->udq.bNumConfigurations = 0; 459184610Salfred USETW(utd->udq.bcdUSB, 0x0200); 460184610Salfred utd->udq.bMaxPacketSize0 = 0; 461184610Salfred 462192500Sthompsa switch (temp->usb_speed) { 463184610Salfred case USB_SPEED_LOW: 464184610Salfred USETW(utd->udd.bcdUSB, 0x0110); 465184610Salfred utd->udd.bMaxPacketSize = 8; 466184610Salfred break; 467184610Salfred case USB_SPEED_FULL: 468184610Salfred USETW(utd->udd.bcdUSB, 0x0110); 469184610Salfred utd->udd.bMaxPacketSize = 32; 470184610Salfred break; 471184610Salfred case USB_SPEED_HIGH: 472184610Salfred USETW(utd->udd.bcdUSB, 0x0200); 473184610Salfred utd->udd.bMaxPacketSize = 64; 474184610Salfred break; 475184610Salfred case USB_SPEED_VARIABLE: 476184610Salfred USETW(utd->udd.bcdUSB, 0x0250); 477184610Salfred utd->udd.bMaxPacketSize = 255; /* 512 bytes */ 478184610Salfred break; 479184610Salfred default: 480184610Salfred temp->err = USB_ERR_INVAL; 481184610Salfred break; 482184610Salfred } 483184610Salfred } 484184610Salfred} 485184610Salfred 486184610Salfred/*------------------------------------------------------------------------* 487194228Sthompsa * usb_hw_ep_match 488184610Salfred * 489184610Salfred * Return values: 490184610Salfred * 0: The endpoint profile does not match the criterias 491184610Salfred * Else: The endpoint profile matches the criterias 492184610Salfred *------------------------------------------------------------------------*/ 493184610Salfredstatic uint8_t 494194228Sthompsausb_hw_ep_match(const struct usb_hw_ep_profile *pf, 495184610Salfred uint8_t ep_type, uint8_t ep_dir_in) 496184610Salfred{ 497184610Salfred if (ep_type == UE_CONTROL) { 498184610Salfred /* special */ 499184610Salfred return (pf->support_control); 500184610Salfred } 501184610Salfred if ((pf->support_in && ep_dir_in) || 502184610Salfred (pf->support_out && !ep_dir_in)) { 503184610Salfred if ((pf->support_interrupt && (ep_type == UE_INTERRUPT)) || 504184610Salfred (pf->support_isochronous && (ep_type == UE_ISOCHRONOUS)) || 505184610Salfred (pf->support_bulk && (ep_type == UE_BULK))) { 506184610Salfred return (1); 507184610Salfred } 508184610Salfred } 509184610Salfred return (0); 510184610Salfred} 511184610Salfred 512184610Salfred/*------------------------------------------------------------------------* 513194228Sthompsa * usb_hw_ep_find_match 514184610Salfred * 515184610Salfred * This function is used to find the best matching endpoint profile 516184610Salfred * for and endpoint belonging to an USB descriptor. 517184610Salfred * 518184610Salfred * Return values: 519184610Salfred * 0: Success. Got a match. 520184610Salfred * Else: Failure. No match. 521184610Salfred *------------------------------------------------------------------------*/ 522184610Salfredstatic uint8_t 523194228Sthompsausb_hw_ep_find_match(struct usb_hw_ep_scratch *ues, 524192984Sthompsa struct usb_hw_ep_scratch_sub *ep, uint8_t is_simplex) 525184610Salfred{ 526192984Sthompsa const struct usb_hw_ep_profile *pf; 527184610Salfred uint16_t distance; 528184610Salfred uint16_t temp; 529184610Salfred uint16_t max_frame_size; 530184610Salfred uint8_t n; 531184610Salfred uint8_t best_n; 532184610Salfred uint8_t dir_in; 533184610Salfred uint8_t dir_out; 534184610Salfred 535184610Salfred distance = 0xFFFF; 536184610Salfred best_n = 0; 537184610Salfred 538184610Salfred if ((!ep->needs_in) && (!ep->needs_out)) { 539184610Salfred return (0); /* we are done */ 540184610Salfred } 541184610Salfred if (ep->needs_ep_type == UE_CONTROL) { 542184610Salfred dir_in = 1; 543184610Salfred dir_out = 1; 544184610Salfred } else { 545184610Salfred if (ep->needs_in) { 546184610Salfred dir_in = 1; 547184610Salfred dir_out = 0; 548184610Salfred } else { 549184610Salfred dir_in = 0; 550184610Salfred dir_out = 1; 551184610Salfred } 552184610Salfred } 553184610Salfred 554184610Salfred for (n = 1; n != (USB_EP_MAX / 2); n++) { 555184610Salfred 556184610Salfred /* get HW endpoint profile */ 557184610Salfred (ues->methods->get_hw_ep_profile) (ues->udev, &pf, n); 558184610Salfred if (pf == NULL) { 559184610Salfred /* end of profiles */ 560184610Salfred break; 561184610Salfred } 562184610Salfred /* check if IN-endpoint is reserved */ 563184610Salfred if (dir_in || pf->is_simplex) { 564184610Salfred if (ues->bmInAlloc[n / 8] & (1 << (n % 8))) { 565184610Salfred /* mismatch */ 566184610Salfred continue; 567184610Salfred } 568184610Salfred } 569184610Salfred /* check if OUT-endpoint is reserved */ 570184610Salfred if (dir_out || pf->is_simplex) { 571184610Salfred if (ues->bmOutAlloc[n / 8] & (1 << (n % 8))) { 572184610Salfred /* mismatch */ 573184610Salfred continue; 574184610Salfred } 575184610Salfred } 576184610Salfred /* check simplex */ 577184610Salfred if (pf->is_simplex == is_simplex) { 578184610Salfred /* mismatch */ 579184610Salfred continue; 580184610Salfred } 581184610Salfred /* check if HW endpoint matches */ 582194228Sthompsa if (!usb_hw_ep_match(pf, ep->needs_ep_type, dir_in)) { 583184610Salfred /* mismatch */ 584184610Salfred continue; 585184610Salfred } 586184610Salfred /* get maximum frame size */ 587184610Salfred if (dir_in) 588184610Salfred max_frame_size = pf->max_in_frame_size; 589184610Salfred else 590184610Salfred max_frame_size = pf->max_out_frame_size; 591184610Salfred 592184610Salfred /* check if we have a matching profile */ 593184610Salfred if (max_frame_size >= ep->max_frame_size) { 594184610Salfred temp = (max_frame_size - ep->max_frame_size); 595184610Salfred if (distance > temp) { 596184610Salfred distance = temp; 597184610Salfred best_n = n; 598184610Salfred ep->pf = pf; 599184610Salfred } 600184610Salfred } 601184610Salfred } 602184610Salfred 603184610Salfred /* see if we got a match */ 604184610Salfred if (best_n != 0) { 605184610Salfred /* get the correct profile */ 606184610Salfred pf = ep->pf; 607184610Salfred 608184610Salfred /* reserve IN-endpoint */ 609184610Salfred if (dir_in) { 610184610Salfred ues->bmInAlloc[best_n / 8] |= 611184610Salfred (1 << (best_n % 8)); 612184610Salfred ep->hw_endpoint_in = best_n | UE_DIR_IN; 613184610Salfred ep->needs_in = 0; 614184610Salfred } 615184610Salfred /* reserve OUT-endpoint */ 616184610Salfred if (dir_out) { 617184610Salfred ues->bmOutAlloc[best_n / 8] |= 618184610Salfred (1 << (best_n % 8)); 619184610Salfred ep->hw_endpoint_out = best_n | UE_DIR_OUT; 620184610Salfred ep->needs_out = 0; 621184610Salfred } 622184610Salfred return (0); /* got a match */ 623184610Salfred } 624184610Salfred return (1); /* failure */ 625184610Salfred} 626184610Salfred 627184610Salfred/*------------------------------------------------------------------------* 628194228Sthompsa * usb_hw_ep_get_needs 629184610Salfred * 630184610Salfred * This function will figure out the type and number of endpoints 631184610Salfred * which are needed for an USB configuration. 632184610Salfred * 633184610Salfred * Return values: 634184610Salfred * 0: Success. 635184610Salfred * Else: Failure. 636184610Salfred *------------------------------------------------------------------------*/ 637184610Salfredstatic uint8_t 638194228Sthompsausb_hw_ep_get_needs(struct usb_hw_ep_scratch *ues, 639184610Salfred uint8_t ep_type, uint8_t is_complete) 640184610Salfred{ 641192984Sthompsa const struct usb_hw_ep_profile *pf; 642192984Sthompsa struct usb_hw_ep_scratch_sub *ep_iface; 643192984Sthompsa struct usb_hw_ep_scratch_sub *ep_curr; 644192984Sthompsa struct usb_hw_ep_scratch_sub *ep_max; 645192984Sthompsa struct usb_hw_ep_scratch_sub *ep_end; 646192984Sthompsa struct usb_descriptor *desc; 647192984Sthompsa struct usb_interface_descriptor *id; 648192984Sthompsa struct usb_endpoint_descriptor *ed; 649192500Sthompsa enum usb_dev_speed speed; 650184610Salfred uint16_t wMaxPacketSize; 651184610Salfred uint16_t temp; 652184610Salfred uint8_t ep_no; 653184610Salfred 654184610Salfred ep_iface = ues->ep_max; 655184610Salfred ep_curr = ues->ep_max; 656184610Salfred ep_end = ues->ep + USB_EP_MAX; 657184610Salfred ep_max = ues->ep_max; 658184610Salfred desc = NULL; 659194228Sthompsa speed = usbd_get_speed(ues->udev); 660184610Salfred 661184610Salfredrepeat: 662184610Salfred 663194228Sthompsa while ((desc = usb_desc_foreach(ues->cd, desc))) { 664184610Salfred 665184610Salfred if ((desc->bDescriptorType == UDESC_INTERFACE) && 666184610Salfred (desc->bLength >= sizeof(*id))) { 667184610Salfred 668184610Salfred id = (void *)desc; 669184610Salfred 670184610Salfred if (id->bAlternateSetting == 0) { 671184610Salfred /* going forward */ 672184610Salfred ep_iface = ep_max; 673184610Salfred } else { 674184610Salfred /* reset */ 675184610Salfred ep_curr = ep_iface; 676184610Salfred } 677184610Salfred } 678184610Salfred if ((desc->bDescriptorType == UDESC_ENDPOINT) && 679184610Salfred (desc->bLength >= sizeof(*ed))) { 680184610Salfred 681184610Salfred ed = (void *)desc; 682184610Salfred 683184610Salfred goto handle_endpoint_desc; 684184610Salfred } 685184610Salfred } 686184610Salfred ues->ep_max = ep_max; 687184610Salfred return (0); 688184610Salfred 689184610Salfredhandle_endpoint_desc: 690184610Salfred temp = (ed->bmAttributes & UE_XFERTYPE); 691184610Salfred 692184610Salfred if (temp == ep_type) { 693184610Salfred 694184610Salfred if (ep_curr == ep_end) { 695184610Salfred /* too many endpoints */ 696184610Salfred return (1); /* failure */ 697184610Salfred } 698184610Salfred wMaxPacketSize = UGETW(ed->wMaxPacketSize); 699184610Salfred if ((wMaxPacketSize & 0xF800) && 700184610Salfred (speed == USB_SPEED_HIGH)) { 701184610Salfred /* handle packet multiplier */ 702184610Salfred temp = (wMaxPacketSize >> 11) & 3; 703184610Salfred wMaxPacketSize &= 0x7FF; 704184610Salfred if (temp == 1) { 705184610Salfred wMaxPacketSize *= 2; 706184610Salfred } else { 707184610Salfred wMaxPacketSize *= 3; 708184610Salfred } 709184610Salfred } 710184610Salfred /* 711184610Salfred * Check if we have a fixed endpoint number, else the 712184610Salfred * endpoint number is allocated dynamically: 713184610Salfred */ 714184610Salfred ep_no = (ed->bEndpointAddress & UE_ADDR); 715184610Salfred if (ep_no != 0) { 716184610Salfred 717184610Salfred /* get HW endpoint profile */ 718184610Salfred (ues->methods->get_hw_ep_profile) 719184610Salfred (ues->udev, &pf, ep_no); 720184610Salfred if (pf == NULL) { 721184610Salfred /* HW profile does not exist - failure */ 722184610Salfred DPRINTFN(0, "Endpoint profile %u " 723184610Salfred "does not exist\n", ep_no); 724184610Salfred return (1); 725184610Salfred } 726184610Salfred /* reserve fixed endpoint number */ 727184610Salfred if (ep_type == UE_CONTROL) { 728184610Salfred ues->bmInAlloc[ep_no / 8] |= 729184610Salfred (1 << (ep_no % 8)); 730184610Salfred ues->bmOutAlloc[ep_no / 8] |= 731184610Salfred (1 << (ep_no % 8)); 732184610Salfred if ((pf->max_in_frame_size < wMaxPacketSize) || 733184610Salfred (pf->max_out_frame_size < wMaxPacketSize)) { 734184610Salfred DPRINTFN(0, "Endpoint profile %u " 735199816Sthompsa "has too small buffer\n", ep_no); 736184610Salfred return (1); 737184610Salfred } 738184610Salfred } else if (ed->bEndpointAddress & UE_DIR_IN) { 739184610Salfred ues->bmInAlloc[ep_no / 8] |= 740184610Salfred (1 << (ep_no % 8)); 741184610Salfred if (pf->max_in_frame_size < wMaxPacketSize) { 742184610Salfred DPRINTFN(0, "Endpoint profile %u " 743199816Sthompsa "has too small buffer\n", ep_no); 744184610Salfred return (1); 745184610Salfred } 746184610Salfred } else { 747184610Salfred ues->bmOutAlloc[ep_no / 8] |= 748184610Salfred (1 << (ep_no % 8)); 749184610Salfred if (pf->max_out_frame_size < wMaxPacketSize) { 750184610Salfred DPRINTFN(0, "Endpoint profile %u " 751199816Sthompsa "has too small buffer\n", ep_no); 752184610Salfred return (1); 753184610Salfred } 754184610Salfred } 755184610Salfred } else if (is_complete) { 756184610Salfred 757184610Salfred /* check if we have enough buffer space */ 758184610Salfred if (wMaxPacketSize > 759184610Salfred ep_curr->max_frame_size) { 760184610Salfred return (1); /* failure */ 761184610Salfred } 762184610Salfred if (ed->bEndpointAddress & UE_DIR_IN) { 763184610Salfred ed->bEndpointAddress = 764184610Salfred ep_curr->hw_endpoint_in; 765184610Salfred } else { 766184610Salfred ed->bEndpointAddress = 767184610Salfred ep_curr->hw_endpoint_out; 768184610Salfred } 769184610Salfred 770184610Salfred } else { 771184610Salfred 772184610Salfred /* compute the maximum frame size */ 773184610Salfred if (ep_curr->max_frame_size < wMaxPacketSize) { 774184610Salfred ep_curr->max_frame_size = wMaxPacketSize; 775184610Salfred } 776184610Salfred if (temp == UE_CONTROL) { 777184610Salfred ep_curr->needs_in = 1; 778184610Salfred ep_curr->needs_out = 1; 779184610Salfred } else { 780184610Salfred if (ed->bEndpointAddress & UE_DIR_IN) { 781184610Salfred ep_curr->needs_in = 1; 782184610Salfred } else { 783184610Salfred ep_curr->needs_out = 1; 784184610Salfred } 785184610Salfred } 786184610Salfred ep_curr->needs_ep_type = ep_type; 787184610Salfred } 788184610Salfred 789184610Salfred ep_curr++; 790184610Salfred if (ep_max < ep_curr) { 791184610Salfred ep_max = ep_curr; 792184610Salfred } 793184610Salfred } 794184610Salfred goto repeat; 795184610Salfred} 796184610Salfred 797184610Salfred/*------------------------------------------------------------------------* 798194228Sthompsa * usb_hw_ep_resolve 799184610Salfred * 800184610Salfred * This function will try to resolve endpoint requirements by the 801184610Salfred * given endpoint profiles that the USB hardware reports. 802184610Salfred * 803184610Salfred * Return values: 804184610Salfred * 0: Success 805184610Salfred * Else: Failure 806184610Salfred *------------------------------------------------------------------------*/ 807193045Sthompsastatic usb_error_t 808194228Sthompsausb_hw_ep_resolve(struct usb_device *udev, 809192984Sthompsa struct usb_descriptor *desc) 810184610Salfred{ 811192984Sthompsa struct usb_hw_ep_scratch *ues; 812192984Sthompsa struct usb_hw_ep_scratch_sub *ep; 813192984Sthompsa const struct usb_hw_ep_profile *pf; 814192984Sthompsa struct usb_bus_methods *methods; 815192984Sthompsa struct usb_device_descriptor *dd; 816184610Salfred uint16_t mps; 817184610Salfred 818184610Salfred if (desc == NULL) { 819184610Salfred return (USB_ERR_INVAL); 820184610Salfred } 821184610Salfred /* get bus methods */ 822184610Salfred methods = udev->bus->methods; 823184610Salfred 824184610Salfred if (methods->get_hw_ep_profile == NULL) { 825184610Salfred return (USB_ERR_INVAL); 826184610Salfred } 827184610Salfred if (desc->bDescriptorType == UDESC_DEVICE) { 828184610Salfred 829184610Salfred if (desc->bLength < sizeof(*dd)) { 830184610Salfred return (USB_ERR_INVAL); 831184610Salfred } 832184610Salfred dd = (void *)desc; 833184610Salfred 834184610Salfred /* get HW control endpoint 0 profile */ 835184610Salfred (methods->get_hw_ep_profile) (udev, &pf, 0); 836184610Salfred if (pf == NULL) { 837184610Salfred return (USB_ERR_INVAL); 838184610Salfred } 839194228Sthompsa if (!usb_hw_ep_match(pf, UE_CONTROL, 0)) { 840184610Salfred DPRINTFN(0, "Endpoint 0 does not " 841184610Salfred "support control\n"); 842184610Salfred return (USB_ERR_INVAL); 843184610Salfred } 844184610Salfred mps = dd->bMaxPacketSize; 845184610Salfred 846184610Salfred if (udev->speed == USB_SPEED_FULL) { 847184610Salfred /* 848184610Salfred * We can optionally choose another packet size ! 849184610Salfred */ 850184610Salfred while (1) { 851184610Salfred /* check if "mps" is ok */ 852184610Salfred if (pf->max_in_frame_size >= mps) { 853184610Salfred break; 854184610Salfred } 855184610Salfred /* reduce maximum packet size */ 856184610Salfred mps /= 2; 857184610Salfred 858184610Salfred /* check if "mps" is too small */ 859184610Salfred if (mps < 8) { 860184610Salfred return (USB_ERR_INVAL); 861184610Salfred } 862184610Salfred } 863184610Salfred 864184610Salfred dd->bMaxPacketSize = mps; 865184610Salfred 866184610Salfred } else { 867184610Salfred /* We only have one choice */ 868184610Salfred if (mps == 255) { 869184610Salfred mps = 512; 870184610Salfred } 871184610Salfred /* Check if we support the specified wMaxPacketSize */ 872184610Salfred if (pf->max_in_frame_size < mps) { 873184610Salfred return (USB_ERR_INVAL); 874184610Salfred } 875184610Salfred } 876184610Salfred return (0); /* success */ 877184610Salfred } 878184610Salfred if (desc->bDescriptorType != UDESC_CONFIG) { 879184610Salfred return (USB_ERR_INVAL); 880184610Salfred } 881184610Salfred if (desc->bLength < sizeof(*(ues->cd))) { 882184610Salfred return (USB_ERR_INVAL); 883184610Salfred } 884184610Salfred ues = udev->bus->scratch[0].hw_ep_scratch; 885184610Salfred 886184610Salfred bzero(ues, sizeof(*ues)); 887184610Salfred 888184610Salfred ues->ep_max = ues->ep; 889184610Salfred ues->cd = (void *)desc; 890184610Salfred ues->methods = methods; 891184610Salfred ues->udev = udev; 892184610Salfred 893184610Salfred /* Get all the endpoints we need */ 894184610Salfred 895194228Sthompsa if (usb_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 0) || 896194228Sthompsa usb_hw_ep_get_needs(ues, UE_INTERRUPT, 0) || 897194228Sthompsa usb_hw_ep_get_needs(ues, UE_CONTROL, 0) || 898194228Sthompsa usb_hw_ep_get_needs(ues, UE_BULK, 0)) { 899184610Salfred DPRINTFN(0, "Could not get needs\n"); 900184610Salfred return (USB_ERR_INVAL); 901184610Salfred } 902184610Salfred for (ep = ues->ep; ep != ues->ep_max; ep++) { 903184610Salfred 904184610Salfred while (ep->needs_in || ep->needs_out) { 905184610Salfred 906184610Salfred /* 907184610Salfred * First try to use a simplex endpoint. 908184610Salfred * Then try to use a duplex endpoint. 909184610Salfred */ 910194228Sthompsa if (usb_hw_ep_find_match(ues, ep, 1) && 911194228Sthompsa usb_hw_ep_find_match(ues, ep, 0)) { 912184610Salfred DPRINTFN(0, "Could not find match\n"); 913184610Salfred return (USB_ERR_INVAL); 914184610Salfred } 915184610Salfred } 916184610Salfred } 917184610Salfred 918184610Salfred ues->ep_max = ues->ep; 919184610Salfred 920184610Salfred /* Update all endpoint addresses */ 921184610Salfred 922194228Sthompsa if (usb_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 1) || 923194228Sthompsa usb_hw_ep_get_needs(ues, UE_INTERRUPT, 1) || 924194228Sthompsa usb_hw_ep_get_needs(ues, UE_CONTROL, 1) || 925194228Sthompsa usb_hw_ep_get_needs(ues, UE_BULK, 1)) { 926184610Salfred DPRINTFN(0, "Could not update endpoint address\n"); 927184610Salfred return (USB_ERR_INVAL); 928184610Salfred } 929184610Salfred return (0); /* success */ 930184610Salfred} 931184610Salfred 932184610Salfred/*------------------------------------------------------------------------* 933194228Sthompsa * usb_temp_get_tdd 934184610Salfred * 935184610Salfred * Returns: 936184610Salfred * NULL: No USB template device descriptor found. 937184610Salfred * Else: Pointer to the USB template device descriptor. 938184610Salfred *------------------------------------------------------------------------*/ 939192984Sthompsastatic const struct usb_temp_device_desc * 940194228Sthompsausb_temp_get_tdd(struct usb_device *udev) 941184610Salfred{ 942194228Sthompsa if (udev->usb_template_ptr == NULL) { 943184610Salfred return (NULL); 944184610Salfred } 945194228Sthompsa return (udev->usb_template_ptr->tdd); 946184610Salfred} 947184610Salfred 948184610Salfred/*------------------------------------------------------------------------* 949194228Sthompsa * usb_temp_get_device_desc 950184610Salfred * 951184610Salfred * Returns: 952184610Salfred * NULL: No USB device descriptor found. 953184610Salfred * Else: Pointer to USB device descriptor. 954184610Salfred *------------------------------------------------------------------------*/ 955184610Salfredstatic void * 956194228Sthompsausb_temp_get_device_desc(struct usb_device *udev) 957184610Salfred{ 958192984Sthompsa struct usb_device_descriptor *dd; 959184610Salfred 960194228Sthompsa if (udev->usb_template_ptr == NULL) { 961184610Salfred return (NULL); 962184610Salfred } 963194228Sthompsa dd = &udev->usb_template_ptr->udd; 964184610Salfred if (dd->bDescriptorType != UDESC_DEVICE) { 965184610Salfred /* sanity check failed */ 966184610Salfred return (NULL); 967184610Salfred } 968184610Salfred return (dd); 969184610Salfred} 970184610Salfred 971184610Salfred/*------------------------------------------------------------------------* 972194228Sthompsa * usb_temp_get_qualifier_desc 973184610Salfred * 974184610Salfred * Returns: 975184610Salfred * NULL: No USB device_qualifier descriptor found. 976184610Salfred * Else: Pointer to USB device_qualifier descriptor. 977184610Salfred *------------------------------------------------------------------------*/ 978184610Salfredstatic void * 979194228Sthompsausb_temp_get_qualifier_desc(struct usb_device *udev) 980184610Salfred{ 981192984Sthompsa struct usb_device_qualifier *dq; 982184610Salfred 983194228Sthompsa if (udev->usb_template_ptr == NULL) { 984184610Salfred return (NULL); 985184610Salfred } 986194228Sthompsa dq = &udev->usb_template_ptr->udq; 987184610Salfred if (dq->bDescriptorType != UDESC_DEVICE_QUALIFIER) { 988184610Salfred /* sanity check failed */ 989184610Salfred return (NULL); 990184610Salfred } 991184610Salfred return (dq); 992184610Salfred} 993184610Salfred 994184610Salfred/*------------------------------------------------------------------------* 995194228Sthompsa * usb_temp_get_config_desc 996184610Salfred * 997184610Salfred * Returns: 998184610Salfred * NULL: No USB config descriptor found. 999184610Salfred * Else: Pointer to USB config descriptor having index "index". 1000184610Salfred *------------------------------------------------------------------------*/ 1001184610Salfredstatic void * 1002194228Sthompsausb_temp_get_config_desc(struct usb_device *udev, 1003184610Salfred uint16_t *pLength, uint8_t index) 1004184610Salfred{ 1005192984Sthompsa struct usb_device_descriptor *dd; 1006192984Sthompsa struct usb_config_descriptor *cd; 1007184610Salfred uint16_t temp; 1008184610Salfred 1009194228Sthompsa if (udev->usb_template_ptr == NULL) { 1010184610Salfred return (NULL); 1011184610Salfred } 1012194228Sthompsa dd = &udev->usb_template_ptr->udd; 1013194228Sthompsa cd = (void *)(udev->usb_template_ptr + 1); 1014184610Salfred 1015184610Salfred if (index >= dd->bNumConfigurations) { 1016184610Salfred /* out of range */ 1017184610Salfred return (NULL); 1018184610Salfred } 1019184610Salfred while (index--) { 1020184610Salfred if (cd->bDescriptorType != UDESC_CONFIG) { 1021184610Salfred /* sanity check failed */ 1022184610Salfred return (NULL); 1023184610Salfred } 1024184610Salfred temp = UGETW(cd->wTotalLength); 1025184610Salfred cd = USB_ADD_BYTES(cd, temp); 1026184610Salfred } 1027184610Salfred 1028184610Salfred if (pLength) { 1029184610Salfred *pLength = UGETW(cd->wTotalLength); 1030184610Salfred } 1031184610Salfred return (cd); 1032184610Salfred} 1033184610Salfred 1034184610Salfred/*------------------------------------------------------------------------* 1035194228Sthompsa * usb_temp_get_vendor_desc 1036184610Salfred * 1037184610Salfred * Returns: 1038184610Salfred * NULL: No vendor descriptor found. 1039184610Salfred * Else: Pointer to a vendor descriptor. 1040184610Salfred *------------------------------------------------------------------------*/ 1041184610Salfredstatic const void * 1042194228Sthompsausb_temp_get_vendor_desc(struct usb_device *udev, 1043205030Sthompsa const struct usb_device_request *req, uint16_t *plen) 1044184610Salfred{ 1045192984Sthompsa const struct usb_temp_device_desc *tdd; 1046184610Salfred 1047194228Sthompsa tdd = usb_temp_get_tdd(udev); 1048184610Salfred if (tdd == NULL) { 1049184610Salfred return (NULL); 1050184610Salfred } 1051184610Salfred if (tdd->getVendorDesc == NULL) { 1052184610Salfred return (NULL); 1053184610Salfred } 1054205030Sthompsa return ((tdd->getVendorDesc) (req, plen)); 1055184610Salfred} 1056184610Salfred 1057184610Salfred/*------------------------------------------------------------------------* 1058194228Sthompsa * usb_temp_get_string_desc 1059184610Salfred * 1060184610Salfred * Returns: 1061184610Salfred * NULL: No string descriptor found. 1062184610Salfred * Else: Pointer to a string descriptor. 1063184610Salfred *------------------------------------------------------------------------*/ 1064184610Salfredstatic const void * 1065194228Sthompsausb_temp_get_string_desc(struct usb_device *udev, 1066184610Salfred uint16_t lang_id, uint8_t string_index) 1067184610Salfred{ 1068192984Sthompsa const struct usb_temp_device_desc *tdd; 1069184610Salfred 1070194228Sthompsa tdd = usb_temp_get_tdd(udev); 1071184610Salfred if (tdd == NULL) { 1072184610Salfred return (NULL); 1073184610Salfred } 1074184610Salfred if (tdd->getStringDesc == NULL) { 1075184610Salfred return (NULL); 1076184610Salfred } 1077184610Salfred return ((tdd->getStringDesc) (lang_id, string_index)); 1078184610Salfred} 1079184610Salfred 1080184610Salfred/*------------------------------------------------------------------------* 1081194228Sthompsa * usb_temp_get_hub_desc 1082184610Salfred * 1083184610Salfred * Returns: 1084184610Salfred * NULL: No USB HUB descriptor found. 1085184610Salfred * Else: Pointer to a USB HUB descriptor. 1086184610Salfred *------------------------------------------------------------------------*/ 1087184610Salfredstatic const void * 1088194228Sthompsausb_temp_get_hub_desc(struct usb_device *udev) 1089184610Salfred{ 1090184610Salfred return (NULL); /* needs to be implemented */ 1091184610Salfred} 1092184610Salfred 1093184610Salfred/*------------------------------------------------------------------------* 1094194228Sthompsa * usb_temp_get_desc 1095184610Salfred * 1096184610Salfred * This function is a demultiplexer for local USB device side control 1097184610Salfred * endpoint requests. 1098184610Salfred *------------------------------------------------------------------------*/ 1099193045Sthompsastatic usb_error_t 1100194228Sthompsausb_temp_get_desc(struct usb_device *udev, struct usb_device_request *req, 1101184610Salfred const void **pPtr, uint16_t *pLength) 1102184610Salfred{ 1103184610Salfred const uint8_t *buf; 1104184610Salfred uint16_t len; 1105184610Salfred 1106184610Salfred buf = NULL; 1107184610Salfred len = 0; 1108184610Salfred 1109184610Salfred switch (req->bmRequestType) { 1110184610Salfred case UT_READ_DEVICE: 1111184610Salfred switch (req->bRequest) { 1112184610Salfred case UR_GET_DESCRIPTOR: 1113184610Salfred goto tr_handle_get_descriptor; 1114184610Salfred default: 1115184610Salfred goto tr_stalled; 1116184610Salfred } 1117184610Salfred case UT_READ_CLASS_DEVICE: 1118184610Salfred switch (req->bRequest) { 1119184610Salfred case UR_GET_DESCRIPTOR: 1120184610Salfred goto tr_handle_get_class_descriptor; 1121184610Salfred default: 1122184610Salfred goto tr_stalled; 1123184610Salfred } 1124184610Salfred default: 1125184610Salfred goto tr_stalled; 1126184610Salfred } 1127184610Salfred 1128184610Salfredtr_handle_get_descriptor: 1129184610Salfred switch (req->wValue[1]) { 1130184610Salfred case UDESC_DEVICE: 1131184610Salfred if (req->wValue[0]) { 1132184610Salfred goto tr_stalled; 1133184610Salfred } 1134194228Sthompsa buf = usb_temp_get_device_desc(udev); 1135184610Salfred goto tr_valid; 1136184610Salfred case UDESC_DEVICE_QUALIFIER: 1137184610Salfred if (udev->speed != USB_SPEED_HIGH) { 1138184610Salfred goto tr_stalled; 1139184610Salfred } 1140184610Salfred if (req->wValue[0]) { 1141184610Salfred goto tr_stalled; 1142184610Salfred } 1143194228Sthompsa buf = usb_temp_get_qualifier_desc(udev); 1144184610Salfred goto tr_valid; 1145184610Salfred case UDESC_OTHER_SPEED_CONFIGURATION: 1146184610Salfred if (udev->speed != USB_SPEED_HIGH) { 1147184610Salfred goto tr_stalled; 1148184610Salfred } 1149184610Salfred case UDESC_CONFIG: 1150194228Sthompsa buf = usb_temp_get_config_desc(udev, 1151184610Salfred &len, req->wValue[0]); 1152184610Salfred goto tr_valid; 1153184610Salfred case UDESC_STRING: 1154194228Sthompsa buf = usb_temp_get_string_desc(udev, 1155184610Salfred UGETW(req->wIndex), req->wValue[0]); 1156184610Salfred goto tr_valid; 1157184610Salfred default: 1158184610Salfred goto tr_stalled; 1159184610Salfred } 1160184610Salfred 1161184610Salfredtr_handle_get_class_descriptor: 1162184610Salfred if (req->wValue[0]) { 1163184610Salfred goto tr_stalled; 1164184610Salfred } 1165194228Sthompsa buf = usb_temp_get_hub_desc(udev); 1166184610Salfred goto tr_valid; 1167184610Salfred 1168184610Salfredtr_valid: 1169205030Sthompsa if (buf == NULL) 1170184610Salfred goto tr_stalled; 1171205030Sthompsa if (len == 0) 1172184610Salfred len = buf[0]; 1173184610Salfred *pPtr = buf; 1174184610Salfred *pLength = len; 1175191402Sthompsa return (0); /* success */ 1176184610Salfred 1177184610Salfredtr_stalled: 1178205030Sthompsa /* try to get a vendor specific descriptor */ 1179205030Sthompsa len = 0; 1180205030Sthompsa buf = usb_temp_get_vendor_desc(udev, req, &len); 1181205030Sthompsa if (buf != NULL) 1182205030Sthompsa goto tr_valid; 1183184610Salfred *pPtr = NULL; 1184184610Salfred *pLength = 0; 1185191402Sthompsa return (0); /* we ignore failures */ 1186184610Salfred} 1187184610Salfred 1188184610Salfred/*------------------------------------------------------------------------* 1189192984Sthompsa * usb_temp_setup 1190184610Salfred * 1191184610Salfred * This function generates USB descriptors according to the given USB 1192184610Salfred * template device descriptor. It will also try to figure out the best 1193184610Salfred * matching endpoint addresses using the hardware endpoint profiles. 1194184610Salfred * 1195184610Salfred * Returns: 1196184610Salfred * 0: Success 1197184610Salfred * Else: Failure 1198184610Salfred *------------------------------------------------------------------------*/ 1199205030Sthompsausb_error_t 1200192984Sthompsausb_temp_setup(struct usb_device *udev, 1201192984Sthompsa const struct usb_temp_device_desc *tdd) 1202184610Salfred{ 1203192984Sthompsa struct usb_temp_setup *uts; 1204184610Salfred void *buf; 1205184610Salfred uint8_t n; 1206184610Salfred 1207184610Salfred if (tdd == NULL) { 1208184610Salfred /* be NULL safe */ 1209184610Salfred return (0); 1210184610Salfred } 1211184610Salfred uts = udev->bus->scratch[0].temp_setup; 1212184610Salfred 1213184610Salfred bzero(uts, sizeof(*uts)); 1214184610Salfred 1215192500Sthompsa uts->usb_speed = udev->speed; 1216184610Salfred uts->self_powered = udev->flags.self_powered; 1217184610Salfred 1218184610Salfred /* first pass */ 1219184610Salfred 1220194228Sthompsa usb_make_device_desc(uts, tdd); 1221184610Salfred 1222184610Salfred if (uts->err) { 1223184610Salfred /* some error happened */ 1224184610Salfred return (uts->err); 1225184610Salfred } 1226184610Salfred /* sanity check */ 1227184610Salfred if (uts->size == 0) { 1228184610Salfred return (USB_ERR_INVAL); 1229184610Salfred } 1230184610Salfred /* allocate zeroed memory */ 1231184610Salfred uts->buf = malloc(uts->size, M_USB, M_WAITOK | M_ZERO); 1232184610Salfred if (uts->buf == NULL) { 1233184610Salfred /* could not allocate memory */ 1234184610Salfred return (USB_ERR_NOMEM); 1235184610Salfred } 1236184610Salfred /* second pass */ 1237184610Salfred 1238184610Salfred uts->size = 0; 1239184610Salfred 1240194228Sthompsa usb_make_device_desc(uts, tdd); 1241184610Salfred 1242184610Salfred /* 1243184610Salfred * Store a pointer to our descriptors: 1244184610Salfred */ 1245194228Sthompsa udev->usb_template_ptr = uts->buf; 1246184610Salfred 1247184610Salfred if (uts->err) { 1248184610Salfred /* some error happened during second pass */ 1249184610Salfred goto error; 1250184610Salfred } 1251184610Salfred /* 1252184610Salfred * Resolve all endpoint addresses ! 1253184610Salfred */ 1254194228Sthompsa buf = usb_temp_get_device_desc(udev); 1255194228Sthompsa uts->err = usb_hw_ep_resolve(udev, buf); 1256184610Salfred if (uts->err) { 1257184610Salfred DPRINTFN(0, "Could not resolve endpoints for " 1258184610Salfred "Device Descriptor, error = %s\n", 1259194228Sthompsa usbd_errstr(uts->err)); 1260184610Salfred goto error; 1261184610Salfred } 1262184610Salfred for (n = 0;; n++) { 1263184610Salfred 1264194228Sthompsa buf = usb_temp_get_config_desc(udev, NULL, n); 1265184610Salfred if (buf == NULL) { 1266184610Salfred break; 1267184610Salfred } 1268194228Sthompsa uts->err = usb_hw_ep_resolve(udev, buf); 1269184610Salfred if (uts->err) { 1270184610Salfred DPRINTFN(0, "Could not resolve endpoints for " 1271184610Salfred "Config Descriptor %u, error = %s\n", n, 1272194228Sthompsa usbd_errstr(uts->err)); 1273184610Salfred goto error; 1274184610Salfred } 1275184610Salfred } 1276184610Salfred return (uts->err); 1277184610Salfred 1278184610Salfrederror: 1279194228Sthompsa usb_temp_unsetup(udev); 1280184610Salfred return (uts->err); 1281184610Salfred} 1282184610Salfred 1283184610Salfred/*------------------------------------------------------------------------* 1284194228Sthompsa * usb_temp_unsetup 1285184610Salfred * 1286184610Salfred * This function frees any memory associated with the currently 1287184610Salfred * setup template, if any. 1288184610Salfred *------------------------------------------------------------------------*/ 1289205030Sthompsavoid 1290194228Sthompsausb_temp_unsetup(struct usb_device *udev) 1291184610Salfred{ 1292194228Sthompsa if (udev->usb_template_ptr) { 1293184610Salfred 1294194228Sthompsa free(udev->usb_template_ptr, M_USB); 1295184610Salfred 1296194228Sthompsa udev->usb_template_ptr = NULL; 1297184610Salfred } 1298184610Salfred} 1299184610Salfred 1300193045Sthompsastatic usb_error_t 1301194228Sthompsausb_temp_setup_by_index(struct usb_device *udev, uint16_t index) 1302184610Salfred{ 1303193045Sthompsa usb_error_t err; 1304184610Salfred 1305184610Salfred switch (index) { 1306184610Salfred case 0: 1307194228Sthompsa err = usb_temp_setup(udev, &usb_template_msc); 1308184610Salfred break; 1309184610Salfred case 1: 1310194228Sthompsa err = usb_temp_setup(udev, &usb_template_cdce); 1311184610Salfred break; 1312184610Salfred case 2: 1313194228Sthompsa err = usb_temp_setup(udev, &usb_template_mtp); 1314184610Salfred break; 1315184610Salfred default: 1316184610Salfred return (USB_ERR_INVAL); 1317184610Salfred } 1318184610Salfred 1319184610Salfred return (err); 1320184610Salfred} 1321184610Salfred 1322184610Salfredstatic void 1323194228Sthompsausb_temp_init(void *arg) 1324184610Salfred{ 1325184610Salfred /* register our functions */ 1326194228Sthompsa usb_temp_get_desc_p = &usb_temp_get_desc; 1327194228Sthompsa usb_temp_setup_by_index_p = &usb_temp_setup_by_index; 1328194228Sthompsa usb_temp_unsetup_p = &usb_temp_unsetup; 1329184610Salfred} 1330184610Salfred 1331194228SthompsaSYSINIT(usb_temp_init, SI_SUB_LOCK, SI_ORDER_FIRST, usb_temp_init, NULL); 1332194228SthompsaSYSUNINIT(usb_temp_unload, SI_SUB_LOCK, SI_ORDER_ANY, usb_temp_unload, NULL); 1333