The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/usb/template/usb_template.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* $FreeBSD$ */
    2 /*-
    3  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    4  *
    5  * Copyright (c) 2007 Hans Petter Selasky. All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 /*
   30  * This file contains sub-routines to build up USB descriptors from
   31  * USB templates.
   32  */
   33 
   34 #ifdef USB_GLOBAL_INCLUDE_FILE
   35 #include USB_GLOBAL_INCLUDE_FILE
   36 #else
   37 #include <sys/stdint.h>
   38 #include <sys/stddef.h>
   39 #include <sys/param.h>
   40 #include <sys/queue.h>
   41 #include <sys/types.h>
   42 #include <sys/systm.h>
   43 #include <sys/kernel.h>
   44 #include <sys/bus.h>
   45 #include <sys/module.h>
   46 #include <sys/lock.h>
   47 #include <sys/mutex.h>
   48 #include <sys/condvar.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/sx.h>
   51 #include <sys/unistd.h>
   52 #include <sys/callout.h>
   53 #include <sys/malloc.h>
   54 #include <sys/priv.h>
   55 
   56 #include <dev/usb/usb.h>
   57 #include <dev/usb/usb_ioctl.h>
   58 #include <dev/usb/usbdi.h>
   59 #include <dev/usb/usbdi_util.h>
   60 #include "usbdevs.h"
   61 
   62 #include <dev/usb/usb_cdc.h>
   63 #include <dev/usb/usb_core.h>
   64 #include <dev/usb/usb_dynamic.h>
   65 #include <dev/usb/usb_busdma.h>
   66 #include <dev/usb/usb_process.h>
   67 #include <dev/usb/usb_device.h>
   68 #include <dev/usb/usb_util.h>
   69 
   70 #define USB_DEBUG_VAR usb_debug
   71 #include <dev/usb/usb_debug.h>
   72 
   73 #include <dev/usb/usb_controller.h>
   74 #include <dev/usb/usb_bus.h>
   75 #include <dev/usb/usb_request.h>
   76 #include <dev/usb/template/usb_template.h>
   77 #endif                  /* USB_GLOBAL_INCLUDE_FILE */
   78 
   79 MODULE_DEPEND(usb_template, usb, 1, 1, 1);
   80 MODULE_VERSION(usb_template, 1);
   81 
   82 /* function prototypes */
   83 
   84 static int      sysctl_hw_usb_template_power(SYSCTL_HANDLER_ARGS);
   85 static void     usb_make_raw_desc(struct usb_temp_setup *, const uint8_t *);
   86 static void     usb_make_endpoint_desc(struct usb_temp_setup *,
   87                     const struct usb_temp_endpoint_desc *);
   88 static void     usb_make_interface_desc(struct usb_temp_setup *,
   89                     const struct usb_temp_interface_desc *);
   90 static void     usb_make_config_desc(struct usb_temp_setup *,
   91                     const struct usb_temp_config_desc *);
   92 static void     usb_make_device_desc(struct usb_temp_setup *,
   93                     const struct usb_temp_device_desc *);
   94 static uint8_t  usb_hw_ep_match(const struct usb_hw_ep_profile *, uint8_t,
   95                     uint8_t);
   96 static uint8_t  usb_hw_ep_find_match(struct usb_hw_ep_scratch *,
   97                     struct usb_hw_ep_scratch_sub *, uint8_t);
   98 static uint8_t  usb_hw_ep_get_needs(struct usb_hw_ep_scratch *, uint8_t,
   99                     uint8_t);
  100 static usb_error_t usb_hw_ep_resolve(struct usb_device *,
  101                     struct usb_descriptor *);
  102 static const struct usb_temp_device_desc *usb_temp_get_tdd(struct usb_device *);
  103 static void     *usb_temp_get_device_desc(struct usb_device *);
  104 static void     *usb_temp_get_qualifier_desc(struct usb_device *);
  105 static void     *usb_temp_get_config_desc(struct usb_device *, uint16_t *,
  106                     uint8_t);
  107 static const void *usb_temp_get_string_desc(struct usb_device *, uint16_t,
  108                     uint8_t);
  109 static const void *usb_temp_get_vendor_desc(struct usb_device *,
  110                     const struct usb_device_request *, uint16_t *plen);
  111 static const void *usb_temp_get_hub_desc(struct usb_device *);
  112 static usb_error_t usb_temp_get_desc(struct usb_device *,
  113                     struct usb_device_request *, const void **, uint16_t *);
  114 static usb_error_t usb_temp_setup_by_index(struct usb_device *,
  115                     uint16_t index);
  116 static void     usb_temp_init(void *);
  117 
  118 SYSCTL_NODE(_hw_usb, OID_AUTO, templates, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
  119     "USB device side templates");
  120 SYSCTL_PROC(_hw_usb, OID_AUTO, template_power,
  121     CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
  122     NULL, 0, sysctl_hw_usb_template_power,
  123     "I", "USB bus power consumption in mA at 5V");
  124 
  125 static int      usb_template_power = 500;       /* 500mA */
  126 
  127 static int
  128 sysctl_hw_usb_template_power(SYSCTL_HANDLER_ARGS)
  129 {
  130         int error, val;
  131 
  132         val = usb_template_power;
  133         error = sysctl_handle_int(oidp, &val, 0, req);
  134         if (error != 0 || req->newptr == NULL)
  135                 return (error);
  136 
  137         if (val < 0 || val > 500)
  138                 return (EINVAL);
  139 
  140         usb_template_power = val;
  141 
  142         return (0);
  143 }
  144 
  145 /*------------------------------------------------------------------------*
  146  *      usb_decode_str_desc
  147  *
  148  * Helper function to decode string descriptors into a C string.
  149  *------------------------------------------------------------------------*/
  150 void
  151 usb_decode_str_desc(struct usb_string_descriptor *sd, char *buf, size_t buflen)
  152 {
  153         size_t i;
  154 
  155         if (sd->bLength < 2) {
  156                 buf[0] = '\0';
  157                 return;
  158         }
  159 
  160         for (i = 0; i < buflen - 1 && i < (sd->bLength / 2) - 1; i++)
  161                 buf[i] = UGETW(sd->bString[i]);
  162 
  163         buf[i] = '\0';
  164 }
  165 
  166 /*------------------------------------------------------------------------*
  167  *      usb_temp_sysctl
  168  *
  169  * Callback for SYSCTL_PROC(9), to set and retrieve template string
  170  * descriptors.
  171  *------------------------------------------------------------------------*/
  172 int
  173 usb_temp_sysctl(SYSCTL_HANDLER_ARGS)
  174 {
  175         char buf[128];
  176         struct usb_string_descriptor *sd = arg1;
  177         size_t len, sdlen = arg2;
  178         int error;
  179 
  180         usb_decode_str_desc(sd, buf, sizeof(buf));
  181 
  182         error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
  183         if (error != 0 || req->newptr == NULL)
  184                 return (error);
  185 
  186         len = usb_make_str_desc(sd, sdlen, buf);
  187         if (len == 0)
  188                 return (EINVAL);
  189 
  190         return (0);
  191 }
  192 
  193 /*------------------------------------------------------------------------*
  194  *      usb_make_raw_desc
  195  *
  196  * This function will insert a raw USB descriptor into the generated
  197  * USB configuration.
  198  *------------------------------------------------------------------------*/
  199 static void
  200 usb_make_raw_desc(struct usb_temp_setup *temp,
  201     const uint8_t *raw)
  202 {
  203         void *dst;
  204         uint8_t len;
  205 
  206         /*
  207          * The first byte of any USB descriptor gives the length.
  208          */
  209         if (raw) {
  210                 len = raw[0];
  211                 if (temp->buf) {
  212                         dst = USB_ADD_BYTES(temp->buf, temp->size);
  213                         memcpy(dst, raw, len);
  214 
  215                         /* check if we have got a CDC union descriptor */
  216 
  217                         if ((raw[0] == sizeof(struct usb_cdc_union_descriptor)) &&
  218                             (raw[1] == UDESC_CS_INTERFACE) &&
  219                             (raw[2] == UDESCSUB_CDC_UNION)) {
  220                                 struct usb_cdc_union_descriptor *ud = (void *)dst;
  221 
  222                                 /* update the interface numbers */
  223 
  224                                 ud->bMasterInterface +=
  225                                     temp->bInterfaceNumber;
  226                                 ud->bSlaveInterface[0] +=
  227                                     temp->bInterfaceNumber;
  228                         }
  229 
  230                         /* check if we have got an interface association descriptor */
  231 
  232                         if ((raw[0] == sizeof(struct usb_interface_assoc_descriptor)) &&
  233                             (raw[1] == UDESC_IFACE_ASSOC)) {
  234                                 struct usb_interface_assoc_descriptor *iad = (void *)dst;
  235 
  236                                 /* update the interface number */
  237 
  238                                 iad->bFirstInterface +=
  239                                     temp->bInterfaceNumber;
  240                         }
  241 
  242                         /* check if we have got a call management descriptor */
  243 
  244                         if ((raw[0] == sizeof(struct usb_cdc_cm_descriptor)) &&
  245                             (raw[1] == UDESC_CS_INTERFACE) &&
  246                             (raw[2] == UDESCSUB_CDC_CM)) {
  247                                 struct usb_cdc_cm_descriptor *ccd = (void *)dst;
  248 
  249                                 /* update the interface number */
  250 
  251                                 ccd->bDataInterface +=
  252                                     temp->bInterfaceNumber;
  253                         }
  254                 }
  255                 temp->size += len;
  256         }
  257 }
  258 
  259 /*------------------------------------------------------------------------*
  260  *      usb_make_endpoint_desc
  261  *
  262  * This function will generate an USB endpoint descriptor from the
  263  * given USB template endpoint descriptor, which will be inserted into
  264  * the USB configuration.
  265  *------------------------------------------------------------------------*/
  266 static void
  267 usb_make_endpoint_desc(struct usb_temp_setup *temp,
  268     const struct usb_temp_endpoint_desc *ted)
  269 {
  270         struct usb_endpoint_descriptor *ed;
  271         const void **rd;
  272         uint16_t old_size;
  273         uint16_t mps;
  274         uint8_t ea;                     /* Endpoint Address */
  275         uint8_t et;                     /* Endpiont Type */
  276 
  277         /* Reserve memory */
  278         old_size = temp->size;
  279 
  280         ea = (ted->bEndpointAddress & (UE_ADDR | UE_DIR_IN | UE_DIR_OUT));
  281         et = (ted->bmAttributes & UE_XFERTYPE);
  282 
  283         if (et == UE_ISOCHRONOUS) {
  284                 /* account for extra byte fields */
  285                 temp->size += sizeof(*ed) + 2;
  286         } else {
  287                 temp->size += sizeof(*ed);
  288         }
  289 
  290         /* Scan all Raw Descriptors first */
  291         rd = ted->ppRawDesc;
  292         if (rd) {
  293                 while (*rd) {
  294                         usb_make_raw_desc(temp, *rd);
  295                         rd++;
  296                 }
  297         }
  298         if (ted->pPacketSize == NULL) {
  299                 /* not initialized */
  300                 temp->err = USB_ERR_INVAL;
  301                 return;
  302         }
  303         mps = ted->pPacketSize->mps[temp->usb_speed];
  304         if (mps == 0) {
  305                 /* not initialized */
  306                 temp->err = USB_ERR_INVAL;
  307                 return;
  308         } else if (mps == UE_ZERO_MPS) {
  309                 /* escape for Zero Max Packet Size */
  310                 mps = 0;
  311         }
  312 
  313         /*
  314          * Fill out the real USB endpoint descriptor
  315          * in case there is a buffer present:
  316          */
  317         if (temp->buf) {
  318                 ed = USB_ADD_BYTES(temp->buf, old_size);
  319                 if (et == UE_ISOCHRONOUS)
  320                         ed->bLength = sizeof(*ed) + 2;
  321                 else
  322                         ed->bLength = sizeof(*ed);
  323                 ed->bDescriptorType = UDESC_ENDPOINT;
  324                 ed->bEndpointAddress = ea;
  325                 ed->bmAttributes = ted->bmAttributes;
  326                 USETW(ed->wMaxPacketSize, mps);
  327 
  328                 /* setup bInterval parameter */
  329 
  330                 if (ted->pIntervals &&
  331                     ted->pIntervals->bInterval[temp->usb_speed]) {
  332                         ed->bInterval =
  333                             ted->pIntervals->bInterval[temp->usb_speed];
  334                 } else {
  335                         switch (et) {
  336                         case UE_BULK:
  337                         case UE_CONTROL:
  338                                 ed->bInterval = 0;      /* not used */
  339                                 break;
  340                         case UE_INTERRUPT:
  341                                 switch (temp->usb_speed) {
  342                                 case USB_SPEED_LOW:
  343                                 case USB_SPEED_FULL:
  344                                         ed->bInterval = 1;      /* 1 ms */
  345                                         break;
  346                                 default:
  347                                         ed->bInterval = 4;      /* 1 ms */
  348                                         break;
  349                                 }
  350                                 break;
  351                         default:        /* UE_ISOCHRONOUS */
  352                                 switch (temp->usb_speed) {
  353                                 case USB_SPEED_LOW:
  354                                 case USB_SPEED_FULL:
  355                                         ed->bInterval = 1;      /* 1 ms */
  356                                         break;
  357                                 default:
  358                                         ed->bInterval = 1;      /* 125 us */
  359                                         break;
  360                                 }
  361                                 break;
  362                         }
  363                 }
  364         }
  365         temp->bNumEndpoints++;
  366 }
  367 
  368 /*------------------------------------------------------------------------*
  369  *      usb_make_interface_desc
  370  *
  371  * This function will generate an USB interface descriptor from the
  372  * given USB template interface descriptor, which will be inserted
  373  * into the USB configuration.
  374  *------------------------------------------------------------------------*/
  375 static void
  376 usb_make_interface_desc(struct usb_temp_setup *temp,
  377     const struct usb_temp_interface_desc *tid)
  378 {
  379         struct usb_interface_descriptor *id;
  380         const struct usb_temp_endpoint_desc **ted;
  381         const void **rd;
  382         uint16_t old_size;
  383 
  384         /* Reserve memory */
  385 
  386         old_size = temp->size;
  387         temp->size += sizeof(*id);
  388 
  389         /* Update interface and alternate interface numbers */
  390 
  391         if (tid->isAltInterface == 0) {
  392                 temp->bAlternateSetting = 0;
  393                 temp->bInterfaceNumber++;
  394         } else {
  395                 temp->bAlternateSetting++;
  396         }
  397 
  398         /* Scan all Raw Descriptors first */
  399 
  400         rd = tid->ppRawDesc;
  401 
  402         if (rd) {
  403                 while (*rd) {
  404                         usb_make_raw_desc(temp, *rd);
  405                         rd++;
  406                 }
  407         }
  408         /* Reset some counters */
  409 
  410         temp->bNumEndpoints = 0;
  411 
  412         /* Scan all Endpoint Descriptors second */
  413 
  414         ted = tid->ppEndpoints;
  415         if (ted) {
  416                 while (*ted) {
  417                         usb_make_endpoint_desc(temp, *ted);
  418                         ted++;
  419                 }
  420         }
  421         /*
  422          * Fill out the real USB interface descriptor
  423          * in case there is a buffer present:
  424          */
  425         if (temp->buf) {
  426                 id = USB_ADD_BYTES(temp->buf, old_size);
  427                 id->bLength = sizeof(*id);
  428                 id->bDescriptorType = UDESC_INTERFACE;
  429                 id->bInterfaceNumber = temp->bInterfaceNumber;
  430                 id->bAlternateSetting = temp->bAlternateSetting;
  431                 id->bNumEndpoints = temp->bNumEndpoints;
  432                 id->bInterfaceClass = tid->bInterfaceClass;
  433                 id->bInterfaceSubClass = tid->bInterfaceSubClass;
  434                 id->bInterfaceProtocol = tid->bInterfaceProtocol;
  435                 id->iInterface = tid->iInterface;
  436         }
  437 }
  438 
  439 /*------------------------------------------------------------------------*
  440  *      usb_make_config_desc
  441  *
  442  * This function will generate an USB config descriptor from the given
  443  * USB template config descriptor, which will be inserted into the USB
  444  * configuration.
  445  *------------------------------------------------------------------------*/
  446 static void
  447 usb_make_config_desc(struct usb_temp_setup *temp,
  448     const struct usb_temp_config_desc *tcd)
  449 {
  450         struct usb_config_descriptor *cd;
  451         const struct usb_temp_interface_desc **tid;
  452         uint16_t old_size;
  453         int power;
  454 
  455         /* Reserve memory */
  456 
  457         old_size = temp->size;
  458         temp->size += sizeof(*cd);
  459 
  460         /* Reset some counters */
  461 
  462         temp->bInterfaceNumber = 0xFF;
  463         temp->bAlternateSetting = 0;
  464 
  465         /* Scan all the USB interfaces */
  466 
  467         tid = tcd->ppIfaceDesc;
  468         if (tid) {
  469                 while (*tid) {
  470                         usb_make_interface_desc(temp, *tid);
  471                         tid++;
  472                 }
  473         }
  474         /*
  475          * Fill out the real USB config descriptor
  476          * in case there is a buffer present:
  477          */
  478         if (temp->buf) {
  479                 cd = USB_ADD_BYTES(temp->buf, old_size);
  480 
  481                 /* compute total size */
  482                 old_size = temp->size - old_size;
  483 
  484                 cd->bLength = sizeof(*cd);
  485                 cd->bDescriptorType = UDESC_CONFIG;
  486                 USETW(cd->wTotalLength, old_size);
  487                 cd->bNumInterface = temp->bInterfaceNumber + 1;
  488                 cd->bConfigurationValue = temp->bConfigurationValue;
  489                 cd->iConfiguration = tcd->iConfiguration;
  490                 cd->bmAttributes = tcd->bmAttributes;
  491 
  492                 power = usb_template_power;
  493                 cd->bMaxPower = power / 2; /* 2 mA units */
  494                 cd->bmAttributes |= UC_REMOTE_WAKEUP;
  495                 if (power > 0) {
  496                         cd->bmAttributes |= UC_BUS_POWERED;
  497                         cd->bmAttributes &= ~UC_SELF_POWERED;
  498                 } else {
  499                         cd->bmAttributes &= ~UC_BUS_POWERED;
  500                         cd->bmAttributes |= UC_SELF_POWERED;
  501                 }
  502         }
  503 }
  504 
  505 /*------------------------------------------------------------------------*
  506  *      usb_make_device_desc
  507  *
  508  * This function will generate an USB device descriptor from the
  509  * given USB template device descriptor.
  510  *------------------------------------------------------------------------*/
  511 static void
  512 usb_make_device_desc(struct usb_temp_setup *temp,
  513     const struct usb_temp_device_desc *tdd)
  514 {
  515         struct usb_temp_data *utd;
  516         const struct usb_temp_config_desc **tcd;
  517         uint16_t old_size;
  518 
  519         /* Reserve memory */
  520 
  521         old_size = temp->size;
  522         temp->size += sizeof(*utd);
  523 
  524         /* Scan all the USB configs */
  525 
  526         temp->bConfigurationValue = 1;
  527         tcd = tdd->ppConfigDesc;
  528         if (tcd) {
  529                 while (*tcd) {
  530                         usb_make_config_desc(temp, *tcd);
  531                         temp->bConfigurationValue++;
  532                         tcd++;
  533                 }
  534         }
  535         /*
  536          * Fill out the real USB device descriptor
  537          * in case there is a buffer present:
  538          */
  539 
  540         if (temp->buf) {
  541                 utd = USB_ADD_BYTES(temp->buf, old_size);
  542 
  543                 /* Store a pointer to our template device descriptor */
  544                 utd->tdd = tdd;
  545 
  546                 /* Fill out USB device descriptor */
  547                 utd->udd.bLength = sizeof(utd->udd);
  548                 utd->udd.bDescriptorType = UDESC_DEVICE;
  549                 utd->udd.bDeviceClass = tdd->bDeviceClass;
  550                 utd->udd.bDeviceSubClass = tdd->bDeviceSubClass;
  551                 utd->udd.bDeviceProtocol = tdd->bDeviceProtocol;
  552                 USETW(utd->udd.idVendor, tdd->idVendor);
  553                 USETW(utd->udd.idProduct, tdd->idProduct);
  554                 USETW(utd->udd.bcdDevice, tdd->bcdDevice);
  555                 utd->udd.iManufacturer = tdd->iManufacturer;
  556                 utd->udd.iProduct = tdd->iProduct;
  557                 utd->udd.iSerialNumber = tdd->iSerialNumber;
  558                 utd->udd.bNumConfigurations = temp->bConfigurationValue - 1;
  559 
  560                 /*
  561                  * Fill out the USB device qualifier. Pretend that we
  562                  * don't support any other speeds by setting
  563                  * "bNumConfigurations" equal to zero. That saves us
  564                  * generating an extra set of configuration
  565                  * descriptors.
  566                  */
  567                 utd->udq.bLength = sizeof(utd->udq);
  568                 utd->udq.bDescriptorType = UDESC_DEVICE_QUALIFIER;
  569                 utd->udq.bDeviceClass = tdd->bDeviceClass;
  570                 utd->udq.bDeviceSubClass = tdd->bDeviceSubClass;
  571                 utd->udq.bDeviceProtocol = tdd->bDeviceProtocol;
  572                 utd->udq.bNumConfigurations = 0;
  573                 USETW(utd->udq.bcdUSB, 0x0200);
  574                 utd->udq.bMaxPacketSize0 = 0;
  575 
  576                 switch (temp->usb_speed) {
  577                 case USB_SPEED_LOW:
  578                         USETW(utd->udd.bcdUSB, 0x0110);
  579                         utd->udd.bMaxPacketSize = 8;
  580                         break;
  581                 case USB_SPEED_FULL:
  582                         USETW(utd->udd.bcdUSB, 0x0110);
  583                         utd->udd.bMaxPacketSize = 32;
  584                         break;
  585                 case USB_SPEED_HIGH:
  586                         USETW(utd->udd.bcdUSB, 0x0200);
  587                         utd->udd.bMaxPacketSize = 64;
  588                         break;
  589                 case USB_SPEED_VARIABLE:
  590                         USETW(utd->udd.bcdUSB, 0x0250);
  591                         utd->udd.bMaxPacketSize = 255;  /* 512 bytes */
  592                         break;
  593                 case USB_SPEED_SUPER:
  594                         USETW(utd->udd.bcdUSB, 0x0300);
  595                         utd->udd.bMaxPacketSize = 9;    /* 2**9 = 512 bytes */
  596                         break;
  597                 default:
  598                         temp->err = USB_ERR_INVAL;
  599                         break;
  600                 }
  601         }
  602 }
  603 
  604 /*------------------------------------------------------------------------*
  605  *      usb_hw_ep_match
  606  *
  607  * Return values:
  608  *    0: The endpoint profile does not match the criteria
  609  * Else: The endpoint profile matches the criteria
  610  *------------------------------------------------------------------------*/
  611 static uint8_t
  612 usb_hw_ep_match(const struct usb_hw_ep_profile *pf,
  613     uint8_t ep_type, uint8_t ep_dir_in)
  614 {
  615         if (ep_type == UE_CONTROL) {
  616                 /* special */
  617                 return (pf->support_control);
  618         }
  619         if ((pf->support_in && ep_dir_in) ||
  620             (pf->support_out && !ep_dir_in)) {
  621                 if ((pf->support_interrupt && (ep_type == UE_INTERRUPT)) ||
  622                     (pf->support_isochronous && (ep_type == UE_ISOCHRONOUS)) ||
  623                     (pf->support_bulk && (ep_type == UE_BULK))) {
  624                         return (1);
  625                 }
  626         }
  627         return (0);
  628 }
  629 
  630 /*------------------------------------------------------------------------*
  631  *      usb_hw_ep_find_match
  632  *
  633  * This function is used to find the best matching endpoint profile
  634  * for and endpoint belonging to an USB descriptor.
  635  *
  636  * Return values:
  637  *    0: Success. Got a match.
  638  * Else: Failure. No match.
  639  *------------------------------------------------------------------------*/
  640 static uint8_t
  641 usb_hw_ep_find_match(struct usb_hw_ep_scratch *ues,
  642     struct usb_hw_ep_scratch_sub *ep, uint8_t is_simplex)
  643 {
  644         const struct usb_hw_ep_profile *pf;
  645         uint16_t distance;
  646         uint16_t temp;
  647         uint16_t max_frame_size;
  648         uint8_t n;
  649         uint8_t best_n;
  650         uint8_t dir_in;
  651         uint8_t dir_out;
  652 
  653         distance = 0xFFFF;
  654         best_n = 0;
  655 
  656         if ((!ep->needs_in) && (!ep->needs_out)) {
  657                 return (0);             /* we are done */
  658         }
  659         if (ep->needs_ep_type == UE_CONTROL) {
  660                 dir_in = 1;
  661                 dir_out = 1;
  662         } else {
  663                 if (ep->needs_in) {
  664                         dir_in = 1;
  665                         dir_out = 0;
  666                 } else {
  667                         dir_in = 0;
  668                         dir_out = 1;
  669                 }
  670         }
  671 
  672         for (n = 1; n != (USB_EP_MAX / 2); n++) {
  673                 /* get HW endpoint profile */
  674                 (ues->methods->get_hw_ep_profile) (ues->udev, &pf, n);
  675                 if (pf == NULL) {
  676                         /* end of profiles */
  677                         break;
  678                 }
  679                 /* check if IN-endpoint is reserved */
  680                 if (dir_in || pf->is_simplex) {
  681                         if (ues->bmInAlloc[n / 8] & (1 << (n % 8))) {
  682                                 /* mismatch */
  683                                 continue;
  684                         }
  685                 }
  686                 /* check if OUT-endpoint is reserved */
  687                 if (dir_out || pf->is_simplex) {
  688                         if (ues->bmOutAlloc[n / 8] & (1 << (n % 8))) {
  689                                 /* mismatch */
  690                                 continue;
  691                         }
  692                 }
  693                 /* check simplex */
  694                 if (pf->is_simplex == is_simplex) {
  695                         /* mismatch */
  696                         continue;
  697                 }
  698                 /* check if HW endpoint matches */
  699                 if (!usb_hw_ep_match(pf, ep->needs_ep_type, dir_in)) {
  700                         /* mismatch */
  701                         continue;
  702                 }
  703                 /* get maximum frame size */
  704                 if (dir_in)
  705                         max_frame_size = pf->max_in_frame_size;
  706                 else
  707                         max_frame_size = pf->max_out_frame_size;
  708 
  709                 /* check if we have a matching profile */
  710                 if (max_frame_size >= ep->max_frame_size) {
  711                         temp = (max_frame_size - ep->max_frame_size);
  712                         if (distance > temp) {
  713                                 distance = temp;
  714                                 best_n = n;
  715                                 ep->pf = pf;
  716                         }
  717                 }
  718         }
  719 
  720         /* see if we got a match */
  721         if (best_n != 0) {
  722                 /* get the correct profile */
  723                 pf = ep->pf;
  724 
  725                 /* reserve IN-endpoint */
  726                 if (dir_in) {
  727                         ues->bmInAlloc[best_n / 8] |=
  728                             (1 << (best_n % 8));
  729                         ep->hw_endpoint_in = best_n | UE_DIR_IN;
  730                         ep->needs_in = 0;
  731                 }
  732                 /* reserve OUT-endpoint */
  733                 if (dir_out) {
  734                         ues->bmOutAlloc[best_n / 8] |=
  735                             (1 << (best_n % 8));
  736                         ep->hw_endpoint_out = best_n | UE_DIR_OUT;
  737                         ep->needs_out = 0;
  738                 }
  739                 return (0);             /* got a match */
  740         }
  741         return (1);                     /* failure */
  742 }
  743 
  744 /*------------------------------------------------------------------------*
  745  *      usb_hw_ep_get_needs
  746  *
  747  * This function will figure out the type and number of endpoints
  748  * which are needed for an USB configuration.
  749  *
  750  * Return values:
  751  *    0: Success.
  752  * Else: Failure.
  753  *------------------------------------------------------------------------*/
  754 static uint8_t
  755 usb_hw_ep_get_needs(struct usb_hw_ep_scratch *ues,
  756     uint8_t ep_type, uint8_t is_complete)
  757 {
  758         const struct usb_hw_ep_profile *pf;
  759         struct usb_hw_ep_scratch_sub *ep_iface;
  760         struct usb_hw_ep_scratch_sub *ep_curr;
  761         struct usb_hw_ep_scratch_sub *ep_max;
  762         struct usb_hw_ep_scratch_sub *ep_end;
  763         struct usb_descriptor *desc;
  764         struct usb_interface_descriptor *id;
  765         struct usb_endpoint_descriptor *ed;
  766         enum usb_dev_speed speed;
  767         uint16_t wMaxPacketSize;
  768         uint16_t temp;
  769         uint8_t ep_no;
  770 
  771         ep_iface = ues->ep_max;
  772         ep_curr = ues->ep_max;
  773         ep_end = ues->ep + USB_EP_MAX;
  774         ep_max = ues->ep_max;
  775         desc = NULL;
  776         speed = usbd_get_speed(ues->udev);
  777 
  778 repeat:
  779 
  780         while ((desc = usb_desc_foreach(ues->cd, desc))) {
  781                 if ((desc->bDescriptorType == UDESC_INTERFACE) &&
  782                     (desc->bLength >= sizeof(*id))) {
  783                         id = (void *)desc;
  784 
  785                         if (id->bAlternateSetting == 0) {
  786                                 /* going forward */
  787                                 ep_iface = ep_max;
  788                         } else {
  789                                 /* reset */
  790                                 ep_curr = ep_iface;
  791                         }
  792                 }
  793                 if ((desc->bDescriptorType == UDESC_ENDPOINT) &&
  794                     (desc->bLength >= sizeof(*ed))) {
  795                         ed = (void *)desc;
  796 
  797                         goto handle_endpoint_desc;
  798                 }
  799         }
  800         ues->ep_max = ep_max;
  801         return (0);
  802 
  803 handle_endpoint_desc:
  804         temp = (ed->bmAttributes & UE_XFERTYPE);
  805 
  806         if (temp == ep_type) {
  807                 if (ep_curr == ep_end) {
  808                         /* too many endpoints */
  809                         return (1);     /* failure */
  810                 }
  811                 wMaxPacketSize = UGETW(ed->wMaxPacketSize);
  812                 if ((wMaxPacketSize & 0xF800) &&
  813                     (speed == USB_SPEED_HIGH)) {
  814                         /* handle packet multiplier */
  815                         temp = (wMaxPacketSize >> 11) & 3;
  816                         wMaxPacketSize &= 0x7FF;
  817                         if (temp == 1) {
  818                                 wMaxPacketSize *= 2;
  819                         } else {
  820                                 wMaxPacketSize *= 3;
  821                         }
  822                 }
  823                 /*
  824                  * Check if we have a fixed endpoint number, else the
  825                  * endpoint number is allocated dynamically:
  826                  */
  827                 ep_no = (ed->bEndpointAddress & UE_ADDR);
  828                 if (ep_no != 0) {
  829                         /* get HW endpoint profile */
  830                         (ues->methods->get_hw_ep_profile)
  831                             (ues->udev, &pf, ep_no);
  832                         if (pf == NULL) {
  833                                 /* HW profile does not exist - failure */
  834                                 DPRINTFN(0, "Endpoint profile %u "
  835                                     "does not exist\n", ep_no);
  836                                 return (1);
  837                         }
  838                         /* reserve fixed endpoint number */
  839                         if (ep_type == UE_CONTROL) {
  840                                 ues->bmInAlloc[ep_no / 8] |=
  841                                     (1 << (ep_no % 8));
  842                                 ues->bmOutAlloc[ep_no / 8] |=
  843                                     (1 << (ep_no % 8));
  844                                 if ((pf->max_in_frame_size < wMaxPacketSize) ||
  845                                     (pf->max_out_frame_size < wMaxPacketSize)) {
  846                                         DPRINTFN(0, "Endpoint profile %u "
  847                                             "has too small buffer\n", ep_no);
  848                                         return (1);
  849                                 }
  850                         } else if (ed->bEndpointAddress & UE_DIR_IN) {
  851                                 ues->bmInAlloc[ep_no / 8] |=
  852                                     (1 << (ep_no % 8));
  853                                 if (pf->max_in_frame_size < wMaxPacketSize) {
  854                                         DPRINTFN(0, "Endpoint profile %u "
  855                                             "has too small buffer\n", ep_no);
  856                                         return (1);
  857                                 }
  858                         } else {
  859                                 ues->bmOutAlloc[ep_no / 8] |=
  860                                     (1 << (ep_no % 8));
  861                                 if (pf->max_out_frame_size < wMaxPacketSize) {
  862                                         DPRINTFN(0, "Endpoint profile %u "
  863                                             "has too small buffer\n", ep_no);
  864                                         return (1);
  865                                 }
  866                         }
  867                 } else if (is_complete) {
  868                         /* check if we have enough buffer space */
  869                         if (wMaxPacketSize >
  870                             ep_curr->max_frame_size) {
  871                                 return (1);     /* failure */
  872                         }
  873                         if (ed->bEndpointAddress & UE_DIR_IN) {
  874                                 ed->bEndpointAddress =
  875                                     ep_curr->hw_endpoint_in;
  876                         } else {
  877                                 ed->bEndpointAddress =
  878                                     ep_curr->hw_endpoint_out;
  879                         }
  880 
  881                 } else {
  882                         /* compute the maximum frame size */
  883                         if (ep_curr->max_frame_size < wMaxPacketSize) {
  884                                 ep_curr->max_frame_size = wMaxPacketSize;
  885                         }
  886                         if (temp == UE_CONTROL) {
  887                                 ep_curr->needs_in = 1;
  888                                 ep_curr->needs_out = 1;
  889                         } else {
  890                                 if (ed->bEndpointAddress & UE_DIR_IN) {
  891                                         ep_curr->needs_in = 1;
  892                                 } else {
  893                                         ep_curr->needs_out = 1;
  894                                 }
  895                         }
  896                         ep_curr->needs_ep_type = ep_type;
  897                 }
  898 
  899                 ep_curr++;
  900                 if (ep_max < ep_curr) {
  901                         ep_max = ep_curr;
  902                 }
  903         }
  904         goto repeat;
  905 }
  906 
  907 /*------------------------------------------------------------------------*
  908  *      usb_hw_ep_resolve
  909  *
  910  * This function will try to resolve endpoint requirements by the
  911  * given endpoint profiles that the USB hardware reports.
  912  *
  913  * Return values:
  914  *    0: Success
  915  * Else: Failure
  916  *------------------------------------------------------------------------*/
  917 static usb_error_t
  918 usb_hw_ep_resolve(struct usb_device *udev,
  919     struct usb_descriptor *desc)
  920 {
  921         struct usb_hw_ep_scratch *ues;
  922         struct usb_hw_ep_scratch_sub *ep;
  923         const struct usb_hw_ep_profile *pf;
  924         const struct usb_bus_methods *methods;
  925         struct usb_device_descriptor *dd;
  926         uint16_t mps;
  927 
  928         if (desc == NULL)
  929                 return (USB_ERR_INVAL);
  930 
  931         /* get bus methods */
  932         methods = udev->bus->methods;
  933 
  934         if (methods->get_hw_ep_profile == NULL)
  935                 return (USB_ERR_INVAL);
  936 
  937         if (desc->bDescriptorType == UDESC_DEVICE) {
  938                 if (desc->bLength < sizeof(*dd))
  939                         return (USB_ERR_INVAL);
  940 
  941                 dd = (void *)desc;
  942 
  943                 /* get HW control endpoint 0 profile */
  944                 (methods->get_hw_ep_profile) (udev, &pf, 0);
  945                 if (pf == NULL) {
  946                         return (USB_ERR_INVAL);
  947                 }
  948                 if (!usb_hw_ep_match(pf, UE_CONTROL, 0)) {
  949                         DPRINTFN(0, "Endpoint 0 does not "
  950                             "support control\n");
  951                         return (USB_ERR_INVAL);
  952                 }
  953                 mps = dd->bMaxPacketSize;
  954 
  955                 if (udev->speed == USB_SPEED_FULL) {
  956                         /*
  957                          * We can optionally choose another packet size !
  958                          */
  959                         while (1) {
  960                                 /* check if "mps" is ok */
  961                                 if (pf->max_in_frame_size >= mps) {
  962                                         break;
  963                                 }
  964                                 /* reduce maximum packet size */
  965                                 mps /= 2;
  966 
  967                                 /* check if "mps" is too small */
  968                                 if (mps < 8) {
  969                                         return (USB_ERR_INVAL);
  970                                 }
  971                         }
  972 
  973                         dd->bMaxPacketSize = mps;
  974 
  975                 } else {
  976                         /* We only have one choice */
  977                         if (mps == 255) {
  978                                 mps = 512;
  979                         }
  980                         /* Check if we support the specified wMaxPacketSize */
  981                         if (pf->max_in_frame_size < mps) {
  982                                 return (USB_ERR_INVAL);
  983                         }
  984                 }
  985                 return (0);             /* success */
  986         }
  987         if (desc->bDescriptorType != UDESC_CONFIG)
  988                 return (USB_ERR_INVAL);
  989         if (desc->bLength < sizeof(*(ues->cd)))
  990                 return (USB_ERR_INVAL);
  991 
  992         ues = udev->scratch.hw_ep_scratch;
  993 
  994         memset(ues, 0, sizeof(*ues));
  995 
  996         ues->ep_max = ues->ep;
  997         ues->cd = (void *)desc;
  998         ues->methods = methods;
  999         ues->udev = udev;
 1000 
 1001         /* Get all the endpoints we need */
 1002 
 1003         if (usb_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 0) ||
 1004             usb_hw_ep_get_needs(ues, UE_INTERRUPT, 0) ||
 1005             usb_hw_ep_get_needs(ues, UE_CONTROL, 0) ||
 1006             usb_hw_ep_get_needs(ues, UE_BULK, 0)) {
 1007                 DPRINTFN(0, "Could not get needs\n");
 1008                 return (USB_ERR_INVAL);
 1009         }
 1010         for (ep = ues->ep; ep != ues->ep_max; ep++) {
 1011                 while (ep->needs_in || ep->needs_out) {
 1012                         /*
 1013                          * First try to use a simplex endpoint.
 1014                          * Then try to use a duplex endpoint.
 1015                          */
 1016                         if (usb_hw_ep_find_match(ues, ep, 1) &&
 1017                             usb_hw_ep_find_match(ues, ep, 0)) {
 1018                                 DPRINTFN(0, "Could not find match\n");
 1019                                 return (USB_ERR_INVAL);
 1020                         }
 1021                 }
 1022         }
 1023 
 1024         ues->ep_max = ues->ep;
 1025 
 1026         /* Update all endpoint addresses */
 1027 
 1028         if (usb_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 1) ||
 1029             usb_hw_ep_get_needs(ues, UE_INTERRUPT, 1) ||
 1030             usb_hw_ep_get_needs(ues, UE_CONTROL, 1) ||
 1031             usb_hw_ep_get_needs(ues, UE_BULK, 1)) {
 1032                 DPRINTFN(0, "Could not update endpoint address\n");
 1033                 return (USB_ERR_INVAL);
 1034         }
 1035         return (0);                     /* success */
 1036 }
 1037 
 1038 /*------------------------------------------------------------------------*
 1039  *      usb_temp_get_tdd
 1040  *
 1041  * Returns:
 1042  *  NULL: No USB template device descriptor found.
 1043  *  Else: Pointer to the USB template device descriptor.
 1044  *------------------------------------------------------------------------*/
 1045 static const struct usb_temp_device_desc *
 1046 usb_temp_get_tdd(struct usb_device *udev)
 1047 {
 1048         if (udev->usb_template_ptr == NULL) {
 1049                 return (NULL);
 1050         }
 1051         return (udev->usb_template_ptr->tdd);
 1052 }
 1053 
 1054 /*------------------------------------------------------------------------*
 1055  *      usb_temp_get_device_desc
 1056  *
 1057  * Returns:
 1058  *  NULL: No USB device descriptor found.
 1059  *  Else: Pointer to USB device descriptor.
 1060  *------------------------------------------------------------------------*/
 1061 static void *
 1062 usb_temp_get_device_desc(struct usb_device *udev)
 1063 {
 1064         struct usb_device_descriptor *dd;
 1065 
 1066         if (udev->usb_template_ptr == NULL) {
 1067                 return (NULL);
 1068         }
 1069         dd = &udev->usb_template_ptr->udd;
 1070         if (dd->bDescriptorType != UDESC_DEVICE) {
 1071                 /* sanity check failed */
 1072                 return (NULL);
 1073         }
 1074         return (dd);
 1075 }
 1076 
 1077 /*------------------------------------------------------------------------*
 1078  *      usb_temp_get_qualifier_desc
 1079  *
 1080  * Returns:
 1081  *  NULL: No USB device_qualifier descriptor found.
 1082  *  Else: Pointer to USB device_qualifier descriptor.
 1083  *------------------------------------------------------------------------*/
 1084 static void *
 1085 usb_temp_get_qualifier_desc(struct usb_device *udev)
 1086 {
 1087         struct usb_device_qualifier *dq;
 1088 
 1089         if (udev->usb_template_ptr == NULL) {
 1090                 return (NULL);
 1091         }
 1092         dq = &udev->usb_template_ptr->udq;
 1093         if (dq->bDescriptorType != UDESC_DEVICE_QUALIFIER) {
 1094                 /* sanity check failed */
 1095                 return (NULL);
 1096         }
 1097         return (dq);
 1098 }
 1099 
 1100 /*------------------------------------------------------------------------*
 1101  *      usb_temp_get_config_desc
 1102  *
 1103  * Returns:
 1104  *  NULL: No USB config descriptor found.
 1105  *  Else: Pointer to USB config descriptor having index "index".
 1106  *------------------------------------------------------------------------*/
 1107 static void *
 1108 usb_temp_get_config_desc(struct usb_device *udev,
 1109     uint16_t *pLength, uint8_t index)
 1110 {
 1111         struct usb_device_descriptor *dd;
 1112         struct usb_config_descriptor *cd;
 1113         uint16_t temp;
 1114 
 1115         if (udev->usb_template_ptr == NULL) {
 1116                 return (NULL);
 1117         }
 1118         dd = &udev->usb_template_ptr->udd;
 1119         cd = (void *)(udev->usb_template_ptr + 1);
 1120 
 1121         if (index >= dd->bNumConfigurations) {
 1122                 /* out of range */
 1123                 return (NULL);
 1124         }
 1125         while (index--) {
 1126                 if (cd->bDescriptorType != UDESC_CONFIG) {
 1127                         /* sanity check failed */
 1128                         return (NULL);
 1129                 }
 1130                 temp = UGETW(cd->wTotalLength);
 1131                 cd = USB_ADD_BYTES(cd, temp);
 1132         }
 1133 
 1134         if (pLength) {
 1135                 *pLength = UGETW(cd->wTotalLength);
 1136         }
 1137         return (cd);
 1138 }
 1139 
 1140 /*------------------------------------------------------------------------*
 1141  *      usb_temp_get_vendor_desc
 1142  *
 1143  * Returns:
 1144  *  NULL: No vendor descriptor found.
 1145  *  Else: Pointer to a vendor descriptor.
 1146  *------------------------------------------------------------------------*/
 1147 static const void *
 1148 usb_temp_get_vendor_desc(struct usb_device *udev,
 1149     const struct usb_device_request *req, uint16_t *plen)
 1150 {
 1151         const struct usb_temp_device_desc *tdd;
 1152 
 1153         tdd = usb_temp_get_tdd(udev);
 1154         if (tdd == NULL) {
 1155                 return (NULL);
 1156         }
 1157         if (tdd->getVendorDesc == NULL) {
 1158                 return (NULL);
 1159         }
 1160         return ((tdd->getVendorDesc) (req, plen));
 1161 }
 1162 
 1163 /*------------------------------------------------------------------------*
 1164  *      usb_temp_get_string_desc
 1165  *
 1166  * Returns:
 1167  *  NULL: No string descriptor found.
 1168  *  Else: Pointer to a string descriptor.
 1169  *------------------------------------------------------------------------*/
 1170 static const void *
 1171 usb_temp_get_string_desc(struct usb_device *udev,
 1172     uint16_t lang_id, uint8_t string_index)
 1173 {
 1174         const struct usb_temp_device_desc *tdd;
 1175 
 1176         tdd = usb_temp_get_tdd(udev);
 1177         if (tdd == NULL) {
 1178                 return (NULL);
 1179         }
 1180         if (tdd->getStringDesc == NULL) {
 1181                 return (NULL);
 1182         }
 1183         return ((tdd->getStringDesc) (lang_id, string_index));
 1184 }
 1185 
 1186 /*------------------------------------------------------------------------*
 1187  *      usb_temp_get_hub_desc
 1188  *
 1189  * Returns:
 1190  *  NULL: No USB HUB descriptor found.
 1191  *  Else: Pointer to a USB HUB descriptor.
 1192  *------------------------------------------------------------------------*/
 1193 static const void *
 1194 usb_temp_get_hub_desc(struct usb_device *udev)
 1195 {
 1196         return (NULL);                  /* needs to be implemented */
 1197 }
 1198 
 1199 /*------------------------------------------------------------------------*
 1200  *      usb_temp_get_desc
 1201  *
 1202  * This function is a demultiplexer for local USB device side control
 1203  * endpoint requests.
 1204  *------------------------------------------------------------------------*/
 1205 static usb_error_t
 1206 usb_temp_get_desc(struct usb_device *udev, struct usb_device_request *req,
 1207     const void **pPtr, uint16_t *pLength)
 1208 {
 1209         const uint8_t *buf;
 1210         uint16_t len;
 1211 
 1212         buf = NULL;
 1213         len = 0;
 1214 
 1215         switch (req->bmRequestType) {
 1216         case UT_READ_DEVICE:
 1217                 switch (req->bRequest) {
 1218                 case UR_GET_DESCRIPTOR:
 1219                         goto tr_handle_get_descriptor;
 1220                 default:
 1221                         goto tr_stalled;
 1222                 }
 1223         case UT_READ_CLASS_DEVICE:
 1224                 switch (req->bRequest) {
 1225                 case UR_GET_DESCRIPTOR:
 1226                         goto tr_handle_get_class_descriptor;
 1227                 default:
 1228                         goto tr_stalled;
 1229                 }
 1230         default:
 1231                 goto tr_stalled;
 1232         }
 1233 
 1234 tr_handle_get_descriptor:
 1235         switch (req->wValue[1]) {
 1236         case UDESC_DEVICE:
 1237                 if (req->wValue[0]) {
 1238                         goto tr_stalled;
 1239                 }
 1240                 buf = usb_temp_get_device_desc(udev);
 1241                 goto tr_valid;
 1242         case UDESC_DEVICE_QUALIFIER:
 1243                 if (udev->speed != USB_SPEED_HIGH) {
 1244                         goto tr_stalled;
 1245                 }
 1246                 if (req->wValue[0]) {
 1247                         goto tr_stalled;
 1248                 }
 1249                 buf = usb_temp_get_qualifier_desc(udev);
 1250                 goto tr_valid;
 1251         case UDESC_OTHER_SPEED_CONFIGURATION:
 1252                 if (udev->speed != USB_SPEED_HIGH) {
 1253                         goto tr_stalled;
 1254                 }
 1255         case UDESC_CONFIG:
 1256                 buf = usb_temp_get_config_desc(udev,
 1257                     &len, req->wValue[0]);
 1258                 goto tr_valid;
 1259         case UDESC_STRING:
 1260                 buf = usb_temp_get_string_desc(udev,
 1261                     UGETW(req->wIndex), req->wValue[0]);
 1262                 goto tr_valid;
 1263         default:
 1264                 goto tr_stalled;
 1265         }
 1266 
 1267 tr_handle_get_class_descriptor:
 1268         if (req->wValue[0]) {
 1269                 goto tr_stalled;
 1270         }
 1271         buf = usb_temp_get_hub_desc(udev);
 1272         goto tr_valid;
 1273 
 1274 tr_valid:
 1275         if (buf == NULL)
 1276                 goto tr_stalled;
 1277         if (len == 0)
 1278                 len = buf[0];
 1279         *pPtr = buf;
 1280         *pLength = len;
 1281         return (0);     /* success */
 1282 
 1283 tr_stalled:
 1284         /* try to get a vendor specific descriptor */
 1285         len = 0;
 1286         buf = usb_temp_get_vendor_desc(udev, req, &len);
 1287         if (buf != NULL)
 1288                 goto tr_valid;
 1289         *pPtr = NULL;
 1290         *pLength = 0;
 1291         return (0);     /* we ignore failures */
 1292 }
 1293 
 1294 /*------------------------------------------------------------------------*
 1295  *      usb_temp_setup
 1296  *
 1297  * This function generates USB descriptors according to the given USB
 1298  * template device descriptor. It will also try to figure out the best
 1299  * matching endpoint addresses using the hardware endpoint profiles.
 1300  *
 1301  * Returns:
 1302  *    0: Success
 1303  * Else: Failure
 1304  *------------------------------------------------------------------------*/
 1305 usb_error_t
 1306 usb_temp_setup(struct usb_device *udev,
 1307     const struct usb_temp_device_desc *tdd)
 1308 {
 1309         struct usb_temp_setup *uts;
 1310         void *buf;
 1311         usb_error_t error;
 1312         uint8_t n;
 1313         uint8_t do_unlock;
 1314 
 1315         /* be NULL safe */
 1316         if (tdd == NULL)
 1317                 return (0);
 1318 
 1319         /* Protect scratch area */
 1320         do_unlock = usbd_ctrl_lock(udev);
 1321 
 1322         uts = udev->scratch.temp_setup;
 1323 
 1324         memset(uts, 0, sizeof(*uts));
 1325 
 1326         uts->usb_speed = udev->speed;
 1327         uts->self_powered = udev->flags.self_powered;
 1328 
 1329         /* first pass */
 1330 
 1331         usb_make_device_desc(uts, tdd);
 1332 
 1333         if (uts->err) {
 1334                 /* some error happened */
 1335                 goto done;
 1336         }
 1337         /* sanity check */
 1338         if (uts->size == 0) {
 1339                 uts->err = USB_ERR_INVAL;
 1340                 goto done;
 1341         }
 1342         /* allocate zeroed memory */
 1343         uts->buf = usbd_alloc_config_desc(udev, uts->size);
 1344         /*
 1345          * Allow malloc() to return NULL regardless of M_WAITOK flag.
 1346          * This helps when porting the software to non-FreeBSD
 1347          * systems.
 1348          */
 1349         if (uts->buf == NULL) {
 1350                 /* could not allocate memory */
 1351                 uts->err = USB_ERR_NOMEM;
 1352                 goto done;
 1353         }
 1354         /* second pass */
 1355 
 1356         uts->size = 0;
 1357 
 1358         usb_make_device_desc(uts, tdd);
 1359 
 1360         /*
 1361          * Store a pointer to our descriptors:
 1362          */
 1363         udev->usb_template_ptr = uts->buf;
 1364 
 1365         if (uts->err) {
 1366                 /* some error happened during second pass */
 1367                 goto done;
 1368         }
 1369         /*
 1370          * Resolve all endpoint addresses !
 1371          */
 1372         buf = usb_temp_get_device_desc(udev);
 1373         uts->err = usb_hw_ep_resolve(udev, buf);
 1374         if (uts->err) {
 1375                 DPRINTFN(0, "Could not resolve endpoints for "
 1376                     "Device Descriptor, error = %s\n",
 1377                     usbd_errstr(uts->err));
 1378                 goto done;
 1379         }
 1380         for (n = 0;; n++) {
 1381                 buf = usb_temp_get_config_desc(udev, NULL, n);
 1382                 if (buf == NULL) {
 1383                         break;
 1384                 }
 1385                 uts->err = usb_hw_ep_resolve(udev, buf);
 1386                 if (uts->err) {
 1387                         DPRINTFN(0, "Could not resolve endpoints for "
 1388                             "Config Descriptor %u, error = %s\n", n,
 1389                             usbd_errstr(uts->err));
 1390                         goto done;
 1391                 }
 1392         }
 1393 done:
 1394         error = uts->err;
 1395         if (error)
 1396                 usb_temp_unsetup(udev);
 1397         if (do_unlock)
 1398                 usbd_ctrl_unlock(udev);
 1399         return (error);
 1400 }
 1401 
 1402 /*------------------------------------------------------------------------*
 1403  *      usb_temp_unsetup
 1404  *
 1405  * This function frees any memory associated with the currently
 1406  * setup template, if any.
 1407  *------------------------------------------------------------------------*/
 1408 void
 1409 usb_temp_unsetup(struct usb_device *udev)
 1410 {
 1411         usbd_free_config_desc(udev, udev->usb_template_ptr);
 1412         udev->usb_template_ptr = NULL;
 1413 }
 1414 
 1415 static usb_error_t
 1416 usb_temp_setup_by_index(struct usb_device *udev, uint16_t index)
 1417 {
 1418         usb_error_t err;
 1419 
 1420         switch (index) {
 1421         case USB_TEMP_MSC:
 1422                 err = usb_temp_setup(udev, &usb_template_msc);
 1423                 break;
 1424         case USB_TEMP_CDCE:
 1425                 err = usb_temp_setup(udev, &usb_template_cdce);
 1426                 break;
 1427         case USB_TEMP_MTP:
 1428                 err = usb_temp_setup(udev, &usb_template_mtp);
 1429                 break;
 1430         case USB_TEMP_MODEM:
 1431                 err = usb_temp_setup(udev, &usb_template_modem);
 1432                 break;
 1433         case USB_TEMP_AUDIO:
 1434                 err = usb_temp_setup(udev, &usb_template_audio);
 1435                 break;
 1436         case USB_TEMP_KBD:
 1437                 err = usb_temp_setup(udev, &usb_template_kbd);
 1438                 break;
 1439         case USB_TEMP_MOUSE:
 1440                 err = usb_temp_setup(udev, &usb_template_mouse);
 1441                 break;
 1442         case USB_TEMP_PHONE:
 1443                 err = usb_temp_setup(udev, &usb_template_phone);
 1444                 break;
 1445         case USB_TEMP_SERIALNET:
 1446                 err = usb_temp_setup(udev, &usb_template_serialnet);
 1447                 break;
 1448         case USB_TEMP_MIDI:
 1449                 err = usb_temp_setup(udev, &usb_template_midi);
 1450                 break;
 1451         case USB_TEMP_MULTI:
 1452                 err = usb_temp_setup(udev, &usb_template_multi);
 1453                 break;
 1454         case USB_TEMP_CDCEEM:
 1455                 err = usb_temp_setup(udev, &usb_template_cdceem);
 1456                 break;
 1457         default:
 1458                 return (USB_ERR_INVAL);
 1459         }
 1460 
 1461         return (err);
 1462 }
 1463 
 1464 static void
 1465 usb_temp_init(void *arg)
 1466 {
 1467         /* register our functions */
 1468         usb_temp_get_desc_p = &usb_temp_get_desc;
 1469         usb_temp_setup_by_index_p = &usb_temp_setup_by_index;
 1470         usb_temp_unsetup_p = &usb_temp_unsetup;
 1471 }
 1472 
 1473 SYSINIT(usb_temp_init, SI_SUB_LOCK, SI_ORDER_FIRST, usb_temp_init, NULL);
 1474 SYSUNINIT(usb_temp_unload, SI_SUB_LOCK, SI_ORDER_ANY, usb_temp_unload, NULL);

Cache object: 975c8dfbe315ac643dca1b4a0bfb50bb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.