usb_template.c revision 223467
1184610Salfred/* $FreeBSD: head/sys/dev/usb/template/usb_template.c 223467 2011-06-23 07:54:03Z 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> 52223467Shselasky#include <dev/usb/usb_ioctl.h> 53194677Sthompsa#include <dev/usb/usbdi.h> 54194677Sthompsa#include <dev/usb/usbdi_util.h> 55194677Sthompsa#include "usbdevs.h" 56194677Sthompsa 57188942Sthompsa#include <dev/usb/usb_cdc.h> 58188942Sthompsa#include <dev/usb/usb_core.h> 59194677Sthompsa#include <dev/usb/usb_dynamic.h> 60188942Sthompsa#include <dev/usb/usb_busdma.h> 61188942Sthompsa#include <dev/usb/usb_process.h> 62188942Sthompsa#include <dev/usb/usb_device.h> 63184610Salfred 64194677Sthompsa#define USB_DEBUG_VAR usb_debug 65194677Sthompsa#include <dev/usb/usb_debug.h> 66194677Sthompsa 67188942Sthompsa#include <dev/usb/usb_controller.h> 68188942Sthompsa#include <dev/usb/usb_bus.h> 69188942Sthompsa#include <dev/usb/template/usb_template.h> 70184610Salfred 71188942SthompsaMODULE_DEPEND(usb_template, usb, 1, 1, 1); 72188942SthompsaMODULE_VERSION(usb_template, 1); 73184610Salfred 74184610Salfred/* function prototypes */ 75184610Salfred 76194228Sthompsastatic void usb_make_raw_desc(struct usb_temp_setup *, const uint8_t *); 77194228Sthompsastatic void usb_make_endpoint_desc(struct usb_temp_setup *, 78192984Sthompsa const struct usb_temp_endpoint_desc *); 79194228Sthompsastatic void usb_make_interface_desc(struct usb_temp_setup *, 80192984Sthompsa const struct usb_temp_interface_desc *); 81194228Sthompsastatic void usb_make_config_desc(struct usb_temp_setup *, 82192984Sthompsa const struct usb_temp_config_desc *); 83194228Sthompsastatic void usb_make_device_desc(struct usb_temp_setup *, 84192984Sthompsa const struct usb_temp_device_desc *); 85194228Sthompsastatic uint8_t usb_hw_ep_match(const struct usb_hw_ep_profile *, uint8_t, 86185948Sthompsa uint8_t); 87194228Sthompsastatic uint8_t usb_hw_ep_find_match(struct usb_hw_ep_scratch *, 88192984Sthompsa struct usb_hw_ep_scratch_sub *, uint8_t); 89194228Sthompsastatic uint8_t usb_hw_ep_get_needs(struct usb_hw_ep_scratch *, uint8_t, 90185948Sthompsa uint8_t); 91194228Sthompsastatic usb_error_t usb_hw_ep_resolve(struct usb_device *, 92192984Sthompsa struct usb_descriptor *); 93194228Sthompsastatic const struct usb_temp_device_desc *usb_temp_get_tdd(struct usb_device *); 94194228Sthompsastatic void *usb_temp_get_device_desc(struct usb_device *); 95194228Sthompsastatic void *usb_temp_get_qualifier_desc(struct usb_device *); 96194228Sthompsastatic void *usb_temp_get_config_desc(struct usb_device *, uint16_t *, 97185948Sthompsa uint8_t); 98194228Sthompsastatic const void *usb_temp_get_string_desc(struct usb_device *, uint16_t, 99185948Sthompsa uint8_t); 100194228Sthompsastatic const void *usb_temp_get_vendor_desc(struct usb_device *, 101205030Sthompsa const struct usb_device_request *, uint16_t *plen); 102194228Sthompsastatic const void *usb_temp_get_hub_desc(struct usb_device *); 103194228Sthompsastatic usb_error_t usb_temp_get_desc(struct usb_device *, 104192984Sthompsa struct usb_device_request *, const void **, uint16_t *); 105194228Sthompsastatic usb_error_t usb_temp_setup_by_index(struct usb_device *, 106185948Sthompsa uint16_t index); 107194228Sthompsastatic void usb_temp_init(void *); 108184610Salfred 109184610Salfred/*------------------------------------------------------------------------* 110194228Sthompsa * usb_make_raw_desc 111184610Salfred * 112184610Salfred * This function will insert a raw USB descriptor into the generated 113184610Salfred * USB configuration. 114184610Salfred *------------------------------------------------------------------------*/ 115184610Salfredstatic void 116194228Sthompsausb_make_raw_desc(struct usb_temp_setup *temp, 117184610Salfred const uint8_t *raw) 118184610Salfred{ 119184610Salfred void *dst; 120184610Salfred uint8_t len; 121184610Salfred 122184610Salfred /* 123184610Salfred * The first byte of any USB descriptor gives the length. 124184610Salfred */ 125184610Salfred if (raw) { 126184610Salfred len = raw[0]; 127184610Salfred if (temp->buf) { 128184610Salfred dst = USB_ADD_BYTES(temp->buf, temp->size); 129218475Shselasky memcpy(dst, raw, len); 130184610Salfred 131184610Salfred /* check if we have got a CDC union descriptor */ 132184610Salfred 133192984Sthompsa if ((raw[0] >= sizeof(struct usb_cdc_union_descriptor)) && 134184610Salfred (raw[1] == UDESC_CS_INTERFACE) && 135184610Salfred (raw[2] == UDESCSUB_CDC_UNION)) { 136192984Sthompsa struct usb_cdc_union_descriptor *ud = (void *)dst; 137184610Salfred 138184610Salfred /* update the interface numbers */ 139184610Salfred 140184610Salfred ud->bMasterInterface += 141184610Salfred temp->bInterfaceNumber; 142184610Salfred ud->bSlaveInterface[0] += 143184610Salfred temp->bInterfaceNumber; 144184610Salfred } 145223467Shselasky 146223467Shselasky /* check if we have got an interface association descriptor */ 147223467Shselasky 148223467Shselasky if ((raw[0] >= sizeof(struct usb_interface_assoc_descriptor)) && 149223467Shselasky (raw[1] == UDESC_IFACE_ASSOC)) { 150223467Shselasky struct usb_interface_assoc_descriptor *iad = (void *)dst; 151223467Shselasky 152223467Shselasky /* update the interface number */ 153223467Shselasky 154223467Shselasky iad->bFirstInterface += 155223467Shselasky temp->bInterfaceNumber; 156223467Shselasky } 157223467Shselasky 158223467Shselasky /* check if we have got a call management descriptor */ 159223467Shselasky 160223467Shselasky if ((raw[0] >= sizeof(struct usb_cdc_cm_descriptor)) && 161223467Shselasky (raw[1] == UDESC_CS_INTERFACE) && 162223467Shselasky (raw[2] == UDESCSUB_CDC_CM)) { 163223467Shselasky struct usb_cdc_cm_descriptor *ccd = (void *)dst; 164223467Shselasky 165223467Shselasky /* update the interface number */ 166223467Shselasky 167223467Shselasky ccd->bDataInterface += 168223467Shselasky temp->bInterfaceNumber; 169223467Shselasky } 170184610Salfred } 171184610Salfred temp->size += len; 172184610Salfred } 173184610Salfred} 174184610Salfred 175184610Salfred/*------------------------------------------------------------------------* 176194228Sthompsa * usb_make_endpoint_desc 177184610Salfred * 178184610Salfred * This function will generate an USB endpoint descriptor from the 179184610Salfred * given USB template endpoint descriptor, which will be inserted into 180184610Salfred * the USB configuration. 181184610Salfred *------------------------------------------------------------------------*/ 182184610Salfredstatic void 183194228Sthompsausb_make_endpoint_desc(struct usb_temp_setup *temp, 184192984Sthompsa const struct usb_temp_endpoint_desc *ted) 185184610Salfred{ 186192984Sthompsa struct usb_endpoint_descriptor *ed; 187184610Salfred const void **rd; 188184610Salfred uint16_t old_size; 189184610Salfred uint16_t mps; 190205033Sthompsa uint8_t ea; /* Endpoint Address */ 191205033Sthompsa uint8_t et; /* Endpiont Type */ 192184610Salfred 193184610Salfred /* Reserve memory */ 194184610Salfred old_size = temp->size; 195184610Salfred 196205033Sthompsa ea = (ted->bEndpointAddress & (UE_ADDR | UE_DIR_IN | UE_DIR_OUT)); 197205033Sthompsa et = (ted->bmAttributes & UE_XFERTYPE); 198205033Sthompsa 199205033Sthompsa if (et == UE_ISOCHRONOUS) { 200205033Sthompsa /* account for extra byte fields */ 201205033Sthompsa temp->size += sizeof(*ed) + 2; 202205033Sthompsa } else { 203205033Sthompsa temp->size += sizeof(*ed); 204205033Sthompsa } 205205033Sthompsa 206184610Salfred /* Scan all Raw Descriptors first */ 207184610Salfred rd = ted->ppRawDesc; 208184610Salfred if (rd) { 209184610Salfred while (*rd) { 210194228Sthompsa usb_make_raw_desc(temp, *rd); 211184610Salfred rd++; 212184610Salfred } 213184610Salfred } 214184610Salfred if (ted->pPacketSize == NULL) { 215184610Salfred /* not initialized */ 216184610Salfred temp->err = USB_ERR_INVAL; 217184610Salfred return; 218184610Salfred } 219192500Sthompsa mps = ted->pPacketSize->mps[temp->usb_speed]; 220184610Salfred if (mps == 0) { 221184610Salfred /* not initialized */ 222184610Salfred temp->err = USB_ERR_INVAL; 223184610Salfred return; 224184610Salfred } else if (mps == UE_ZERO_MPS) { 225184610Salfred /* escape for Zero Max Packet Size */ 226184610Salfred mps = 0; 227184610Salfred } 228184610Salfred 229184610Salfred /* 230184610Salfred * Fill out the real USB endpoint descriptor 231184610Salfred * in case there is a buffer present: 232184610Salfred */ 233184610Salfred if (temp->buf) { 234184610Salfred ed = USB_ADD_BYTES(temp->buf, old_size); 235205033Sthompsa if (et == UE_ISOCHRONOUS) 236205033Sthompsa ed->bLength = sizeof(*ed) + 2; 237205033Sthompsa else 238205033Sthompsa ed->bLength = sizeof(*ed); 239184610Salfred ed->bDescriptorType = UDESC_ENDPOINT; 240184610Salfred ed->bEndpointAddress = ea; 241184610Salfred ed->bmAttributes = ted->bmAttributes; 242184610Salfred USETW(ed->wMaxPacketSize, mps); 243184610Salfred 244184610Salfred /* setup bInterval parameter */ 245184610Salfred 246184610Salfred if (ted->pIntervals && 247192500Sthompsa ted->pIntervals->bInterval[temp->usb_speed]) { 248184610Salfred ed->bInterval = 249192500Sthompsa ted->pIntervals->bInterval[temp->usb_speed]; 250184610Salfred } else { 251184610Salfred switch (et) { 252184610Salfred case UE_BULK: 253184610Salfred case UE_CONTROL: 254184610Salfred ed->bInterval = 0; /* not used */ 255184610Salfred break; 256184610Salfred case UE_INTERRUPT: 257192500Sthompsa switch (temp->usb_speed) { 258184610Salfred case USB_SPEED_LOW: 259184610Salfred case USB_SPEED_FULL: 260184610Salfred ed->bInterval = 1; /* 1 ms */ 261184610Salfred break; 262184610Salfred default: 263184610Salfred ed->bInterval = 8; /* 8*125 us */ 264184610Salfred break; 265184610Salfred } 266184610Salfred break; 267184610Salfred default: /* UE_ISOCHRONOUS */ 268192500Sthompsa switch (temp->usb_speed) { 269184610Salfred case USB_SPEED_LOW: 270184610Salfred case USB_SPEED_FULL: 271184610Salfred ed->bInterval = 1; /* 1 ms */ 272184610Salfred break; 273184610Salfred default: 274184610Salfred ed->bInterval = 1; /* 125 us */ 275184610Salfred break; 276184610Salfred } 277184610Salfred break; 278184610Salfred } 279184610Salfred } 280184610Salfred } 281184610Salfred temp->bNumEndpoints++; 282184610Salfred} 283184610Salfred 284184610Salfred/*------------------------------------------------------------------------* 285194228Sthompsa * usb_make_interface_desc 286184610Salfred * 287184610Salfred * This function will generate an USB interface descriptor from the 288184610Salfred * given USB template interface descriptor, which will be inserted 289184610Salfred * into the USB configuration. 290184610Salfred *------------------------------------------------------------------------*/ 291184610Salfredstatic void 292194228Sthompsausb_make_interface_desc(struct usb_temp_setup *temp, 293192984Sthompsa const struct usb_temp_interface_desc *tid) 294184610Salfred{ 295192984Sthompsa struct usb_interface_descriptor *id; 296192984Sthompsa const struct usb_temp_endpoint_desc **ted; 297184610Salfred const void **rd; 298184610Salfred uint16_t old_size; 299184610Salfred 300184610Salfred /* Reserve memory */ 301184610Salfred 302184610Salfred old_size = temp->size; 303184610Salfred temp->size += sizeof(*id); 304184610Salfred 305184610Salfred /* Update interface and alternate interface numbers */ 306184610Salfred 307184610Salfred if (tid->isAltInterface == 0) { 308184610Salfred temp->bAlternateSetting = 0; 309184610Salfred temp->bInterfaceNumber++; 310184610Salfred } else { 311184610Salfred temp->bAlternateSetting++; 312184610Salfred } 313184610Salfred 314184610Salfred /* Scan all Raw Descriptors first */ 315184610Salfred 316184610Salfred rd = tid->ppRawDesc; 317184610Salfred 318184610Salfred if (rd) { 319184610Salfred while (*rd) { 320194228Sthompsa usb_make_raw_desc(temp, *rd); 321184610Salfred rd++; 322184610Salfred } 323184610Salfred } 324184610Salfred /* Reset some counters */ 325184610Salfred 326184610Salfred temp->bNumEndpoints = 0; 327184610Salfred 328184610Salfred /* Scan all Endpoint Descriptors second */ 329184610Salfred 330184610Salfred ted = tid->ppEndpoints; 331184610Salfred if (ted) { 332184610Salfred while (*ted) { 333194228Sthompsa usb_make_endpoint_desc(temp, *ted); 334184610Salfred ted++; 335184610Salfred } 336184610Salfred } 337184610Salfred /* 338184610Salfred * Fill out the real USB interface descriptor 339184610Salfred * in case there is a buffer present: 340184610Salfred */ 341184610Salfred if (temp->buf) { 342184610Salfred id = USB_ADD_BYTES(temp->buf, old_size); 343184610Salfred id->bLength = sizeof(*id); 344184610Salfred id->bDescriptorType = UDESC_INTERFACE; 345184610Salfred id->bInterfaceNumber = temp->bInterfaceNumber; 346184610Salfred id->bAlternateSetting = temp->bAlternateSetting; 347184610Salfred id->bNumEndpoints = temp->bNumEndpoints; 348184610Salfred id->bInterfaceClass = tid->bInterfaceClass; 349184610Salfred id->bInterfaceSubClass = tid->bInterfaceSubClass; 350184610Salfred id->bInterfaceProtocol = tid->bInterfaceProtocol; 351184610Salfred id->iInterface = tid->iInterface; 352184610Salfred } 353184610Salfred} 354184610Salfred 355184610Salfred/*------------------------------------------------------------------------* 356194228Sthompsa * usb_make_config_desc 357184610Salfred * 358184610Salfred * This function will generate an USB config descriptor from the given 359184610Salfred * USB template config descriptor, which will be inserted into the USB 360184610Salfred * configuration. 361184610Salfred *------------------------------------------------------------------------*/ 362184610Salfredstatic void 363194228Sthompsausb_make_config_desc(struct usb_temp_setup *temp, 364192984Sthompsa const struct usb_temp_config_desc *tcd) 365184610Salfred{ 366192984Sthompsa struct usb_config_descriptor *cd; 367192984Sthompsa const struct usb_temp_interface_desc **tid; 368184610Salfred uint16_t old_size; 369184610Salfred 370184610Salfred /* Reserve memory */ 371184610Salfred 372184610Salfred old_size = temp->size; 373184610Salfred temp->size += sizeof(*cd); 374184610Salfred 375184610Salfred /* Reset some counters */ 376184610Salfred 377184610Salfred temp->bInterfaceNumber = 0 - 1; 378184610Salfred temp->bAlternateSetting = 0; 379184610Salfred 380184610Salfred /* Scan all the USB interfaces */ 381184610Salfred 382184610Salfred tid = tcd->ppIfaceDesc; 383184610Salfred if (tid) { 384184610Salfred while (*tid) { 385194228Sthompsa usb_make_interface_desc(temp, *tid); 386184610Salfred tid++; 387184610Salfred } 388184610Salfred } 389184610Salfred /* 390184610Salfred * Fill out the real USB config descriptor 391184610Salfred * in case there is a buffer present: 392184610Salfred */ 393184610Salfred if (temp->buf) { 394184610Salfred cd = USB_ADD_BYTES(temp->buf, old_size); 395184610Salfred 396184610Salfred /* compute total size */ 397184610Salfred old_size = temp->size - old_size; 398184610Salfred 399184610Salfred cd->bLength = sizeof(*cd); 400184610Salfred cd->bDescriptorType = UDESC_CONFIG; 401184610Salfred USETW(cd->wTotalLength, old_size); 402184610Salfred cd->bNumInterface = temp->bInterfaceNumber + 1; 403184610Salfred cd->bConfigurationValue = temp->bConfigurationValue; 404184610Salfred cd->iConfiguration = tcd->iConfiguration; 405184610Salfred cd->bmAttributes = tcd->bmAttributes; 406184610Salfred cd->bMaxPower = tcd->bMaxPower; 407184610Salfred cd->bmAttributes |= (UC_REMOTE_WAKEUP | UC_BUS_POWERED); 408184610Salfred 409184610Salfred if (temp->self_powered) { 410184610Salfred cd->bmAttributes |= UC_SELF_POWERED; 411184610Salfred } else { 412184610Salfred cd->bmAttributes &= ~UC_SELF_POWERED; 413184610Salfred } 414184610Salfred } 415184610Salfred} 416184610Salfred 417184610Salfred/*------------------------------------------------------------------------* 418194228Sthompsa * usb_make_device_desc 419184610Salfred * 420184610Salfred * This function will generate an USB device descriptor from the 421184610Salfred * given USB template device descriptor. 422184610Salfred *------------------------------------------------------------------------*/ 423184610Salfredstatic void 424194228Sthompsausb_make_device_desc(struct usb_temp_setup *temp, 425192984Sthompsa const struct usb_temp_device_desc *tdd) 426184610Salfred{ 427192984Sthompsa struct usb_temp_data *utd; 428192984Sthompsa const struct usb_temp_config_desc **tcd; 429184610Salfred uint16_t old_size; 430184610Salfred 431184610Salfred /* Reserve memory */ 432184610Salfred 433184610Salfred old_size = temp->size; 434184610Salfred temp->size += sizeof(*utd); 435184610Salfred 436184610Salfred /* Scan all the USB configs */ 437184610Salfred 438184610Salfred temp->bConfigurationValue = 1; 439184610Salfred tcd = tdd->ppConfigDesc; 440184610Salfred if (tcd) { 441184610Salfred while (*tcd) { 442194228Sthompsa usb_make_config_desc(temp, *tcd); 443184610Salfred temp->bConfigurationValue++; 444184610Salfred tcd++; 445184610Salfred } 446184610Salfred } 447184610Salfred /* 448184610Salfred * Fill out the real USB device descriptor 449184610Salfred * in case there is a buffer present: 450184610Salfred */ 451184610Salfred 452184610Salfred if (temp->buf) { 453184610Salfred utd = USB_ADD_BYTES(temp->buf, old_size); 454184610Salfred 455184610Salfred /* Store a pointer to our template device descriptor */ 456184610Salfred utd->tdd = tdd; 457184610Salfred 458184610Salfred /* Fill out USB device descriptor */ 459184610Salfred utd->udd.bLength = sizeof(utd->udd); 460184610Salfred utd->udd.bDescriptorType = UDESC_DEVICE; 461184610Salfred utd->udd.bDeviceClass = tdd->bDeviceClass; 462184610Salfred utd->udd.bDeviceSubClass = tdd->bDeviceSubClass; 463184610Salfred utd->udd.bDeviceProtocol = tdd->bDeviceProtocol; 464184610Salfred USETW(utd->udd.idVendor, tdd->idVendor); 465184610Salfred USETW(utd->udd.idProduct, tdd->idProduct); 466184610Salfred USETW(utd->udd.bcdDevice, tdd->bcdDevice); 467184610Salfred utd->udd.iManufacturer = tdd->iManufacturer; 468184610Salfred utd->udd.iProduct = tdd->iProduct; 469184610Salfred utd->udd.iSerialNumber = tdd->iSerialNumber; 470184610Salfred utd->udd.bNumConfigurations = temp->bConfigurationValue - 1; 471184610Salfred 472184610Salfred /* 473184610Salfred * Fill out the USB device qualifier. Pretend that we 474184610Salfred * don't support any other speeds by setting 475184610Salfred * "bNumConfigurations" equal to zero. That saves us 476184610Salfred * generating an extra set of configuration 477184610Salfred * descriptors. 478184610Salfred */ 479184610Salfred utd->udq.bLength = sizeof(utd->udq); 480184610Salfred utd->udq.bDescriptorType = UDESC_DEVICE_QUALIFIER; 481184610Salfred utd->udq.bDeviceClass = tdd->bDeviceClass; 482184610Salfred utd->udq.bDeviceSubClass = tdd->bDeviceSubClass; 483184610Salfred utd->udq.bDeviceProtocol = tdd->bDeviceProtocol; 484184610Salfred utd->udq.bNumConfigurations = 0; 485184610Salfred USETW(utd->udq.bcdUSB, 0x0200); 486184610Salfred utd->udq.bMaxPacketSize0 = 0; 487184610Salfred 488192500Sthompsa switch (temp->usb_speed) { 489184610Salfred case USB_SPEED_LOW: 490184610Salfred USETW(utd->udd.bcdUSB, 0x0110); 491184610Salfred utd->udd.bMaxPacketSize = 8; 492184610Salfred break; 493184610Salfred case USB_SPEED_FULL: 494184610Salfred USETW(utd->udd.bcdUSB, 0x0110); 495184610Salfred utd->udd.bMaxPacketSize = 32; 496184610Salfred break; 497184610Salfred case USB_SPEED_HIGH: 498184610Salfred USETW(utd->udd.bcdUSB, 0x0200); 499184610Salfred utd->udd.bMaxPacketSize = 64; 500184610Salfred break; 501184610Salfred case USB_SPEED_VARIABLE: 502184610Salfred USETW(utd->udd.bcdUSB, 0x0250); 503184610Salfred utd->udd.bMaxPacketSize = 255; /* 512 bytes */ 504184610Salfred break; 505223467Shselasky case USB_SPEED_SUPER: 506223467Shselasky USETW(utd->udd.bcdUSB, 0x0300); 507223467Shselasky utd->udd.bMaxPacketSize = 9; /* 2**9 = 512 bytes */ 508223467Shselasky break; 509184610Salfred default: 510184610Salfred temp->err = USB_ERR_INVAL; 511184610Salfred break; 512184610Salfred } 513184610Salfred } 514184610Salfred} 515184610Salfred 516184610Salfred/*------------------------------------------------------------------------* 517194228Sthompsa * usb_hw_ep_match 518184610Salfred * 519184610Salfred * Return values: 520184610Salfred * 0: The endpoint profile does not match the criterias 521184610Salfred * Else: The endpoint profile matches the criterias 522184610Salfred *------------------------------------------------------------------------*/ 523184610Salfredstatic uint8_t 524194228Sthompsausb_hw_ep_match(const struct usb_hw_ep_profile *pf, 525184610Salfred uint8_t ep_type, uint8_t ep_dir_in) 526184610Salfred{ 527184610Salfred if (ep_type == UE_CONTROL) { 528184610Salfred /* special */ 529184610Salfred return (pf->support_control); 530184610Salfred } 531184610Salfred if ((pf->support_in && ep_dir_in) || 532184610Salfred (pf->support_out && !ep_dir_in)) { 533184610Salfred if ((pf->support_interrupt && (ep_type == UE_INTERRUPT)) || 534184610Salfred (pf->support_isochronous && (ep_type == UE_ISOCHRONOUS)) || 535184610Salfred (pf->support_bulk && (ep_type == UE_BULK))) { 536184610Salfred return (1); 537184610Salfred } 538184610Salfred } 539184610Salfred return (0); 540184610Salfred} 541184610Salfred 542184610Salfred/*------------------------------------------------------------------------* 543194228Sthompsa * usb_hw_ep_find_match 544184610Salfred * 545184610Salfred * This function is used to find the best matching endpoint profile 546184610Salfred * for and endpoint belonging to an USB descriptor. 547184610Salfred * 548184610Salfred * Return values: 549184610Salfred * 0: Success. Got a match. 550184610Salfred * Else: Failure. No match. 551184610Salfred *------------------------------------------------------------------------*/ 552184610Salfredstatic uint8_t 553194228Sthompsausb_hw_ep_find_match(struct usb_hw_ep_scratch *ues, 554192984Sthompsa struct usb_hw_ep_scratch_sub *ep, uint8_t is_simplex) 555184610Salfred{ 556192984Sthompsa const struct usb_hw_ep_profile *pf; 557184610Salfred uint16_t distance; 558184610Salfred uint16_t temp; 559184610Salfred uint16_t max_frame_size; 560184610Salfred uint8_t n; 561184610Salfred uint8_t best_n; 562184610Salfred uint8_t dir_in; 563184610Salfred uint8_t dir_out; 564184610Salfred 565184610Salfred distance = 0xFFFF; 566184610Salfred best_n = 0; 567184610Salfred 568184610Salfred if ((!ep->needs_in) && (!ep->needs_out)) { 569184610Salfred return (0); /* we are done */ 570184610Salfred } 571184610Salfred if (ep->needs_ep_type == UE_CONTROL) { 572184610Salfred dir_in = 1; 573184610Salfred dir_out = 1; 574184610Salfred } else { 575184610Salfred if (ep->needs_in) { 576184610Salfred dir_in = 1; 577184610Salfred dir_out = 0; 578184610Salfred } else { 579184610Salfred dir_in = 0; 580184610Salfred dir_out = 1; 581184610Salfred } 582184610Salfred } 583184610Salfred 584184610Salfred for (n = 1; n != (USB_EP_MAX / 2); n++) { 585184610Salfred 586184610Salfred /* get HW endpoint profile */ 587184610Salfred (ues->methods->get_hw_ep_profile) (ues->udev, &pf, n); 588184610Salfred if (pf == NULL) { 589184610Salfred /* end of profiles */ 590184610Salfred break; 591184610Salfred } 592184610Salfred /* check if IN-endpoint is reserved */ 593184610Salfred if (dir_in || pf->is_simplex) { 594184610Salfred if (ues->bmInAlloc[n / 8] & (1 << (n % 8))) { 595184610Salfred /* mismatch */ 596184610Salfred continue; 597184610Salfred } 598184610Salfred } 599184610Salfred /* check if OUT-endpoint is reserved */ 600184610Salfred if (dir_out || pf->is_simplex) { 601184610Salfred if (ues->bmOutAlloc[n / 8] & (1 << (n % 8))) { 602184610Salfred /* mismatch */ 603184610Salfred continue; 604184610Salfred } 605184610Salfred } 606184610Salfred /* check simplex */ 607184610Salfred if (pf->is_simplex == is_simplex) { 608184610Salfred /* mismatch */ 609184610Salfred continue; 610184610Salfred } 611184610Salfred /* check if HW endpoint matches */ 612194228Sthompsa if (!usb_hw_ep_match(pf, ep->needs_ep_type, dir_in)) { 613184610Salfred /* mismatch */ 614184610Salfred continue; 615184610Salfred } 616184610Salfred /* get maximum frame size */ 617184610Salfred if (dir_in) 618184610Salfred max_frame_size = pf->max_in_frame_size; 619184610Salfred else 620184610Salfred max_frame_size = pf->max_out_frame_size; 621184610Salfred 622184610Salfred /* check if we have a matching profile */ 623184610Salfred if (max_frame_size >= ep->max_frame_size) { 624184610Salfred temp = (max_frame_size - ep->max_frame_size); 625184610Salfred if (distance > temp) { 626184610Salfred distance = temp; 627184610Salfred best_n = n; 628184610Salfred ep->pf = pf; 629184610Salfred } 630184610Salfred } 631184610Salfred } 632184610Salfred 633184610Salfred /* see if we got a match */ 634184610Salfred if (best_n != 0) { 635184610Salfred /* get the correct profile */ 636184610Salfred pf = ep->pf; 637184610Salfred 638184610Salfred /* reserve IN-endpoint */ 639184610Salfred if (dir_in) { 640184610Salfred ues->bmInAlloc[best_n / 8] |= 641184610Salfred (1 << (best_n % 8)); 642184610Salfred ep->hw_endpoint_in = best_n | UE_DIR_IN; 643184610Salfred ep->needs_in = 0; 644184610Salfred } 645184610Salfred /* reserve OUT-endpoint */ 646184610Salfred if (dir_out) { 647184610Salfred ues->bmOutAlloc[best_n / 8] |= 648184610Salfred (1 << (best_n % 8)); 649184610Salfred ep->hw_endpoint_out = best_n | UE_DIR_OUT; 650184610Salfred ep->needs_out = 0; 651184610Salfred } 652184610Salfred return (0); /* got a match */ 653184610Salfred } 654184610Salfred return (1); /* failure */ 655184610Salfred} 656184610Salfred 657184610Salfred/*------------------------------------------------------------------------* 658194228Sthompsa * usb_hw_ep_get_needs 659184610Salfred * 660184610Salfred * This function will figure out the type and number of endpoints 661184610Salfred * which are needed for an USB configuration. 662184610Salfred * 663184610Salfred * Return values: 664184610Salfred * 0: Success. 665184610Salfred * Else: Failure. 666184610Salfred *------------------------------------------------------------------------*/ 667184610Salfredstatic uint8_t 668194228Sthompsausb_hw_ep_get_needs(struct usb_hw_ep_scratch *ues, 669184610Salfred uint8_t ep_type, uint8_t is_complete) 670184610Salfred{ 671192984Sthompsa const struct usb_hw_ep_profile *pf; 672192984Sthompsa struct usb_hw_ep_scratch_sub *ep_iface; 673192984Sthompsa struct usb_hw_ep_scratch_sub *ep_curr; 674192984Sthompsa struct usb_hw_ep_scratch_sub *ep_max; 675192984Sthompsa struct usb_hw_ep_scratch_sub *ep_end; 676192984Sthompsa struct usb_descriptor *desc; 677192984Sthompsa struct usb_interface_descriptor *id; 678192984Sthompsa struct usb_endpoint_descriptor *ed; 679192500Sthompsa enum usb_dev_speed speed; 680184610Salfred uint16_t wMaxPacketSize; 681184610Salfred uint16_t temp; 682184610Salfred uint8_t ep_no; 683184610Salfred 684184610Salfred ep_iface = ues->ep_max; 685184610Salfred ep_curr = ues->ep_max; 686184610Salfred ep_end = ues->ep + USB_EP_MAX; 687184610Salfred ep_max = ues->ep_max; 688184610Salfred desc = NULL; 689194228Sthompsa speed = usbd_get_speed(ues->udev); 690184610Salfred 691184610Salfredrepeat: 692184610Salfred 693194228Sthompsa while ((desc = usb_desc_foreach(ues->cd, desc))) { 694184610Salfred 695184610Salfred if ((desc->bDescriptorType == UDESC_INTERFACE) && 696184610Salfred (desc->bLength >= sizeof(*id))) { 697184610Salfred 698184610Salfred id = (void *)desc; 699184610Salfred 700184610Salfred if (id->bAlternateSetting == 0) { 701184610Salfred /* going forward */ 702184610Salfred ep_iface = ep_max; 703184610Salfred } else { 704184610Salfred /* reset */ 705184610Salfred ep_curr = ep_iface; 706184610Salfred } 707184610Salfred } 708184610Salfred if ((desc->bDescriptorType == UDESC_ENDPOINT) && 709184610Salfred (desc->bLength >= sizeof(*ed))) { 710184610Salfred 711184610Salfred ed = (void *)desc; 712184610Salfred 713184610Salfred goto handle_endpoint_desc; 714184610Salfred } 715184610Salfred } 716184610Salfred ues->ep_max = ep_max; 717184610Salfred return (0); 718184610Salfred 719184610Salfredhandle_endpoint_desc: 720184610Salfred temp = (ed->bmAttributes & UE_XFERTYPE); 721184610Salfred 722184610Salfred if (temp == ep_type) { 723184610Salfred 724184610Salfred if (ep_curr == ep_end) { 725184610Salfred /* too many endpoints */ 726184610Salfred return (1); /* failure */ 727184610Salfred } 728184610Salfred wMaxPacketSize = UGETW(ed->wMaxPacketSize); 729184610Salfred if ((wMaxPacketSize & 0xF800) && 730184610Salfred (speed == USB_SPEED_HIGH)) { 731184610Salfred /* handle packet multiplier */ 732184610Salfred temp = (wMaxPacketSize >> 11) & 3; 733184610Salfred wMaxPacketSize &= 0x7FF; 734184610Salfred if (temp == 1) { 735184610Salfred wMaxPacketSize *= 2; 736184610Salfred } else { 737184610Salfred wMaxPacketSize *= 3; 738184610Salfred } 739184610Salfred } 740184610Salfred /* 741184610Salfred * Check if we have a fixed endpoint number, else the 742184610Salfred * endpoint number is allocated dynamically: 743184610Salfred */ 744184610Salfred ep_no = (ed->bEndpointAddress & UE_ADDR); 745184610Salfred if (ep_no != 0) { 746184610Salfred 747184610Salfred /* get HW endpoint profile */ 748184610Salfred (ues->methods->get_hw_ep_profile) 749184610Salfred (ues->udev, &pf, ep_no); 750184610Salfred if (pf == NULL) { 751184610Salfred /* HW profile does not exist - failure */ 752184610Salfred DPRINTFN(0, "Endpoint profile %u " 753184610Salfred "does not exist\n", ep_no); 754184610Salfred return (1); 755184610Salfred } 756184610Salfred /* reserve fixed endpoint number */ 757184610Salfred if (ep_type == UE_CONTROL) { 758184610Salfred ues->bmInAlloc[ep_no / 8] |= 759184610Salfred (1 << (ep_no % 8)); 760184610Salfred ues->bmOutAlloc[ep_no / 8] |= 761184610Salfred (1 << (ep_no % 8)); 762184610Salfred if ((pf->max_in_frame_size < wMaxPacketSize) || 763184610Salfred (pf->max_out_frame_size < wMaxPacketSize)) { 764184610Salfred DPRINTFN(0, "Endpoint profile %u " 765199816Sthompsa "has too small buffer\n", ep_no); 766184610Salfred return (1); 767184610Salfred } 768184610Salfred } else if (ed->bEndpointAddress & UE_DIR_IN) { 769184610Salfred ues->bmInAlloc[ep_no / 8] |= 770184610Salfred (1 << (ep_no % 8)); 771184610Salfred if (pf->max_in_frame_size < wMaxPacketSize) { 772184610Salfred DPRINTFN(0, "Endpoint profile %u " 773199816Sthompsa "has too small buffer\n", ep_no); 774184610Salfred return (1); 775184610Salfred } 776184610Salfred } else { 777184610Salfred ues->bmOutAlloc[ep_no / 8] |= 778184610Salfred (1 << (ep_no % 8)); 779184610Salfred if (pf->max_out_frame_size < wMaxPacketSize) { 780184610Salfred DPRINTFN(0, "Endpoint profile %u " 781199816Sthompsa "has too small buffer\n", ep_no); 782184610Salfred return (1); 783184610Salfred } 784184610Salfred } 785184610Salfred } else if (is_complete) { 786184610Salfred 787184610Salfred /* check if we have enough buffer space */ 788184610Salfred if (wMaxPacketSize > 789184610Salfred ep_curr->max_frame_size) { 790184610Salfred return (1); /* failure */ 791184610Salfred } 792184610Salfred if (ed->bEndpointAddress & UE_DIR_IN) { 793184610Salfred ed->bEndpointAddress = 794184610Salfred ep_curr->hw_endpoint_in; 795184610Salfred } else { 796184610Salfred ed->bEndpointAddress = 797184610Salfred ep_curr->hw_endpoint_out; 798184610Salfred } 799184610Salfred 800184610Salfred } else { 801184610Salfred 802184610Salfred /* compute the maximum frame size */ 803184610Salfred if (ep_curr->max_frame_size < wMaxPacketSize) { 804184610Salfred ep_curr->max_frame_size = wMaxPacketSize; 805184610Salfred } 806184610Salfred if (temp == UE_CONTROL) { 807184610Salfred ep_curr->needs_in = 1; 808184610Salfred ep_curr->needs_out = 1; 809184610Salfred } else { 810184610Salfred if (ed->bEndpointAddress & UE_DIR_IN) { 811184610Salfred ep_curr->needs_in = 1; 812184610Salfred } else { 813184610Salfred ep_curr->needs_out = 1; 814184610Salfred } 815184610Salfred } 816184610Salfred ep_curr->needs_ep_type = ep_type; 817184610Salfred } 818184610Salfred 819184610Salfred ep_curr++; 820184610Salfred if (ep_max < ep_curr) { 821184610Salfred ep_max = ep_curr; 822184610Salfred } 823184610Salfred } 824184610Salfred goto repeat; 825184610Salfred} 826184610Salfred 827184610Salfred/*------------------------------------------------------------------------* 828194228Sthompsa * usb_hw_ep_resolve 829184610Salfred * 830184610Salfred * This function will try to resolve endpoint requirements by the 831184610Salfred * given endpoint profiles that the USB hardware reports. 832184610Salfred * 833184610Salfred * Return values: 834184610Salfred * 0: Success 835184610Salfred * Else: Failure 836184610Salfred *------------------------------------------------------------------------*/ 837193045Sthompsastatic usb_error_t 838194228Sthompsausb_hw_ep_resolve(struct usb_device *udev, 839192984Sthompsa struct usb_descriptor *desc) 840184610Salfred{ 841192984Sthompsa struct usb_hw_ep_scratch *ues; 842192984Sthompsa struct usb_hw_ep_scratch_sub *ep; 843192984Sthompsa const struct usb_hw_ep_profile *pf; 844192984Sthompsa struct usb_bus_methods *methods; 845192984Sthompsa struct usb_device_descriptor *dd; 846184610Salfred uint16_t mps; 847184610Salfred 848184610Salfred if (desc == NULL) { 849184610Salfred return (USB_ERR_INVAL); 850184610Salfred } 851184610Salfred /* get bus methods */ 852184610Salfred methods = udev->bus->methods; 853184610Salfred 854184610Salfred if (methods->get_hw_ep_profile == NULL) { 855184610Salfred return (USB_ERR_INVAL); 856184610Salfred } 857184610Salfred if (desc->bDescriptorType == UDESC_DEVICE) { 858184610Salfred 859184610Salfred if (desc->bLength < sizeof(*dd)) { 860184610Salfred return (USB_ERR_INVAL); 861184610Salfred } 862184610Salfred dd = (void *)desc; 863184610Salfred 864184610Salfred /* get HW control endpoint 0 profile */ 865184610Salfred (methods->get_hw_ep_profile) (udev, &pf, 0); 866184610Salfred if (pf == NULL) { 867184610Salfred return (USB_ERR_INVAL); 868184610Salfred } 869194228Sthompsa if (!usb_hw_ep_match(pf, UE_CONTROL, 0)) { 870184610Salfred DPRINTFN(0, "Endpoint 0 does not " 871184610Salfred "support control\n"); 872184610Salfred return (USB_ERR_INVAL); 873184610Salfred } 874184610Salfred mps = dd->bMaxPacketSize; 875184610Salfred 876184610Salfred if (udev->speed == USB_SPEED_FULL) { 877184610Salfred /* 878184610Salfred * We can optionally choose another packet size ! 879184610Salfred */ 880184610Salfred while (1) { 881184610Salfred /* check if "mps" is ok */ 882184610Salfred if (pf->max_in_frame_size >= mps) { 883184610Salfred break; 884184610Salfred } 885184610Salfred /* reduce maximum packet size */ 886184610Salfred mps /= 2; 887184610Salfred 888184610Salfred /* check if "mps" is too small */ 889184610Salfred if (mps < 8) { 890184610Salfred return (USB_ERR_INVAL); 891184610Salfred } 892184610Salfred } 893184610Salfred 894184610Salfred dd->bMaxPacketSize = mps; 895184610Salfred 896184610Salfred } else { 897184610Salfred /* We only have one choice */ 898184610Salfred if (mps == 255) { 899184610Salfred mps = 512; 900184610Salfred } 901184610Salfred /* Check if we support the specified wMaxPacketSize */ 902184610Salfred if (pf->max_in_frame_size < mps) { 903184610Salfred return (USB_ERR_INVAL); 904184610Salfred } 905184610Salfred } 906184610Salfred return (0); /* success */ 907184610Salfred } 908184610Salfred if (desc->bDescriptorType != UDESC_CONFIG) { 909184610Salfred return (USB_ERR_INVAL); 910184610Salfred } 911184610Salfred if (desc->bLength < sizeof(*(ues->cd))) { 912184610Salfred return (USB_ERR_INVAL); 913184610Salfred } 914184610Salfred ues = udev->bus->scratch[0].hw_ep_scratch; 915184610Salfred 916184610Salfred bzero(ues, sizeof(*ues)); 917184610Salfred 918184610Salfred ues->ep_max = ues->ep; 919184610Salfred ues->cd = (void *)desc; 920184610Salfred ues->methods = methods; 921184610Salfred ues->udev = udev; 922184610Salfred 923184610Salfred /* Get all the endpoints we need */ 924184610Salfred 925194228Sthompsa if (usb_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 0) || 926194228Sthompsa usb_hw_ep_get_needs(ues, UE_INTERRUPT, 0) || 927194228Sthompsa usb_hw_ep_get_needs(ues, UE_CONTROL, 0) || 928194228Sthompsa usb_hw_ep_get_needs(ues, UE_BULK, 0)) { 929184610Salfred DPRINTFN(0, "Could not get needs\n"); 930184610Salfred return (USB_ERR_INVAL); 931184610Salfred } 932184610Salfred for (ep = ues->ep; ep != ues->ep_max; ep++) { 933184610Salfred 934184610Salfred while (ep->needs_in || ep->needs_out) { 935184610Salfred 936184610Salfred /* 937184610Salfred * First try to use a simplex endpoint. 938184610Salfred * Then try to use a duplex endpoint. 939184610Salfred */ 940194228Sthompsa if (usb_hw_ep_find_match(ues, ep, 1) && 941194228Sthompsa usb_hw_ep_find_match(ues, ep, 0)) { 942184610Salfred DPRINTFN(0, "Could not find match\n"); 943184610Salfred return (USB_ERR_INVAL); 944184610Salfred } 945184610Salfred } 946184610Salfred } 947184610Salfred 948184610Salfred ues->ep_max = ues->ep; 949184610Salfred 950184610Salfred /* Update all endpoint addresses */ 951184610Salfred 952194228Sthompsa if (usb_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 1) || 953194228Sthompsa usb_hw_ep_get_needs(ues, UE_INTERRUPT, 1) || 954194228Sthompsa usb_hw_ep_get_needs(ues, UE_CONTROL, 1) || 955194228Sthompsa usb_hw_ep_get_needs(ues, UE_BULK, 1)) { 956184610Salfred DPRINTFN(0, "Could not update endpoint address\n"); 957184610Salfred return (USB_ERR_INVAL); 958184610Salfred } 959184610Salfred return (0); /* success */ 960184610Salfred} 961184610Salfred 962184610Salfred/*------------------------------------------------------------------------* 963194228Sthompsa * usb_temp_get_tdd 964184610Salfred * 965184610Salfred * Returns: 966184610Salfred * NULL: No USB template device descriptor found. 967184610Salfred * Else: Pointer to the USB template device descriptor. 968184610Salfred *------------------------------------------------------------------------*/ 969192984Sthompsastatic const struct usb_temp_device_desc * 970194228Sthompsausb_temp_get_tdd(struct usb_device *udev) 971184610Salfred{ 972194228Sthompsa if (udev->usb_template_ptr == NULL) { 973184610Salfred return (NULL); 974184610Salfred } 975194228Sthompsa return (udev->usb_template_ptr->tdd); 976184610Salfred} 977184610Salfred 978184610Salfred/*------------------------------------------------------------------------* 979194228Sthompsa * usb_temp_get_device_desc 980184610Salfred * 981184610Salfred * Returns: 982184610Salfred * NULL: No USB device descriptor found. 983184610Salfred * Else: Pointer to USB device descriptor. 984184610Salfred *------------------------------------------------------------------------*/ 985184610Salfredstatic void * 986194228Sthompsausb_temp_get_device_desc(struct usb_device *udev) 987184610Salfred{ 988192984Sthompsa struct usb_device_descriptor *dd; 989184610Salfred 990194228Sthompsa if (udev->usb_template_ptr == NULL) { 991184610Salfred return (NULL); 992184610Salfred } 993194228Sthompsa dd = &udev->usb_template_ptr->udd; 994184610Salfred if (dd->bDescriptorType != UDESC_DEVICE) { 995184610Salfred /* sanity check failed */ 996184610Salfred return (NULL); 997184610Salfred } 998184610Salfred return (dd); 999184610Salfred} 1000184610Salfred 1001184610Salfred/*------------------------------------------------------------------------* 1002194228Sthompsa * usb_temp_get_qualifier_desc 1003184610Salfred * 1004184610Salfred * Returns: 1005184610Salfred * NULL: No USB device_qualifier descriptor found. 1006184610Salfred * Else: Pointer to USB device_qualifier descriptor. 1007184610Salfred *------------------------------------------------------------------------*/ 1008184610Salfredstatic void * 1009194228Sthompsausb_temp_get_qualifier_desc(struct usb_device *udev) 1010184610Salfred{ 1011192984Sthompsa struct usb_device_qualifier *dq; 1012184610Salfred 1013194228Sthompsa if (udev->usb_template_ptr == NULL) { 1014184610Salfred return (NULL); 1015184610Salfred } 1016194228Sthompsa dq = &udev->usb_template_ptr->udq; 1017184610Salfred if (dq->bDescriptorType != UDESC_DEVICE_QUALIFIER) { 1018184610Salfred /* sanity check failed */ 1019184610Salfred return (NULL); 1020184610Salfred } 1021184610Salfred return (dq); 1022184610Salfred} 1023184610Salfred 1024184610Salfred/*------------------------------------------------------------------------* 1025194228Sthompsa * usb_temp_get_config_desc 1026184610Salfred * 1027184610Salfred * Returns: 1028184610Salfred * NULL: No USB config descriptor found. 1029184610Salfred * Else: Pointer to USB config descriptor having index "index". 1030184610Salfred *------------------------------------------------------------------------*/ 1031184610Salfredstatic void * 1032194228Sthompsausb_temp_get_config_desc(struct usb_device *udev, 1033184610Salfred uint16_t *pLength, uint8_t index) 1034184610Salfred{ 1035192984Sthompsa struct usb_device_descriptor *dd; 1036192984Sthompsa struct usb_config_descriptor *cd; 1037184610Salfred uint16_t temp; 1038184610Salfred 1039194228Sthompsa if (udev->usb_template_ptr == NULL) { 1040184610Salfred return (NULL); 1041184610Salfred } 1042194228Sthompsa dd = &udev->usb_template_ptr->udd; 1043194228Sthompsa cd = (void *)(udev->usb_template_ptr + 1); 1044184610Salfred 1045184610Salfred if (index >= dd->bNumConfigurations) { 1046184610Salfred /* out of range */ 1047184610Salfred return (NULL); 1048184610Salfred } 1049184610Salfred while (index--) { 1050184610Salfred if (cd->bDescriptorType != UDESC_CONFIG) { 1051184610Salfred /* sanity check failed */ 1052184610Salfred return (NULL); 1053184610Salfred } 1054184610Salfred temp = UGETW(cd->wTotalLength); 1055184610Salfred cd = USB_ADD_BYTES(cd, temp); 1056184610Salfred } 1057184610Salfred 1058184610Salfred if (pLength) { 1059184610Salfred *pLength = UGETW(cd->wTotalLength); 1060184610Salfred } 1061184610Salfred return (cd); 1062184610Salfred} 1063184610Salfred 1064184610Salfred/*------------------------------------------------------------------------* 1065194228Sthompsa * usb_temp_get_vendor_desc 1066184610Salfred * 1067184610Salfred * Returns: 1068184610Salfred * NULL: No vendor descriptor found. 1069184610Salfred * Else: Pointer to a vendor descriptor. 1070184610Salfred *------------------------------------------------------------------------*/ 1071184610Salfredstatic const void * 1072194228Sthompsausb_temp_get_vendor_desc(struct usb_device *udev, 1073205030Sthompsa const struct usb_device_request *req, uint16_t *plen) 1074184610Salfred{ 1075192984Sthompsa const struct usb_temp_device_desc *tdd; 1076184610Salfred 1077194228Sthompsa tdd = usb_temp_get_tdd(udev); 1078184610Salfred if (tdd == NULL) { 1079184610Salfred return (NULL); 1080184610Salfred } 1081184610Salfred if (tdd->getVendorDesc == NULL) { 1082184610Salfred return (NULL); 1083184610Salfred } 1084205030Sthompsa return ((tdd->getVendorDesc) (req, plen)); 1085184610Salfred} 1086184610Salfred 1087184610Salfred/*------------------------------------------------------------------------* 1088194228Sthompsa * usb_temp_get_string_desc 1089184610Salfred * 1090184610Salfred * Returns: 1091184610Salfred * NULL: No string descriptor found. 1092184610Salfred * Else: Pointer to a string descriptor. 1093184610Salfred *------------------------------------------------------------------------*/ 1094184610Salfredstatic const void * 1095194228Sthompsausb_temp_get_string_desc(struct usb_device *udev, 1096184610Salfred uint16_t lang_id, uint8_t string_index) 1097184610Salfred{ 1098192984Sthompsa const struct usb_temp_device_desc *tdd; 1099184610Salfred 1100194228Sthompsa tdd = usb_temp_get_tdd(udev); 1101184610Salfred if (tdd == NULL) { 1102184610Salfred return (NULL); 1103184610Salfred } 1104184610Salfred if (tdd->getStringDesc == NULL) { 1105184610Salfred return (NULL); 1106184610Salfred } 1107184610Salfred return ((tdd->getStringDesc) (lang_id, string_index)); 1108184610Salfred} 1109184610Salfred 1110184610Salfred/*------------------------------------------------------------------------* 1111194228Sthompsa * usb_temp_get_hub_desc 1112184610Salfred * 1113184610Salfred * Returns: 1114184610Salfred * NULL: No USB HUB descriptor found. 1115184610Salfred * Else: Pointer to a USB HUB descriptor. 1116184610Salfred *------------------------------------------------------------------------*/ 1117184610Salfredstatic const void * 1118194228Sthompsausb_temp_get_hub_desc(struct usb_device *udev) 1119184610Salfred{ 1120184610Salfred return (NULL); /* needs to be implemented */ 1121184610Salfred} 1122184610Salfred 1123184610Salfred/*------------------------------------------------------------------------* 1124194228Sthompsa * usb_temp_get_desc 1125184610Salfred * 1126184610Salfred * This function is a demultiplexer for local USB device side control 1127184610Salfred * endpoint requests. 1128184610Salfred *------------------------------------------------------------------------*/ 1129193045Sthompsastatic usb_error_t 1130194228Sthompsausb_temp_get_desc(struct usb_device *udev, struct usb_device_request *req, 1131184610Salfred const void **pPtr, uint16_t *pLength) 1132184610Salfred{ 1133184610Salfred const uint8_t *buf; 1134184610Salfred uint16_t len; 1135184610Salfred 1136184610Salfred buf = NULL; 1137184610Salfred len = 0; 1138184610Salfred 1139184610Salfred switch (req->bmRequestType) { 1140184610Salfred case UT_READ_DEVICE: 1141184610Salfred switch (req->bRequest) { 1142184610Salfred case UR_GET_DESCRIPTOR: 1143184610Salfred goto tr_handle_get_descriptor; 1144184610Salfred default: 1145184610Salfred goto tr_stalled; 1146184610Salfred } 1147184610Salfred case UT_READ_CLASS_DEVICE: 1148184610Salfred switch (req->bRequest) { 1149184610Salfred case UR_GET_DESCRIPTOR: 1150184610Salfred goto tr_handle_get_class_descriptor; 1151184610Salfred default: 1152184610Salfred goto tr_stalled; 1153184610Salfred } 1154184610Salfred default: 1155184610Salfred goto tr_stalled; 1156184610Salfred } 1157184610Salfred 1158184610Salfredtr_handle_get_descriptor: 1159184610Salfred switch (req->wValue[1]) { 1160184610Salfred case UDESC_DEVICE: 1161184610Salfred if (req->wValue[0]) { 1162184610Salfred goto tr_stalled; 1163184610Salfred } 1164194228Sthompsa buf = usb_temp_get_device_desc(udev); 1165184610Salfred goto tr_valid; 1166184610Salfred case UDESC_DEVICE_QUALIFIER: 1167184610Salfred if (udev->speed != USB_SPEED_HIGH) { 1168184610Salfred goto tr_stalled; 1169184610Salfred } 1170184610Salfred if (req->wValue[0]) { 1171184610Salfred goto tr_stalled; 1172184610Salfred } 1173194228Sthompsa buf = usb_temp_get_qualifier_desc(udev); 1174184610Salfred goto tr_valid; 1175184610Salfred case UDESC_OTHER_SPEED_CONFIGURATION: 1176184610Salfred if (udev->speed != USB_SPEED_HIGH) { 1177184610Salfred goto tr_stalled; 1178184610Salfred } 1179184610Salfred case UDESC_CONFIG: 1180194228Sthompsa buf = usb_temp_get_config_desc(udev, 1181184610Salfred &len, req->wValue[0]); 1182184610Salfred goto tr_valid; 1183184610Salfred case UDESC_STRING: 1184194228Sthompsa buf = usb_temp_get_string_desc(udev, 1185184610Salfred UGETW(req->wIndex), req->wValue[0]); 1186184610Salfred goto tr_valid; 1187184610Salfred default: 1188184610Salfred goto tr_stalled; 1189184610Salfred } 1190184610Salfred 1191184610Salfredtr_handle_get_class_descriptor: 1192184610Salfred if (req->wValue[0]) { 1193184610Salfred goto tr_stalled; 1194184610Salfred } 1195194228Sthompsa buf = usb_temp_get_hub_desc(udev); 1196184610Salfred goto tr_valid; 1197184610Salfred 1198184610Salfredtr_valid: 1199205030Sthompsa if (buf == NULL) 1200184610Salfred goto tr_stalled; 1201205030Sthompsa if (len == 0) 1202184610Salfred len = buf[0]; 1203184610Salfred *pPtr = buf; 1204184610Salfred *pLength = len; 1205191402Sthompsa return (0); /* success */ 1206184610Salfred 1207184610Salfredtr_stalled: 1208205030Sthompsa /* try to get a vendor specific descriptor */ 1209205030Sthompsa len = 0; 1210205030Sthompsa buf = usb_temp_get_vendor_desc(udev, req, &len); 1211205030Sthompsa if (buf != NULL) 1212205030Sthompsa goto tr_valid; 1213184610Salfred *pPtr = NULL; 1214184610Salfred *pLength = 0; 1215191402Sthompsa return (0); /* we ignore failures */ 1216184610Salfred} 1217184610Salfred 1218184610Salfred/*------------------------------------------------------------------------* 1219192984Sthompsa * usb_temp_setup 1220184610Salfred * 1221184610Salfred * This function generates USB descriptors according to the given USB 1222184610Salfred * template device descriptor. It will also try to figure out the best 1223184610Salfred * matching endpoint addresses using the hardware endpoint profiles. 1224184610Salfred * 1225184610Salfred * Returns: 1226184610Salfred * 0: Success 1227184610Salfred * Else: Failure 1228184610Salfred *------------------------------------------------------------------------*/ 1229205030Sthompsausb_error_t 1230192984Sthompsausb_temp_setup(struct usb_device *udev, 1231192984Sthompsa const struct usb_temp_device_desc *tdd) 1232184610Salfred{ 1233192984Sthompsa struct usb_temp_setup *uts; 1234184610Salfred void *buf; 1235184610Salfred uint8_t n; 1236184610Salfred 1237184610Salfred if (tdd == NULL) { 1238184610Salfred /* be NULL safe */ 1239184610Salfred return (0); 1240184610Salfred } 1241184610Salfred uts = udev->bus->scratch[0].temp_setup; 1242184610Salfred 1243184610Salfred bzero(uts, sizeof(*uts)); 1244184610Salfred 1245192500Sthompsa uts->usb_speed = udev->speed; 1246184610Salfred uts->self_powered = udev->flags.self_powered; 1247184610Salfred 1248184610Salfred /* first pass */ 1249184610Salfred 1250194228Sthompsa usb_make_device_desc(uts, tdd); 1251184610Salfred 1252184610Salfred if (uts->err) { 1253184610Salfred /* some error happened */ 1254184610Salfred return (uts->err); 1255184610Salfred } 1256184610Salfred /* sanity check */ 1257184610Salfred if (uts->size == 0) { 1258184610Salfred return (USB_ERR_INVAL); 1259184610Salfred } 1260184610Salfred /* allocate zeroed memory */ 1261184610Salfred uts->buf = malloc(uts->size, M_USB, M_WAITOK | M_ZERO); 1262184610Salfred if (uts->buf == NULL) { 1263184610Salfred /* could not allocate memory */ 1264184610Salfred return (USB_ERR_NOMEM); 1265184610Salfred } 1266184610Salfred /* second pass */ 1267184610Salfred 1268184610Salfred uts->size = 0; 1269184610Salfred 1270194228Sthompsa usb_make_device_desc(uts, tdd); 1271184610Salfred 1272184610Salfred /* 1273184610Salfred * Store a pointer to our descriptors: 1274184610Salfred */ 1275194228Sthompsa udev->usb_template_ptr = uts->buf; 1276184610Salfred 1277184610Salfred if (uts->err) { 1278184610Salfred /* some error happened during second pass */ 1279184610Salfred goto error; 1280184610Salfred } 1281184610Salfred /* 1282184610Salfred * Resolve all endpoint addresses ! 1283184610Salfred */ 1284194228Sthompsa buf = usb_temp_get_device_desc(udev); 1285194228Sthompsa uts->err = usb_hw_ep_resolve(udev, buf); 1286184610Salfred if (uts->err) { 1287184610Salfred DPRINTFN(0, "Could not resolve endpoints for " 1288184610Salfred "Device Descriptor, error = %s\n", 1289194228Sthompsa usbd_errstr(uts->err)); 1290184610Salfred goto error; 1291184610Salfred } 1292184610Salfred for (n = 0;; n++) { 1293184610Salfred 1294194228Sthompsa buf = usb_temp_get_config_desc(udev, NULL, n); 1295184610Salfred if (buf == NULL) { 1296184610Salfred break; 1297184610Salfred } 1298194228Sthompsa uts->err = usb_hw_ep_resolve(udev, buf); 1299184610Salfred if (uts->err) { 1300184610Salfred DPRINTFN(0, "Could not resolve endpoints for " 1301184610Salfred "Config Descriptor %u, error = %s\n", n, 1302194228Sthompsa usbd_errstr(uts->err)); 1303184610Salfred goto error; 1304184610Salfred } 1305184610Salfred } 1306184610Salfred return (uts->err); 1307184610Salfred 1308184610Salfrederror: 1309194228Sthompsa usb_temp_unsetup(udev); 1310184610Salfred return (uts->err); 1311184610Salfred} 1312184610Salfred 1313184610Salfred/*------------------------------------------------------------------------* 1314194228Sthompsa * usb_temp_unsetup 1315184610Salfred * 1316184610Salfred * This function frees any memory associated with the currently 1317184610Salfred * setup template, if any. 1318184610Salfred *------------------------------------------------------------------------*/ 1319205030Sthompsavoid 1320194228Sthompsausb_temp_unsetup(struct usb_device *udev) 1321184610Salfred{ 1322194228Sthompsa if (udev->usb_template_ptr) { 1323184610Salfred 1324194228Sthompsa free(udev->usb_template_ptr, M_USB); 1325184610Salfred 1326194228Sthompsa udev->usb_template_ptr = NULL; 1327184610Salfred } 1328184610Salfred} 1329184610Salfred 1330193045Sthompsastatic usb_error_t 1331194228Sthompsausb_temp_setup_by_index(struct usb_device *udev, uint16_t index) 1332184610Salfred{ 1333193045Sthompsa usb_error_t err; 1334184610Salfred 1335184610Salfred switch (index) { 1336223467Shselasky case USB_TEMP_MSC: 1337194228Sthompsa err = usb_temp_setup(udev, &usb_template_msc); 1338184610Salfred break; 1339223467Shselasky case USB_TEMP_CDCE: 1340194228Sthompsa err = usb_temp_setup(udev, &usb_template_cdce); 1341184610Salfred break; 1342223467Shselasky case USB_TEMP_MTP: 1343194228Sthompsa err = usb_temp_setup(udev, &usb_template_mtp); 1344184610Salfred break; 1345223467Shselasky case USB_TEMP_MODEM: 1346223467Shselasky err = usb_temp_setup(udev, &usb_template_modem); 1347223467Shselasky break; 1348223467Shselasky case USB_TEMP_AUDIO: 1349223467Shselasky err = usb_temp_setup(udev, &usb_template_audio); 1350223467Shselasky break; 1351223467Shselasky case USB_TEMP_KBD: 1352223467Shselasky err = usb_temp_setup(udev, &usb_template_kbd); 1353223467Shselasky break; 1354223467Shselasky case USB_TEMP_MOUSE: 1355223467Shselasky err = usb_temp_setup(udev, &usb_template_mouse); 1356223467Shselasky break; 1357184610Salfred default: 1358184610Salfred return (USB_ERR_INVAL); 1359184610Salfred } 1360184610Salfred 1361184610Salfred return (err); 1362184610Salfred} 1363184610Salfred 1364184610Salfredstatic void 1365194228Sthompsausb_temp_init(void *arg) 1366184610Salfred{ 1367184610Salfred /* register our functions */ 1368194228Sthompsa usb_temp_get_desc_p = &usb_temp_get_desc; 1369194228Sthompsa usb_temp_setup_by_index_p = &usb_temp_setup_by_index; 1370194228Sthompsa usb_temp_unsetup_p = &usb_temp_unsetup; 1371184610Salfred} 1372184610Salfred 1373194228SthompsaSYSINIT(usb_temp_init, SI_SUB_LOCK, SI_ORDER_FIRST, usb_temp_init, NULL); 1374194228SthompsaSYSUNINIT(usb_temp_unload, SI_SUB_LOCK, SI_ORDER_ANY, usb_temp_unload, NULL); 1375