usb_template.c revision 188942
1184610Salfred/* $FreeBSD: head/sys/dev/usb/template/usb_template.c 188942 2009-02-23 18:31:00Z thompsa $ */ 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 32188942Sthompsa#include <dev/usb/usb.h> 33188942Sthompsa#include <dev/usb/usb_cdc.h> 34188942Sthompsa#include <dev/usb/usb_mfunc.h> 35188942Sthompsa#include <dev/usb/usb_defs.h> 36188942Sthompsa#include <dev/usb/usb_error.h> 37184610Salfred 38184610Salfred#define USB_DEBUG_VAR usb2_debug 39184610Salfred 40188942Sthompsa#include <dev/usb/usb_core.h> 41188942Sthompsa#include <dev/usb/usb_busdma.h> 42188942Sthompsa#include <dev/usb/usb_process.h> 43188942Sthompsa#include <dev/usb/usb_debug.h> 44188942Sthompsa#include <dev/usb/usb_parse.h> 45188942Sthompsa#include <dev/usb/usb_device.h> 46188942Sthompsa#include <dev/usb/usb_dynamic.h> 47184610Salfred 48188942Sthompsa#include <dev/usb/usb_controller.h> 49188942Sthompsa#include <dev/usb/usb_bus.h> 50184610Salfred 51188942Sthompsa#include <dev/usb/template/usb_template.h> 52184610Salfred 53188942SthompsaMODULE_DEPEND(usb_template, usb, 1, 1, 1); 54188942SthompsaMODULE_VERSION(usb_template, 1); 55184610Salfred 56184610Salfred/* function prototypes */ 57184610Salfred 58185948Sthompsastatic void usb2_make_raw_desc(struct usb2_temp_setup *, const uint8_t *); 59185948Sthompsastatic void usb2_make_endpoint_desc(struct usb2_temp_setup *, 60185948Sthompsa const struct usb2_temp_endpoint_desc *); 61185948Sthompsastatic void usb2_make_interface_desc(struct usb2_temp_setup *, 62185948Sthompsa const struct usb2_temp_interface_desc *); 63185948Sthompsastatic void usb2_make_config_desc(struct usb2_temp_setup *, 64185948Sthompsa const struct usb2_temp_config_desc *); 65185948Sthompsastatic void usb2_make_device_desc(struct usb2_temp_setup *, 66185948Sthompsa const struct usb2_temp_device_desc *); 67185948Sthompsastatic uint8_t usb2_hw_ep_match(const struct usb2_hw_ep_profile *, uint8_t, 68185948Sthompsa uint8_t); 69185948Sthompsastatic uint8_t usb2_hw_ep_find_match(struct usb2_hw_ep_scratch *, 70185948Sthompsa struct usb2_hw_ep_scratch_sub *, uint8_t); 71185948Sthompsastatic uint8_t usb2_hw_ep_get_needs(struct usb2_hw_ep_scratch *, uint8_t, 72185948Sthompsa uint8_t); 73185948Sthompsastatic usb2_error_t usb2_hw_ep_resolve(struct usb2_device *, 74185948Sthompsa struct usb2_descriptor *); 75185948Sthompsastatic const struct usb2_temp_device_desc *usb2_temp_get_tdd(struct usb2_device *); 76185948Sthompsastatic void *usb2_temp_get_device_desc(struct usb2_device *); 77185948Sthompsastatic void *usb2_temp_get_qualifier_desc(struct usb2_device *); 78185948Sthompsastatic void *usb2_temp_get_config_desc(struct usb2_device *, uint16_t *, 79185948Sthompsa uint8_t); 80185948Sthompsastatic const void *usb2_temp_get_string_desc(struct usb2_device *, uint16_t, 81185948Sthompsa uint8_t); 82185948Sthompsastatic const void *usb2_temp_get_vendor_desc(struct usb2_device *, 83185948Sthompsa const struct usb2_device_request *); 84185948Sthompsastatic const void *usb2_temp_get_hub_desc(struct usb2_device *); 85185948Sthompsastatic void usb2_temp_get_desc(struct usb2_device *, 86185948Sthompsa struct usb2_device_request *, const void **, uint16_t *); 87185948Sthompsastatic usb2_error_t usb2_temp_setup(struct usb2_device *, 88185948Sthompsa const struct usb2_temp_device_desc *); 89185948Sthompsastatic void usb2_temp_unsetup(struct usb2_device *); 90185948Sthompsastatic usb2_error_t usb2_temp_setup_by_index(struct usb2_device *, 91185948Sthompsa uint16_t index); 92185948Sthompsastatic void usb2_temp_init(void *); 93184610Salfred 94184610Salfred/*------------------------------------------------------------------------* 95184610Salfred * usb2_make_raw_desc 96184610Salfred * 97184610Salfred * This function will insert a raw USB descriptor into the generated 98184610Salfred * USB configuration. 99184610Salfred *------------------------------------------------------------------------*/ 100184610Salfredstatic void 101184610Salfredusb2_make_raw_desc(struct usb2_temp_setup *temp, 102184610Salfred const uint8_t *raw) 103184610Salfred{ 104184610Salfred void *dst; 105184610Salfred uint8_t len; 106184610Salfred 107184610Salfred /* 108184610Salfred * The first byte of any USB descriptor gives the length. 109184610Salfred */ 110184610Salfred if (raw) { 111184610Salfred len = raw[0]; 112184610Salfred if (temp->buf) { 113184610Salfred dst = USB_ADD_BYTES(temp->buf, temp->size); 114184610Salfred bcopy(raw, dst, len); 115184610Salfred 116184610Salfred /* check if we have got a CDC union descriptor */ 117184610Salfred 118184610Salfred if ((raw[0] >= sizeof(struct usb2_cdc_union_descriptor)) && 119184610Salfred (raw[1] == UDESC_CS_INTERFACE) && 120184610Salfred (raw[2] == UDESCSUB_CDC_UNION)) { 121184610Salfred struct usb2_cdc_union_descriptor *ud = (void *)dst; 122184610Salfred 123184610Salfred /* update the interface numbers */ 124184610Salfred 125184610Salfred ud->bMasterInterface += 126184610Salfred temp->bInterfaceNumber; 127184610Salfred ud->bSlaveInterface[0] += 128184610Salfred temp->bInterfaceNumber; 129184610Salfred } 130184610Salfred } 131184610Salfred temp->size += len; 132184610Salfred } 133184610Salfred} 134184610Salfred 135184610Salfred/*------------------------------------------------------------------------* 136184610Salfred * usb2_make_endpoint_desc 137184610Salfred * 138184610Salfred * This function will generate an USB endpoint descriptor from the 139184610Salfred * given USB template endpoint descriptor, which will be inserted into 140184610Salfred * the USB configuration. 141184610Salfred *------------------------------------------------------------------------*/ 142184610Salfredstatic void 143184610Salfredusb2_make_endpoint_desc(struct usb2_temp_setup *temp, 144184610Salfred const struct usb2_temp_endpoint_desc *ted) 145184610Salfred{ 146184610Salfred struct usb2_endpoint_descriptor *ed; 147184610Salfred const void **rd; 148184610Salfred uint16_t old_size; 149184610Salfred uint16_t mps; 150184610Salfred uint8_t ea = 0; /* Endpoint Address */ 151184610Salfred uint8_t et = 0; /* Endpiont Type */ 152184610Salfred 153184610Salfred /* Reserve memory */ 154184610Salfred old_size = temp->size; 155184610Salfred temp->size += sizeof(*ed); 156184610Salfred 157184610Salfred /* Scan all Raw Descriptors first */ 158184610Salfred 159184610Salfred rd = ted->ppRawDesc; 160184610Salfred if (rd) { 161184610Salfred while (*rd) { 162184610Salfred usb2_make_raw_desc(temp, *rd); 163184610Salfred rd++; 164184610Salfred } 165184610Salfred } 166184610Salfred if (ted->pPacketSize == NULL) { 167184610Salfred /* not initialized */ 168184610Salfred temp->err = USB_ERR_INVAL; 169184610Salfred return; 170184610Salfred } 171184610Salfred mps = ted->pPacketSize->mps[temp->usb2_speed]; 172184610Salfred if (mps == 0) { 173184610Salfred /* not initialized */ 174184610Salfred temp->err = USB_ERR_INVAL; 175184610Salfred return; 176184610Salfred } else if (mps == UE_ZERO_MPS) { 177184610Salfred /* escape for Zero Max Packet Size */ 178184610Salfred mps = 0; 179184610Salfred } 180184610Salfred ea = (ted->bEndpointAddress & (UE_ADDR | UE_DIR_IN | UE_DIR_OUT)); 181184610Salfred et = (ted->bmAttributes & UE_XFERTYPE); 182184610Salfred 183184610Salfred /* 184184610Salfred * Fill out the real USB endpoint descriptor 185184610Salfred * in case there is a buffer present: 186184610Salfred */ 187184610Salfred if (temp->buf) { 188184610Salfred ed = USB_ADD_BYTES(temp->buf, old_size); 189184610Salfred ed->bLength = sizeof(*ed); 190184610Salfred ed->bDescriptorType = UDESC_ENDPOINT; 191184610Salfred ed->bEndpointAddress = ea; 192184610Salfred ed->bmAttributes = ted->bmAttributes; 193184610Salfred USETW(ed->wMaxPacketSize, mps); 194184610Salfred 195184610Salfred /* setup bInterval parameter */ 196184610Salfred 197184610Salfred if (ted->pIntervals && 198184610Salfred ted->pIntervals->bInterval[temp->usb2_speed]) { 199184610Salfred ed->bInterval = 200184610Salfred ted->pIntervals->bInterval[temp->usb2_speed]; 201184610Salfred } else { 202184610Salfred switch (et) { 203184610Salfred case UE_BULK: 204184610Salfred case UE_CONTROL: 205184610Salfred ed->bInterval = 0; /* not used */ 206184610Salfred break; 207184610Salfred case UE_INTERRUPT: 208184610Salfred switch (temp->usb2_speed) { 209184610Salfred case USB_SPEED_LOW: 210184610Salfred case USB_SPEED_FULL: 211184610Salfred ed->bInterval = 1; /* 1 ms */ 212184610Salfred break; 213184610Salfred default: 214184610Salfred ed->bInterval = 8; /* 8*125 us */ 215184610Salfred break; 216184610Salfred } 217184610Salfred break; 218184610Salfred default: /* UE_ISOCHRONOUS */ 219184610Salfred switch (temp->usb2_speed) { 220184610Salfred case USB_SPEED_LOW: 221184610Salfred case USB_SPEED_FULL: 222184610Salfred ed->bInterval = 1; /* 1 ms */ 223184610Salfred break; 224184610Salfred default: 225184610Salfred ed->bInterval = 1; /* 125 us */ 226184610Salfred break; 227184610Salfred } 228184610Salfred break; 229184610Salfred } 230184610Salfred } 231184610Salfred } 232184610Salfred temp->bNumEndpoints++; 233184610Salfred} 234184610Salfred 235184610Salfred/*------------------------------------------------------------------------* 236184610Salfred * usb2_make_interface_desc 237184610Salfred * 238184610Salfred * This function will generate an USB interface descriptor from the 239184610Salfred * given USB template interface descriptor, which will be inserted 240184610Salfred * into the USB configuration. 241184610Salfred *------------------------------------------------------------------------*/ 242184610Salfredstatic void 243184610Salfredusb2_make_interface_desc(struct usb2_temp_setup *temp, 244184610Salfred const struct usb2_temp_interface_desc *tid) 245184610Salfred{ 246184610Salfred struct usb2_interface_descriptor *id; 247184610Salfred const struct usb2_temp_endpoint_desc **ted; 248184610Salfred const void **rd; 249184610Salfred uint16_t old_size; 250184610Salfred 251184610Salfred /* Reserve memory */ 252184610Salfred 253184610Salfred old_size = temp->size; 254184610Salfred temp->size += sizeof(*id); 255184610Salfred 256184610Salfred /* Update interface and alternate interface numbers */ 257184610Salfred 258184610Salfred if (tid->isAltInterface == 0) { 259184610Salfred temp->bAlternateSetting = 0; 260184610Salfred temp->bInterfaceNumber++; 261184610Salfred } else { 262184610Salfred temp->bAlternateSetting++; 263184610Salfred } 264184610Salfred 265184610Salfred /* Scan all Raw Descriptors first */ 266184610Salfred 267184610Salfred rd = tid->ppRawDesc; 268184610Salfred 269184610Salfred if (rd) { 270184610Salfred while (*rd) { 271184610Salfred usb2_make_raw_desc(temp, *rd); 272184610Salfred rd++; 273184610Salfred } 274184610Salfred } 275184610Salfred /* Reset some counters */ 276184610Salfred 277184610Salfred temp->bNumEndpoints = 0; 278184610Salfred 279184610Salfred /* Scan all Endpoint Descriptors second */ 280184610Salfred 281184610Salfred ted = tid->ppEndpoints; 282184610Salfred if (ted) { 283184610Salfred while (*ted) { 284184610Salfred usb2_make_endpoint_desc(temp, *ted); 285184610Salfred ted++; 286184610Salfred } 287184610Salfred } 288184610Salfred /* 289184610Salfred * Fill out the real USB interface descriptor 290184610Salfred * in case there is a buffer present: 291184610Salfred */ 292184610Salfred if (temp->buf) { 293184610Salfred id = USB_ADD_BYTES(temp->buf, old_size); 294184610Salfred id->bLength = sizeof(*id); 295184610Salfred id->bDescriptorType = UDESC_INTERFACE; 296184610Salfred id->bInterfaceNumber = temp->bInterfaceNumber; 297184610Salfred id->bAlternateSetting = temp->bAlternateSetting; 298184610Salfred id->bNumEndpoints = temp->bNumEndpoints; 299184610Salfred id->bInterfaceClass = tid->bInterfaceClass; 300184610Salfred id->bInterfaceSubClass = tid->bInterfaceSubClass; 301184610Salfred id->bInterfaceProtocol = tid->bInterfaceProtocol; 302184610Salfred id->iInterface = tid->iInterface; 303184610Salfred } 304184610Salfred} 305184610Salfred 306184610Salfred/*------------------------------------------------------------------------* 307184610Salfred * usb2_make_config_desc 308184610Salfred * 309184610Salfred * This function will generate an USB config descriptor from the given 310184610Salfred * USB template config descriptor, which will be inserted into the USB 311184610Salfred * configuration. 312184610Salfred *------------------------------------------------------------------------*/ 313184610Salfredstatic void 314184610Salfredusb2_make_config_desc(struct usb2_temp_setup *temp, 315184610Salfred const struct usb2_temp_config_desc *tcd) 316184610Salfred{ 317184610Salfred struct usb2_config_descriptor *cd; 318184610Salfred const struct usb2_temp_interface_desc **tid; 319184610Salfred uint16_t old_size; 320184610Salfred 321184610Salfred /* Reserve memory */ 322184610Salfred 323184610Salfred old_size = temp->size; 324184610Salfred temp->size += sizeof(*cd); 325184610Salfred 326184610Salfred /* Reset some counters */ 327184610Salfred 328184610Salfred temp->bInterfaceNumber = 0 - 1; 329184610Salfred temp->bAlternateSetting = 0; 330184610Salfred 331184610Salfred /* Scan all the USB interfaces */ 332184610Salfred 333184610Salfred tid = tcd->ppIfaceDesc; 334184610Salfred if (tid) { 335184610Salfred while (*tid) { 336184610Salfred usb2_make_interface_desc(temp, *tid); 337184610Salfred tid++; 338184610Salfred } 339184610Salfred } 340184610Salfred /* 341184610Salfred * Fill out the real USB config descriptor 342184610Salfred * in case there is a buffer present: 343184610Salfred */ 344184610Salfred if (temp->buf) { 345184610Salfred cd = USB_ADD_BYTES(temp->buf, old_size); 346184610Salfred 347184610Salfred /* compute total size */ 348184610Salfred old_size = temp->size - old_size; 349184610Salfred 350184610Salfred cd->bLength = sizeof(*cd); 351184610Salfred cd->bDescriptorType = UDESC_CONFIG; 352184610Salfred USETW(cd->wTotalLength, old_size); 353184610Salfred cd->bNumInterface = temp->bInterfaceNumber + 1; 354184610Salfred cd->bConfigurationValue = temp->bConfigurationValue; 355184610Salfred cd->iConfiguration = tcd->iConfiguration; 356184610Salfred cd->bmAttributes = tcd->bmAttributes; 357184610Salfred cd->bMaxPower = tcd->bMaxPower; 358184610Salfred cd->bmAttributes |= (UC_REMOTE_WAKEUP | UC_BUS_POWERED); 359184610Salfred 360184610Salfred if (temp->self_powered) { 361184610Salfred cd->bmAttributes |= UC_SELF_POWERED; 362184610Salfred } else { 363184610Salfred cd->bmAttributes &= ~UC_SELF_POWERED; 364184610Salfred } 365184610Salfred } 366184610Salfred} 367184610Salfred 368184610Salfred/*------------------------------------------------------------------------* 369184610Salfred * usb2_make_device_desc 370184610Salfred * 371184610Salfred * This function will generate an USB device descriptor from the 372184610Salfred * given USB template device descriptor. 373184610Salfred *------------------------------------------------------------------------*/ 374184610Salfredstatic void 375184610Salfredusb2_make_device_desc(struct usb2_temp_setup *temp, 376184610Salfred const struct usb2_temp_device_desc *tdd) 377184610Salfred{ 378184610Salfred struct usb2_temp_data *utd; 379184610Salfred const struct usb2_temp_config_desc **tcd; 380184610Salfred uint16_t old_size; 381184610Salfred 382184610Salfred /* Reserve memory */ 383184610Salfred 384184610Salfred old_size = temp->size; 385184610Salfred temp->size += sizeof(*utd); 386184610Salfred 387184610Salfred /* Scan all the USB configs */ 388184610Salfred 389184610Salfred temp->bConfigurationValue = 1; 390184610Salfred tcd = tdd->ppConfigDesc; 391184610Salfred if (tcd) { 392184610Salfred while (*tcd) { 393184610Salfred usb2_make_config_desc(temp, *tcd); 394184610Salfred temp->bConfigurationValue++; 395184610Salfred tcd++; 396184610Salfred } 397184610Salfred } 398184610Salfred /* 399184610Salfred * Fill out the real USB device descriptor 400184610Salfred * in case there is a buffer present: 401184610Salfred */ 402184610Salfred 403184610Salfred if (temp->buf) { 404184610Salfred utd = USB_ADD_BYTES(temp->buf, old_size); 405184610Salfred 406184610Salfred /* Store a pointer to our template device descriptor */ 407184610Salfred utd->tdd = tdd; 408184610Salfred 409184610Salfred /* Fill out USB device descriptor */ 410184610Salfred utd->udd.bLength = sizeof(utd->udd); 411184610Salfred utd->udd.bDescriptorType = UDESC_DEVICE; 412184610Salfred utd->udd.bDeviceClass = tdd->bDeviceClass; 413184610Salfred utd->udd.bDeviceSubClass = tdd->bDeviceSubClass; 414184610Salfred utd->udd.bDeviceProtocol = tdd->bDeviceProtocol; 415184610Salfred USETW(utd->udd.idVendor, tdd->idVendor); 416184610Salfred USETW(utd->udd.idProduct, tdd->idProduct); 417184610Salfred USETW(utd->udd.bcdDevice, tdd->bcdDevice); 418184610Salfred utd->udd.iManufacturer = tdd->iManufacturer; 419184610Salfred utd->udd.iProduct = tdd->iProduct; 420184610Salfred utd->udd.iSerialNumber = tdd->iSerialNumber; 421184610Salfred utd->udd.bNumConfigurations = temp->bConfigurationValue - 1; 422184610Salfred 423184610Salfred /* 424184610Salfred * Fill out the USB device qualifier. Pretend that we 425184610Salfred * don't support any other speeds by setting 426184610Salfred * "bNumConfigurations" equal to zero. That saves us 427184610Salfred * generating an extra set of configuration 428184610Salfred * descriptors. 429184610Salfred */ 430184610Salfred utd->udq.bLength = sizeof(utd->udq); 431184610Salfred utd->udq.bDescriptorType = UDESC_DEVICE_QUALIFIER; 432184610Salfred utd->udq.bDeviceClass = tdd->bDeviceClass; 433184610Salfred utd->udq.bDeviceSubClass = tdd->bDeviceSubClass; 434184610Salfred utd->udq.bDeviceProtocol = tdd->bDeviceProtocol; 435184610Salfred utd->udq.bNumConfigurations = 0; 436184610Salfred USETW(utd->udq.bcdUSB, 0x0200); 437184610Salfred utd->udq.bMaxPacketSize0 = 0; 438184610Salfred 439184610Salfred switch (temp->usb2_speed) { 440184610Salfred case USB_SPEED_LOW: 441184610Salfred USETW(utd->udd.bcdUSB, 0x0110); 442184610Salfred utd->udd.bMaxPacketSize = 8; 443184610Salfred break; 444184610Salfred case USB_SPEED_FULL: 445184610Salfred USETW(utd->udd.bcdUSB, 0x0110); 446184610Salfred utd->udd.bMaxPacketSize = 32; 447184610Salfred break; 448184610Salfred case USB_SPEED_HIGH: 449184610Salfred USETW(utd->udd.bcdUSB, 0x0200); 450184610Salfred utd->udd.bMaxPacketSize = 64; 451184610Salfred break; 452184610Salfred case USB_SPEED_VARIABLE: 453184610Salfred USETW(utd->udd.bcdUSB, 0x0250); 454184610Salfred utd->udd.bMaxPacketSize = 255; /* 512 bytes */ 455184610Salfred break; 456184610Salfred default: 457184610Salfred temp->err = USB_ERR_INVAL; 458184610Salfred break; 459184610Salfred } 460184610Salfred } 461184610Salfred} 462184610Salfred 463184610Salfred/*------------------------------------------------------------------------* 464184610Salfred * usb2_hw_ep_match 465184610Salfred * 466184610Salfred * Return values: 467184610Salfred * 0: The endpoint profile does not match the criterias 468184610Salfred * Else: The endpoint profile matches the criterias 469184610Salfred *------------------------------------------------------------------------*/ 470184610Salfredstatic uint8_t 471184610Salfredusb2_hw_ep_match(const struct usb2_hw_ep_profile *pf, 472184610Salfred uint8_t ep_type, uint8_t ep_dir_in) 473184610Salfred{ 474184610Salfred if (ep_type == UE_CONTROL) { 475184610Salfred /* special */ 476184610Salfred return (pf->support_control); 477184610Salfred } 478184610Salfred if ((pf->support_in && ep_dir_in) || 479184610Salfred (pf->support_out && !ep_dir_in)) { 480184610Salfred if ((pf->support_interrupt && (ep_type == UE_INTERRUPT)) || 481184610Salfred (pf->support_isochronous && (ep_type == UE_ISOCHRONOUS)) || 482184610Salfred (pf->support_bulk && (ep_type == UE_BULK))) { 483184610Salfred return (1); 484184610Salfred } 485184610Salfred } 486184610Salfred return (0); 487184610Salfred} 488184610Salfred 489184610Salfred/*------------------------------------------------------------------------* 490184610Salfred * usb2_hw_ep_find_match 491184610Salfred * 492184610Salfred * This function is used to find the best matching endpoint profile 493184610Salfred * for and endpoint belonging to an USB descriptor. 494184610Salfred * 495184610Salfred * Return values: 496184610Salfred * 0: Success. Got a match. 497184610Salfred * Else: Failure. No match. 498184610Salfred *------------------------------------------------------------------------*/ 499184610Salfredstatic uint8_t 500184610Salfredusb2_hw_ep_find_match(struct usb2_hw_ep_scratch *ues, 501184610Salfred struct usb2_hw_ep_scratch_sub *ep, uint8_t is_simplex) 502184610Salfred{ 503184610Salfred const struct usb2_hw_ep_profile *pf; 504184610Salfred uint16_t distance; 505184610Salfred uint16_t temp; 506184610Salfred uint16_t max_frame_size; 507184610Salfred uint8_t n; 508184610Salfred uint8_t best_n; 509184610Salfred uint8_t dir_in; 510184610Salfred uint8_t dir_out; 511184610Salfred 512184610Salfred distance = 0xFFFF; 513184610Salfred best_n = 0; 514184610Salfred 515184610Salfred if ((!ep->needs_in) && (!ep->needs_out)) { 516184610Salfred return (0); /* we are done */ 517184610Salfred } 518184610Salfred if (ep->needs_ep_type == UE_CONTROL) { 519184610Salfred dir_in = 1; 520184610Salfred dir_out = 1; 521184610Salfred } else { 522184610Salfred if (ep->needs_in) { 523184610Salfred dir_in = 1; 524184610Salfred dir_out = 0; 525184610Salfred } else { 526184610Salfred dir_in = 0; 527184610Salfred dir_out = 1; 528184610Salfred } 529184610Salfred } 530184610Salfred 531184610Salfred for (n = 1; n != (USB_EP_MAX / 2); n++) { 532184610Salfred 533184610Salfred /* get HW endpoint profile */ 534184610Salfred (ues->methods->get_hw_ep_profile) (ues->udev, &pf, n); 535184610Salfred if (pf == NULL) { 536184610Salfred /* end of profiles */ 537184610Salfred break; 538184610Salfred } 539184610Salfred /* check if IN-endpoint is reserved */ 540184610Salfred if (dir_in || pf->is_simplex) { 541184610Salfred if (ues->bmInAlloc[n / 8] & (1 << (n % 8))) { 542184610Salfred /* mismatch */ 543184610Salfred continue; 544184610Salfred } 545184610Salfred } 546184610Salfred /* check if OUT-endpoint is reserved */ 547184610Salfred if (dir_out || pf->is_simplex) { 548184610Salfred if (ues->bmOutAlloc[n / 8] & (1 << (n % 8))) { 549184610Salfred /* mismatch */ 550184610Salfred continue; 551184610Salfred } 552184610Salfred } 553184610Salfred /* check simplex */ 554184610Salfred if (pf->is_simplex == is_simplex) { 555184610Salfred /* mismatch */ 556184610Salfred continue; 557184610Salfred } 558184610Salfred /* check if HW endpoint matches */ 559184610Salfred if (!usb2_hw_ep_match(pf, ep->needs_ep_type, dir_in)) { 560184610Salfred /* mismatch */ 561184610Salfred continue; 562184610Salfred } 563184610Salfred /* get maximum frame size */ 564184610Salfred if (dir_in) 565184610Salfred max_frame_size = pf->max_in_frame_size; 566184610Salfred else 567184610Salfred max_frame_size = pf->max_out_frame_size; 568184610Salfred 569184610Salfred /* check if we have a matching profile */ 570184610Salfred if (max_frame_size >= ep->max_frame_size) { 571184610Salfred temp = (max_frame_size - ep->max_frame_size); 572184610Salfred if (distance > temp) { 573184610Salfred distance = temp; 574184610Salfred best_n = n; 575184610Salfred ep->pf = pf; 576184610Salfred } 577184610Salfred } 578184610Salfred } 579184610Salfred 580184610Salfred /* see if we got a match */ 581184610Salfred if (best_n != 0) { 582184610Salfred /* get the correct profile */ 583184610Salfred pf = ep->pf; 584184610Salfred 585184610Salfred /* reserve IN-endpoint */ 586184610Salfred if (dir_in) { 587184610Salfred ues->bmInAlloc[best_n / 8] |= 588184610Salfred (1 << (best_n % 8)); 589184610Salfred ep->hw_endpoint_in = best_n | UE_DIR_IN; 590184610Salfred ep->needs_in = 0; 591184610Salfred } 592184610Salfred /* reserve OUT-endpoint */ 593184610Salfred if (dir_out) { 594184610Salfred ues->bmOutAlloc[best_n / 8] |= 595184610Salfred (1 << (best_n % 8)); 596184610Salfred ep->hw_endpoint_out = best_n | UE_DIR_OUT; 597184610Salfred ep->needs_out = 0; 598184610Salfred } 599184610Salfred return (0); /* got a match */ 600184610Salfred } 601184610Salfred return (1); /* failure */ 602184610Salfred} 603184610Salfred 604184610Salfred/*------------------------------------------------------------------------* 605184610Salfred * usb2_hw_ep_get_needs 606184610Salfred * 607184610Salfred * This function will figure out the type and number of endpoints 608184610Salfred * which are needed for an USB configuration. 609184610Salfred * 610184610Salfred * Return values: 611184610Salfred * 0: Success. 612184610Salfred * Else: Failure. 613184610Salfred *------------------------------------------------------------------------*/ 614184610Salfredstatic uint8_t 615184610Salfredusb2_hw_ep_get_needs(struct usb2_hw_ep_scratch *ues, 616184610Salfred uint8_t ep_type, uint8_t is_complete) 617184610Salfred{ 618184610Salfred const struct usb2_hw_ep_profile *pf; 619184610Salfred struct usb2_hw_ep_scratch_sub *ep_iface; 620184610Salfred struct usb2_hw_ep_scratch_sub *ep_curr; 621184610Salfred struct usb2_hw_ep_scratch_sub *ep_max; 622184610Salfred struct usb2_hw_ep_scratch_sub *ep_end; 623184610Salfred struct usb2_descriptor *desc; 624184610Salfred struct usb2_interface_descriptor *id; 625184610Salfred struct usb2_endpoint_descriptor *ed; 626184610Salfred uint16_t wMaxPacketSize; 627184610Salfred uint16_t temp; 628184610Salfred uint8_t speed; 629184610Salfred uint8_t ep_no; 630184610Salfred 631184610Salfred ep_iface = ues->ep_max; 632184610Salfred ep_curr = ues->ep_max; 633184610Salfred ep_end = ues->ep + USB_EP_MAX; 634184610Salfred ep_max = ues->ep_max; 635184610Salfred desc = NULL; 636184610Salfred speed = usb2_get_speed(ues->udev); 637184610Salfred 638184610Salfredrepeat: 639184610Salfred 640184610Salfred while ((desc = usb2_desc_foreach(ues->cd, desc))) { 641184610Salfred 642184610Salfred if ((desc->bDescriptorType == UDESC_INTERFACE) && 643184610Salfred (desc->bLength >= sizeof(*id))) { 644184610Salfred 645184610Salfred id = (void *)desc; 646184610Salfred 647184610Salfred if (id->bAlternateSetting == 0) { 648184610Salfred /* going forward */ 649184610Salfred ep_iface = ep_max; 650184610Salfred } else { 651184610Salfred /* reset */ 652184610Salfred ep_curr = ep_iface; 653184610Salfred } 654184610Salfred } 655184610Salfred if ((desc->bDescriptorType == UDESC_ENDPOINT) && 656184610Salfred (desc->bLength >= sizeof(*ed))) { 657184610Salfred 658184610Salfred ed = (void *)desc; 659184610Salfred 660184610Salfred goto handle_endpoint_desc; 661184610Salfred } 662184610Salfred } 663184610Salfred ues->ep_max = ep_max; 664184610Salfred return (0); 665184610Salfred 666184610Salfredhandle_endpoint_desc: 667184610Salfred temp = (ed->bmAttributes & UE_XFERTYPE); 668184610Salfred 669184610Salfred if (temp == ep_type) { 670184610Salfred 671184610Salfred if (ep_curr == ep_end) { 672184610Salfred /* too many endpoints */ 673184610Salfred return (1); /* failure */ 674184610Salfred } 675184610Salfred wMaxPacketSize = UGETW(ed->wMaxPacketSize); 676184610Salfred if ((wMaxPacketSize & 0xF800) && 677184610Salfred (speed == USB_SPEED_HIGH)) { 678184610Salfred /* handle packet multiplier */ 679184610Salfred temp = (wMaxPacketSize >> 11) & 3; 680184610Salfred wMaxPacketSize &= 0x7FF; 681184610Salfred if (temp == 1) { 682184610Salfred wMaxPacketSize *= 2; 683184610Salfred } else { 684184610Salfred wMaxPacketSize *= 3; 685184610Salfred } 686184610Salfred } 687184610Salfred /* 688184610Salfred * Check if we have a fixed endpoint number, else the 689184610Salfred * endpoint number is allocated dynamically: 690184610Salfred */ 691184610Salfred ep_no = (ed->bEndpointAddress & UE_ADDR); 692184610Salfred if (ep_no != 0) { 693184610Salfred 694184610Salfred /* get HW endpoint profile */ 695184610Salfred (ues->methods->get_hw_ep_profile) 696184610Salfred (ues->udev, &pf, ep_no); 697184610Salfred if (pf == NULL) { 698184610Salfred /* HW profile does not exist - failure */ 699184610Salfred DPRINTFN(0, "Endpoint profile %u " 700184610Salfred "does not exist\n", ep_no); 701184610Salfred return (1); 702184610Salfred } 703184610Salfred /* reserve fixed endpoint number */ 704184610Salfred if (ep_type == UE_CONTROL) { 705184610Salfred ues->bmInAlloc[ep_no / 8] |= 706184610Salfred (1 << (ep_no % 8)); 707184610Salfred ues->bmOutAlloc[ep_no / 8] |= 708184610Salfred (1 << (ep_no % 8)); 709184610Salfred if ((pf->max_in_frame_size < wMaxPacketSize) || 710184610Salfred (pf->max_out_frame_size < wMaxPacketSize)) { 711184610Salfred DPRINTFN(0, "Endpoint profile %u " 712184610Salfred "has too small buffer!\n", ep_no); 713184610Salfred return (1); 714184610Salfred } 715184610Salfred } else if (ed->bEndpointAddress & UE_DIR_IN) { 716184610Salfred ues->bmInAlloc[ep_no / 8] |= 717184610Salfred (1 << (ep_no % 8)); 718184610Salfred if (pf->max_in_frame_size < wMaxPacketSize) { 719184610Salfred DPRINTFN(0, "Endpoint profile %u " 720184610Salfred "has too small buffer!\n", ep_no); 721184610Salfred return (1); 722184610Salfred } 723184610Salfred } else { 724184610Salfred ues->bmOutAlloc[ep_no / 8] |= 725184610Salfred (1 << (ep_no % 8)); 726184610Salfred if (pf->max_out_frame_size < wMaxPacketSize) { 727184610Salfred DPRINTFN(0, "Endpoint profile %u " 728184610Salfred "has too small buffer!\n", ep_no); 729184610Salfred return (1); 730184610Salfred } 731184610Salfred } 732184610Salfred } else if (is_complete) { 733184610Salfred 734184610Salfred /* check if we have enough buffer space */ 735184610Salfred if (wMaxPacketSize > 736184610Salfred ep_curr->max_frame_size) { 737184610Salfred return (1); /* failure */ 738184610Salfred } 739184610Salfred if (ed->bEndpointAddress & UE_DIR_IN) { 740184610Salfred ed->bEndpointAddress = 741184610Salfred ep_curr->hw_endpoint_in; 742184610Salfred } else { 743184610Salfred ed->bEndpointAddress = 744184610Salfred ep_curr->hw_endpoint_out; 745184610Salfred } 746184610Salfred 747184610Salfred } else { 748184610Salfred 749184610Salfred /* compute the maximum frame size */ 750184610Salfred if (ep_curr->max_frame_size < wMaxPacketSize) { 751184610Salfred ep_curr->max_frame_size = wMaxPacketSize; 752184610Salfred } 753184610Salfred if (temp == UE_CONTROL) { 754184610Salfred ep_curr->needs_in = 1; 755184610Salfred ep_curr->needs_out = 1; 756184610Salfred } else { 757184610Salfred if (ed->bEndpointAddress & UE_DIR_IN) { 758184610Salfred ep_curr->needs_in = 1; 759184610Salfred } else { 760184610Salfred ep_curr->needs_out = 1; 761184610Salfred } 762184610Salfred } 763184610Salfred ep_curr->needs_ep_type = ep_type; 764184610Salfred } 765184610Salfred 766184610Salfred ep_curr++; 767184610Salfred if (ep_max < ep_curr) { 768184610Salfred ep_max = ep_curr; 769184610Salfred } 770184610Salfred } 771184610Salfred goto repeat; 772184610Salfred} 773184610Salfred 774184610Salfred/*------------------------------------------------------------------------* 775184610Salfred * usb2_hw_ep_resolve 776184610Salfred * 777184610Salfred * This function will try to resolve endpoint requirements by the 778184610Salfred * given endpoint profiles that the USB hardware reports. 779184610Salfred * 780184610Salfred * Return values: 781184610Salfred * 0: Success 782184610Salfred * Else: Failure 783184610Salfred *------------------------------------------------------------------------*/ 784184610Salfredstatic usb2_error_t 785184610Salfredusb2_hw_ep_resolve(struct usb2_device *udev, 786184610Salfred struct usb2_descriptor *desc) 787184610Salfred{ 788184610Salfred struct usb2_hw_ep_scratch *ues; 789184610Salfred struct usb2_hw_ep_scratch_sub *ep; 790184610Salfred const struct usb2_hw_ep_profile *pf; 791184610Salfred struct usb2_bus_methods *methods; 792184610Salfred struct usb2_device_descriptor *dd; 793184610Salfred uint16_t mps; 794184610Salfred 795184610Salfred if (desc == NULL) { 796184610Salfred return (USB_ERR_INVAL); 797184610Salfred } 798184610Salfred /* get bus methods */ 799184610Salfred methods = udev->bus->methods; 800184610Salfred 801184610Salfred if (methods->get_hw_ep_profile == NULL) { 802184610Salfred return (USB_ERR_INVAL); 803184610Salfred } 804184610Salfred if (desc->bDescriptorType == UDESC_DEVICE) { 805184610Salfred 806184610Salfred if (desc->bLength < sizeof(*dd)) { 807184610Salfred return (USB_ERR_INVAL); 808184610Salfred } 809184610Salfred dd = (void *)desc; 810184610Salfred 811184610Salfred /* get HW control endpoint 0 profile */ 812184610Salfred (methods->get_hw_ep_profile) (udev, &pf, 0); 813184610Salfred if (pf == NULL) { 814184610Salfred return (USB_ERR_INVAL); 815184610Salfred } 816184610Salfred if (!usb2_hw_ep_match(pf, UE_CONTROL, 0)) { 817184610Salfred DPRINTFN(0, "Endpoint 0 does not " 818184610Salfred "support control\n"); 819184610Salfred return (USB_ERR_INVAL); 820184610Salfred } 821184610Salfred mps = dd->bMaxPacketSize; 822184610Salfred 823184610Salfred if (udev->speed == USB_SPEED_FULL) { 824184610Salfred /* 825184610Salfred * We can optionally choose another packet size ! 826184610Salfred */ 827184610Salfred while (1) { 828184610Salfred /* check if "mps" is ok */ 829184610Salfred if (pf->max_in_frame_size >= mps) { 830184610Salfred break; 831184610Salfred } 832184610Salfred /* reduce maximum packet size */ 833184610Salfred mps /= 2; 834184610Salfred 835184610Salfred /* check if "mps" is too small */ 836184610Salfred if (mps < 8) { 837184610Salfred return (USB_ERR_INVAL); 838184610Salfred } 839184610Salfred } 840184610Salfred 841184610Salfred dd->bMaxPacketSize = mps; 842184610Salfred 843184610Salfred } else { 844184610Salfred /* We only have one choice */ 845184610Salfred if (mps == 255) { 846184610Salfred mps = 512; 847184610Salfred } 848184610Salfred /* Check if we support the specified wMaxPacketSize */ 849184610Salfred if (pf->max_in_frame_size < mps) { 850184610Salfred return (USB_ERR_INVAL); 851184610Salfred } 852184610Salfred } 853184610Salfred return (0); /* success */ 854184610Salfred } 855184610Salfred if (desc->bDescriptorType != UDESC_CONFIG) { 856184610Salfred return (USB_ERR_INVAL); 857184610Salfred } 858184610Salfred if (desc->bLength < sizeof(*(ues->cd))) { 859184610Salfred return (USB_ERR_INVAL); 860184610Salfred } 861184610Salfred ues = udev->bus->scratch[0].hw_ep_scratch; 862184610Salfred 863184610Salfred bzero(ues, sizeof(*ues)); 864184610Salfred 865184610Salfred ues->ep_max = ues->ep; 866184610Salfred ues->cd = (void *)desc; 867184610Salfred ues->methods = methods; 868184610Salfred ues->udev = udev; 869184610Salfred 870184610Salfred /* Get all the endpoints we need */ 871184610Salfred 872184610Salfred if (usb2_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 0) || 873184610Salfred usb2_hw_ep_get_needs(ues, UE_INTERRUPT, 0) || 874184610Salfred usb2_hw_ep_get_needs(ues, UE_CONTROL, 0) || 875184610Salfred usb2_hw_ep_get_needs(ues, UE_BULK, 0)) { 876184610Salfred DPRINTFN(0, "Could not get needs\n"); 877184610Salfred return (USB_ERR_INVAL); 878184610Salfred } 879184610Salfred for (ep = ues->ep; ep != ues->ep_max; ep++) { 880184610Salfred 881184610Salfred while (ep->needs_in || ep->needs_out) { 882184610Salfred 883184610Salfred /* 884184610Salfred * First try to use a simplex endpoint. 885184610Salfred * Then try to use a duplex endpoint. 886184610Salfred */ 887184610Salfred if (usb2_hw_ep_find_match(ues, ep, 1) && 888184610Salfred usb2_hw_ep_find_match(ues, ep, 0)) { 889184610Salfred DPRINTFN(0, "Could not find match\n"); 890184610Salfred return (USB_ERR_INVAL); 891184610Salfred } 892184610Salfred } 893184610Salfred } 894184610Salfred 895184610Salfred ues->ep_max = ues->ep; 896184610Salfred 897184610Salfred /* Update all endpoint addresses */ 898184610Salfred 899184610Salfred if (usb2_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 1) || 900184610Salfred usb2_hw_ep_get_needs(ues, UE_INTERRUPT, 1) || 901184610Salfred usb2_hw_ep_get_needs(ues, UE_CONTROL, 1) || 902184610Salfred usb2_hw_ep_get_needs(ues, UE_BULK, 1)) { 903184610Salfred DPRINTFN(0, "Could not update endpoint address\n"); 904184610Salfred return (USB_ERR_INVAL); 905184610Salfred } 906184610Salfred return (0); /* success */ 907184610Salfred} 908184610Salfred 909184610Salfred/*------------------------------------------------------------------------* 910184610Salfred * usb2_temp_get_tdd 911184610Salfred * 912184610Salfred * Returns: 913184610Salfred * NULL: No USB template device descriptor found. 914184610Salfred * Else: Pointer to the USB template device descriptor. 915184610Salfred *------------------------------------------------------------------------*/ 916184610Salfredstatic const struct usb2_temp_device_desc * 917184610Salfredusb2_temp_get_tdd(struct usb2_device *udev) 918184610Salfred{ 919184610Salfred if (udev->usb2_template_ptr == NULL) { 920184610Salfred return (NULL); 921184610Salfred } 922184610Salfred return (udev->usb2_template_ptr->tdd); 923184610Salfred} 924184610Salfred 925184610Salfred/*------------------------------------------------------------------------* 926184610Salfred * usb2_temp_get_device_desc 927184610Salfred * 928184610Salfred * Returns: 929184610Salfred * NULL: No USB device descriptor found. 930184610Salfred * Else: Pointer to USB device descriptor. 931184610Salfred *------------------------------------------------------------------------*/ 932184610Salfredstatic void * 933184610Salfredusb2_temp_get_device_desc(struct usb2_device *udev) 934184610Salfred{ 935184610Salfred struct usb2_device_descriptor *dd; 936184610Salfred 937184610Salfred if (udev->usb2_template_ptr == NULL) { 938184610Salfred return (NULL); 939184610Salfred } 940184610Salfred dd = &udev->usb2_template_ptr->udd; 941184610Salfred if (dd->bDescriptorType != UDESC_DEVICE) { 942184610Salfred /* sanity check failed */ 943184610Salfred return (NULL); 944184610Salfred } 945184610Salfred return (dd); 946184610Salfred} 947184610Salfred 948184610Salfred/*------------------------------------------------------------------------* 949184610Salfred * usb2_temp_get_qualifier_desc 950184610Salfred * 951184610Salfred * Returns: 952184610Salfred * NULL: No USB device_qualifier descriptor found. 953184610Salfred * Else: Pointer to USB device_qualifier descriptor. 954184610Salfred *------------------------------------------------------------------------*/ 955184610Salfredstatic void * 956184610Salfredusb2_temp_get_qualifier_desc(struct usb2_device *udev) 957184610Salfred{ 958184610Salfred struct usb2_device_qualifier *dq; 959184610Salfred 960184610Salfred if (udev->usb2_template_ptr == NULL) { 961184610Salfred return (NULL); 962184610Salfred } 963184610Salfred dq = &udev->usb2_template_ptr->udq; 964184610Salfred if (dq->bDescriptorType != UDESC_DEVICE_QUALIFIER) { 965184610Salfred /* sanity check failed */ 966184610Salfred return (NULL); 967184610Salfred } 968184610Salfred return (dq); 969184610Salfred} 970184610Salfred 971184610Salfred/*------------------------------------------------------------------------* 972184610Salfred * usb2_temp_get_config_desc 973184610Salfred * 974184610Salfred * Returns: 975184610Salfred * NULL: No USB config descriptor found. 976184610Salfred * Else: Pointer to USB config descriptor having index "index". 977184610Salfred *------------------------------------------------------------------------*/ 978184610Salfredstatic void * 979184610Salfredusb2_temp_get_config_desc(struct usb2_device *udev, 980184610Salfred uint16_t *pLength, uint8_t index) 981184610Salfred{ 982184610Salfred struct usb2_device_descriptor *dd; 983184610Salfred struct usb2_config_descriptor *cd; 984184610Salfred uint16_t temp; 985184610Salfred 986184610Salfred if (udev->usb2_template_ptr == NULL) { 987184610Salfred return (NULL); 988184610Salfred } 989184610Salfred dd = &udev->usb2_template_ptr->udd; 990184610Salfred cd = (void *)(udev->usb2_template_ptr + 1); 991184610Salfred 992184610Salfred if (index >= dd->bNumConfigurations) { 993184610Salfred /* out of range */ 994184610Salfred return (NULL); 995184610Salfred } 996184610Salfred while (index--) { 997184610Salfred if (cd->bDescriptorType != UDESC_CONFIG) { 998184610Salfred /* sanity check failed */ 999184610Salfred return (NULL); 1000184610Salfred } 1001184610Salfred temp = UGETW(cd->wTotalLength); 1002184610Salfred cd = USB_ADD_BYTES(cd, temp); 1003184610Salfred } 1004184610Salfred 1005184610Salfred if (pLength) { 1006184610Salfred *pLength = UGETW(cd->wTotalLength); 1007184610Salfred } 1008184610Salfred return (cd); 1009184610Salfred} 1010184610Salfred 1011184610Salfred/*------------------------------------------------------------------------* 1012184610Salfred * usb2_temp_get_vendor_desc 1013184610Salfred * 1014184610Salfred * Returns: 1015184610Salfred * NULL: No vendor descriptor found. 1016184610Salfred * Else: Pointer to a vendor descriptor. 1017184610Salfred *------------------------------------------------------------------------*/ 1018184610Salfredstatic const void * 1019184610Salfredusb2_temp_get_vendor_desc(struct usb2_device *udev, 1020184610Salfred const struct usb2_device_request *req) 1021184610Salfred{ 1022184610Salfred const struct usb2_temp_device_desc *tdd; 1023184610Salfred 1024184610Salfred tdd = usb2_temp_get_tdd(udev); 1025184610Salfred if (tdd == NULL) { 1026184610Salfred return (NULL); 1027184610Salfred } 1028184610Salfred if (tdd->getVendorDesc == NULL) { 1029184610Salfred return (NULL); 1030184610Salfred } 1031184610Salfred return ((tdd->getVendorDesc) (req)); 1032184610Salfred} 1033184610Salfred 1034184610Salfred/*------------------------------------------------------------------------* 1035184610Salfred * usb2_temp_get_string_desc 1036184610Salfred * 1037184610Salfred * Returns: 1038184610Salfred * NULL: No string descriptor found. 1039184610Salfred * Else: Pointer to a string descriptor. 1040184610Salfred *------------------------------------------------------------------------*/ 1041184610Salfredstatic const void * 1042184610Salfredusb2_temp_get_string_desc(struct usb2_device *udev, 1043184610Salfred uint16_t lang_id, uint8_t string_index) 1044184610Salfred{ 1045184610Salfred const struct usb2_temp_device_desc *tdd; 1046184610Salfred 1047184610Salfred tdd = usb2_temp_get_tdd(udev); 1048184610Salfred if (tdd == NULL) { 1049184610Salfred return (NULL); 1050184610Salfred } 1051184610Salfred if (tdd->getStringDesc == NULL) { 1052184610Salfred return (NULL); 1053184610Salfred } 1054184610Salfred return ((tdd->getStringDesc) (lang_id, string_index)); 1055184610Salfred} 1056184610Salfred 1057184610Salfred/*------------------------------------------------------------------------* 1058184610Salfred * usb2_temp_get_hub_desc 1059184610Salfred * 1060184610Salfred * Returns: 1061184610Salfred * NULL: No USB HUB descriptor found. 1062184610Salfred * Else: Pointer to a USB HUB descriptor. 1063184610Salfred *------------------------------------------------------------------------*/ 1064184610Salfredstatic const void * 1065184610Salfredusb2_temp_get_hub_desc(struct usb2_device *udev) 1066184610Salfred{ 1067184610Salfred return (NULL); /* needs to be implemented */ 1068184610Salfred} 1069184610Salfred 1070184610Salfred/*------------------------------------------------------------------------* 1071184610Salfred * usb2_temp_get_desc 1072184610Salfred * 1073184610Salfred * This function is a demultiplexer for local USB device side control 1074184610Salfred * endpoint requests. 1075184610Salfred *------------------------------------------------------------------------*/ 1076184610Salfredstatic void 1077184610Salfredusb2_temp_get_desc(struct usb2_device *udev, struct usb2_device_request *req, 1078184610Salfred const void **pPtr, uint16_t *pLength) 1079184610Salfred{ 1080184610Salfred const uint8_t *buf; 1081184610Salfred uint16_t len; 1082184610Salfred 1083184610Salfred buf = NULL; 1084184610Salfred len = 0; 1085184610Salfred 1086184610Salfred switch (req->bmRequestType) { 1087184610Salfred case UT_READ_DEVICE: 1088184610Salfred switch (req->bRequest) { 1089184610Salfred case UR_GET_DESCRIPTOR: 1090184610Salfred goto tr_handle_get_descriptor; 1091184610Salfred default: 1092184610Salfred goto tr_stalled; 1093184610Salfred } 1094184610Salfred break; 1095184610Salfred case UT_READ_CLASS_DEVICE: 1096184610Salfred switch (req->bRequest) { 1097184610Salfred case UR_GET_DESCRIPTOR: 1098184610Salfred goto tr_handle_get_class_descriptor; 1099184610Salfred default: 1100184610Salfred goto tr_stalled; 1101184610Salfred } 1102184610Salfred break; 1103184610Salfred case UT_READ_VENDOR_DEVICE: 1104184610Salfred case UT_READ_VENDOR_OTHER: 1105184610Salfred buf = usb2_temp_get_vendor_desc(udev, req); 1106184610Salfred goto tr_valid; 1107184610Salfred default: 1108184610Salfred goto tr_stalled; 1109184610Salfred } 1110184610Salfred 1111184610Salfredtr_handle_get_descriptor: 1112184610Salfred switch (req->wValue[1]) { 1113184610Salfred case UDESC_DEVICE: 1114184610Salfred if (req->wValue[0]) { 1115184610Salfred goto tr_stalled; 1116184610Salfred } 1117184610Salfred buf = usb2_temp_get_device_desc(udev); 1118184610Salfred goto tr_valid; 1119184610Salfred case UDESC_DEVICE_QUALIFIER: 1120184610Salfred if (udev->speed != USB_SPEED_HIGH) { 1121184610Salfred goto tr_stalled; 1122184610Salfred } 1123184610Salfred if (req->wValue[0]) { 1124184610Salfred goto tr_stalled; 1125184610Salfred } 1126184610Salfred buf = usb2_temp_get_qualifier_desc(udev); 1127184610Salfred goto tr_valid; 1128184610Salfred case UDESC_OTHER_SPEED_CONFIGURATION: 1129184610Salfred if (udev->speed != USB_SPEED_HIGH) { 1130184610Salfred goto tr_stalled; 1131184610Salfred } 1132184610Salfred case UDESC_CONFIG: 1133184610Salfred buf = usb2_temp_get_config_desc(udev, 1134184610Salfred &len, req->wValue[0]); 1135184610Salfred goto tr_valid; 1136184610Salfred case UDESC_STRING: 1137184610Salfred buf = usb2_temp_get_string_desc(udev, 1138184610Salfred UGETW(req->wIndex), req->wValue[0]); 1139184610Salfred goto tr_valid; 1140184610Salfred default: 1141184610Salfred goto tr_stalled; 1142184610Salfred } 1143184610Salfred goto tr_stalled; 1144184610Salfred 1145184610Salfredtr_handle_get_class_descriptor: 1146184610Salfred if (req->wValue[0]) { 1147184610Salfred goto tr_stalled; 1148184610Salfred } 1149184610Salfred buf = usb2_temp_get_hub_desc(udev); 1150184610Salfred goto tr_valid; 1151184610Salfred 1152184610Salfredtr_valid: 1153184610Salfred if (buf == NULL) { 1154184610Salfred goto tr_stalled; 1155184610Salfred } 1156184610Salfred if (len == 0) { 1157184610Salfred len = buf[0]; 1158184610Salfred } 1159184610Salfred *pPtr = buf; 1160184610Salfred *pLength = len; 1161184610Salfred return; 1162184610Salfred 1163184610Salfredtr_stalled: 1164184610Salfred *pPtr = NULL; 1165184610Salfred *pLength = 0; 1166184610Salfred} 1167184610Salfred 1168184610Salfred/*------------------------------------------------------------------------* 1169184610Salfred * usb2_temp_setup 1170184610Salfred * 1171184610Salfred * This function generates USB descriptors according to the given USB 1172184610Salfred * template device descriptor. It will also try to figure out the best 1173184610Salfred * matching endpoint addresses using the hardware endpoint profiles. 1174184610Salfred * 1175184610Salfred * Returns: 1176184610Salfred * 0: Success 1177184610Salfred * Else: Failure 1178184610Salfred *------------------------------------------------------------------------*/ 1179184610Salfredstatic usb2_error_t 1180184610Salfredusb2_temp_setup(struct usb2_device *udev, 1181184610Salfred const struct usb2_temp_device_desc *tdd) 1182184610Salfred{ 1183184610Salfred struct usb2_temp_setup *uts; 1184184610Salfred void *buf; 1185184610Salfred uint8_t n; 1186184610Salfred 1187184610Salfred if (tdd == NULL) { 1188184610Salfred /* be NULL safe */ 1189184610Salfred return (0); 1190184610Salfred } 1191184610Salfred uts = udev->bus->scratch[0].temp_setup; 1192184610Salfred 1193184610Salfred bzero(uts, sizeof(*uts)); 1194184610Salfred 1195184610Salfred uts->usb2_speed = udev->speed; 1196184610Salfred uts->self_powered = udev->flags.self_powered; 1197184610Salfred 1198184610Salfred /* first pass */ 1199184610Salfred 1200184610Salfred usb2_make_device_desc(uts, tdd); 1201184610Salfred 1202184610Salfred if (uts->err) { 1203184610Salfred /* some error happened */ 1204184610Salfred return (uts->err); 1205184610Salfred } 1206184610Salfred /* sanity check */ 1207184610Salfred if (uts->size == 0) { 1208184610Salfred return (USB_ERR_INVAL); 1209184610Salfred } 1210184610Salfred /* allocate zeroed memory */ 1211184610Salfred uts->buf = malloc(uts->size, M_USB, M_WAITOK | M_ZERO); 1212184610Salfred if (uts->buf == NULL) { 1213184610Salfred /* could not allocate memory */ 1214184610Salfred return (USB_ERR_NOMEM); 1215184610Salfred } 1216184610Salfred /* second pass */ 1217184610Salfred 1218184610Salfred uts->size = 0; 1219184610Salfred 1220184610Salfred usb2_make_device_desc(uts, tdd); 1221184610Salfred 1222184610Salfred /* 1223184610Salfred * Store a pointer to our descriptors: 1224184610Salfred */ 1225184610Salfred udev->usb2_template_ptr = uts->buf; 1226184610Salfred 1227184610Salfred if (uts->err) { 1228184610Salfred /* some error happened during second pass */ 1229184610Salfred goto error; 1230184610Salfred } 1231184610Salfred /* 1232184610Salfred * Resolve all endpoint addresses ! 1233184610Salfred */ 1234184610Salfred buf = usb2_temp_get_device_desc(udev); 1235184610Salfred uts->err = usb2_hw_ep_resolve(udev, buf); 1236184610Salfred if (uts->err) { 1237184610Salfred DPRINTFN(0, "Could not resolve endpoints for " 1238184610Salfred "Device Descriptor, error = %s\n", 1239184610Salfred usb2_errstr(uts->err)); 1240184610Salfred goto error; 1241184610Salfred } 1242184610Salfred for (n = 0;; n++) { 1243184610Salfred 1244184610Salfred buf = usb2_temp_get_config_desc(udev, NULL, n); 1245184610Salfred if (buf == NULL) { 1246184610Salfred break; 1247184610Salfred } 1248184610Salfred uts->err = usb2_hw_ep_resolve(udev, buf); 1249184610Salfred if (uts->err) { 1250184610Salfred DPRINTFN(0, "Could not resolve endpoints for " 1251184610Salfred "Config Descriptor %u, error = %s\n", n, 1252184610Salfred usb2_errstr(uts->err)); 1253184610Salfred goto error; 1254184610Salfred } 1255184610Salfred } 1256184610Salfred return (uts->err); 1257184610Salfred 1258184610Salfrederror: 1259184610Salfred usb2_temp_unsetup(udev); 1260184610Salfred return (uts->err); 1261184610Salfred} 1262184610Salfred 1263184610Salfred/*------------------------------------------------------------------------* 1264184610Salfred * usb2_temp_unsetup 1265184610Salfred * 1266184610Salfred * This function frees any memory associated with the currently 1267184610Salfred * setup template, if any. 1268184610Salfred *------------------------------------------------------------------------*/ 1269184610Salfredstatic void 1270184610Salfredusb2_temp_unsetup(struct usb2_device *udev) 1271184610Salfred{ 1272184610Salfred if (udev->usb2_template_ptr) { 1273184610Salfred 1274184610Salfred free(udev->usb2_template_ptr, M_USB); 1275184610Salfred 1276184610Salfred udev->usb2_template_ptr = NULL; 1277184610Salfred } 1278184610Salfred} 1279184610Salfred 1280184610Salfredstatic usb2_error_t 1281184610Salfredusb2_temp_setup_by_index(struct usb2_device *udev, uint16_t index) 1282184610Salfred{ 1283184610Salfred usb2_error_t err; 1284184610Salfred 1285184610Salfred switch (index) { 1286184610Salfred case 0: 1287184610Salfred err = usb2_temp_setup(udev, &usb2_template_msc); 1288184610Salfred break; 1289184610Salfred case 1: 1290184610Salfred err = usb2_temp_setup(udev, &usb2_template_cdce); 1291184610Salfred break; 1292184610Salfred case 2: 1293184610Salfred err = usb2_temp_setup(udev, &usb2_template_mtp); 1294184610Salfred break; 1295184610Salfred default: 1296184610Salfred return (USB_ERR_INVAL); 1297184610Salfred } 1298184610Salfred 1299184610Salfred return (err); 1300184610Salfred} 1301184610Salfred 1302184610Salfredstatic void 1303184610Salfredusb2_temp_init(void *arg) 1304184610Salfred{ 1305184610Salfred /* register our functions */ 1306184610Salfred usb2_temp_get_desc_p = &usb2_temp_get_desc; 1307184610Salfred usb2_temp_setup_by_index_p = &usb2_temp_setup_by_index; 1308184610Salfred usb2_temp_unsetup_p = &usb2_temp_unsetup; 1309184610Salfred} 1310184610Salfred 1311184610SalfredSYSINIT(usb2_temp_init, SI_SUB_LOCK, SI_ORDER_FIRST, usb2_temp_init, NULL); 1312184610SalfredSYSUNINIT(usb2_temp_unload, SI_SUB_LOCK, SI_ORDER_ANY, usb2_temp_unload, NULL); 1313