usb_template.c revision 184610
187139Smarkm/* $FreeBSD: head/sys/dev/usb2/template/usb2_template.c 184610 2008-11-04 02:31:03Z alfred $ */ 229088Smarkm/*- 329088Smarkm * Copyright (c) 2007 Hans Petter Selasky. All rights reserved. 429088Smarkm * 529088Smarkm * Redistribution and use in source and binary forms, with or without 629088Smarkm * modification, are permitted provided that the following conditions 729088Smarkm * are met: 829088Smarkm * 1. Redistributions of source code must retain the above copyright 929088Smarkm * notice, this list of conditions and the following disclaimer. 1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1129088Smarkm * notice, this list of conditions and the following disclaimer in the 1229088Smarkm * documentation and/or other materials provided with the distribution. 1329088Smarkm * 1429088Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1529088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1629088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1729088Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1829088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1929088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2029088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2129088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2229088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2329088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2429088Smarkm * SUCH DAMAGE. 2529088Smarkm */ 2629088Smarkm 2729088Smarkm/* 2829088Smarkm * This file contains sub-routines to build up USB descriptors from 2929088Smarkm * USB templates. 3029088Smarkm */ 3129088Smarkm 3229088Smarkm#include <dev/usb2/include/usb2_standard.h> 3329088Smarkm#include <dev/usb2/include/usb2_cdc.h> 34114630Sobrien#include <dev/usb2/include/usb2_mfunc.h> 3529088Smarkm#include <dev/usb2/include/usb2_defs.h> 3629181Smarkm#include <dev/usb2/include/usb2_error.h> 3731622Scharnier 38114630Sobrien#define USB_DEBUG_VAR usb2_debug 39114630Sobrien 40114630Sobrien#include <dev/usb2/core/usb2_core.h> 4129088Smarkm#include <dev/usb2/core/usb2_busdma.h> 4287139Smarkm#include <dev/usb2/core/usb2_process.h> 4387139Smarkm#include <dev/usb2/core/usb2_debug.h> 4487139Smarkm#include <dev/usb2/core/usb2_parse.h> 4587139Smarkm#include <dev/usb2/core/usb2_device.h> 4687139Smarkm#include <dev/usb2/core/usb2_dynamic.h> 4787139Smarkm 4829088Smarkm#include <dev/usb2/controller/usb2_controller.h> 4929088Smarkm#include <dev/usb2/controller/usb2_bus.h> 5029088Smarkm 5187139Smarkm#include <dev/usb2/template/usb2_template.h> 5229088Smarkm 5329088SmarkmMODULE_DEPEND(usb2_template, usb2_core, 1, 1, 1); 5429088SmarkmMODULE_VERSION(usb2_template, 1); 5587139Smarkm 5629181Smarkm/* function prototypes */ 5729181Smarkm 5829088Smarkmstatic void usb2_make_raw_desc(struct usb2_temp_setup *temp, const uint8_t *raw); 5929088Smarkmstatic void usb2_make_endpoint_desc(struct usb2_temp_setup *temp, const struct usb2_temp_endpoint_desc *ted); 6029181Smarkmstatic void usb2_make_interface_desc(struct usb2_temp_setup *temp, const struct usb2_temp_interface_desc *tid); 6129181Smarkmstatic void usb2_make_config_desc(struct usb2_temp_setup *temp, const struct usb2_temp_config_desc *tcd); 6229181Smarkmstatic void usb2_make_device_desc(struct usb2_temp_setup *temp, const struct usb2_temp_device_desc *tdd); 6387139Smarkmstatic uint8_t usb2_hw_ep_match(const struct usb2_hw_ep_profile *pf, uint8_t ep_type, uint8_t ep_dir_in); 6429181Smarkmstatic uint8_t usb2_hw_ep_find_match(struct usb2_hw_ep_scratch *ues, struct usb2_hw_ep_scratch_sub *ep, uint8_t is_simplex); 6529181Smarkmstatic uint8_t usb2_hw_ep_get_needs(struct usb2_hw_ep_scratch *ues, uint8_t ep_type, uint8_t is_complete); 6629181Smarkmstatic usb2_error_t usb2_hw_ep_resolve(struct usb2_device *udev, struct usb2_descriptor *desc); 6729181Smarkmstatic const struct usb2_temp_device_desc *usb2_temp_get_tdd(struct usb2_device *udev); 6887139Smarkmstatic void *usb2_temp_get_device_desc(struct usb2_device *udev); 6929181Smarkmstatic void *usb2_temp_get_qualifier_desc(struct usb2_device *udev); 7029088Smarkmstatic void *usb2_temp_get_config_desc(struct usb2_device *udev, uint16_t *pLength, uint8_t index); 7187139Smarkmstatic const void *usb2_temp_get_string_desc(struct usb2_device *udev, uint16_t lang_id, uint8_t string_index); 7287139Smarkmstatic const void *usb2_temp_get_vendor_desc(struct usb2_device *udev, const struct usb2_device_request *req); 7329181Smarkmstatic const void *usb2_temp_get_hub_desc(struct usb2_device *udev); 7429088Smarkmstatic void usb2_temp_get_desc(struct usb2_device *udev, struct usb2_device_request *req, const void **pPtr, uint16_t *pLength); 7529088Smarkmstatic usb2_error_t usb2_temp_setup(struct usb2_device *udev, const struct usb2_temp_device_desc *tdd); 7629088Smarkmstatic void usb2_temp_unsetup(struct usb2_device *udev); 7729088Smarkmstatic usb2_error_t usb2_temp_setup_by_index(struct usb2_device *udev, uint16_t index); 7829088Smarkmstatic void usb2_temp_init(void *arg); 7929088Smarkm 8029088Smarkm/*------------------------------------------------------------------------* 8129088Smarkm * usb2_make_raw_desc 8229088Smarkm * 8329088Smarkm * This function will insert a raw USB descriptor into the generated 8429088Smarkm * USB configuration. 8529088Smarkm *------------------------------------------------------------------------*/ 8629088Smarkmstatic void 8729088Smarkmusb2_make_raw_desc(struct usb2_temp_setup *temp, 8829088Smarkm const uint8_t *raw) 8929088Smarkm{ 9029088Smarkm void *dst; 9129088Smarkm uint8_t len; 9229088Smarkm 9329088Smarkm /* 9429088Smarkm * The first byte of any USB descriptor gives the length. 9529088Smarkm */ 9629088Smarkm if (raw) { 9729088Smarkm len = raw[0]; 9829088Smarkm if (temp->buf) { 9929088Smarkm dst = USB_ADD_BYTES(temp->buf, temp->size); 10029088Smarkm bcopy(raw, dst, len); 10129088Smarkm 10229088Smarkm /* check if we have got a CDC union descriptor */ 10329088Smarkm 10429088Smarkm if ((raw[0] >= sizeof(struct usb2_cdc_union_descriptor)) && 10529088Smarkm (raw[1] == UDESC_CS_INTERFACE) && 10629088Smarkm (raw[2] == UDESCSUB_CDC_UNION)) { 10729088Smarkm struct usb2_cdc_union_descriptor *ud = (void *)dst; 10829088Smarkm 10929088Smarkm /* update the interface numbers */ 11029088Smarkm 11129088Smarkm ud->bMasterInterface += 11229088Smarkm temp->bInterfaceNumber; 11329088Smarkm ud->bSlaveInterface[0] += 11429088Smarkm temp->bInterfaceNumber; 11529088Smarkm } 11629088Smarkm } 11729088Smarkm temp->size += len; 11829088Smarkm } 11929088Smarkm return; 12029088Smarkm} 12129088Smarkm 12229088Smarkm/*------------------------------------------------------------------------* 12329088Smarkm * usb2_make_endpoint_desc 12429088Smarkm * 12529088Smarkm * This function will generate an USB endpoint descriptor from the 12629088Smarkm * given USB template endpoint descriptor, which will be inserted into 12729088Smarkm * the USB configuration. 12829088Smarkm *------------------------------------------------------------------------*/ 12929088Smarkmstatic void 13029088Smarkmusb2_make_endpoint_desc(struct usb2_temp_setup *temp, 13129088Smarkm const struct usb2_temp_endpoint_desc *ted) 13229088Smarkm{ 13329088Smarkm struct usb2_endpoint_descriptor *ed; 13429088Smarkm const void **rd; 13529088Smarkm uint16_t old_size; 13629088Smarkm uint16_t mps; 13729088Smarkm uint8_t ea = 0; /* Endpoint Address */ 13829088Smarkm uint8_t et = 0; /* Endpiont Type */ 13929088Smarkm 14031622Scharnier /* Reserve memory */ 14131622Scharnier old_size = temp->size; 14231622Scharnier temp->size += sizeof(*ed); 14387155Smarkm 14487155Smarkm /* Scan all Raw Descriptors first */ 14587155Smarkm 14631622Scharnier rd = ted->ppRawDesc; 14729088Smarkm if (rd) { 14829088Smarkm while (*rd) { 14929088Smarkm usb2_make_raw_desc(temp, *rd); 15029088Smarkm rd++; 15129088Smarkm } 15229088Smarkm } 15329088Smarkm if (ted->pPacketSize == NULL) { 15429088Smarkm /* not initialized */ 15529088Smarkm temp->err = USB_ERR_INVAL; 15629088Smarkm return; 15729088Smarkm } 15887139Smarkm mps = ted->pPacketSize->mps[temp->usb2_speed]; 15987139Smarkm if (mps == 0) { 16029088Smarkm /* not initialized */ 16129088Smarkm temp->err = USB_ERR_INVAL; 16229088Smarkm return; 16329088Smarkm } else if (mps == UE_ZERO_MPS) { 16429088Smarkm /* escape for Zero Max Packet Size */ 16529088Smarkm mps = 0; 16629088Smarkm } 16729088Smarkm ea = (ted->bEndpointAddress & (UE_ADDR | UE_DIR_IN | UE_DIR_OUT)); 16829088Smarkm et = (ted->bmAttributes & UE_XFERTYPE); 16929088Smarkm 17029088Smarkm /* 17129088Smarkm * Fill out the real USB endpoint descriptor 17229088Smarkm * in case there is a buffer present: 17329088Smarkm */ 17429088Smarkm if (temp->buf) { 17587139Smarkm ed = USB_ADD_BYTES(temp->buf, old_size); 17687139Smarkm ed->bLength = sizeof(*ed); 17729088Smarkm ed->bDescriptorType = UDESC_ENDPOINT; 17829088Smarkm ed->bEndpointAddress = ea; 17929088Smarkm ed->bmAttributes = ted->bmAttributes; 18029088Smarkm USETW(ed->wMaxPacketSize, mps); 18129088Smarkm 18229088Smarkm /* setup bInterval parameter */ 18329088Smarkm 18429088Smarkm if (ted->pIntervals && 18587139Smarkm ted->pIntervals->bInterval[temp->usb2_speed]) { 18687139Smarkm ed->bInterval = 18729088Smarkm ted->pIntervals->bInterval[temp->usb2_speed]; 18829088Smarkm } else { 18929088Smarkm switch (et) { 19029088Smarkm case UE_BULK: 19129088Smarkm case UE_CONTROL: 19229088Smarkm ed->bInterval = 0; /* not used */ 19329088Smarkm break; 19429088Smarkm case UE_INTERRUPT: 19529088Smarkm switch (temp->usb2_speed) { 19629088Smarkm case USB_SPEED_LOW: 19729088Smarkm case USB_SPEED_FULL: 19829088Smarkm ed->bInterval = 1; /* 1 ms */ 19929088Smarkm break; 20029088Smarkm default: 20129088Smarkm ed->bInterval = 8; /* 8*125 us */ 20229088Smarkm break; 20329088Smarkm } 20429088Smarkm break; 20529088Smarkm default: /* UE_ISOCHRONOUS */ 20629088Smarkm switch (temp->usb2_speed) { 20729088Smarkm case USB_SPEED_LOW: 20829088Smarkm case USB_SPEED_FULL: 20929088Smarkm ed->bInterval = 1; /* 1 ms */ 21029088Smarkm break; 21129088Smarkm default: 21229088Smarkm ed->bInterval = 1; /* 125 us */ 21329088Smarkm break; 21429088Smarkm } 21529088Smarkm break; 21629088Smarkm } 21729088Smarkm } 21829088Smarkm } 21929088Smarkm temp->bNumEndpoints++; 22029088Smarkm return; 22129088Smarkm} 22287139Smarkm 22387139Smarkm/*------------------------------------------------------------------------* 22429088Smarkm * usb2_make_interface_desc 22529088Smarkm * 22629088Smarkm * This function will generate an USB interface descriptor from the 22729088Smarkm * given USB template interface descriptor, which will be inserted 22829088Smarkm * into the USB configuration. 22929088Smarkm *------------------------------------------------------------------------*/ 23029088Smarkmstatic void 23129088Smarkmusb2_make_interface_desc(struct usb2_temp_setup *temp, 23229088Smarkm const struct usb2_temp_interface_desc *tid) 23329088Smarkm{ 23429088Smarkm struct usb2_interface_descriptor *id; 23529088Smarkm const struct usb2_temp_endpoint_desc **ted; 23629088Smarkm const void **rd; 23729088Smarkm uint16_t old_size; 23829088Smarkm 23929088Smarkm /* Reserve memory */ 24029088Smarkm 24129088Smarkm old_size = temp->size; 24229088Smarkm temp->size += sizeof(*id); 24329088Smarkm 24429088Smarkm /* Update interface and alternate interface numbers */ 24529088Smarkm 24629088Smarkm if (tid->isAltInterface == 0) { 24729088Smarkm temp->bAlternateSetting = 0; 24829088Smarkm temp->bInterfaceNumber++; 24929088Smarkm } else { 25029088Smarkm temp->bAlternateSetting++; 25129088Smarkm } 25229088Smarkm 25329088Smarkm /* Scan all Raw Descriptors first */ 25429088Smarkm 25529088Smarkm rd = tid->ppRawDesc; 25629088Smarkm 25729088Smarkm if (rd) { 25829088Smarkm while (*rd) { 25929088Smarkm usb2_make_raw_desc(temp, *rd); 26029088Smarkm rd++; 26129088Smarkm } 26229088Smarkm } 26329088Smarkm /* Reset some counters */ 26429088Smarkm 26529088Smarkm temp->bNumEndpoints = 0; 26629088Smarkm 26729088Smarkm /* Scan all Endpoint Descriptors second */ 26829088Smarkm 26929088Smarkm ted = tid->ppEndpoints; 27029088Smarkm if (ted) { 27129088Smarkm while (*ted) { 27229088Smarkm usb2_make_endpoint_desc(temp, *ted); 27329088Smarkm ted++; 27429088Smarkm } 27529088Smarkm } 27629088Smarkm /* 27729088Smarkm * Fill out the real USB interface descriptor 27829088Smarkm * in case there is a buffer present: 27929088Smarkm */ 28029088Smarkm if (temp->buf) { 28129088Smarkm id = USB_ADD_BYTES(temp->buf, old_size); 28229088Smarkm id->bLength = sizeof(*id); 28329088Smarkm id->bDescriptorType = UDESC_INTERFACE; 28429088Smarkm id->bInterfaceNumber = temp->bInterfaceNumber; 28529088Smarkm id->bAlternateSetting = temp->bAlternateSetting; 28629088Smarkm id->bNumEndpoints = temp->bNumEndpoints; 28729088Smarkm id->bInterfaceClass = tid->bInterfaceClass; 28829088Smarkm id->bInterfaceSubClass = tid->bInterfaceSubClass; 28929088Smarkm id->bInterfaceProtocol = tid->bInterfaceProtocol; 29029088Smarkm id->iInterface = tid->iInterface; 29129088Smarkm } 29229088Smarkm return; 29329088Smarkm} 29429088Smarkm 29529088Smarkm/*------------------------------------------------------------------------* 29629088Smarkm * usb2_make_config_desc 29729088Smarkm * 29829088Smarkm * This function will generate an USB config descriptor from the given 29929088Smarkm * USB template config descriptor, which will be inserted into the USB 30087139Smarkm * configuration. 30187139Smarkm *------------------------------------------------------------------------*/ 30287139Smarkmstatic void 30329088Smarkmusb2_make_config_desc(struct usb2_temp_setup *temp, 30429088Smarkm const struct usb2_temp_config_desc *tcd) 30529088Smarkm{ 30629088Smarkm struct usb2_config_descriptor *cd; 30729088Smarkm const struct usb2_temp_interface_desc **tid; 30829088Smarkm uint16_t old_size; 30929088Smarkm 31029088Smarkm /* Reserve memory */ 31129088Smarkm 31229088Smarkm old_size = temp->size; 31329088Smarkm temp->size += sizeof(*cd); 31429088Smarkm 31529088Smarkm /* Reset some counters */ 31629088Smarkm 31729088Smarkm temp->bInterfaceNumber = 0 - 1; 31829088Smarkm temp->bAlternateSetting = 0; 31929088Smarkm 32029088Smarkm /* Scan all the USB interfaces */ 32129088Smarkm 32229088Smarkm tid = tcd->ppIfaceDesc; 32329088Smarkm if (tid) { 32429088Smarkm while (*tid) { 32529088Smarkm usb2_make_interface_desc(temp, *tid); 32629088Smarkm tid++; 32729088Smarkm } 32829088Smarkm } 32929088Smarkm /* 33029088Smarkm * Fill out the real USB config descriptor 33129088Smarkm * in case there is a buffer present: 33229088Smarkm */ 33329088Smarkm if (temp->buf) { 33429088Smarkm cd = USB_ADD_BYTES(temp->buf, old_size); 33529088Smarkm 33629088Smarkm /* compute total size */ 33729088Smarkm old_size = temp->size - old_size; 33829088Smarkm 33929088Smarkm cd->bLength = sizeof(*cd); 34029088Smarkm cd->bDescriptorType = UDESC_CONFIG; 34129088Smarkm USETW(cd->wTotalLength, old_size); 34229088Smarkm cd->bNumInterface = temp->bInterfaceNumber + 1; 34329088Smarkm cd->bConfigurationValue = temp->bConfigurationValue; 34429088Smarkm cd->iConfiguration = tcd->iConfiguration; 34529088Smarkm cd->bmAttributes = tcd->bmAttributes; 34629088Smarkm cd->bMaxPower = tcd->bMaxPower; 34729088Smarkm cd->bmAttributes |= (UC_REMOTE_WAKEUP | UC_BUS_POWERED); 34829088Smarkm 34929088Smarkm if (temp->self_powered) { 35029088Smarkm cd->bmAttributes |= UC_SELF_POWERED; 35129088Smarkm } else { 35229088Smarkm cd->bmAttributes &= ~UC_SELF_POWERED; 35329088Smarkm } 35429088Smarkm } 35529088Smarkm return; 35629088Smarkm} 35729088Smarkm 35829088Smarkm/*------------------------------------------------------------------------* 35929088Smarkm * usb2_make_device_desc 36029088Smarkm * 36129088Smarkm * This function will generate an USB device descriptor from the 36229088Smarkm * given USB template device descriptor. 36329088Smarkm *------------------------------------------------------------------------*/ 36429088Smarkmstatic void 36529088Smarkmusb2_make_device_desc(struct usb2_temp_setup *temp, 36629088Smarkm const struct usb2_temp_device_desc *tdd) 36729088Smarkm{ 36829088Smarkm struct usb2_temp_data *utd; 36929088Smarkm const struct usb2_temp_config_desc **tcd; 37029088Smarkm uint16_t old_size; 37129088Smarkm 37229088Smarkm /* Reserve memory */ 37329088Smarkm 37429088Smarkm old_size = temp->size; 37529088Smarkm temp->size += sizeof(*utd); 37629088Smarkm 37729088Smarkm /* Scan all the USB configs */ 37829088Smarkm 37929088Smarkm temp->bConfigurationValue = 1; 38029088Smarkm tcd = tdd->ppConfigDesc; 38129088Smarkm if (tcd) { 38229088Smarkm while (*tcd) { 38329088Smarkm usb2_make_config_desc(temp, *tcd); 38429088Smarkm temp->bConfigurationValue++; 38529088Smarkm tcd++; 38629088Smarkm } 38729088Smarkm } 38829088Smarkm /* 38929088Smarkm * Fill out the real USB device descriptor 39029088Smarkm * in case there is a buffer present: 39129088Smarkm */ 39229088Smarkm 39329088Smarkm if (temp->buf) { 39429088Smarkm utd = USB_ADD_BYTES(temp->buf, old_size); 39587139Smarkm 39681965Smarkm /* Store a pointer to our template device descriptor */ 39729088Smarkm utd->tdd = tdd; 39887139Smarkm 39987139Smarkm /* Fill out USB device descriptor */ 40029088Smarkm utd->udd.bLength = sizeof(utd->udd); 40187139Smarkm utd->udd.bDescriptorType = UDESC_DEVICE; 40287139Smarkm utd->udd.bDeviceClass = tdd->bDeviceClass; 40387139Smarkm utd->udd.bDeviceSubClass = tdd->bDeviceSubClass; 40487139Smarkm utd->udd.bDeviceProtocol = tdd->bDeviceProtocol; 40529088Smarkm USETW(utd->udd.idVendor, tdd->idVendor); 40681965Smarkm USETW(utd->udd.idProduct, tdd->idProduct); 40781965Smarkm USETW(utd->udd.bcdDevice, tdd->bcdDevice); 40829088Smarkm utd->udd.iManufacturer = tdd->iManufacturer; 40929088Smarkm utd->udd.iProduct = tdd->iProduct; 41029088Smarkm utd->udd.iSerialNumber = tdd->iSerialNumber; 41129181Smarkm utd->udd.bNumConfigurations = temp->bConfigurationValue - 1; 41229088Smarkm 41329088Smarkm /* 41429088Smarkm * Fill out the USB device qualifier. Pretend that we 41529088Smarkm * don't support any other speeds by setting 41629088Smarkm * "bNumConfigurations" equal to zero. That saves us 41729088Smarkm * generating an extra set of configuration 41829088Smarkm * descriptors. 41929088Smarkm */ 42029088Smarkm utd->udq.bLength = sizeof(utd->udq); 42129088Smarkm utd->udq.bDescriptorType = UDESC_DEVICE_QUALIFIER; 42229088Smarkm utd->udq.bDeviceClass = tdd->bDeviceClass; 42329181Smarkm utd->udq.bDeviceSubClass = tdd->bDeviceSubClass; 42487139Smarkm utd->udq.bDeviceProtocol = tdd->bDeviceProtocol; 42529088Smarkm utd->udq.bNumConfigurations = 0; 42629088Smarkm USETW(utd->udq.bcdUSB, 0x0200); 42729088Smarkm utd->udq.bMaxPacketSize0 = 0; 42829088Smarkm 42929088Smarkm switch (temp->usb2_speed) { 43029088Smarkm case USB_SPEED_LOW: 43129088Smarkm USETW(utd->udd.bcdUSB, 0x0110); 43229088Smarkm utd->udd.bMaxPacketSize = 8; 43329088Smarkm break; 43429088Smarkm case USB_SPEED_FULL: 43529088Smarkm USETW(utd->udd.bcdUSB, 0x0110); 43629088Smarkm utd->udd.bMaxPacketSize = 32; 43729088Smarkm break; 43829088Smarkm case USB_SPEED_HIGH: 43929088Smarkm USETW(utd->udd.bcdUSB, 0x0200); 44029088Smarkm utd->udd.bMaxPacketSize = 64; 44129088Smarkm break; 44229088Smarkm case USB_SPEED_VARIABLE: 44329088Smarkm USETW(utd->udd.bcdUSB, 0x0250); 44429088Smarkm utd->udd.bMaxPacketSize = 255; /* 512 bytes */ 44529088Smarkm break; 44629088Smarkm default: 44729088Smarkm temp->err = USB_ERR_INVAL; 44829088Smarkm break; 44929088Smarkm } 45029088Smarkm } 45129088Smarkm return; 45229088Smarkm} 45329088Smarkm 45429088Smarkm/*------------------------------------------------------------------------* 45529088Smarkm * usb2_hw_ep_match 45629088Smarkm * 45729088Smarkm * Return values: 45829088Smarkm * 0: The endpoint profile does not match the criterias 45929088Smarkm * Else: The endpoint profile matches the criterias 46087139Smarkm *------------------------------------------------------------------------*/ 46187139Smarkmstatic uint8_t 46229088Smarkmusb2_hw_ep_match(const struct usb2_hw_ep_profile *pf, 46329088Smarkm uint8_t ep_type, uint8_t ep_dir_in) 46429088Smarkm{ 46529088Smarkm if (ep_type == UE_CONTROL) { 46629088Smarkm /* special */ 46729088Smarkm return (pf->support_control); 46829088Smarkm } 46929088Smarkm if ((pf->support_in && ep_dir_in) || 47087139Smarkm (pf->support_out && !ep_dir_in)) { 47187139Smarkm if ((pf->support_interrupt && (ep_type == UE_INTERRUPT)) || 47229088Smarkm (pf->support_isochronous && (ep_type == UE_ISOCHRONOUS)) || 47329088Smarkm (pf->support_bulk && (ep_type == UE_BULK))) { 47429088Smarkm return (1); 47529088Smarkm } 47629088Smarkm } 47729088Smarkm return (0); 47829088Smarkm} 47929088Smarkm 48029088Smarkm/*------------------------------------------------------------------------* 48129088Smarkm * usb2_hw_ep_find_match 48229088Smarkm * 48329088Smarkm * This function is used to find the best matching endpoint profile 48429088Smarkm * for and endpoint belonging to an USB descriptor. 48529088Smarkm * 48629088Smarkm * Return values: 48729088Smarkm * 0: Success. Got a match. 48887139Smarkm * Else: Failure. No match. 48987139Smarkm *------------------------------------------------------------------------*/ 49029088Smarkmstatic uint8_t 49129088Smarkmusb2_hw_ep_find_match(struct usb2_hw_ep_scratch *ues, 49229088Smarkm struct usb2_hw_ep_scratch_sub *ep, uint8_t is_simplex) 49329088Smarkm{ 49429088Smarkm const struct usb2_hw_ep_profile *pf; 49529088Smarkm uint16_t distance; 49629088Smarkm uint16_t temp; 49729088Smarkm uint16_t max_frame_size; 49887139Smarkm uint8_t n; 49987139Smarkm uint8_t best_n; 50029088Smarkm uint8_t dir_in; 50129088Smarkm uint8_t dir_out; 50229088Smarkm 50329088Smarkm distance = 0xFFFF; 50429088Smarkm best_n = 0; 50529088Smarkm 50629088Smarkm if ((!ep->needs_in) && (!ep->needs_out)) { 50729088Smarkm return (0); /* we are done */ 50887139Smarkm } 50987139Smarkm if (ep->needs_ep_type == UE_CONTROL) { 51029088Smarkm dir_in = 1; 51129088Smarkm dir_out = 1; 51229088Smarkm } else { 51329088Smarkm if (ep->needs_in) { 51429088Smarkm dir_in = 1; 51529088Smarkm dir_out = 0; 51629088Smarkm } else { 51729088Smarkm dir_in = 0; 51829088Smarkm dir_out = 1; 51929088Smarkm } 52029088Smarkm } 52129088Smarkm 52287139Smarkm for (n = 1; n != (USB_EP_MAX / 2); n++) { 52387139Smarkm 52429088Smarkm /* get HW endpoint profile */ 52529088Smarkm (ues->methods->get_hw_ep_profile) (ues->udev, &pf, n); 52629088Smarkm if (pf == NULL) { 52729088Smarkm /* end of profiles */ 52829088Smarkm break; 52929088Smarkm } 53029088Smarkm /* check if IN-endpoint is reserved */ 53129088Smarkm if (dir_in || pf->is_simplex) { 53229088Smarkm if (ues->bmInAlloc[n / 8] & (1 << (n % 8))) { 53329088Smarkm /* mismatch */ 53429088Smarkm continue; 53529088Smarkm } 53629088Smarkm } 53729088Smarkm /* check if OUT-endpoint is reserved */ 53887139Smarkm if (dir_out || pf->is_simplex) { 53987139Smarkm if (ues->bmOutAlloc[n / 8] & (1 << (n % 8))) { 54029088Smarkm /* mismatch */ 54129088Smarkm continue; 54229088Smarkm } 54329088Smarkm } 54429088Smarkm /* check simplex */ 54529088Smarkm if (pf->is_simplex == is_simplex) { 54629088Smarkm /* mismatch */ 54729088Smarkm continue; 54887139Smarkm } 54987139Smarkm /* check if HW endpoint matches */ 55087139Smarkm if (!usb2_hw_ep_match(pf, ep->needs_ep_type, dir_in)) { 55187139Smarkm /* mismatch */ 55229088Smarkm continue; 55329088Smarkm } 55429088Smarkm /* get maximum frame size */ 55529088Smarkm if (dir_in) 55629088Smarkm max_frame_size = pf->max_in_frame_size; 55729088Smarkm else 55829088Smarkm max_frame_size = pf->max_out_frame_size; 55929088Smarkm 56029088Smarkm /* check if we have a matching profile */ 56129088Smarkm if (max_frame_size >= ep->max_frame_size) { 56229088Smarkm temp = (max_frame_size - ep->max_frame_size); 56329088Smarkm if (distance > temp) { 56429088Smarkm distance = temp; 56529088Smarkm best_n = n; 56687139Smarkm ep->pf = pf; 56729088Smarkm } 56887139Smarkm } 56987139Smarkm } 57029088Smarkm 57129088Smarkm /* see if we got a match */ 57229088Smarkm if (best_n != 0) { 57329088Smarkm /* get the correct profile */ 57429088Smarkm pf = ep->pf; 57529088Smarkm 57629088Smarkm /* reserve IN-endpoint */ 57729088Smarkm if (dir_in) { 57829088Smarkm ues->bmInAlloc[best_n / 8] |= 57929088Smarkm (1 << (best_n % 8)); 58029088Smarkm ep->hw_endpoint_in = best_n | UE_DIR_IN; 58129088Smarkm ep->needs_in = 0; 58229088Smarkm } 58329088Smarkm /* reserve OUT-endpoint */ 58429088Smarkm if (dir_out) { 58587139Smarkm ues->bmOutAlloc[best_n / 8] |= 58687139Smarkm (1 << (best_n % 8)); 58729088Smarkm ep->hw_endpoint_out = best_n | UE_DIR_OUT; 58829088Smarkm ep->needs_out = 0; 58929088Smarkm } 59029088Smarkm return (0); /* got a match */ 59129088Smarkm } 59229088Smarkm return (1); /* failure */ 59329088Smarkm} 59429088Smarkm 59529088Smarkm/*------------------------------------------------------------------------* 59629088Smarkm * usb2_hw_ep_get_needs 59729088Smarkm * 59829088Smarkm * This function will figure out the type and number of endpoints 59929088Smarkm * which are needed for an USB configuration. 60029088Smarkm * 60129088Smarkm * Return values: 60229088Smarkm * 0: Success. 60329088Smarkm * Else: Failure. 60429088Smarkm *------------------------------------------------------------------------*/ 60529088Smarkmstatic uint8_t 60687139Smarkmusb2_hw_ep_get_needs(struct usb2_hw_ep_scratch *ues, 60787139Smarkm uint8_t ep_type, uint8_t is_complete) 60829088Smarkm{ 60929088Smarkm const struct usb2_hw_ep_profile *pf; 61029088Smarkm struct usb2_hw_ep_scratch_sub *ep_iface; 61129088Smarkm struct usb2_hw_ep_scratch_sub *ep_curr; 61229088Smarkm struct usb2_hw_ep_scratch_sub *ep_max; 61329088Smarkm struct usb2_hw_ep_scratch_sub *ep_end; 61429088Smarkm struct usb2_descriptor *desc; 61529088Smarkm struct usb2_interface_descriptor *id; 61687139Smarkm struct usb2_endpoint_descriptor *ed; 61787139Smarkm uint16_t wMaxPacketSize; 61829088Smarkm uint16_t temp; 61929088Smarkm uint8_t speed; 62029088Smarkm uint8_t ep_no; 62129088Smarkm 62229088Smarkm ep_iface = ues->ep_max; 62329088Smarkm ep_curr = ues->ep_max; 62429088Smarkm ep_end = ues->ep + USB_EP_MAX; 62529088Smarkm ep_max = ues->ep_max; 62629088Smarkm desc = NULL; 62787139Smarkm speed = usb2_get_speed(ues->udev); 62887139Smarkm 62929088Smarkmrepeat: 63029088Smarkm 63129088Smarkm while ((desc = usb2_desc_foreach(ues->cd, desc))) { 63229088Smarkm 63329088Smarkm if ((desc->bDescriptorType == UDESC_INTERFACE) && 63429088Smarkm (desc->bLength >= sizeof(*id))) { 63529088Smarkm 63629088Smarkm id = (void *)desc; 63787139Smarkm 63887139Smarkm if (id->bAlternateSetting == 0) { 63929088Smarkm /* going forward */ 64029088Smarkm ep_iface = ep_max; 64129088Smarkm } else { 64229088Smarkm /* reset */ 64329088Smarkm ep_curr = ep_iface; 64429088Smarkm } 64529088Smarkm } 64629088Smarkm if ((desc->bDescriptorType == UDESC_ENDPOINT) && 64787139Smarkm (desc->bLength >= sizeof(*ed))) { 64887139Smarkm 64929088Smarkm ed = (void *)desc; 65029088Smarkm 65129088Smarkm goto handle_endpoint_desc; 65229088Smarkm } 65329088Smarkm } 65429088Smarkm ues->ep_max = ep_max; 65529088Smarkm return (0); 65629088Smarkm 65729088Smarkmhandle_endpoint_desc: 65829088Smarkm temp = (ed->bmAttributes & UE_XFERTYPE); 65929088Smarkm 66029088Smarkm if (temp == ep_type) { 66129088Smarkm 66229088Smarkm if (ep_curr == ep_end) { 66387139Smarkm /* too many endpoints */ 66487139Smarkm return (1); /* failure */ 66529088Smarkm } 66629088Smarkm wMaxPacketSize = UGETW(ed->wMaxPacketSize); 66729088Smarkm if ((wMaxPacketSize & 0xF800) && 66829088Smarkm (speed == USB_SPEED_HIGH)) { 66929088Smarkm /* handle packet multiplier */ 67029088Smarkm temp = (wMaxPacketSize >> 11) & 3; 67129088Smarkm wMaxPacketSize &= 0x7FF; 67229088Smarkm if (temp == 1) { 67329088Smarkm wMaxPacketSize *= 2; 67429088Smarkm } else { 67529088Smarkm wMaxPacketSize *= 3; 67629088Smarkm } 67729088Smarkm } 67887139Smarkm /* 67987139Smarkm * Check if we have a fixed endpoint number, else the 68029088Smarkm * endpoint number is allocated dynamically: 68129088Smarkm */ 68229088Smarkm ep_no = (ed->bEndpointAddress & UE_ADDR); 68329088Smarkm if (ep_no != 0) { 68429088Smarkm 68529088Smarkm /* get HW endpoint profile */ 68629088Smarkm (ues->methods->get_hw_ep_profile) 68729088Smarkm (ues->udev, &pf, ep_no); 68829088Smarkm if (pf == NULL) { 68929088Smarkm /* HW profile does not exist - failure */ 69029088Smarkm DPRINTFN(0, "Endpoint profile %u " 69129088Smarkm "does not exist\n", ep_no); 69229088Smarkm return (1); 69387139Smarkm } 69487139Smarkm /* reserve fixed endpoint number */ 69529088Smarkm if (ep_type == UE_CONTROL) { 69629088Smarkm ues->bmInAlloc[ep_no / 8] |= 69729088Smarkm (1 << (ep_no % 8)); 69829088Smarkm ues->bmOutAlloc[ep_no / 8] |= 69929088Smarkm (1 << (ep_no % 8)); 70029088Smarkm if ((pf->max_in_frame_size < wMaxPacketSize) || 70129088Smarkm (pf->max_out_frame_size < wMaxPacketSize)) { 70229088Smarkm DPRINTFN(0, "Endpoint profile %u " 70329088Smarkm "has too small buffer!\n", ep_no); 70429088Smarkm return (1); 70529088Smarkm } 70629088Smarkm } else if (ed->bEndpointAddress & UE_DIR_IN) { 70729088Smarkm ues->bmInAlloc[ep_no / 8] |= 70829088Smarkm (1 << (ep_no % 8)); 70929088Smarkm if (pf->max_in_frame_size < wMaxPacketSize) { 71029088Smarkm DPRINTFN(0, "Endpoint profile %u " 71129088Smarkm "has too small buffer!\n", ep_no); 71229088Smarkm return (1); 71329088Smarkm } 71429088Smarkm } else { 71529088Smarkm ues->bmOutAlloc[ep_no / 8] |= 71629088Smarkm (1 << (ep_no % 8)); 71729088Smarkm if (pf->max_out_frame_size < wMaxPacketSize) { 71829088Smarkm DPRINTFN(0, "Endpoint profile %u " 71929088Smarkm "has too small buffer!\n", ep_no); 72029088Smarkm return (1); 72129088Smarkm } 72287139Smarkm } 72387139Smarkm } else if (is_complete) { 72429088Smarkm 72529088Smarkm /* check if we have enough buffer space */ 72629088Smarkm if (wMaxPacketSize > 72729088Smarkm ep_curr->max_frame_size) { 72829088Smarkm return (1); /* failure */ 72929088Smarkm } 73029088Smarkm if (ed->bEndpointAddress & UE_DIR_IN) { 73129088Smarkm ed->bEndpointAddress = 73229088Smarkm ep_curr->hw_endpoint_in; 73329088Smarkm } else { 73429088Smarkm ed->bEndpointAddress = 73529088Smarkm ep_curr->hw_endpoint_out; 73629088Smarkm } 73729088Smarkm 73829088Smarkm } else { 73929088Smarkm 74087139Smarkm /* compute the maximum frame size */ 74187139Smarkm if (ep_curr->max_frame_size < wMaxPacketSize) { 74229088Smarkm ep_curr->max_frame_size = wMaxPacketSize; 74329088Smarkm } 74429088Smarkm if (temp == UE_CONTROL) { 74529088Smarkm ep_curr->needs_in = 1; 74629088Smarkm ep_curr->needs_out = 1; 74729088Smarkm } else { 74829088Smarkm if (ed->bEndpointAddress & UE_DIR_IN) { 74929088Smarkm ep_curr->needs_in = 1; 75029088Smarkm } else { 75129088Smarkm ep_curr->needs_out = 1; 75229088Smarkm } 75329088Smarkm } 75429088Smarkm ep_curr->needs_ep_type = ep_type; 75529088Smarkm } 75629088Smarkm 75729088Smarkm ep_curr++; 75829088Smarkm if (ep_max < ep_curr) { 75929088Smarkm ep_max = ep_curr; 76029088Smarkm } 76129088Smarkm } 76229088Smarkm goto repeat; 76329088Smarkm} 76487139Smarkm 76587139Smarkm/*------------------------------------------------------------------------* 76629088Smarkm * usb2_hw_ep_resolve 76729088Smarkm * 76829088Smarkm * This function will try to resolve endpoint requirements by the 76929088Smarkm * given endpoint profiles that the USB hardware reports. 77029088Smarkm * 77129088Smarkm * Return values: 77229088Smarkm * 0: Success 77329088Smarkm * Else: Failure 77429088Smarkm *------------------------------------------------------------------------*/ 77529088Smarkmstatic usb2_error_t 77629088Smarkmusb2_hw_ep_resolve(struct usb2_device *udev, 77729088Smarkm struct usb2_descriptor *desc) 77829088Smarkm{ 77929088Smarkm struct usb2_hw_ep_scratch *ues; 78029088Smarkm struct usb2_hw_ep_scratch_sub *ep; 78129088Smarkm const struct usb2_hw_ep_profile *pf; 78229088Smarkm struct usb2_bus_methods *methods; 78329088Smarkm struct usb2_device_descriptor *dd; 78429088Smarkm uint16_t mps; 78529088Smarkm 78629088Smarkm if (desc == NULL) { 78729088Smarkm return (USB_ERR_INVAL); 78829088Smarkm } 78929088Smarkm /* get bus methods */ 79029088Smarkm methods = udev->bus->methods; 79129088Smarkm 79229088Smarkm if (methods->get_hw_ep_profile == NULL) { 79329088Smarkm return (USB_ERR_INVAL); 79429088Smarkm } 79529088Smarkm if (desc->bDescriptorType == UDESC_DEVICE) { 79629088Smarkm 79729088Smarkm if (desc->bLength < sizeof(*dd)) { 79829088Smarkm return (USB_ERR_INVAL); 79929088Smarkm } 80029088Smarkm dd = (void *)desc; 80129088Smarkm 80229088Smarkm /* get HW control endpoint 0 profile */ 80329088Smarkm (methods->get_hw_ep_profile) (udev, &pf, 0); 80429088Smarkm if (pf == NULL) { 80529088Smarkm return (USB_ERR_INVAL); 80629088Smarkm } 80729088Smarkm if (!usb2_hw_ep_match(pf, UE_CONTROL, 0)) { 80829088Smarkm DPRINTFN(0, "Endpoint 0 does not " 80929088Smarkm "support control\n"); 81029088Smarkm return (USB_ERR_INVAL); 81129088Smarkm } 81229088Smarkm mps = dd->bMaxPacketSize; 81329088Smarkm 81429088Smarkm if (udev->speed == USB_SPEED_FULL) { 81529088Smarkm /* 81629088Smarkm * We can optionally choose another packet size ! 81729088Smarkm */ 81829088Smarkm while (1) { 81929088Smarkm /* check if "mps" is ok */ 82029088Smarkm if (pf->max_in_frame_size >= mps) { 82129088Smarkm break; 82231622Scharnier } 82329088Smarkm /* reduce maximum packet size */ 82487139Smarkm mps /= 2; 82587139Smarkm 82629088Smarkm /* check if "mps" is too small */ 82729088Smarkm if (mps < 8) { 82887139Smarkm return (USB_ERR_INVAL); 82929088Smarkm } 83029088Smarkm } 83129088Smarkm 83229088Smarkm dd->bMaxPacketSize = mps; 83329088Smarkm 83429088Smarkm } else { 83531622Scharnier /* We only have one choice */ 83629088Smarkm if (mps == 255) { 83731622Scharnier mps = 512; 83829088Smarkm } 83929088Smarkm /* Check if we support the specified wMaxPacketSize */ 84087139Smarkm if (pf->max_in_frame_size < mps) { 84187139Smarkm return (USB_ERR_INVAL); 84229088Smarkm } 84329088Smarkm } 84487139Smarkm return (0); /* success */ 84529088Smarkm } 84629088Smarkm if (desc->bDescriptorType != UDESC_CONFIG) { 84729088Smarkm return (USB_ERR_INVAL); 84829088Smarkm } 84929088Smarkm if (desc->bLength < sizeof(*(ues->cd))) { 85029088Smarkm return (USB_ERR_INVAL); 85129088Smarkm } 85229088Smarkm ues = udev->bus->scratch[0].hw_ep_scratch; 85329088Smarkm 85429088Smarkm bzero(ues, sizeof(*ues)); 85529088Smarkm 85629088Smarkm ues->ep_max = ues->ep; 85729088Smarkm ues->cd = (void *)desc; 85829088Smarkm ues->methods = methods; 85929088Smarkm ues->udev = udev; 86031622Scharnier 86129088Smarkm /* Get all the endpoints we need */ 86287139Smarkm 86387139Smarkm if (usb2_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 0) || 86429088Smarkm usb2_hw_ep_get_needs(ues, UE_INTERRUPT, 0) || 86587139Smarkm usb2_hw_ep_get_needs(ues, UE_CONTROL, 0) || 86629181Smarkm usb2_hw_ep_get_needs(ues, UE_BULK, 0)) { 86729088Smarkm DPRINTFN(0, "Could not get needs\n"); 86829088Smarkm return (USB_ERR_INVAL); 86929088Smarkm } 87029088Smarkm for (ep = ues->ep; ep != ues->ep_max; ep++) { 87129088Smarkm 87229088Smarkm while (ep->needs_in || ep->needs_out) { 87329088Smarkm 87429088Smarkm /* 87529088Smarkm * First try to use a simplex endpoint. 87629088Smarkm * Then try to use a duplex endpoint. 87729088Smarkm */ 87829088Smarkm if (usb2_hw_ep_find_match(ues, ep, 1) && 87929088Smarkm usb2_hw_ep_find_match(ues, ep, 0)) { 88029088Smarkm DPRINTFN(0, "Could not find match\n"); 88129088Smarkm return (USB_ERR_INVAL); 88229181Smarkm } 88329088Smarkm } 88429088Smarkm } 88529088Smarkm 88629088Smarkm ues->ep_max = ues->ep; 88729088Smarkm 88829181Smarkm /* Update all endpoint addresses */ 88929088Smarkm 89029088Smarkm if (usb2_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 1) || 89129088Smarkm usb2_hw_ep_get_needs(ues, UE_INTERRUPT, 1) || 89229088Smarkm usb2_hw_ep_get_needs(ues, UE_CONTROL, 1) || 89329088Smarkm usb2_hw_ep_get_needs(ues, UE_BULK, 1)) { 89429088Smarkm DPRINTFN(0, "Could not update endpoint address\n"); 89529088Smarkm return (USB_ERR_INVAL); 89629088Smarkm } 89729088Smarkm return (0); /* success */ 89829088Smarkm} 89929088Smarkm 90029088Smarkm/*------------------------------------------------------------------------* 90129088Smarkm * usb2_temp_get_tdd 90229088Smarkm * 90329088Smarkm * Returns: 90429088Smarkm * NULL: No USB template device descriptor found. 90529088Smarkm * Else: Pointer to the USB template device descriptor. 90629088Smarkm *------------------------------------------------------------------------*/ 90729088Smarkmstatic const struct usb2_temp_device_desc * 90829088Smarkmusb2_temp_get_tdd(struct usb2_device *udev) 90929088Smarkm{ 91029088Smarkm if (udev->usb2_template_ptr == NULL) { 91129088Smarkm return (NULL); 91229088Smarkm } 91329088Smarkm return (udev->usb2_template_ptr->tdd); 91429088Smarkm} 91529088Smarkm 91629088Smarkm/*------------------------------------------------------------------------* 91729088Smarkm * usb2_temp_get_device_desc 91829088Smarkm * 91929088Smarkm * Returns: 92029088Smarkm * NULL: No USB device descriptor found. 92129088Smarkm * Else: Pointer to USB device descriptor. 92229088Smarkm *------------------------------------------------------------------------*/ 92329088Smarkmstatic void * 92429088Smarkmusb2_temp_get_device_desc(struct usb2_device *udev) 92529088Smarkm{ 92629088Smarkm struct usb2_device_descriptor *dd; 92729088Smarkm 92829088Smarkm if (udev->usb2_template_ptr == NULL) { 92929088Smarkm return (NULL); 93029088Smarkm } 93129088Smarkm dd = &udev->usb2_template_ptr->udd; 93229088Smarkm if (dd->bDescriptorType != UDESC_DEVICE) { 93329088Smarkm /* sanity check failed */ 93429181Smarkm return (NULL); 93529181Smarkm } 93629088Smarkm return (dd); 93729088Smarkm} 93829088Smarkm 93929088Smarkm/*------------------------------------------------------------------------* 94029088Smarkm * usb2_temp_get_qualifier_desc 94129088Smarkm * 94229088Smarkm * Returns: 94329088Smarkm * NULL: No USB device_qualifier descriptor found. 94429088Smarkm * Else: Pointer to USB device_qualifier descriptor. 94529088Smarkm *------------------------------------------------------------------------*/ 94629088Smarkmstatic void * 94729088Smarkmusb2_temp_get_qualifier_desc(struct usb2_device *udev) 94829088Smarkm{ 94987139Smarkm struct usb2_device_qualifier *dq; 95087139Smarkm 95129088Smarkm if (udev->usb2_template_ptr == NULL) { 95229088Smarkm return (NULL); 95329088Smarkm } 95429088Smarkm dq = &udev->usb2_template_ptr->udq; 95529088Smarkm if (dq->bDescriptorType != UDESC_DEVICE_QUALIFIER) { 95629088Smarkm /* sanity check failed */ 95729088Smarkm return (NULL); 95829088Smarkm } 95929088Smarkm return (dq); 96029088Smarkm} 96187139Smarkm 96229088Smarkm/*------------------------------------------------------------------------* 96329088Smarkm * usb2_temp_get_config_desc 96429088Smarkm * 96529088Smarkm * Returns: 96629088Smarkm * NULL: No USB config descriptor found. 96729088Smarkm * Else: Pointer to USB config descriptor having index "index". 96829088Smarkm *------------------------------------------------------------------------*/ 96929088Smarkmstatic void * 97029088Smarkmusb2_temp_get_config_desc(struct usb2_device *udev, 97187139Smarkm uint16_t *pLength, uint8_t index) 97287139Smarkm{ 97329088Smarkm struct usb2_device_descriptor *dd; 97487139Smarkm struct usb2_config_descriptor *cd; 97529088Smarkm uint16_t temp; 97629088Smarkm 97729088Smarkm if (udev->usb2_template_ptr == NULL) { 97829088Smarkm return (NULL); 97929088Smarkm } 98087139Smarkm dd = &udev->usb2_template_ptr->udd; 98187139Smarkm cd = (void *)(udev->usb2_template_ptr + 1); 98229088Smarkm 98387139Smarkm if (index >= dd->bNumConfigurations) { 98429088Smarkm /* out of range */ 98529088Smarkm return (NULL); 98629088Smarkm } 98729088Smarkm while (index--) { 98829088Smarkm if (cd->bDescriptorType != UDESC_CONFIG) { 98929088Smarkm /* sanity check failed */ 99029088Smarkm return (NULL); 99129088Smarkm } 99229088Smarkm temp = UGETW(cd->wTotalLength); 99329088Smarkm cd = USB_ADD_BYTES(cd, temp); 99429088Smarkm } 99529088Smarkm 99629088Smarkm if (pLength) { 99729088Smarkm *pLength = UGETW(cd->wTotalLength); 99829088Smarkm } 99929088Smarkm return (cd); 100029088Smarkm} 100187139Smarkm 100287139Smarkm/*------------------------------------------------------------------------* 100329088Smarkm * usb2_temp_get_vendor_desc 100487139Smarkm * 100529088Smarkm * Returns: 100687139Smarkm * NULL: No vendor descriptor found. 100729088Smarkm * Else: Pointer to a vendor descriptor. 100829088Smarkm *------------------------------------------------------------------------*/ 100929088Smarkmstatic const void * 101029088Smarkmusb2_temp_get_vendor_desc(struct usb2_device *udev, 101129088Smarkm const struct usb2_device_request *req) 101229088Smarkm{ 101329088Smarkm const struct usb2_temp_device_desc *tdd; 101429088Smarkm 101529088Smarkm tdd = usb2_temp_get_tdd(udev); 101629088Smarkm if (tdd == NULL) { 101729088Smarkm return (NULL); 101829088Smarkm } 101929088Smarkm if (tdd->getVendorDesc == NULL) { 102029088Smarkm return (NULL); 102187139Smarkm } 102229088Smarkm return ((tdd->getVendorDesc) (req)); 102329088Smarkm} 102429088Smarkm 102529088Smarkm/*------------------------------------------------------------------------* 102629088Smarkm * usb2_temp_get_string_desc 102787139Smarkm * 102887139Smarkm * Returns: 102929088Smarkm * NULL: No string descriptor found. 103029088Smarkm * Else: Pointer to a string descriptor. 103129088Smarkm *------------------------------------------------------------------------*/ 103229088Smarkmstatic const void * 103329181Smarkmusb2_temp_get_string_desc(struct usb2_device *udev, 103429088Smarkm uint16_t lang_id, uint8_t string_index) 103529088Smarkm{ 103629088Smarkm const struct usb2_temp_device_desc *tdd; 103729088Smarkm 103829088Smarkm tdd = usb2_temp_get_tdd(udev); 103929088Smarkm if (tdd == NULL) { 104029088Smarkm return (NULL); 104129088Smarkm } 104229088Smarkm if (tdd->getStringDesc == NULL) { 104329088Smarkm return (NULL); 104429088Smarkm } 104529088Smarkm return ((tdd->getStringDesc) (lang_id, string_index)); 104629088Smarkm} 104787139Smarkm 104887139Smarkm/*------------------------------------------------------------------------* 104987139Smarkm * usb2_temp_get_hub_desc 105087139Smarkm * 105129088Smarkm * Returns: 105229088Smarkm * NULL: No USB HUB descriptor found. 105387139Smarkm * Else: Pointer to a USB HUB descriptor. 105487139Smarkm *------------------------------------------------------------------------*/ 105587139Smarkmstatic const void * 105687139Smarkmusb2_temp_get_hub_desc(struct usb2_device *udev) 105729088Smarkm{ 105829088Smarkm return (NULL); /* needs to be implemented */ 105929088Smarkm} 106029088Smarkm 106129088Smarkm/*------------------------------------------------------------------------* 106229088Smarkm * usb2_temp_get_desc 106329088Smarkm * 106429088Smarkm * This function is a demultiplexer for local USB device side control 106529088Smarkm * endpoint requests. 106629088Smarkm *------------------------------------------------------------------------*/ 106729088Smarkmstatic void 106829088Smarkmusb2_temp_get_desc(struct usb2_device *udev, struct usb2_device_request *req, 106929088Smarkm const void **pPtr, uint16_t *pLength) 107029088Smarkm{ 107187139Smarkm const uint8_t *buf; 107287139Smarkm uint16_t len; 107329088Smarkm 107429088Smarkm buf = NULL; 107529088Smarkm len = 0; 107629088Smarkm 107729088Smarkm switch (req->bmRequestType) { 107829088Smarkm case UT_READ_DEVICE: 107929088Smarkm switch (req->bRequest) { 108029088Smarkm case UR_GET_DESCRIPTOR: 108129088Smarkm goto tr_handle_get_descriptor; 108229088Smarkm default: 108387139Smarkm goto tr_stalled; 108429088Smarkm } 108529088Smarkm break; 108629088Smarkm case UT_READ_CLASS_DEVICE: 108729088Smarkm switch (req->bRequest) { 108829088Smarkm case UR_GET_DESCRIPTOR: 108929088Smarkm goto tr_handle_get_class_descriptor; 109029088Smarkm default: 109129088Smarkm goto tr_stalled; 109229088Smarkm } 109329088Smarkm break; 109429088Smarkm case UT_READ_VENDOR_DEVICE: 109529088Smarkm case UT_READ_VENDOR_OTHER: 109629088Smarkm buf = usb2_temp_get_vendor_desc(udev, req); 109729088Smarkm goto tr_valid; 109829088Smarkm default: 109929088Smarkm goto tr_stalled; 110029088Smarkm } 110129088Smarkm 110229088Smarkmtr_handle_get_descriptor: 110329088Smarkm switch (req->wValue[1]) { 110429088Smarkm case UDESC_DEVICE: 110529088Smarkm if (req->wValue[0]) { 110629088Smarkm goto tr_stalled; 110729088Smarkm } 110829088Smarkm buf = usb2_temp_get_device_desc(udev); 110929088Smarkm goto tr_valid; 111029088Smarkm case UDESC_DEVICE_QUALIFIER: 111187139Smarkm if (udev->speed != USB_SPEED_HIGH) { 111229088Smarkm goto tr_stalled; 111329088Smarkm } 111429088Smarkm if (req->wValue[0]) { 111529181Smarkm goto tr_stalled; 111629088Smarkm } 111729088Smarkm buf = usb2_temp_get_qualifier_desc(udev); 111829088Smarkm goto tr_valid; 111929088Smarkm case UDESC_OTHER_SPEED_CONFIGURATION: 112029088Smarkm if (udev->speed != USB_SPEED_HIGH) { 112129088Smarkm goto tr_stalled; 112229088Smarkm } 112329088Smarkm case UDESC_CONFIG: 112429088Smarkm buf = usb2_temp_get_config_desc(udev, 112529088Smarkm &len, req->wValue[0]); 112629088Smarkm goto tr_valid; 112729088Smarkm case UDESC_STRING: 112887139Smarkm buf = usb2_temp_get_string_desc(udev, 112929088Smarkm UGETW(req->wIndex), req->wValue[0]); 113029088Smarkm goto tr_valid; 113129088Smarkm default: 113229088Smarkm goto tr_stalled; 113329088Smarkm } 113429088Smarkm goto tr_stalled; 113529088Smarkm 113629088Smarkmtr_handle_get_class_descriptor: 113729088Smarkm if (req->wValue[0]) { 113829088Smarkm goto tr_stalled; 113929088Smarkm } 114029088Smarkm buf = usb2_temp_get_hub_desc(udev); 114129088Smarkm goto tr_valid; 114229088Smarkm 114329088Smarkmtr_valid: 114429088Smarkm if (buf == NULL) { 114529088Smarkm goto tr_stalled; 114629088Smarkm } 114729088Smarkm if (len == 0) { 114829088Smarkm len = buf[0]; 114929088Smarkm } 115029088Smarkm *pPtr = buf; 115129088Smarkm *pLength = len; 115229088Smarkm return; 115329088Smarkm 115429088Smarkmtr_stalled: 115529088Smarkm *pPtr = NULL; 115629088Smarkm *pLength = 0; 115729088Smarkm return; 115829088Smarkm} 115929088Smarkm 116029088Smarkm/*------------------------------------------------------------------------* 116129088Smarkm * usb2_temp_setup 116232688Simp * 116332688Simp * This function generates USB descriptors according to the given USB 116429088Smarkm * template device descriptor. It will also try to figure out the best 116529088Smarkm * matching endpoint addresses using the hardware endpoint profiles. 116629088Smarkm * 116729088Smarkm * Returns: 116829088Smarkm * 0: Success 116929088Smarkm * Else: Failure 117029088Smarkm *------------------------------------------------------------------------*/ 117129088Smarkmstatic usb2_error_t 117229088Smarkmusb2_temp_setup(struct usb2_device *udev, 117329088Smarkm const struct usb2_temp_device_desc *tdd) 117429088Smarkm{ 117529088Smarkm struct usb2_temp_setup *uts; 117629088Smarkm void *buf; 117729088Smarkm uint8_t n; 117829088Smarkm 117929088Smarkm if (tdd == NULL) { 118029088Smarkm /* be NULL safe */ 118129088Smarkm return (0); 118229088Smarkm } 118329088Smarkm uts = udev->bus->scratch[0].temp_setup; 118429088Smarkm 118529181Smarkm bzero(uts, sizeof(*uts)); 118629088Smarkm 118729088Smarkm uts->usb2_speed = udev->speed; 118829088Smarkm uts->self_powered = udev->flags.self_powered; 118929088Smarkm 119029088Smarkm /* first pass */ 119129088Smarkm 119229181Smarkm usb2_make_device_desc(uts, tdd); 119329088Smarkm 119429088Smarkm if (uts->err) { 119529088Smarkm /* some error happened */ 119687139Smarkm return (uts->err); 119729088Smarkm } 119829088Smarkm /* sanity check */ 119929088Smarkm if (uts->size == 0) { 120029088Smarkm return (USB_ERR_INVAL); 120129088Smarkm } 120229088Smarkm /* allocate zeroed memory */ 120329088Smarkm uts->buf = malloc(uts->size, M_USB, M_WAITOK | M_ZERO); 120429088Smarkm if (uts->buf == NULL) { 120529088Smarkm /* could not allocate memory */ 120629088Smarkm return (USB_ERR_NOMEM); 120729088Smarkm } 120829088Smarkm /* second pass */ 120929088Smarkm 121029088Smarkm uts->size = 0; 121129088Smarkm 121229088Smarkm usb2_make_device_desc(uts, tdd); 121387139Smarkm 121487139Smarkm /* 121529088Smarkm * Store a pointer to our descriptors: 121629088Smarkm */ 121729088Smarkm udev->usb2_template_ptr = uts->buf; 121887139Smarkm 121929088Smarkm if (uts->err) { 122029088Smarkm /* some error happened during second pass */ 122129181Smarkm goto error; 122229181Smarkm } 122329181Smarkm /* 122429181Smarkm * Resolve all endpoint addresses ! 122529181Smarkm */ 122631622Scharnier buf = usb2_temp_get_device_desc(udev); 122729181Smarkm uts->err = usb2_hw_ep_resolve(udev, buf); 122829088Smarkm if (uts->err) { 122929088Smarkm DPRINTFN(0, "Could not resolve endpoints for " 123029088Smarkm "Device Descriptor, error = %s\n", 123187139Smarkm usb2_errstr(uts->err)); 123287139Smarkm goto error; 123329088Smarkm } 123487139Smarkm for (n = 0;; n++) { 123529088Smarkm 123629088Smarkm buf = usb2_temp_get_config_desc(udev, NULL, n); 123729088Smarkm if (buf == NULL) { 123829088Smarkm break; 123929088Smarkm } 124029088Smarkm uts->err = usb2_hw_ep_resolve(udev, buf); 124129088Smarkm if (uts->err) { 124229088Smarkm DPRINTFN(0, "Could not resolve endpoints for " 124329088Smarkm "Config Descriptor %u, error = %s\n", n, 124429088Smarkm usb2_errstr(uts->err)); 124529088Smarkm goto error; 124629088Smarkm } 124729088Smarkm } 124887267Smarkm return (uts->err); 124929088Smarkm 125087267Smarkmerror: 125187267Smarkm usb2_temp_unsetup(udev); 125229088Smarkm return (uts->err); 125329088Smarkm} 125429088Smarkm 125587267Smarkm/*------------------------------------------------------------------------* 125629088Smarkm * usb2_temp_unsetup 125787139Smarkm * 125829088Smarkm * This function frees any memory associated with the currently 125929088Smarkm * setup template, if any. 126029088Smarkm *------------------------------------------------------------------------*/ 126129088Smarkmstatic void 126229088Smarkmusb2_temp_unsetup(struct usb2_device *udev) 126329088Smarkm{ 126429088Smarkm if (udev->usb2_template_ptr) { 126569825Sassar 126629088Smarkm free(udev->usb2_template_ptr, M_USB); 126787139Smarkm 126887139Smarkm udev->usb2_template_ptr = NULL; 126929088Smarkm } 127087139Smarkm return; 127169825Sassar} 127269825Sassar 127369825Sassarstatic usb2_error_t 127429088Smarkmusb2_temp_setup_by_index(struct usb2_device *udev, uint16_t index) 127587139Smarkm{ 127669825Sassar usb2_error_t err; 127769825Sassar 127869825Sassar switch (index) { 127969825Sassar case 0: 128069825Sassar err = usb2_temp_setup(udev, &usb2_template_msc); 128169825Sassar break; 128269825Sassar case 1: 128369825Sassar err = usb2_temp_setup(udev, &usb2_template_cdce); 128469825Sassar break; 128569825Sassar case 2: 128669825Sassar err = usb2_temp_setup(udev, &usb2_template_mtp); 128769825Sassar break; 128869825Sassar default: 128969825Sassar return (USB_ERR_INVAL); 129069825Sassar } 129169825Sassar 129287139Smarkm return (err); 129369825Sassar} 129469825Sassar 129569825Sassarstatic void 129669825Sassarusb2_temp_init(void *arg) 129769825Sassar{ 129869825Sassar /* register our functions */ 129969825Sassar usb2_temp_get_desc_p = &usb2_temp_get_desc; 130087139Smarkm usb2_temp_setup_by_index_p = &usb2_temp_setup_by_index; 130169825Sassar usb2_temp_unsetup_p = &usb2_temp_unsetup; 130269825Sassar return; 130369825Sassar} 130469825Sassar 130569825SassarSYSINIT(usb2_temp_init, SI_SUB_LOCK, SI_ORDER_FIRST, usb2_temp_init, NULL); 130669825SassarSYSUNINIT(usb2_temp_unload, SI_SUB_LOCK, SI_ORDER_ANY, usb2_temp_unload, NULL); 130729088Smarkm