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/emulation/ndis/subr_usbd.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2005
    3  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by Bill Paul.
   16  * 4. Neither the name of the author nor the names of any co-contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   30  * THE POSSIBILITY OF SUCH DAMAGE.
   31  *
   32  * $FreeBSD: src/sys/compat/ndis/subr_usbd.c,v 1.6 2009/02/24 18:09:31 rdivacky Exp $
   33  */
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/unistd.h>
   38 #include <sys/types.h>
   39 
   40 #include <sys/kernel.h>
   41 #include <sys/malloc.h>
   42 #include <sys/lock.h>
   43 #include <sys/mutex.h>
   44 #include <sys/module.h>
   45 #include <sys/conf.h>
   46 #include <sys/mbuf.h>
   47 #include <sys/socket.h>
   48 #include <sys/bus.h>
   49 
   50 #include <sys/queue.h>
   51 #include <sys/mplock2.h>
   52 
   53 #include <net/if.h>
   54 #include <net/if_media.h>
   55 #include <netproto/802_11/ieee80211_var.h>
   56 #include <netproto/802_11/ieee80211_ioctl.h>
   57 
   58 #include <bus/usb/usb.h>
   59 #include <bus/usb/usbdi.h>
   60 #include <bus/usb/usbdi_util.h>
   61 #include <bus/usb/usbdivar.h>
   62 #include <bus/usb/usb_quirks.h>
   63 
   64 #include <emulation/ndis/pe_var.h>
   65 #include <emulation/ndis/cfg_var.h>
   66 #include <emulation/ndis/resource_var.h>
   67 #include <emulation/ndis/ntoskrnl_var.h>
   68 #include <emulation/ndis/ndis_var.h>
   69 #include <emulation/ndis/hal_var.h>
   70 #include <emulation/ndis/usbd_var.h>
   71 #include <dev/netif/ndis/if_ndisvar.h>
   72 
   73 static driver_object usbd_driver;
   74 
   75 static int32_t           usbd_func_bulkintr(irp *);
   76 static int32_t           usbd_func_vendorclass(irp *);
   77 static int32_t           usbd_func_selconf(irp *);
   78 static int32_t           usbd_func_abort_pipe(irp *);
   79 static int32_t           usbd_func_getdesc(irp *);
   80 static usbd_status       usbd_get_desc_ndis(usbd_device_handle, int, int, int,
   81                             void *, int *);
   82 static union usbd_urb   *usbd_geturb(irp *);
   83 static usbd_status       usbd_init_ndispipe(irp *, usb_endpoint_descriptor_t *);
   84 static usbd_xfer_handle  usbd_init_ndisxfer(irp *, usb_endpoint_descriptor_t *,
   85                             void *, uint32_t);
   86 static int32_t           usbd_iodispatch(device_object *, irp *);
   87 static int32_t           usbd_ioinvalid(device_object *, irp *);
   88 static int32_t           usbd_pnp(device_object *, irp *);
   89 static int32_t           usbd_power(device_object *, irp *);
   90 static void              usbd_irpcancel(device_object *, irp *);
   91 static void              usbd_irpcancel_cb(void *);
   92 static int32_t           usbd_submit_urb(irp *);
   93 static int32_t           usbd_urb2nt(int32_t);
   94 static void              usbd_xfereof(usbd_xfer_handle, usbd_private_handle,
   95                             usbd_status);
   96 static void              usbd_xferadd(usbd_xfer_handle, usbd_private_handle,
   97                             usbd_status);
   98 static void              usbd_xfertask(device_object *, void *);
   99 static void              dummy(void);
  100 
  101 static union usbd_urb   *USBD_CreateConfigurationRequestEx(
  102                             usb_config_descriptor_t *,
  103                             struct usbd_interface_list_entry *);
  104 static union usbd_urb   *USBD_CreateConfigurationRequest(
  105                             usb_config_descriptor_t *,
  106                             uint16_t *);
  107 static void              USBD_GetUSBDIVersion(usbd_version_info *);
  108 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptorEx(
  109                             usb_config_descriptor_t *, void *, int32_t, int32_t,
  110                             int32_t, int32_t, int32_t);
  111 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptor(
  112                     usb_config_descriptor_t *, uint8_t, uint8_t);
  113 
  114 /*
  115  * We need to wrap these functions because these need `context switch' from
  116  * Windows to UNIX before it's called.
  117  */
  118 static funcptr usbd_iodispatch_wrap;
  119 static funcptr usbd_ioinvalid_wrap;
  120 static funcptr usbd_pnp_wrap;
  121 static funcptr usbd_power_wrap;
  122 static funcptr usbd_irpcancel_wrap;
  123 static funcptr usbd_xfertask_wrap;
  124 
  125 int
  126 usbd_libinit(void)
  127 {
  128         image_patch_table       *patch;
  129         int i;
  130 
  131         patch = usbd_functbl;
  132         while (patch->ipt_func != NULL) {
  133                 windrv_wrap((funcptr)patch->ipt_func,
  134                     (funcptr *)&patch->ipt_wrap,
  135                     patch->ipt_argcnt, patch->ipt_ftype);
  136                 patch++;
  137         }
  138 
  139         windrv_wrap((funcptr)usbd_ioinvalid,
  140             &usbd_ioinvalid_wrap, 2, WINDRV_WRAP_STDCALL);
  141         windrv_wrap((funcptr)usbd_iodispatch,
  142             &usbd_iodispatch_wrap, 2, WINDRV_WRAP_STDCALL);
  143         windrv_wrap((funcptr)usbd_pnp,
  144             &usbd_pnp_wrap, 2, WINDRV_WRAP_STDCALL);
  145         windrv_wrap((funcptr)usbd_power,
  146             &usbd_power_wrap, 2, WINDRV_WRAP_STDCALL);
  147         windrv_wrap((funcptr)usbd_irpcancel,
  148             &usbd_irpcancel_wrap, 2, WINDRV_WRAP_STDCALL);
  149         windrv_wrap((funcptr)usbd_xfertask,
  150             &usbd_xfertask_wrap, 2, WINDRV_WRAP_STDCALL);
  151 
  152         /* Create a fake USB driver instance. */
  153 
  154         windrv_bus_attach(&usbd_driver, "USB Bus");
  155 
  156         /* Set up our dipatch routine. */
  157         for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
  158                 usbd_driver.dro_dispatch[i] =
  159                         (driver_dispatch)usbd_ioinvalid_wrap;
  160 
  161         usbd_driver.dro_dispatch[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
  162             (driver_dispatch)usbd_iodispatch_wrap;
  163         usbd_driver.dro_dispatch[IRP_MJ_DEVICE_CONTROL] =
  164             (driver_dispatch)usbd_iodispatch_wrap;
  165         usbd_driver.dro_dispatch[IRP_MJ_POWER] =
  166             (driver_dispatch)usbd_power_wrap;
  167         usbd_driver.dro_dispatch[IRP_MJ_PNP] =
  168             (driver_dispatch)usbd_pnp_wrap;
  169 
  170         return(0);
  171 }
  172 
  173 int
  174 usbd_libfini(void)
  175 {
  176         image_patch_table       *patch;
  177 
  178         patch = usbd_functbl;
  179         while (patch->ipt_func != NULL) {
  180                 windrv_unwrap(patch->ipt_wrap);
  181                 patch++;
  182         }
  183 
  184         windrv_unwrap(usbd_ioinvalid_wrap);
  185         windrv_unwrap(usbd_iodispatch_wrap);
  186         windrv_unwrap(usbd_pnp_wrap);
  187         windrv_unwrap(usbd_power_wrap);
  188         windrv_unwrap(usbd_irpcancel_wrap);
  189         windrv_unwrap(usbd_xfertask_wrap);
  190 
  191         kfree(usbd_driver.dro_drivername.us_buf, M_DEVBUF);
  192 
  193         return (0);
  194 }
  195 
  196 static int32_t
  197 usbd_iodispatch(device_object *dobj, irp *ip)
  198 {
  199         device_t dev = dobj->do_devext;
  200         int32_t status;
  201         struct io_stack_location *irp_sl;
  202 
  203         irp_sl = IoGetCurrentIrpStackLocation(ip);
  204         switch (irp_sl->isl_parameters.isl_ioctl.isl_iocode) {
  205         case IOCTL_INTERNAL_USB_SUBMIT_URB:
  206                 IRP_NDIS_DEV(ip) = dev;
  207 
  208                 status = usbd_submit_urb(ip);
  209                 break;
  210         default:
  211                 device_printf(dev, "ioctl 0x%x isn't supported\n",
  212                     irp_sl->isl_parameters.isl_ioctl.isl_iocode);
  213                 status = USBD_STATUS_NOT_SUPPORTED;
  214                 break;
  215         }
  216 
  217         if (status == USBD_STATUS_PENDING)
  218                 return (STATUS_PENDING);
  219 
  220         ip->irp_iostat.isb_status = usbd_urb2nt(status);
  221         if (status != USBD_STATUS_SUCCESS)
  222                 ip->irp_iostat.isb_info = 0;
  223         return (ip->irp_iostat.isb_status);
  224 }
  225 
  226 static int32_t
  227 usbd_ioinvalid(device_object *dobj, irp *ip)
  228 {
  229         device_t dev = dobj->do_devext;
  230         struct io_stack_location *irp_sl;
  231 
  232         irp_sl = IoGetCurrentIrpStackLocation(ip);
  233         device_printf(dev, "invalid I/O dispatch %d:%d\n", irp_sl->isl_major,
  234             irp_sl->isl_minor);
  235 
  236         ip->irp_iostat.isb_status = STATUS_FAILURE;
  237         ip->irp_iostat.isb_info = 0;
  238 
  239         IoCompleteRequest(ip, IO_NO_INCREMENT);
  240 
  241         return (STATUS_FAILURE);
  242 }
  243 
  244 static int32_t
  245 usbd_pnp(device_object *dobj, irp *ip)
  246 {
  247         device_t dev = dobj->do_devext;
  248         struct io_stack_location *irp_sl;
  249 
  250         irp_sl = IoGetCurrentIrpStackLocation(ip);
  251         device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
  252             __func__, irp_sl->isl_major, irp_sl->isl_minor);
  253 
  254         ip->irp_iostat.isb_status = STATUS_FAILURE;
  255         ip->irp_iostat.isb_info = 0;
  256 
  257         IoCompleteRequest(ip, IO_NO_INCREMENT);
  258 
  259         return (STATUS_FAILURE);
  260 }
  261 
  262 static int32_t
  263 usbd_power(device_object *dobj, irp *ip)
  264 {
  265         device_t dev = dobj->do_devext;
  266         struct io_stack_location *irp_sl;
  267 
  268         irp_sl = IoGetCurrentIrpStackLocation(ip);
  269         device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
  270             __func__, irp_sl->isl_major, irp_sl->isl_minor);
  271 
  272         ip->irp_iostat.isb_status = STATUS_FAILURE;
  273         ip->irp_iostat.isb_info = 0;
  274 
  275         IoCompleteRequest(ip, IO_NO_INCREMENT);
  276 
  277         return (STATUS_FAILURE);
  278 }
  279 
  280 /* Convert USBD_STATUS to NTSTATUS  */
  281 static int32_t
  282 usbd_urb2nt(int32_t status)
  283 {
  284 
  285         switch (status) {
  286         case USBD_STATUS_SUCCESS:
  287                 return (STATUS_SUCCESS);
  288         case USBD_STATUS_DEVICE_GONE:
  289                 return (STATUS_DEVICE_NOT_CONNECTED);
  290         case USBD_STATUS_PENDING:
  291                 return (STATUS_PENDING);
  292         case USBD_STATUS_NOT_SUPPORTED:
  293                 return (STATUS_NOT_IMPLEMENTED);
  294         case USBD_STATUS_NO_MEMORY:
  295                 return (STATUS_NO_MEMORY);
  296         case USBD_STATUS_REQUEST_FAILED:
  297                 return (STATUS_NOT_SUPPORTED);
  298         case USBD_STATUS_CANCELED:
  299                 return (STATUS_CANCELLED);
  300         default:
  301                 break;
  302         }
  303 
  304         return (STATUS_FAILURE);
  305 }
  306 
  307 /* Convert FreeBSD's usbd_status to USBD_STATUS  */
  308 static int32_t
  309 usbd_usb2urb(int status)
  310 {
  311 
  312         switch (status) {
  313         case USBD_NORMAL_COMPLETION:
  314                 return (USBD_STATUS_SUCCESS);
  315         case USBD_IN_PROGRESS:
  316                 return (USBD_STATUS_PENDING);
  317         case USBD_TIMEOUT:
  318                 return (USBD_STATUS_TIMEOUT);
  319         case USBD_SHORT_XFER:
  320                 return (USBD_STATUS_ERROR_SHORT_TRANSFER);
  321         case USBD_IOERROR:
  322                 return (USBD_STATUS_XACT_ERROR);
  323         case USBD_NOMEM:
  324                 return (USBD_STATUS_NO_MEMORY);
  325         case USBD_INVAL:
  326                 return (USBD_STATUS_REQUEST_FAILED);
  327         case USBD_NOT_STARTED:
  328         case USBD_TOO_DEEP:
  329         case USBD_NO_POWER:
  330                 return (USBD_STATUS_DEVICE_GONE);
  331         case USBD_CANCELLED:
  332                 return (USBD_STATUS_CANCELED);
  333         default:
  334                 break;
  335         }
  336 
  337         return (USBD_STATUS_NOT_SUPPORTED);
  338 }
  339 
  340 static union usbd_urb *
  341 usbd_geturb(irp *ip)
  342 {
  343         struct io_stack_location *irp_sl;
  344 
  345         irp_sl = IoGetCurrentIrpStackLocation(ip);
  346 
  347         return (irp_sl->isl_parameters.isl_others.isl_arg1);
  348 }
  349 
  350 static int32_t
  351 usbd_submit_urb(irp *ip)
  352 {
  353         device_t dev = IRP_NDIS_DEV(ip);
  354         int32_t status;
  355         union usbd_urb *urb;
  356 
  357         urb = usbd_geturb(ip);
  358         /*
  359          * In a case of URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
  360          * USBD_URB_STATUS(urb) would be set at callback functions like
  361          * usbd_intr() or usbd_xfereof().
  362          */
  363         switch (urb->uu_hdr.uuh_func) {
  364         case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
  365                 status = usbd_func_bulkintr(ip);
  366                 if (status != USBD_STATUS_SUCCESS &&
  367                     status != USBD_STATUS_PENDING)
  368                         USBD_URB_STATUS(urb) = status;
  369                 break;
  370         case URB_FUNCTION_VENDOR_DEVICE:
  371         case URB_FUNCTION_VENDOR_INTERFACE:
  372         case URB_FUNCTION_VENDOR_ENDPOINT:
  373         case URB_FUNCTION_VENDOR_OTHER:
  374         case URB_FUNCTION_CLASS_DEVICE:
  375         case URB_FUNCTION_CLASS_INTERFACE:
  376         case URB_FUNCTION_CLASS_ENDPOINT:
  377         case URB_FUNCTION_CLASS_OTHER:
  378                 status = usbd_func_vendorclass(ip);
  379                 USBD_URB_STATUS(urb) = status;
  380                 break;
  381         case URB_FUNCTION_SELECT_CONFIGURATION:
  382                 status = usbd_func_selconf(ip);
  383                 USBD_URB_STATUS(urb) = status;
  384                 break;
  385         case URB_FUNCTION_ABORT_PIPE:
  386                 status = usbd_func_abort_pipe(ip);
  387                 USBD_URB_STATUS(urb) = status;
  388                 break;
  389         case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
  390                 status = usbd_func_getdesc(ip);
  391                 USBD_URB_STATUS(urb) = status;
  392                 break;
  393         default:
  394                 device_printf(dev, "func 0x%x isn't supported\n",
  395                     urb->uu_hdr.uuh_func);
  396                 USBD_URB_STATUS(urb) = status = USBD_STATUS_NOT_SUPPORTED;
  397                 break;
  398         }
  399 
  400         return (status);
  401 }
  402 
  403 static int32_t
  404 usbd_func_getdesc(irp *ip)
  405 {
  406         device_t dev = IRP_NDIS_DEV(ip);
  407         int actlen, i;
  408         struct usb_attach_arg *uaa = device_get_ivars(dev);
  409         struct usbd_urb_control_descriptor_request *ctldesc;
  410         uint32_t len;
  411         union usbd_urb *urb;
  412         usb_config_descriptor_t cd, *cdp;
  413         usbd_status status;
  414 
  415         get_mplock();
  416 
  417         urb = usbd_geturb(ip);
  418         ctldesc = &urb->uu_ctldesc;
  419         if (ctldesc->ucd_desctype == UDESC_CONFIG) {
  420                 /* Get the short config descriptor. */
  421                 status = usbd_get_config_desc(uaa->device, ctldesc->ucd_idx,
  422                     &cd);
  423                 if (status != USBD_NORMAL_COMPLETION) {
  424                         ctldesc->ucd_trans_buflen = 0;
  425                         rel_mplock();
  426                         return usbd_usb2urb(status);
  427                 }
  428                 /* Get the full descriptor.  Try a few times for slow devices. */
  429                 len = MIN(ctldesc->ucd_trans_buflen, UGETW(cd.wTotalLength));
  430                 for (i = 0; i < 3; i++) {
  431                         status = usbd_get_desc_ndis(uaa->device,
  432                             ctldesc->ucd_desctype, ctldesc->ucd_idx,
  433                             len, ctldesc->ucd_trans_buf, &actlen);
  434                         if (status == USBD_NORMAL_COMPLETION)
  435                                 break;
  436                         usbd_delay_ms(uaa->device, 200);
  437                 }
  438                 if (status != USBD_NORMAL_COMPLETION) {
  439                         ctldesc->ucd_trans_buflen = 0;
  440                         rel_mplock();
  441                         return usbd_usb2urb(status);
  442                 }
  443 
  444                 cdp = (usb_config_descriptor_t *)ctldesc->ucd_trans_buf;
  445                 if (cdp->bDescriptorType != UDESC_CONFIG) {
  446                         device_printf(dev, "bad desc %d\n",
  447                             cdp->bDescriptorType);
  448                         status = USBD_INVAL;
  449                 }
  450         } else if (ctldesc->ucd_desctype == UDESC_STRING) {
  451                 /* Try a few times for slow devices.  */
  452                 for (i = 0; i < 3; i++) {
  453                         status = usbd_get_string_desc(uaa->device,
  454                             (UDESC_STRING << 8) + ctldesc->ucd_idx,
  455                             ctldesc->ucd_langid, ctldesc->ucd_trans_buf,
  456                             &actlen);
  457                         if (actlen > ctldesc->ucd_trans_buflen)
  458                                 panic("small string buffer for UDESC_STRING");
  459                         if (status == USBD_NORMAL_COMPLETION)
  460                                 break;
  461                         usbd_delay_ms(uaa->device, 200);
  462                 }
  463         } else
  464                 status = usbd_get_desc_ndis(uaa->device, ctldesc->ucd_desctype,
  465                     ctldesc->ucd_idx, ctldesc->ucd_trans_buflen,
  466                     ctldesc->ucd_trans_buf, &actlen);
  467 
  468         if (status != USBD_NORMAL_COMPLETION) {
  469                 ctldesc->ucd_trans_buflen = 0;
  470                 rel_mplock();
  471                 return usbd_usb2urb(status);
  472         }
  473 
  474         ctldesc->ucd_trans_buflen = actlen;
  475         ip->irp_iostat.isb_info = actlen;
  476 
  477         rel_mplock();
  478 
  479         return (USBD_STATUS_SUCCESS);
  480 }
  481 
  482 /*
  483  * FIXME: at USB1, not USB2, framework, there's no a interface to get `actlen'.
  484  * However, we need it!!!
  485  */
  486 static usbd_status
  487 usbd_get_desc_ndis(usbd_device_handle dev, int type, int index, int len,
  488     void *desc, int *actlen)
  489 {
  490         usb_device_request_t req;
  491 
  492         req.bmRequestType = UT_READ_DEVICE;
  493         req.bRequest = UR_GET_DESCRIPTOR;
  494         USETW2(req.wValue, type, index);
  495         USETW(req.wIndex, 0);
  496         USETW(req.wLength, len);
  497         return usbd_do_request_flags_pipe(dev, dev->default_pipe, &req, desc,
  498             0, actlen, USBD_DEFAULT_TIMEOUT);
  499 }
  500 
  501 static int32_t
  502 usbd_func_selconf(irp *ip)
  503 {
  504         device_t dev = IRP_NDIS_DEV(ip);
  505         int i, j;
  506         struct usb_attach_arg *uaa = device_get_ivars(dev);
  507         struct usbd_interface_information *intf;
  508         struct usbd_pipe_information *pipe;
  509         struct usbd_urb_select_configuration *selconf;
  510         union usbd_urb *urb;
  511         usb_config_descriptor_t *conf;
  512         usb_endpoint_descriptor_t *edesc;
  513         usbd_device_handle udev = uaa->device;
  514         usbd_interface_handle iface;
  515         usbd_status ret;
  516 
  517         urb = usbd_geturb(ip);
  518 
  519         selconf = &urb->uu_selconf;
  520         conf = selconf->usc_conf;
  521         if (conf == NULL) {
  522                 device_printf(dev, "select configuration is NULL\n");
  523                 return usbd_usb2urb(USBD_NORMAL_COMPLETION);
  524         }
  525 
  526         if (conf->bConfigurationValue > NDISUSB_CONFIG_NO)
  527                 device_printf(dev, "warning: config_no is larger than default");
  528 
  529         intf = &selconf->usc_intf;
  530         for (i = 0; i < conf->bNumInterface && intf->uii_len > 0; i++) {
  531                 ret = usbd_device2interface_handle(uaa->device,
  532                     intf->uii_intfnum, &iface);
  533                 if (ret != USBD_NORMAL_COMPLETION) {
  534                         device_printf(dev,
  535                             "getting interface handle failed: %s\n",
  536                             usbd_errstr(ret));
  537                         return usbd_usb2urb(ret);
  538                 }
  539 
  540                 ret = usbd_set_interface(iface, intf->uii_altset);
  541                 if (ret != USBD_NORMAL_COMPLETION && ret != USBD_IN_USE) {
  542                         device_printf(dev,
  543                             "setting alternate interface failed: %s\n",
  544                             usbd_errstr(ret));
  545                         return usbd_usb2urb(ret);
  546                 }
  547 
  548                 for (j = 0; j < iface->idesc->bNumEndpoints; j++) {
  549                         if (j >= intf->uii_numeps) {
  550                                 device_printf(dev,
  551                                     "endpoint %d and above are ignored",
  552                                     intf->uii_numeps);
  553                                 break;
  554                         }
  555                         edesc = iface->endpoints[j].edesc;
  556                         pipe = &intf->uii_pipes[j];
  557                         pipe->upi_handle = edesc;
  558                         pipe->upi_epaddr = edesc->bEndpointAddress;
  559                         pipe->upi_maxpktsize = UGETW(edesc->wMaxPacketSize);
  560                         pipe->upi_type = UE_GET_XFERTYPE(edesc->bmAttributes);
  561                         if (pipe->upi_type != UE_INTERRUPT)
  562                                 continue;
  563 
  564                         /* XXX we're following linux USB's interval policy.  */
  565                         if (udev->speed == USB_SPEED_LOW)
  566                                 pipe->upi_interval = edesc->bInterval + 5;
  567                         else if (udev->speed == USB_SPEED_FULL)
  568                                 pipe->upi_interval = edesc->bInterval;
  569                         else {
  570                                 int k0 = 0, k1 = 1;
  571                                 do {
  572                                         k1 = k1 * 2;
  573                                         k0 = k0 + 1;
  574                                 } while (k1 < edesc->bInterval);
  575                                 pipe->upi_interval = k0;
  576                         }
  577                 }
  578 
  579                 intf = (struct usbd_interface_information *)(((char *)intf) +
  580                     intf->uii_len);
  581         }
  582 
  583         return (USBD_STATUS_SUCCESS);
  584 }
  585 
  586 static int32_t
  587 usbd_func_abort_pipe(irp *ip)
  588 {
  589         device_t dev = IRP_NDIS_DEV(ip);
  590         struct ndis_softc *sc = device_get_softc(dev);
  591         union usbd_urb *urb;
  592         struct usbd_urb_bulk_or_intr_transfer *ubi;
  593         usb_endpoint_descriptor_t *ep;
  594         uint8_t irql;
  595         usbd_status status;
  596 
  597         urb = usbd_geturb(ip);
  598         ubi = &urb->uu_bulkintr;
  599         ep = ubi->ubi_epdesc;
  600         if (ep == NULL)
  601                 return (USBD_STATUS_INVALID_PIPE_HANDLE);
  602 
  603         KeRaiseIrql(DISPATCH_LEVEL, &irql);
  604         status = usbd_abort_pipe(sc->ndisusb_ep[NDISUSB_ENDPT_BIN]);
  605         if (status != USBD_NORMAL_COMPLETION)
  606                 device_printf(dev, "can't be canceld");
  607         KeLowerIrql(irql);
  608 
  609         return (USBD_STATUS_SUCCESS);
  610 }
  611 
  612 static int32_t
  613 usbd_func_vendorclass(irp *ip)
  614 {
  615         device_t dev = IRP_NDIS_DEV(ip);
  616         struct usb_attach_arg *uaa = device_get_ivars(dev);
  617         struct usbd_urb_vendor_or_class_request *vcreq;
  618         uint8_t type = 0;
  619         union usbd_urb *urb;
  620         usb_device_request_t req;
  621         usbd_status status;
  622 
  623         urb = usbd_geturb(ip);
  624         vcreq = &urb->uu_vcreq;
  625 
  626         switch (urb->uu_hdr.uuh_func) {
  627         case URB_FUNCTION_CLASS_DEVICE:
  628                 type = UT_CLASS | UT_DEVICE;
  629                 break;
  630         case URB_FUNCTION_CLASS_INTERFACE:
  631                 type = UT_CLASS | UT_INTERFACE;
  632                 break;
  633         case URB_FUNCTION_CLASS_OTHER:
  634                 type = UT_CLASS | UT_OTHER;
  635                 break;
  636         case URB_FUNCTION_CLASS_ENDPOINT:
  637                 type = UT_CLASS | UT_ENDPOINT;
  638                 break;
  639         case URB_FUNCTION_VENDOR_DEVICE:
  640                 type = UT_VENDOR | UT_DEVICE;
  641                 break;
  642         case URB_FUNCTION_VENDOR_INTERFACE:
  643                 type = UT_VENDOR | UT_INTERFACE;
  644                 break;
  645         case URB_FUNCTION_VENDOR_OTHER:
  646                 type = UT_VENDOR | UT_OTHER;
  647                 break;
  648         case URB_FUNCTION_VENDOR_ENDPOINT:
  649                 type = UT_VENDOR | UT_ENDPOINT;
  650                 break;
  651         default:
  652                 /* never reach.  */
  653                 break;
  654         }
  655 
  656         type |= (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ?
  657             UT_READ : UT_WRITE;
  658         type |= vcreq->uvc_reserved1;
  659 
  660         req.bmRequestType = type;
  661         req.bRequest = vcreq->uvc_req;
  662         USETW(req.wIndex, vcreq->uvc_idx);
  663         USETW(req.wValue, vcreq->uvc_value);
  664         USETW(req.wLength, vcreq->uvc_trans_buflen);
  665 
  666         if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
  667                 get_mplock();
  668                 status = usbd_do_request(uaa->device, &req,
  669                     vcreq->uvc_trans_buf);
  670                 rel_mplock();
  671         } else
  672                 status = usbd_do_request_async(uaa->device, &req,
  673                     vcreq->uvc_trans_buf);
  674 
  675         return usbd_usb2urb(status);
  676 }
  677 
  678 static usbd_status
  679 usbd_init_ndispipe(irp *ip, usb_endpoint_descriptor_t *ep)
  680 {
  681         device_t dev = IRP_NDIS_DEV(ip);
  682         struct ndis_softc *sc = device_get_softc(dev);
  683         struct usb_attach_arg *uaa = device_get_ivars(dev);
  684         usbd_interface_handle iface;
  685         usbd_status status;
  686 
  687         status = usbd_device2interface_handle(uaa->device, NDISUSB_IFACE_INDEX,
  688             &iface);
  689         if (status != USBD_NORMAL_COMPLETION) {
  690                 device_printf(dev, "could not get interface handle\n");
  691                 return (status);
  692         }
  693 
  694         switch (UE_GET_XFERTYPE(ep->bmAttributes)) {
  695         case UE_BULK:
  696                 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) {
  697                         /* RX (bulk IN)  */
  698                         if (sc->ndisusb_ep[NDISUSB_ENDPT_BIN] != NULL)
  699                                 return (USBD_NORMAL_COMPLETION);
  700 
  701                         status = usbd_open_pipe(iface, ep->bEndpointAddress,
  702                             USBD_EXCLUSIVE_USE,
  703                             &sc->ndisusb_ep[NDISUSB_ENDPT_BIN]);
  704                         break;
  705                 }
  706 
  707                 /* TX (bulk OUT)  */
  708                 if (sc->ndisusb_ep[NDISUSB_ENDPT_BOUT] != NULL)
  709                         return (USBD_NORMAL_COMPLETION);
  710 
  711                 status = usbd_open_pipe(iface, ep->bEndpointAddress,
  712                     USBD_EXCLUSIVE_USE, &sc->ndisusb_ep[NDISUSB_ENDPT_BOUT]);
  713                 break;
  714         case UE_INTERRUPT:
  715                 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) {
  716                         /* Interrupt IN.  */
  717                         if (sc->ndisusb_ep[NDISUSB_ENDPT_IIN] != NULL)
  718                                 return (USBD_NORMAL_COMPLETION);
  719 
  720                         status = usbd_open_pipe(iface, ep->bEndpointAddress,
  721                             USBD_EXCLUSIVE_USE,
  722                             &sc->ndisusb_ep[NDISUSB_ENDPT_IIN]);
  723                         break;
  724                 }
  725 
  726                 /* Interrupt OUT.  */
  727                 if (sc->ndisusb_ep[NDISUSB_ENDPT_IOUT] != NULL)
  728                         return (USBD_NORMAL_COMPLETION);
  729 
  730                 status = usbd_open_pipe(iface, ep->bEndpointAddress,
  731                     USBD_EXCLUSIVE_USE, &sc->ndisusb_ep[NDISUSB_ENDPT_IOUT]);
  732                 break;
  733         default:
  734                 device_printf(dev, "can't handle xfertype 0x%x\n",
  735                     UE_GET_XFERTYPE(ep->bmAttributes));
  736                 return (USBD_INVAL);
  737         }
  738 
  739         if (status != USBD_NORMAL_COMPLETION)
  740                 device_printf(dev,  "open pipe failed: (0x%x) %s\n",
  741                     ep->bEndpointAddress, usbd_errstr(status));
  742 
  743         return (status);
  744 }
  745 
  746 static void
  747 usbd_irpcancel_cb(void *priv)
  748 {
  749         struct ndisusb_cancel *nc = priv;
  750         struct ndis_softc *sc = device_get_softc(nc->dev);
  751         usbd_status status;
  752         usbd_xfer_handle xfer = nc->xfer;
  753 
  754         if (sc->ndisusb_status & NDISUSB_STATUS_DETACH)
  755                 goto exit;
  756 
  757         status = usbd_abort_pipe(xfer->pipe);
  758         if (status != USBD_NORMAL_COMPLETION)
  759                 device_printf(nc->dev, "can't be canceld");
  760 exit:
  761         kfree(nc, M_USBDEV);
  762 }
  763 
  764 static void
  765 usbd_irpcancel(device_object *dobj, irp *ip)
  766 {
  767         device_t dev = IRP_NDIS_DEV(ip);
  768         struct ndisusb_cancel *nc;
  769         struct usb_attach_arg *uaa = device_get_ivars(dev);
  770 
  771         if (IRP_NDISUSB_XFER(ip) == NULL) {
  772                 ip->irp_cancel = TRUE;
  773                 IoReleaseCancelSpinLock(ip->irp_cancelirql);
  774                 return;
  775         }
  776 
  777         /*
  778          * XXX Since we're under DISPATCH_LEVEL during calling usbd_irpcancel(),
  779          * we can't sleep at all.  However, currently FreeBSD's USB stack
  780          * requires a sleep to abort a transfer.  It's inevitable! so it causes
  781          * serveral fatal problems (e.g. kernel hangups or crashes).  I think
  782          * that there are no ways to make this reliable.  In this implementation,
  783          * I used usb_add_task() but it's not a perfect method to solve this
  784          * because of as follows: NDIS drivers would expect that IRP's
  785          * completely canceld when usbd_irpcancel() is returned but we need
  786          * a sleep to do it.  During canceling XFERs, usbd_intr() would be
  787          * called with a status, USBD_CANCELLED.
  788          */
  789         nc = kmalloc(sizeof(struct ndisusb_cancel), M_USBDEV, M_NOWAIT | M_ZERO);
  790         if (nc == NULL) {
  791                 ip->irp_cancel = FALSE;
  792                 IoReleaseCancelSpinLock(ip->irp_cancelirql);
  793                 return;
  794         }
  795 
  796         nc->dev = dev;
  797         nc->xfer = IRP_NDISUSB_XFER(ip);
  798         usb_init_task(&nc->task, usbd_irpcancel_cb, nc);
  799 
  800         IRP_NDISUSB_XFER(ip) = NULL;
  801         usb_add_task(uaa->device, &nc->task, USB_TASKQ_DRIVER);
  802 
  803         ip->irp_cancel = TRUE;
  804         IoReleaseCancelSpinLock(ip->irp_cancelirql);
  805 }
  806 
  807 static usbd_xfer_handle
  808 usbd_init_ndisxfer(irp *ip, usb_endpoint_descriptor_t *ep, void *buf,
  809     uint32_t buflen)
  810 {
  811         device_t dev = IRP_NDIS_DEV(ip);
  812         struct usb_attach_arg *uaa = device_get_ivars(dev);
  813         usbd_xfer_handle xfer;
  814 
  815         xfer = usbd_alloc_xfer(uaa->device);
  816         if (xfer == NULL)
  817                 return (NULL);
  818 
  819         if (buf != NULL && MmIsAddressValid(buf) == FALSE && buflen > 0) {
  820                 xfer->buffer = usbd_alloc_buffer(xfer, buflen);
  821                 if (xfer->buffer == NULL)
  822                         return (NULL);
  823 
  824                 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_OUT)
  825                         memcpy(xfer->buffer, buf, buflen);
  826         } else
  827                 xfer->buffer = buf;
  828 
  829         xfer->length = buflen;
  830 
  831         IoAcquireCancelSpinLock(&ip->irp_cancelirql);
  832         IRP_NDISUSB_XFER(ip) = xfer;
  833         ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap;
  834         IoReleaseCancelSpinLock(ip->irp_cancelirql);
  835 
  836         return (xfer);
  837 }
  838 
  839 static void
  840 usbd_xferadd(usbd_xfer_handle xfer, usbd_private_handle priv,
  841     usbd_status status)
  842 {
  843         irp *ip = priv;
  844         device_t dev = IRP_NDIS_DEV(ip);
  845         struct ndis_softc *sc = device_get_softc(dev);
  846         struct ndisusb_xfer *nx;
  847         uint8_t irql;
  848 
  849         nx = kmalloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO);
  850         if (nx == NULL) {
  851                 device_printf(dev, "out of memory");
  852                 return;
  853         }
  854         nx->nx_xfer = xfer;
  855         nx->nx_priv = priv;
  856         nx->nx_status = status;
  857 
  858         KeAcquireSpinLock(&sc->ndisusb_xferlock, &irql);
  859         InsertTailList((&sc->ndisusb_xferlist), (&nx->nx_xferlist));
  860         KeReleaseSpinLock(&sc->ndisusb_xferlock, irql);
  861 
  862         IoQueueWorkItem(sc->ndisusb_xferitem,
  863             (io_workitem_func)usbd_xfertask_wrap, WORKQUEUE_CRITICAL, sc);
  864 }
  865 
  866 static void
  867 usbd_xfereof(usbd_xfer_handle xfer, usbd_private_handle priv,
  868     usbd_status status)
  869 {
  870 
  871         usbd_xferadd(xfer, priv, status);
  872 }
  873 
  874 static void
  875 usbd_xfertask(device_object *dobj, void *arg)
  876 {
  877         int error;
  878         irp *ip;
  879         device_t dev;
  880         list_entry *l;
  881         struct ndis_softc *sc = arg;
  882         struct ndisusb_xfer *nx;
  883         struct usbd_urb_bulk_or_intr_transfer *ubi;
  884         uint8_t irql;
  885         union usbd_urb *urb;
  886         usbd_private_handle priv;
  887         usbd_status status;
  888         usbd_xfer_handle xfer;
  889 
  890         dev = sc->ndis_dev;
  891 
  892         if (IsListEmpty(&sc->ndisusb_xferlist))
  893                 return;
  894 
  895         KeAcquireSpinLock(&sc->ndisusb_xferlock, &irql);
  896         l = sc->ndisusb_xferlist.nle_flink;
  897         while (l != &sc->ndisusb_xferlist) {
  898                 nx = CONTAINING_RECORD(l, struct ndisusb_xfer, nx_xferlist);
  899                 xfer = nx->nx_xfer;
  900                 priv = nx->nx_priv;
  901                 status = nx->nx_status;
  902                 error = 0;
  903                 ip = priv;
  904 
  905                 if (status != USBD_NORMAL_COMPLETION) {
  906                         if (status == USBD_NOT_STARTED) {
  907                                 error = 1;
  908                                 goto next;
  909                         }
  910                         if (status == USBD_STALLED)
  911                                 usbd_clear_endpoint_stall_async(xfer->pipe);
  912                         /*
  913                          * NB: just for notice.  We must handle error cases also
  914                          * because if we just return without notifying to the
  915                          * NDIS driver the driver never knows about that there
  916                          * was a error.  This can cause a lot of problems like
  917                          * system hangs.
  918                          */
  919                         device_printf(dev, "usb xfer warning (%s)\n",
  920                             usbd_errstr(status));
  921                 }
  922 
  923                 urb = usbd_geturb(ip);
  924 
  925                 KASSERT(urb->uu_hdr.uuh_func ==
  926                     URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
  927                     ("function(%d) isn't for bulk or interrupt",
  928                         urb->uu_hdr.uuh_func));
  929 
  930                 IoAcquireCancelSpinLock(&ip->irp_cancelirql);
  931 
  932                 ip->irp_cancelfunc = NULL;
  933                 IRP_NDISUSB_XFER(ip) = NULL;
  934 
  935                 switch (status) {
  936                 case USBD_NORMAL_COMPLETION:
  937                         ubi = &urb->uu_bulkintr;
  938                         ubi->ubi_trans_buflen = xfer->actlen;
  939                         if (ubi->ubi_trans_flags & USBD_TRANSFER_DIRECTION_IN)
  940                                 memcpy(ubi->ubi_trans_buf, xfer->buffer,
  941                                     xfer->actlen);
  942 
  943                         ip->irp_iostat.isb_info = xfer->actlen;
  944                         ip->irp_iostat.isb_status = STATUS_SUCCESS;
  945                         USBD_URB_STATUS(urb) = USBD_STATUS_SUCCESS;
  946                         break;
  947                 case USBD_CANCELLED:
  948                         ip->irp_iostat.isb_info = 0;
  949                         ip->irp_iostat.isb_status = STATUS_CANCELLED;
  950                         USBD_URB_STATUS(urb) = USBD_STATUS_CANCELED;
  951                         break;
  952                 default:
  953                         ip->irp_iostat.isb_info = 0;
  954                         USBD_URB_STATUS(urb) = usbd_usb2urb(status);
  955                         ip->irp_iostat.isb_status =
  956                             usbd_urb2nt(USBD_URB_STATUS(urb));
  957                         break;
  958                 }
  959 
  960                 IoReleaseCancelSpinLock(ip->irp_cancelirql);
  961 next:
  962                 l = l->nle_flink;
  963                 RemoveEntryList(&nx->nx_xferlist);
  964                 usbd_free_xfer(nx->nx_xfer);
  965                 kfree(nx, M_USBDEV);
  966                 if (error)
  967                         continue;
  968                 /* NB: call after cleaning  */
  969                 IoCompleteRequest(ip, IO_NO_INCREMENT);
  970         }
  971         KeReleaseSpinLock(&sc->ndisusb_xferlock, irql);
  972 }
  973 
  974 static int32_t
  975 usbd_func_bulkintr(irp *ip)
  976 {
  977         device_t dev = IRP_NDIS_DEV(ip);
  978         struct ndis_softc *sc = device_get_softc(dev);
  979         struct usbd_urb_bulk_or_intr_transfer *ubi;
  980         union usbd_urb *urb;
  981         usb_endpoint_descriptor_t *ep;
  982         usbd_status status;
  983         usbd_xfer_handle xfer;
  984 
  985         urb = usbd_geturb(ip);
  986         ubi = &urb->uu_bulkintr;
  987         ep = ubi->ubi_epdesc;
  988         if (ep == NULL)
  989                 return (USBD_STATUS_INVALID_PIPE_HANDLE);
  990 
  991         status = usbd_init_ndispipe(ip, ep);
  992         if (status != USBD_NORMAL_COMPLETION)
  993                 return usbd_usb2urb(status);
  994 
  995         xfer = usbd_init_ndisxfer(ip, ep, ubi->ubi_trans_buf,
  996             ubi->ubi_trans_buflen);
  997         if (xfer == NULL) {
  998                 device_printf(IRP_NDIS_DEV(ip), "can't allocate xfer\n");
  999                 return (USBD_STATUS_NO_MEMORY);
 1000         }
 1001 
 1002         if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) {
 1003                 xfer->flags |= USBD_SHORT_XFER_OK;
 1004                 if (!(ubi->ubi_trans_flags & USBD_SHORT_TRANSFER_OK))
 1005                         xfer->flags &= ~USBD_SHORT_XFER_OK;
 1006         }
 1007 
 1008         if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_BULK) {
 1009                 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
 1010                         /* RX (bulk IN)  */
 1011                         usbd_setup_xfer(xfer, sc->ndisusb_ep[NDISUSB_ENDPT_BIN],
 1012                             ip, xfer->buffer, xfer->length, xfer->flags,
 1013                             USBD_NO_TIMEOUT, usbd_xfereof);
 1014                 else {
 1015                         /* TX (bulk OUT)  */
 1016                         xfer->flags |= USBD_NO_COPY;
 1017 
 1018                         usbd_setup_xfer(xfer, sc->ndisusb_ep[NDISUSB_ENDPT_BOUT],
 1019                             ip, xfer->buffer, xfer->length, xfer->flags,
 1020                             NDISUSB_TX_TIMEOUT, usbd_xfereof);
 1021                 }
 1022         } else {
 1023                 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
 1024                         /* Interrupt IN  */
 1025                         usbd_setup_xfer(xfer, sc->ndisusb_ep[NDISUSB_ENDPT_IIN],
 1026                             ip, xfer->buffer, xfer->length, xfer->flags,
 1027                             USBD_NO_TIMEOUT, usbd_xfereof);
 1028                 else
 1029                         /* Interrupt OUT  */
 1030                         usbd_setup_xfer(xfer, sc->ndisusb_ep[NDISUSB_ENDPT_IOUT],
 1031                             ip, xfer->buffer, xfer->length, xfer->flags,
 1032                             NDISUSB_INTR_TIMEOUT, usbd_xfereof);
 1033         }
 1034 
 1035         /* we've done to setup xfer.  Let's transfer it.  */
 1036         ip->irp_iostat.isb_status = STATUS_PENDING;
 1037         ip->irp_iostat.isb_info = 0;
 1038         USBD_URB_STATUS(urb) = USBD_STATUS_PENDING;
 1039         IoMarkIrpPending(ip);
 1040 
 1041         status = usbd_transfer(xfer);
 1042         if (status == USBD_IN_PROGRESS)
 1043                 return (USBD_STATUS_PENDING);
 1044 
 1045         usbd_free_xfer(xfer);
 1046         IRP_NDISUSB_XFER(ip) = NULL;
 1047         IoUnmarkIrpPending(ip);
 1048         USBD_URB_STATUS(urb) = usbd_usb2urb(status);
 1049 
 1050         return USBD_URB_STATUS(urb);
 1051 }
 1052 
 1053 static union usbd_urb *
 1054 USBD_CreateConfigurationRequest(usb_config_descriptor_t *conf, uint16_t *len)
 1055 {
 1056         struct usbd_interface_list_entry list[2];
 1057         union usbd_urb *urb;
 1058 
 1059         bzero(list, sizeof(struct usbd_interface_list_entry) * 2);
 1060         list[0].uil_intfdesc = USBD_ParseConfigurationDescriptorEx(conf, conf,
 1061             -1, -1, -1, -1, -1);
 1062         urb = USBD_CreateConfigurationRequestEx(conf, list);
 1063         if (urb == NULL)
 1064                 return (NULL);
 1065 
 1066         *len = urb->uu_selconf.usc_hdr.uuh_len;
 1067         return (urb);
 1068 }
 1069 
 1070 static union usbd_urb *
 1071 USBD_CreateConfigurationRequestEx(usb_config_descriptor_t *conf,
 1072     struct usbd_interface_list_entry *list)
 1073 {
 1074         int i, j, size;
 1075         struct usbd_interface_information *intf;
 1076         struct usbd_pipe_information *pipe;
 1077         struct usbd_urb_select_configuration *selconf;
 1078         usb_interface_descriptor_t *desc;
 1079 
 1080         for (i = 0, size = 0; i < conf->bNumInterface; i++) {
 1081                 j = list[i].uil_intfdesc->bNumEndpoints;
 1082                 size = size + sizeof(struct usbd_interface_information) +
 1083                     sizeof(struct usbd_pipe_information) * (j - 1);
 1084         }
 1085         size += sizeof(struct usbd_urb_select_configuration) -
 1086             sizeof(struct usbd_interface_information);
 1087 
 1088         selconf = ExAllocatePoolWithTag(NonPagedPool, size, 0);
 1089         if (selconf == NULL)
 1090                 return (NULL);
 1091         selconf->usc_hdr.uuh_func = URB_FUNCTION_SELECT_CONFIGURATION;
 1092         selconf->usc_hdr.uuh_len = size;
 1093         selconf->usc_handle = conf;
 1094         selconf->usc_conf = conf;
 1095 
 1096         intf = &selconf->usc_intf;
 1097         for (i = 0; i < conf->bNumInterface; i++) {
 1098                 if (list[i].uil_intfdesc == NULL)
 1099                         break;
 1100 
 1101                 list[i].uil_intf = intf;
 1102                 desc = list[i].uil_intfdesc;
 1103 
 1104                 intf->uii_len = sizeof(struct usbd_interface_information) +
 1105                     (desc->bNumEndpoints - 1) *
 1106                     sizeof(struct usbd_pipe_information);
 1107                 intf->uii_intfnum = desc->bInterfaceNumber;
 1108                 intf->uii_altset = desc->bAlternateSetting;
 1109                 intf->uii_intfclass = desc->bInterfaceClass;
 1110                 intf->uii_intfsubclass = desc->bInterfaceSubClass;
 1111                 intf->uii_intfproto = desc->bInterfaceProtocol;
 1112                 intf->uii_handle = desc;
 1113                 intf->uii_numeps = desc->bNumEndpoints;
 1114 
 1115                 pipe = &intf->uii_pipes[0];
 1116                 for (j = 0; j < intf->uii_numeps; j++)
 1117                         pipe[j].upi_maxtxsize =
 1118                             USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
 1119 
 1120                 intf = (struct usbd_interface_information *)((char *)intf +
 1121                     intf->uii_len);
 1122         }
 1123 
 1124         return ((union usbd_urb *)selconf);
 1125 }
 1126 
 1127 static void
 1128 USBD_GetUSBDIVersion(usbd_version_info *ui)
 1129 {
 1130 
 1131         /* Pretend to be Windows XP. */
 1132 
 1133         ui->uvi_usbdi_vers = USBDI_VERSION;
 1134         ui->uvi_supported_vers = USB_VER_2_0;
 1135 }
 1136 
 1137 static usb_interface_descriptor_t *
 1138 USBD_ParseConfigurationDescriptor(usb_config_descriptor_t *conf,
 1139         uint8_t intfnum, uint8_t altset)
 1140 {
 1141 
 1142         return USBD_ParseConfigurationDescriptorEx(conf, conf, intfnum, altset,
 1143             -1, -1, -1);
 1144 }
 1145 
 1146 static usb_interface_descriptor_t *
 1147 USBD_ParseConfigurationDescriptorEx(usb_config_descriptor_t *conf,
 1148     void *start, int32_t intfnum, int32_t altset, int32_t intfclass,
 1149     int32_t intfsubclass, int32_t intfproto)
 1150 {
 1151         char *pos;
 1152         usb_interface_descriptor_t *desc;
 1153 
 1154         for (pos = start; pos < ((char *)conf + UGETW(conf->wTotalLength));
 1155              pos += desc->bLength) {
 1156                 desc = (usb_interface_descriptor_t *)pos;
 1157                 if (desc->bDescriptorType != UDESC_INTERFACE)
 1158                         continue;
 1159                 if (!(intfnum == -1 || desc->bInterfaceNumber == intfnum))
 1160                         continue;
 1161                 if (!(altset == -1 || desc->bAlternateSetting == altset))
 1162                         continue;
 1163                 if (!(intfclass == -1 || desc->bInterfaceClass == intfclass))
 1164                         continue;
 1165                 if (!(intfsubclass == -1 ||
 1166                     desc->bInterfaceSubClass == intfsubclass))
 1167                         continue;
 1168                 if (!(intfproto == -1 || desc->bInterfaceProtocol == intfproto))
 1169                         continue;
 1170                 return (desc);
 1171         }
 1172 
 1173         return (NULL);
 1174 }
 1175 
 1176 static void
 1177 dummy(void)
 1178 {
 1179         kprintf("USBD dummy called\n");
 1180 }
 1181 
 1182 image_patch_table usbd_functbl[] = {
 1183         IMPORT_SFUNC(USBD_CreateConfigurationRequest, 2),
 1184         IMPORT_SFUNC(USBD_CreateConfigurationRequestEx, 2),
 1185         IMPORT_SFUNC_MAP(_USBD_CreateConfigurationRequestEx@8,
 1186             USBD_CreateConfigurationRequestEx, 2),
 1187         IMPORT_SFUNC(USBD_GetUSBDIVersion, 1),
 1188         IMPORT_SFUNC(USBD_ParseConfigurationDescriptor, 3),
 1189         IMPORT_SFUNC(USBD_ParseConfigurationDescriptorEx, 7),
 1190         IMPORT_SFUNC_MAP(_USBD_ParseConfigurationDescriptorEx@28,
 1191             USBD_ParseConfigurationDescriptorEx, 7),
 1192 
 1193         /*
 1194          * This last entry is a catch-all for any function we haven't
 1195          * implemented yet. The PE import list patching routine will
 1196          * use it for any function that doesn't have an explicit match
 1197          * in this table.
 1198          */
 1199 
 1200         { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL },
 1201 
 1202         /* End of list. */
 1203 
 1204         { NULL, NULL, NULL }
 1205 };
 1206 
 1207 MODULE_DEPEND(ndis, usb, 1, 1, 1);

Cache object: 4c5b7271b4615df65d761ef59b95b607


[ 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.