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/compat/ndis/subr_usbd.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 /*-
    2  * SPDX-License-Identifier: BSD-4-Clause
    3  *
    4  * Copyright (c) 2005
    5  *      Bill Paul <wpaul@windriver.com>.  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  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Bill Paul.
   18  * 4. Neither the name of the author nor the names of any co-contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
   26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   32  * THE POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD: releng/12.0/sys/compat/ndis/subr_usbd.c 325966 2017-11-18 14:26:50Z pfg $");
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/unistd.h>
   41 #include <sys/types.h>
   42 
   43 #include <sys/kernel.h>
   44 #include <sys/malloc.h>
   45 #include <sys/lock.h>
   46 #include <sys/mutex.h>
   47 #include <sys/sx.h>
   48 #include <sys/condvar.h>
   49 #include <sys/module.h>
   50 #include <sys/conf.h>
   51 #include <sys/mbuf.h>
   52 #include <sys/socket.h>
   53 #include <machine/bus.h>
   54 #include <sys/bus.h>
   55 
   56 #include <sys/queue.h>
   57 
   58 #include <net/if.h>
   59 #include <net/if_var.h>
   60 #include <net/if_media.h>
   61 #include <net/ethernet.h>
   62 #include <net80211/ieee80211_var.h>
   63 #include <net80211/ieee80211_ioctl.h>
   64 
   65 #include <dev/usb/usb.h>
   66 #include <dev/usb/usbdi.h>
   67 #include <dev/usb/usbdi_util.h>
   68 #include <dev/usb/usb_busdma.h>
   69 #include <dev/usb/usb_device.h>
   70 #include <dev/usb/usb_request.h>
   71 
   72 #include <compat/ndis/pe_var.h>
   73 #include <compat/ndis/cfg_var.h>
   74 #include <compat/ndis/resource_var.h>
   75 #include <compat/ndis/ntoskrnl_var.h>
   76 #include <compat/ndis/ndis_var.h>
   77 #include <compat/ndis/hal_var.h>
   78 #include <compat/ndis/usbd_var.h>
   79 #include <dev/if_ndis/if_ndisvar.h>
   80 
   81 static driver_object usbd_driver;
   82 static usb_callback_t usbd_non_isoc_callback;
   83 static usb_callback_t usbd_ctrl_callback;
   84 
   85 #define USBD_CTRL_READ_PIPE             0
   86 #define USBD_CTRL_WRITE_PIPE            1
   87 #define USBD_CTRL_MAX_PIPE              2
   88 #define USBD_CTRL_READ_BUFFER_SP        256
   89 #define USBD_CTRL_WRITE_BUFFER_SP       256
   90 #define USBD_CTRL_READ_BUFFER_SIZE      \
   91         (sizeof(struct usb_device_request) + USBD_CTRL_READ_BUFFER_SP)
   92 #define USBD_CTRL_WRITE_BUFFER_SIZE     \
   93         (sizeof(struct usb_device_request) + USBD_CTRL_WRITE_BUFFER_SP)
   94 static struct usb_config usbd_default_epconfig[USBD_CTRL_MAX_PIPE] = {
   95         [USBD_CTRL_READ_PIPE] = {
   96                 .type =         UE_CONTROL,
   97                 .endpoint =     0x00,   /* control pipe */
   98                 .direction =    UE_DIR_ANY,
   99                 .if_index =     0,
  100                 .bufsize =      USBD_CTRL_READ_BUFFER_SIZE,
  101                 .flags =        { .short_xfer_ok = 1, },
  102                 .callback =     &usbd_ctrl_callback,
  103                 .timeout =      5000,   /* 5 seconds */
  104         },
  105         [USBD_CTRL_WRITE_PIPE] = {
  106                 .type =         UE_CONTROL,
  107                 .endpoint =     0x00,   /* control pipe */
  108                 .direction =    UE_DIR_ANY,
  109                 .if_index =     0,
  110                 .bufsize =      USBD_CTRL_WRITE_BUFFER_SIZE,
  111                 .flags =        { .proxy_buffer = 1, },
  112                 .callback =     &usbd_ctrl_callback,
  113                 .timeout =      5000,   /* 5 seconds */
  114         }
  115 };
  116 
  117 static int32_t           usbd_func_bulkintr(irp *);
  118 static int32_t           usbd_func_vendorclass(irp *);
  119 static int32_t           usbd_func_selconf(irp *);
  120 static int32_t           usbd_func_abort_pipe(irp *);
  121 static usb_error_t       usbd_setup_endpoint(irp *, uint8_t,
  122                             struct usb_endpoint_descriptor      *);
  123 static usb_error_t       usbd_setup_endpoint_default(irp *, uint8_t);
  124 static usb_error_t       usbd_setup_endpoint_one(irp *, uint8_t,
  125                             struct ndisusb_ep *, struct usb_config *);
  126 static int32_t           usbd_func_getdesc(irp *);
  127 static union usbd_urb   *usbd_geturb(irp *);
  128 static struct ndisusb_ep*usbd_get_ndisep(irp *, usb_endpoint_descriptor_t *);
  129 static int32_t           usbd_iodispatch(device_object *, irp *);
  130 static int32_t           usbd_ioinvalid(device_object *, irp *);
  131 static int32_t           usbd_pnp(device_object *, irp *);
  132 static int32_t           usbd_power(device_object *, irp *);
  133 static void              usbd_irpcancel(device_object *, irp *);
  134 static int32_t           usbd_submit_urb(irp *);
  135 static int32_t           usbd_urb2nt(int32_t);
  136 static void              usbd_task(device_object *, void *);
  137 static int32_t           usbd_taskadd(irp *, unsigned);
  138 static void              usbd_xfertask(device_object *, void *);
  139 static void              dummy(void);
  140 
  141 static union usbd_urb   *USBD_CreateConfigurationRequestEx(
  142                             usb_config_descriptor_t *,
  143                             struct usbd_interface_list_entry *);
  144 static union usbd_urb   *USBD_CreateConfigurationRequest(
  145                             usb_config_descriptor_t *,
  146                             uint16_t *);
  147 static void              USBD_GetUSBDIVersion(usbd_version_info *);
  148 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptorEx(
  149                             usb_config_descriptor_t *, void *, int32_t, int32_t,
  150                             int32_t, int32_t, int32_t);
  151 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptor(
  152                     usb_config_descriptor_t *, uint8_t, uint8_t);
  153 
  154 /*
  155  * We need to wrap these functions because these need `context switch' from
  156  * Windows to UNIX before it's called.
  157  */
  158 static funcptr usbd_iodispatch_wrap;
  159 static funcptr usbd_ioinvalid_wrap;
  160 static funcptr usbd_pnp_wrap;
  161 static funcptr usbd_power_wrap;
  162 static funcptr usbd_irpcancel_wrap;
  163 static funcptr usbd_task_wrap;
  164 static funcptr usbd_xfertask_wrap;
  165 
  166 int
  167 usbd_libinit(void)
  168 {
  169         image_patch_table       *patch;
  170         int i;
  171 
  172         patch = usbd_functbl;
  173         while (patch->ipt_func != NULL) {
  174                 windrv_wrap((funcptr)patch->ipt_func,
  175                     (funcptr *)&patch->ipt_wrap,
  176                     patch->ipt_argcnt, patch->ipt_ftype);
  177                 patch++;
  178         }
  179 
  180         windrv_wrap((funcptr)usbd_ioinvalid,
  181             (funcptr *)&usbd_ioinvalid_wrap, 2, WINDRV_WRAP_STDCALL);
  182         windrv_wrap((funcptr)usbd_iodispatch,
  183             (funcptr *)&usbd_iodispatch_wrap, 2, WINDRV_WRAP_STDCALL);
  184         windrv_wrap((funcptr)usbd_pnp,
  185             (funcptr *)&usbd_pnp_wrap, 2, WINDRV_WRAP_STDCALL);
  186         windrv_wrap((funcptr)usbd_power,
  187             (funcptr *)&usbd_power_wrap, 2, WINDRV_WRAP_STDCALL);
  188         windrv_wrap((funcptr)usbd_irpcancel,
  189             (funcptr *)&usbd_irpcancel_wrap, 2, WINDRV_WRAP_STDCALL);
  190         windrv_wrap((funcptr)usbd_task,
  191             (funcptr *)&usbd_task_wrap, 2, WINDRV_WRAP_STDCALL);
  192         windrv_wrap((funcptr)usbd_xfertask,
  193             (funcptr *)&usbd_xfertask_wrap, 2, WINDRV_WRAP_STDCALL);
  194 
  195         /* Create a fake USB driver instance. */
  196 
  197         windrv_bus_attach(&usbd_driver, "USB Bus");
  198 
  199         /* Set up our dipatch routine. */
  200         for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
  201                 usbd_driver.dro_dispatch[i] =
  202                         (driver_dispatch)usbd_ioinvalid_wrap;
  203 
  204         usbd_driver.dro_dispatch[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
  205             (driver_dispatch)usbd_iodispatch_wrap;
  206         usbd_driver.dro_dispatch[IRP_MJ_DEVICE_CONTROL] =
  207             (driver_dispatch)usbd_iodispatch_wrap;
  208         usbd_driver.dro_dispatch[IRP_MJ_POWER] =
  209             (driver_dispatch)usbd_power_wrap;
  210         usbd_driver.dro_dispatch[IRP_MJ_PNP] =
  211             (driver_dispatch)usbd_pnp_wrap;
  212 
  213         return (0);
  214 }
  215 
  216 int
  217 usbd_libfini(void)
  218 {
  219         image_patch_table       *patch;
  220 
  221         patch = usbd_functbl;
  222         while (patch->ipt_func != NULL) {
  223                 windrv_unwrap(patch->ipt_wrap);
  224                 patch++;
  225         }
  226 
  227         windrv_unwrap(usbd_ioinvalid_wrap);
  228         windrv_unwrap(usbd_iodispatch_wrap);
  229         windrv_unwrap(usbd_pnp_wrap);
  230         windrv_unwrap(usbd_power_wrap);
  231         windrv_unwrap(usbd_irpcancel_wrap);
  232         windrv_unwrap(usbd_task_wrap);
  233         windrv_unwrap(usbd_xfertask_wrap);
  234 
  235         free(usbd_driver.dro_drivername.us_buf, M_DEVBUF);
  236 
  237         return (0);
  238 }
  239 
  240 static int32_t
  241 usbd_iodispatch(device_object *dobj, irp *ip)
  242 {
  243         device_t dev = dobj->do_devext;
  244         int32_t status;
  245         struct io_stack_location *irp_sl;
  246 
  247         irp_sl = IoGetCurrentIrpStackLocation(ip);
  248         switch (irp_sl->isl_parameters.isl_ioctl.isl_iocode) {
  249         case IOCTL_INTERNAL_USB_SUBMIT_URB:
  250                 IRP_NDIS_DEV(ip) = dev;
  251 
  252                 status = usbd_submit_urb(ip);
  253                 break;
  254         default:
  255                 device_printf(dev, "ioctl 0x%x isn't supported\n",
  256                     irp_sl->isl_parameters.isl_ioctl.isl_iocode);
  257                 status = USBD_STATUS_NOT_SUPPORTED;
  258                 break;
  259         }
  260 
  261         if (status == USBD_STATUS_PENDING)
  262                 return (STATUS_PENDING);
  263 
  264         ip->irp_iostat.isb_status = usbd_urb2nt(status);
  265         if (status != USBD_STATUS_SUCCESS)
  266                 ip->irp_iostat.isb_info = 0;
  267         return (ip->irp_iostat.isb_status);
  268 }
  269 
  270 static int32_t
  271 usbd_ioinvalid(device_object *dobj, irp *ip)
  272 {
  273         device_t dev = dobj->do_devext;
  274         struct io_stack_location *irp_sl;
  275 
  276         irp_sl = IoGetCurrentIrpStackLocation(ip);
  277         device_printf(dev, "invalid I/O dispatch %d:%d\n", irp_sl->isl_major,
  278             irp_sl->isl_minor);
  279 
  280         ip->irp_iostat.isb_status = STATUS_FAILURE;
  281         ip->irp_iostat.isb_info = 0;
  282 
  283         IoCompleteRequest(ip, IO_NO_INCREMENT);
  284 
  285         return (STATUS_FAILURE);
  286 }
  287 
  288 static int32_t
  289 usbd_pnp(device_object *dobj, irp *ip)
  290 {
  291         device_t dev = dobj->do_devext;
  292         struct io_stack_location *irp_sl;
  293 
  294         irp_sl = IoGetCurrentIrpStackLocation(ip);
  295         device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
  296             __func__, irp_sl->isl_major, irp_sl->isl_minor);
  297 
  298         ip->irp_iostat.isb_status = STATUS_FAILURE;
  299         ip->irp_iostat.isb_info = 0;
  300 
  301         IoCompleteRequest(ip, IO_NO_INCREMENT);
  302 
  303         return (STATUS_FAILURE);
  304 }
  305 
  306 static int32_t
  307 usbd_power(device_object *dobj, irp *ip)
  308 {
  309         device_t dev = dobj->do_devext;
  310         struct io_stack_location *irp_sl;
  311 
  312         irp_sl = IoGetCurrentIrpStackLocation(ip);
  313         device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
  314             __func__, irp_sl->isl_major, irp_sl->isl_minor);
  315 
  316         ip->irp_iostat.isb_status = STATUS_FAILURE;
  317         ip->irp_iostat.isb_info = 0;
  318 
  319         IoCompleteRequest(ip, IO_NO_INCREMENT);
  320 
  321         return (STATUS_FAILURE);
  322 }
  323 
  324 /* Convert USBD_STATUS to NTSTATUS  */
  325 static int32_t
  326 usbd_urb2nt(int32_t status)
  327 {
  328 
  329         switch (status) {
  330         case USBD_STATUS_SUCCESS:
  331                 return (STATUS_SUCCESS);
  332         case USBD_STATUS_DEVICE_GONE:
  333                 return (STATUS_DEVICE_NOT_CONNECTED);
  334         case USBD_STATUS_PENDING:
  335                 return (STATUS_PENDING);
  336         case USBD_STATUS_NOT_SUPPORTED:
  337                 return (STATUS_NOT_IMPLEMENTED);
  338         case USBD_STATUS_NO_MEMORY:
  339                 return (STATUS_NO_MEMORY);
  340         case USBD_STATUS_REQUEST_FAILED:
  341                 return (STATUS_NOT_SUPPORTED);
  342         case USBD_STATUS_CANCELED:
  343                 return (STATUS_CANCELLED);
  344         default:
  345                 break;
  346         }
  347 
  348         return (STATUS_FAILURE);
  349 }
  350 
  351 /* Convert FreeBSD's usb_error_t to USBD_STATUS  */
  352 static int32_t
  353 usbd_usb2urb(int status)
  354 {
  355 
  356         switch (status) {
  357         case USB_ERR_NORMAL_COMPLETION:
  358                 return (USBD_STATUS_SUCCESS);
  359         case USB_ERR_PENDING_REQUESTS:
  360                 return (USBD_STATUS_PENDING);
  361         case USB_ERR_TIMEOUT:
  362                 return (USBD_STATUS_TIMEOUT);
  363         case USB_ERR_SHORT_XFER:
  364                 return (USBD_STATUS_ERROR_SHORT_TRANSFER);
  365         case USB_ERR_IOERROR:
  366                 return (USBD_STATUS_XACT_ERROR);
  367         case USB_ERR_NOMEM:
  368                 return (USBD_STATUS_NO_MEMORY);
  369         case USB_ERR_INVAL:
  370                 return (USBD_STATUS_REQUEST_FAILED);
  371         case USB_ERR_NOT_STARTED:
  372         case USB_ERR_TOO_DEEP:
  373         case USB_ERR_NO_POWER:
  374                 return (USBD_STATUS_DEVICE_GONE);
  375         case USB_ERR_CANCELLED:
  376                 return (USBD_STATUS_CANCELED);
  377         default:
  378                 break;
  379         }
  380 
  381         return (USBD_STATUS_NOT_SUPPORTED);
  382 }
  383 
  384 static union usbd_urb *
  385 usbd_geturb(irp *ip)
  386 {
  387         struct io_stack_location *irp_sl;
  388 
  389         irp_sl = IoGetCurrentIrpStackLocation(ip);
  390 
  391         return (irp_sl->isl_parameters.isl_others.isl_arg1);
  392 }
  393 
  394 static int32_t
  395 usbd_submit_urb(irp *ip)
  396 {
  397         device_t dev = IRP_NDIS_DEV(ip);
  398         int32_t status;
  399         union usbd_urb *urb;
  400 
  401         urb = usbd_geturb(ip);
  402         /*
  403          * In a case of URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
  404          * USBD_URB_STATUS(urb) would be set at callback functions like
  405          * usbd_intr() or usbd_xfereof().
  406          */
  407         switch (urb->uu_hdr.uuh_func) {
  408         case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
  409                 status = usbd_func_bulkintr(ip);
  410                 if (status != USBD_STATUS_SUCCESS &&
  411                     status != USBD_STATUS_PENDING)
  412                         USBD_URB_STATUS(urb) = status;
  413                 break;
  414         case URB_FUNCTION_VENDOR_DEVICE:
  415         case URB_FUNCTION_VENDOR_INTERFACE:
  416         case URB_FUNCTION_VENDOR_ENDPOINT:
  417         case URB_FUNCTION_VENDOR_OTHER:
  418         case URB_FUNCTION_CLASS_DEVICE:
  419         case URB_FUNCTION_CLASS_INTERFACE:
  420         case URB_FUNCTION_CLASS_ENDPOINT:
  421         case URB_FUNCTION_CLASS_OTHER:
  422                 status = usbd_func_vendorclass(ip);
  423                 USBD_URB_STATUS(urb) = status;
  424                 break;
  425         case URB_FUNCTION_SELECT_CONFIGURATION:
  426                 status = usbd_func_selconf(ip);
  427                 USBD_URB_STATUS(urb) = status;
  428                 break;
  429         case URB_FUNCTION_ABORT_PIPE:
  430                 status = usbd_func_abort_pipe(ip);
  431                 USBD_URB_STATUS(urb) = status;
  432                 break;
  433         case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
  434                 status = usbd_func_getdesc(ip);
  435                 USBD_URB_STATUS(urb) = status;
  436                 break;
  437         default:
  438                 device_printf(dev, "func 0x%x isn't supported\n",
  439                     urb->uu_hdr.uuh_func);
  440                 USBD_URB_STATUS(urb) = status = USBD_STATUS_NOT_SUPPORTED;
  441                 break;
  442         }
  443 
  444         return (status);
  445 }
  446 
  447 static int32_t
  448 usbd_func_getdesc(irp *ip)
  449 {
  450 #define NDISUSB_GETDESC_MAXRETRIES              3
  451         device_t dev = IRP_NDIS_DEV(ip);
  452         struct ndis_softc *sc = device_get_softc(dev);
  453         struct usbd_urb_control_descriptor_request *ctldesc;
  454         uint16_t actlen;
  455         uint32_t len;
  456         union usbd_urb *urb;
  457         usb_config_descriptor_t *cdp;
  458         usb_error_t status;
  459 
  460         urb = usbd_geturb(ip);
  461         ctldesc = &urb->uu_ctldesc;
  462         if (ctldesc->ucd_desctype == UDESC_CONFIG) {
  463                 /*
  464                  * The NDIS driver is not allowed to change the
  465                  * config! There is only one choice!
  466                  */
  467                 cdp = usbd_get_config_descriptor(sc->ndisusb_dev);
  468                 if (cdp == NULL) {
  469                         status = USB_ERR_INVAL;
  470                         goto exit;
  471                 }
  472                 if (cdp->bDescriptorType != UDESC_CONFIG) {
  473                         device_printf(dev, "bad desc %d\n",
  474                             cdp->bDescriptorType);
  475                         status = USB_ERR_INVAL;
  476                         goto exit;
  477                 }
  478                 /* get minimum length */
  479                 len = MIN(UGETW(cdp->wTotalLength), ctldesc->ucd_trans_buflen);
  480                 /* copy out config descriptor */
  481                 memcpy(ctldesc->ucd_trans_buf, cdp, len);
  482                 /* set actual length */
  483                 actlen = len;
  484                 status = USB_ERR_NORMAL_COMPLETION;
  485         } else {
  486                 NDISUSB_LOCK(sc);
  487                 status = usbd_req_get_desc(sc->ndisusb_dev, &sc->ndisusb_mtx,
  488                     &actlen, ctldesc->ucd_trans_buf, 2,
  489                     ctldesc->ucd_trans_buflen, ctldesc->ucd_langid,
  490                     ctldesc->ucd_desctype, ctldesc->ucd_idx,
  491                     NDISUSB_GETDESC_MAXRETRIES);
  492                 NDISUSB_UNLOCK(sc);
  493         }
  494 exit:
  495         if (status != USB_ERR_NORMAL_COMPLETION) {
  496                 ctldesc->ucd_trans_buflen = 0;
  497                 return usbd_usb2urb(status);
  498         }
  499 
  500         ctldesc->ucd_trans_buflen = actlen;
  501         ip->irp_iostat.isb_info = actlen;
  502 
  503         return (USBD_STATUS_SUCCESS);
  504 #undef NDISUSB_GETDESC_MAXRETRIES
  505 }
  506 
  507 static int32_t
  508 usbd_func_selconf(irp *ip)
  509 {
  510         device_t dev = IRP_NDIS_DEV(ip);
  511         int i, j;
  512         struct ndis_softc *sc = device_get_softc(dev);
  513         struct usb_device *udev = sc->ndisusb_dev;
  514         struct usb_endpoint *ep = NULL;
  515         struct usbd_interface_information *intf;
  516         struct usbd_pipe_information *pipe;
  517         struct usbd_urb_select_configuration *selconf;
  518         union usbd_urb *urb;
  519         usb_config_descriptor_t *conf;
  520         usb_endpoint_descriptor_t *edesc;
  521         usb_error_t ret;
  522 
  523         urb = usbd_geturb(ip);
  524 
  525         selconf = &urb->uu_selconf;
  526         conf = selconf->usc_conf;
  527         if (conf == NULL) {
  528                 device_printf(dev, "select configuration is NULL\n");
  529                 return usbd_usb2urb(USB_ERR_NORMAL_COMPLETION);
  530         }
  531 
  532         intf = &selconf->usc_intf;
  533         for (i = 0; i < conf->bNumInterface && intf->uii_len > 0; i++) {
  534                 ret = usbd_set_alt_interface_index(udev,
  535                     intf->uii_intfnum, intf->uii_altset);
  536                 if (ret != USB_ERR_NORMAL_COMPLETION && ret != USB_ERR_IN_USE) {
  537                         device_printf(dev,
  538                             "setting alternate interface failed: %s\n",
  539                             usbd_errstr(ret));
  540                         return usbd_usb2urb(ret);
  541                 }
  542 
  543                 for (j = 0; (ep = usb_endpoint_foreach(udev, ep)); j++) {
  544                         if (j >= intf->uii_numeps) {
  545                                 device_printf(dev,
  546                                     "endpoint %d and above are ignored",
  547                                     intf->uii_numeps);
  548                                 break;
  549                         }
  550                         edesc = ep->edesc;
  551                         pipe = &intf->uii_pipes[j];
  552                         pipe->upi_handle = edesc;
  553                         pipe->upi_epaddr = edesc->bEndpointAddress;
  554                         pipe->upi_maxpktsize = UGETW(edesc->wMaxPacketSize);
  555                         pipe->upi_type = UE_GET_XFERTYPE(edesc->bmAttributes);
  556 
  557                         ret = usbd_setup_endpoint(ip, intf->uii_intfnum, edesc);
  558                         if (ret != USB_ERR_NORMAL_COMPLETION)
  559                                 return usbd_usb2urb(ret);
  560 
  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 usb_error_t
  587 usbd_setup_endpoint_one(irp *ip, uint8_t ifidx, struct ndisusb_ep *ne,
  588     struct usb_config *epconf)
  589 {
  590         device_t dev = IRP_NDIS_DEV(ip);
  591         struct ndis_softc *sc = device_get_softc(dev);
  592         struct usb_xfer *xfer;
  593         usb_error_t status;
  594 
  595         InitializeListHead(&ne->ne_active);
  596         InitializeListHead(&ne->ne_pending);
  597         KeInitializeSpinLock(&ne->ne_lock);
  598 
  599         status = usbd_transfer_setup(sc->ndisusb_dev, &ifidx, ne->ne_xfer,
  600             epconf, 1, sc, &sc->ndisusb_mtx);
  601         if (status != USB_ERR_NORMAL_COMPLETION) {
  602                 device_printf(dev, "couldn't setup xfer: %s\n",
  603                     usbd_errstr(status));
  604                 return (status);
  605         }
  606         xfer = ne->ne_xfer[0];
  607         usbd_xfer_set_priv(xfer, ne);
  608 
  609         return (status);
  610 }
  611 
  612 static usb_error_t
  613 usbd_setup_endpoint_default(irp *ip, uint8_t ifidx)
  614 {
  615         device_t dev = IRP_NDIS_DEV(ip);
  616         struct ndis_softc *sc = device_get_softc(dev);
  617         usb_error_t status;
  618 
  619         if (ifidx > 0)
  620                 device_printf(dev, "warning: ifidx > 0 isn't supported.\n");
  621 
  622         status = usbd_setup_endpoint_one(ip, ifidx, &sc->ndisusb_dread_ep,
  623             &usbd_default_epconfig[USBD_CTRL_READ_PIPE]);
  624         if (status != USB_ERR_NORMAL_COMPLETION)
  625                 return (status);
  626 
  627         status = usbd_setup_endpoint_one(ip, ifidx, &sc->ndisusb_dwrite_ep,
  628             &usbd_default_epconfig[USBD_CTRL_WRITE_PIPE]);
  629         return (status);
  630 }
  631 
  632 static usb_error_t
  633 usbd_setup_endpoint(irp *ip, uint8_t ifidx,
  634     struct usb_endpoint_descriptor *ep)
  635 {
  636         device_t dev = IRP_NDIS_DEV(ip);
  637         struct ndis_softc *sc = device_get_softc(dev);
  638         struct ndisusb_ep *ne;
  639         struct usb_config cfg;
  640         struct usb_xfer *xfer;
  641         usb_error_t status;
  642 
  643         /* check for non-supported transfer types */
  644         if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_CONTROL ||
  645             UE_GET_XFERTYPE(ep->bmAttributes) == UE_ISOCHRONOUS) {
  646                 device_printf(dev, "%s: unsuppotted transfer types %#x\n",
  647                     __func__, UE_GET_XFERTYPE(ep->bmAttributes));
  648                 return (USB_ERR_INVAL);
  649         }
  650 
  651         ne = &sc->ndisusb_ep[NDISUSB_GET_ENDPT(ep->bEndpointAddress)];
  652         InitializeListHead(&ne->ne_active);
  653         InitializeListHead(&ne->ne_pending);
  654         KeInitializeSpinLock(&ne->ne_lock);
  655         ne->ne_dirin = UE_GET_DIR(ep->bEndpointAddress) >> 7;
  656 
  657         memset(&cfg, 0, sizeof(struct usb_config));
  658         cfg.type        = UE_GET_XFERTYPE(ep->bmAttributes);
  659         cfg.endpoint    = UE_GET_ADDR(ep->bEndpointAddress);
  660         cfg.direction   = UE_GET_DIR(ep->bEndpointAddress);
  661         cfg.callback    = &usbd_non_isoc_callback;
  662         cfg.bufsize     = UGETW(ep->wMaxPacketSize);
  663         cfg.flags.proxy_buffer = 1;
  664         if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
  665                 cfg.flags.short_xfer_ok = 1;
  666 
  667         status = usbd_transfer_setup(sc->ndisusb_dev, &ifidx, ne->ne_xfer,
  668             &cfg, 1, sc, &sc->ndisusb_mtx);
  669         if (status != USB_ERR_NORMAL_COMPLETION) {
  670                 device_printf(dev, "couldn't setup xfer: %s\n",
  671                     usbd_errstr(status));
  672                 return (status);
  673         }
  674         xfer = ne->ne_xfer[0];
  675         usbd_xfer_set_priv(xfer, ne);
  676         if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
  677                 usbd_xfer_set_timeout(xfer, NDISUSB_NO_TIMEOUT);
  678         else {
  679                 if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_BULK)
  680                         usbd_xfer_set_timeout(xfer, NDISUSB_TX_TIMEOUT);
  681                 else
  682                         usbd_xfer_set_timeout(xfer, NDISUSB_INTR_TIMEOUT);
  683         }
  684 
  685         return (status);
  686 }
  687 
  688 static int32_t
  689 usbd_func_abort_pipe(irp *ip)
  690 {
  691         device_t dev = IRP_NDIS_DEV(ip);
  692         struct ndis_softc *sc = device_get_softc(dev);
  693         struct ndisusb_ep *ne;
  694         union usbd_urb *urb;
  695 
  696         urb = usbd_geturb(ip);
  697         ne = usbd_get_ndisep(ip, urb->uu_pipe.upr_handle);
  698         if (ne == NULL) {
  699                 device_printf(IRP_NDIS_DEV(ip), "get NULL endpoint info.\n");
  700                 return (USBD_STATUS_INVALID_PIPE_HANDLE);
  701         }
  702 
  703         NDISUSB_LOCK(sc);
  704         usbd_transfer_stop(ne->ne_xfer[0]);
  705         usbd_transfer_start(ne->ne_xfer[0]);
  706         NDISUSB_UNLOCK(sc);
  707 
  708         return (USBD_STATUS_SUCCESS);
  709 }
  710 
  711 static int32_t
  712 usbd_func_vendorclass(irp *ip)
  713 {
  714         device_t dev = IRP_NDIS_DEV(ip);
  715         int32_t error;
  716         struct ndis_softc *sc = device_get_softc(dev);
  717         struct ndisusb_ep *ne;
  718         struct ndisusb_xfer *nx;
  719         struct usbd_urb_vendor_or_class_request *vcreq;
  720         union usbd_urb *urb;
  721 
  722         if (!(sc->ndisusb_status & NDISUSB_STATUS_SETUP_EP)) {
  723                 /*
  724                  * XXX In some cases the interface number isn't 0.  However
  725                  * some driver (eg. RTL8187L NDIS driver) calls this function
  726                  * before calling URB_FUNCTION_SELECT_CONFIGURATION.
  727                  */
  728                 error = usbd_setup_endpoint_default(ip, 0);
  729                 if (error != USB_ERR_NORMAL_COMPLETION)
  730                         return usbd_usb2urb(error);
  731                 sc->ndisusb_status |= NDISUSB_STATUS_SETUP_EP;
  732         }
  733 
  734         urb = usbd_geturb(ip);
  735         vcreq = &urb->uu_vcreq;
  736         ne = (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ?
  737             &sc->ndisusb_dread_ep : &sc->ndisusb_dwrite_ep;
  738         IRP_NDISUSB_EP(ip) = ne;
  739         ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap;
  740 
  741         nx = malloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO);
  742         if (nx == NULL) {
  743                 device_printf(IRP_NDIS_DEV(ip), "out of memory\n");
  744                 return (USBD_STATUS_NO_MEMORY);
  745         }
  746         nx->nx_ep = ne;
  747         nx->nx_priv = ip;
  748         KeAcquireSpinLockAtDpcLevel(&ne->ne_lock);
  749         InsertTailList((&ne->ne_pending), (&nx->nx_next));
  750         KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
  751 
  752         /* we've done to setup xfer.  Let's transfer it.  */
  753         ip->irp_iostat.isb_status = STATUS_PENDING;
  754         ip->irp_iostat.isb_info = 0;
  755         USBD_URB_STATUS(urb) = USBD_STATUS_PENDING;
  756         IoMarkIrpPending(ip);
  757 
  758         error = usbd_taskadd(ip, NDISUSB_TASK_VENDOR);
  759         if (error != USBD_STATUS_SUCCESS)
  760                 return (error);
  761 
  762         return (USBD_STATUS_PENDING);
  763 }
  764 
  765 static void
  766 usbd_irpcancel(device_object *dobj, irp *ip)
  767 {
  768         device_t dev = IRP_NDIS_DEV(ip);
  769         struct ndis_softc *sc = device_get_softc(dev);
  770         struct ndisusb_ep *ne = IRP_NDISUSB_EP(ip);
  771 
  772         if (ne == NULL) {
  773                 ip->irp_cancel = TRUE;
  774                 IoReleaseCancelSpinLock(ip->irp_cancelirql);
  775                 return;
  776         }
  777 
  778         /*
  779          * Make sure that the current USB transfer proxy is
  780          * cancelled and then restarted.
  781          */
  782         NDISUSB_LOCK(sc);
  783         usbd_transfer_stop(ne->ne_xfer[0]);
  784         usbd_transfer_start(ne->ne_xfer[0]);
  785         NDISUSB_UNLOCK(sc);
  786 
  787         ip->irp_cancel = TRUE;
  788         IoReleaseCancelSpinLock(ip->irp_cancelirql);
  789 }
  790 
  791 static void
  792 usbd_xfer_complete(struct ndis_softc *sc, struct ndisusb_ep *ne,
  793     struct ndisusb_xfer *nx, usb_error_t status)
  794 {
  795         struct ndisusb_xferdone *nd;
  796         uint8_t irql;
  797 
  798         nd = malloc(sizeof(struct ndisusb_xferdone), M_USBDEV,
  799             M_NOWAIT | M_ZERO);
  800         if (nd == NULL) {
  801                 device_printf(sc->ndis_dev, "out of memory");
  802                 return;
  803         }
  804         nd->nd_xfer = nx;
  805         nd->nd_status = status;
  806 
  807         KeAcquireSpinLock(&sc->ndisusb_xferdonelock, &irql);
  808         InsertTailList((&sc->ndisusb_xferdonelist), (&nd->nd_donelist));
  809         KeReleaseSpinLock(&sc->ndisusb_xferdonelock, irql);
  810 
  811         IoQueueWorkItem(sc->ndisusb_xferdoneitem,
  812             (io_workitem_func)usbd_xfertask_wrap, WORKQUEUE_CRITICAL, sc);
  813 }
  814 
  815 static struct ndisusb_xfer *
  816 usbd_aq_getfirst(struct ndis_softc *sc, struct ndisusb_ep *ne)
  817 {
  818         struct ndisusb_xfer *nx;
  819 
  820         KeAcquireSpinLockAtDpcLevel(&ne->ne_lock);
  821         if (IsListEmpty(&ne->ne_active)) {
  822                 device_printf(sc->ndis_dev,
  823                     "%s: the active queue can't be empty.\n", __func__);
  824                 KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
  825                 return (NULL);
  826         }
  827         nx = CONTAINING_RECORD(ne->ne_active.nle_flink, struct ndisusb_xfer,
  828             nx_next);
  829         RemoveEntryList(&nx->nx_next);
  830         KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
  831 
  832         return (nx);
  833 }
  834 
  835 static void
  836 usbd_non_isoc_callback(struct usb_xfer *xfer, usb_error_t error)
  837 {
  838         irp *ip;
  839         struct ndis_softc *sc = usbd_xfer_softc(xfer);
  840         struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer);
  841         struct ndisusb_xfer *nx;
  842         struct usbd_urb_bulk_or_intr_transfer *ubi;
  843         struct usb_page_cache *pc;
  844         uint8_t irql;
  845         uint32_t len;
  846         union usbd_urb *urb;
  847         usb_endpoint_descriptor_t *ep;
  848         int actlen, sumlen;
  849 
  850         usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
  851 
  852         switch (USB_GET_STATE(xfer)) {
  853         case USB_ST_TRANSFERRED:
  854                 nx = usbd_aq_getfirst(sc, ne);
  855                 pc = usbd_xfer_get_frame(xfer, 0);
  856                 if (nx == NULL)
  857                         return;
  858 
  859                 /* copy in data with regard to the URB */
  860                 if (ne->ne_dirin != 0)
  861                         usbd_copy_out(pc, 0, nx->nx_urbbuf, actlen);
  862                 nx->nx_urbbuf += actlen;
  863                 nx->nx_urbactlen += actlen;
  864                 nx->nx_urblen -= actlen;
  865 
  866                 /* check for short transfer */
  867                 if (actlen < sumlen)
  868                         nx->nx_urblen = 0;
  869                 else {
  870                         /* check remainder */
  871                         if (nx->nx_urblen > 0) {
  872                                 KeAcquireSpinLock(&ne->ne_lock, &irql);
  873                                 InsertHeadList((&ne->ne_active), (&nx->nx_next));
  874                                 KeReleaseSpinLock(&ne->ne_lock, irql);
  875 
  876                                 ip = nx->nx_priv;
  877                                 urb = usbd_geturb(ip);
  878                                 ubi = &urb->uu_bulkintr;
  879                                 ep = ubi->ubi_epdesc;
  880                                 goto extra;
  881                         }
  882                 }
  883                 usbd_xfer_complete(sc, ne, nx,
  884                     ((actlen < sumlen) && (nx->nx_shortxfer == 0)) ?
  885                     USB_ERR_SHORT_XFER : USB_ERR_NORMAL_COMPLETION);
  886 
  887                 /* fall through */
  888         case USB_ST_SETUP:
  889 next:
  890                 /* get next transfer */
  891                 KeAcquireSpinLock(&ne->ne_lock, &irql);
  892                 if (IsListEmpty(&ne->ne_pending)) {
  893                         KeReleaseSpinLock(&ne->ne_lock, irql);
  894                         return;
  895                 }
  896                 nx = CONTAINING_RECORD(ne->ne_pending.nle_flink,
  897                     struct ndisusb_xfer, nx_next);
  898                 RemoveEntryList(&nx->nx_next);
  899                 /* add a entry to the active queue's tail.  */
  900                 InsertTailList((&ne->ne_active), (&nx->nx_next));
  901                 KeReleaseSpinLock(&ne->ne_lock, irql);
  902 
  903                 ip = nx->nx_priv;
  904                 urb = usbd_geturb(ip);
  905                 ubi = &urb->uu_bulkintr;
  906                 ep = ubi->ubi_epdesc;
  907 
  908                 nx->nx_urbbuf           = ubi->ubi_trans_buf;
  909                 nx->nx_urbactlen        = 0;
  910                 nx->nx_urblen           = ubi->ubi_trans_buflen;
  911                 nx->nx_shortxfer        = (ubi->ubi_trans_flags &
  912                     USBD_SHORT_TRANSFER_OK) ? 1 : 0;
  913 extra:
  914                 len = MIN(usbd_xfer_max_len(xfer), nx->nx_urblen);
  915                 pc = usbd_xfer_get_frame(xfer, 0);
  916                 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_OUT)
  917                         usbd_copy_in(pc, 0, nx->nx_urbbuf, len);
  918                 usbd_xfer_set_frame_len(xfer, 0, len);
  919                 usbd_xfer_set_frames(xfer, 1);
  920                 usbd_transfer_submit(xfer);
  921                 break;
  922         default:
  923                 nx = usbd_aq_getfirst(sc, ne);
  924                 if (nx == NULL)
  925                         return;
  926                 if (error != USB_ERR_CANCELLED) {
  927                         usbd_xfer_set_stall(xfer);
  928                         device_printf(sc->ndis_dev, "usb xfer warning (%s)\n",
  929                             usbd_errstr(error));
  930                 }
  931                 usbd_xfer_complete(sc, ne, nx, error);
  932                 if (error != USB_ERR_CANCELLED)
  933                         goto next;
  934                 break;
  935         }
  936 }
  937 
  938 static void
  939 usbd_ctrl_callback(struct usb_xfer *xfer, usb_error_t error)
  940 {
  941         irp *ip;
  942         struct ndis_softc *sc = usbd_xfer_softc(xfer);
  943         struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer);
  944         struct ndisusb_xfer *nx;
  945         uint8_t irql;
  946         union usbd_urb *urb;
  947         struct usbd_urb_vendor_or_class_request *vcreq;
  948         struct usb_page_cache *pc;
  949         uint8_t type = 0;
  950         struct usb_device_request req;
  951         int len;
  952 
  953         switch (USB_GET_STATE(xfer)) {
  954         case USB_ST_TRANSFERRED:
  955                 nx = usbd_aq_getfirst(sc, ne);
  956                 if (nx == NULL)
  957                         return;
  958 
  959                 ip = nx->nx_priv;
  960                 urb = usbd_geturb(ip);
  961                 vcreq = &urb->uu_vcreq;
  962 
  963                 if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
  964                         pc = usbd_xfer_get_frame(xfer, 1);
  965                         len = usbd_xfer_frame_len(xfer, 1);
  966                         usbd_copy_out(pc, 0, vcreq->uvc_trans_buf, len);
  967                         nx->nx_urbactlen += len;
  968                 }
  969 
  970                 usbd_xfer_complete(sc, ne, nx, USB_ERR_NORMAL_COMPLETION);
  971                 /* fall through */
  972         case USB_ST_SETUP:
  973 next:
  974                 /* get next transfer */
  975                 KeAcquireSpinLock(&ne->ne_lock, &irql);
  976                 if (IsListEmpty(&ne->ne_pending)) {
  977                         KeReleaseSpinLock(&ne->ne_lock, irql);
  978                         return;
  979                 }
  980                 nx = CONTAINING_RECORD(ne->ne_pending.nle_flink,
  981                     struct ndisusb_xfer, nx_next);
  982                 RemoveEntryList(&nx->nx_next);
  983                 /* add a entry to the active queue's tail.  */
  984                 InsertTailList((&ne->ne_active), (&nx->nx_next));
  985                 KeReleaseSpinLock(&ne->ne_lock, irql);
  986 
  987                 ip = nx->nx_priv;
  988                 urb = usbd_geturb(ip);
  989                 vcreq = &urb->uu_vcreq;
  990 
  991                 switch (urb->uu_hdr.uuh_func) {
  992                 case URB_FUNCTION_CLASS_DEVICE:
  993                         type = UT_CLASS | UT_DEVICE;
  994                         break;
  995                 case URB_FUNCTION_CLASS_INTERFACE:
  996                         type = UT_CLASS | UT_INTERFACE;
  997                         break;
  998                 case URB_FUNCTION_CLASS_OTHER:
  999                         type = UT_CLASS | UT_OTHER;
 1000                         break;
 1001                 case URB_FUNCTION_CLASS_ENDPOINT:
 1002                         type = UT_CLASS | UT_ENDPOINT;
 1003                         break;
 1004                 case URB_FUNCTION_VENDOR_DEVICE:
 1005                         type = UT_VENDOR | UT_DEVICE;
 1006                         break;
 1007                 case URB_FUNCTION_VENDOR_INTERFACE:
 1008                         type = UT_VENDOR | UT_INTERFACE;
 1009                         break;
 1010                 case URB_FUNCTION_VENDOR_OTHER:
 1011                         type = UT_VENDOR | UT_OTHER;
 1012                         break;
 1013                 case URB_FUNCTION_VENDOR_ENDPOINT:
 1014                         type = UT_VENDOR | UT_ENDPOINT;
 1015                         break;
 1016                 default:
 1017                         /* never reached.  */
 1018                         break;
 1019                 }
 1020 
 1021                 type |= (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ?
 1022                     UT_READ : UT_WRITE;
 1023                 type |= vcreq->uvc_reserved1;
 1024 
 1025                 req.bmRequestType = type;
 1026                 req.bRequest = vcreq->uvc_req;
 1027                 USETW(req.wIndex, vcreq->uvc_idx);
 1028                 USETW(req.wValue, vcreq->uvc_value);
 1029                 USETW(req.wLength, vcreq->uvc_trans_buflen);
 1030 
 1031                 nx->nx_urbbuf           = vcreq->uvc_trans_buf;
 1032                 nx->nx_urblen           = vcreq->uvc_trans_buflen;
 1033                 nx->nx_urbactlen        = 0;
 1034 
 1035                 pc = usbd_xfer_get_frame(xfer, 0);
 1036                 usbd_copy_in(pc, 0, &req, sizeof(req));
 1037                 usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
 1038                 usbd_xfer_set_frames(xfer, 1);
 1039                 if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
 1040                         if (vcreq->uvc_trans_buflen >= USBD_CTRL_READ_BUFFER_SP)
 1041                                 device_printf(sc->ndis_dev,
 1042                                     "warning: not enough buffer space (%d).\n",
 1043                                     vcreq->uvc_trans_buflen);
 1044                         usbd_xfer_set_frame_len(xfer, 1,
 1045                             MIN(usbd_xfer_max_len(xfer),
 1046                                     vcreq->uvc_trans_buflen));
 1047                         usbd_xfer_set_frames(xfer, 2);
 1048                 } else {
 1049                         if (nx->nx_urblen > USBD_CTRL_WRITE_BUFFER_SP)
 1050                                 device_printf(sc->ndis_dev,
 1051                                     "warning: not enough write buffer space"
 1052                                     " (%d).\n", nx->nx_urblen);
 1053                         /*
 1054                          * XXX with my local tests there was no cases to require
 1055                          * a extra buffer until now but it'd need to update in
 1056                          * the future if it needs to be.
 1057                          */
 1058                         if (nx->nx_urblen > 0) {
 1059                                 pc = usbd_xfer_get_frame(xfer, 1);
 1060                                 usbd_copy_in(pc, 0, nx->nx_urbbuf,
 1061                                     nx->nx_urblen);
 1062                                 usbd_xfer_set_frame_len(xfer, 1, nx->nx_urblen);
 1063                                 usbd_xfer_set_frames(xfer, 2);
 1064                         }
 1065                 }
 1066                 usbd_transfer_submit(xfer);
 1067                 break;
 1068         default:
 1069                 nx = usbd_aq_getfirst(sc, ne);
 1070                 if (nx == NULL)
 1071                         return;
 1072                 if (error != USB_ERR_CANCELLED) {
 1073                         usbd_xfer_set_stall(xfer);
 1074                         device_printf(sc->ndis_dev, "usb xfer warning (%s)\n",
 1075                             usbd_errstr(error));
 1076                 }
 1077                 usbd_xfer_complete(sc, ne, nx, error);
 1078                 if (error != USB_ERR_CANCELLED)
 1079                         goto next;
 1080                 break;
 1081         }
 1082 }
 1083 
 1084 static struct ndisusb_ep *
 1085 usbd_get_ndisep(irp *ip, usb_endpoint_descriptor_t *ep)
 1086 {
 1087         device_t dev = IRP_NDIS_DEV(ip);
 1088         struct ndis_softc *sc = device_get_softc(dev);
 1089         struct ndisusb_ep *ne;
 1090 
 1091         ne = &sc->ndisusb_ep[NDISUSB_GET_ENDPT(ep->bEndpointAddress)];
 1092 
 1093         IRP_NDISUSB_EP(ip) = ne;
 1094         ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap;
 1095 
 1096         return (ne);
 1097 }
 1098 
 1099 static void
 1100 usbd_xfertask(device_object *dobj, void *arg)
 1101 {
 1102         int error;
 1103         irp *ip;
 1104         device_t dev;
 1105         list_entry *l;
 1106         struct ndis_softc *sc = arg;
 1107         struct ndisusb_xferdone *nd;
 1108         struct ndisusb_xfer *nq;
 1109         struct usbd_urb_bulk_or_intr_transfer *ubi;
 1110         struct usbd_urb_vendor_or_class_request *vcreq;
 1111         union usbd_urb *urb;
 1112         usb_error_t status;
 1113         void *priv;
 1114 
 1115         dev = sc->ndis_dev;
 1116 
 1117         if (IsListEmpty(&sc->ndisusb_xferdonelist))
 1118                 return;
 1119 
 1120         KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_xferdonelock);
 1121         l = sc->ndisusb_xferdonelist.nle_flink;
 1122         while (l != &sc->ndisusb_xferdonelist) {
 1123                 nd = CONTAINING_RECORD(l, struct ndisusb_xferdone, nd_donelist);
 1124                 nq = nd->nd_xfer;
 1125                 priv = nq->nx_priv;
 1126                 status = nd->nd_status;
 1127                 error = 0;
 1128                 ip = priv;
 1129                 urb = usbd_geturb(ip);
 1130 
 1131                 ip->irp_cancelfunc = NULL;
 1132                 IRP_NDISUSB_EP(ip) = NULL;
 1133 
 1134                 switch (status) {
 1135                 case USB_ERR_NORMAL_COMPLETION:
 1136                         if (urb->uu_hdr.uuh_func ==
 1137                             URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) {
 1138                                 ubi = &urb->uu_bulkintr;
 1139                                 ubi->ubi_trans_buflen = nq->nx_urbactlen;
 1140                         } else {
 1141                                 vcreq = &urb->uu_vcreq;
 1142                                 vcreq->uvc_trans_buflen = nq->nx_urbactlen;
 1143                         }
 1144                         ip->irp_iostat.isb_info = nq->nx_urbactlen;
 1145                         ip->irp_iostat.isb_status = STATUS_SUCCESS;
 1146                         USBD_URB_STATUS(urb) = USBD_STATUS_SUCCESS;
 1147                         break;
 1148                 case USB_ERR_CANCELLED:
 1149                         ip->irp_iostat.isb_info = 0;
 1150                         ip->irp_iostat.isb_status = STATUS_CANCELLED;
 1151                         USBD_URB_STATUS(urb) = USBD_STATUS_CANCELED;
 1152                         break;
 1153                 default:
 1154                         ip->irp_iostat.isb_info = 0;
 1155                         USBD_URB_STATUS(urb) = usbd_usb2urb(status);
 1156                         ip->irp_iostat.isb_status =
 1157                             usbd_urb2nt(USBD_URB_STATUS(urb));
 1158                         break;
 1159                 }
 1160 
 1161                 l = l->nle_flink;
 1162                 RemoveEntryList(&nd->nd_donelist);
 1163                 free(nq, M_USBDEV);
 1164                 free(nd, M_USBDEV);
 1165                 if (error)
 1166                         continue;
 1167                 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_xferdonelock);
 1168                 /* NB: call after cleaning  */
 1169                 IoCompleteRequest(ip, IO_NO_INCREMENT);
 1170                 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_xferdonelock);
 1171         }
 1172         KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_xferdonelock);
 1173 }
 1174 
 1175 /*
 1176  * this function is for mainly deferring a task to the another thread because
 1177  * we don't want to be in the scope of HAL lock.
 1178  */
 1179 static int32_t
 1180 usbd_taskadd(irp *ip, unsigned type)
 1181 {
 1182         device_t dev = IRP_NDIS_DEV(ip);
 1183         struct ndis_softc *sc = device_get_softc(dev);
 1184         struct ndisusb_task *nt;
 1185 
 1186         nt = malloc(sizeof(struct ndisusb_task), M_USBDEV, M_NOWAIT | M_ZERO);
 1187         if (nt == NULL)
 1188                 return (USBD_STATUS_NO_MEMORY);
 1189         nt->nt_type = type;
 1190         nt->nt_ctx = ip;
 1191 
 1192         KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock);
 1193         InsertTailList((&sc->ndisusb_tasklist), (&nt->nt_tasklist));
 1194         KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock);
 1195 
 1196         IoQueueWorkItem(sc->ndisusb_taskitem,
 1197             (io_workitem_func)usbd_task_wrap, WORKQUEUE_CRITICAL, sc);
 1198 
 1199         return (USBD_STATUS_SUCCESS);
 1200 }
 1201 
 1202 static void
 1203 usbd_task(device_object *dobj, void *arg)
 1204 {
 1205         irp *ip;
 1206         list_entry *l;
 1207         struct ndis_softc *sc = arg;
 1208         struct ndisusb_ep *ne;
 1209         struct ndisusb_task *nt;
 1210         union usbd_urb *urb;
 1211 
 1212         if (IsListEmpty(&sc->ndisusb_tasklist))
 1213                 return;
 1214 
 1215         KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock);
 1216         l = sc->ndisusb_tasklist.nle_flink;
 1217         while (l != &sc->ndisusb_tasklist) {
 1218                 nt = CONTAINING_RECORD(l, struct ndisusb_task, nt_tasklist);
 1219 
 1220                 ip = nt->nt_ctx;
 1221                 urb = usbd_geturb(ip);
 1222 
 1223                 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock);
 1224                 NDISUSB_LOCK(sc);
 1225                 switch (nt->nt_type) {
 1226                 case NDISUSB_TASK_TSTART:
 1227                         ne = usbd_get_ndisep(ip, urb->uu_bulkintr.ubi_epdesc);
 1228                         if (ne == NULL)
 1229                                 goto exit;
 1230                         usbd_transfer_start(ne->ne_xfer[0]);
 1231                         break;
 1232                 case NDISUSB_TASK_IRPCANCEL:
 1233                         ne = usbd_get_ndisep(ip,
 1234                             (nt->nt_type == NDISUSB_TASK_IRPCANCEL) ?
 1235                             urb->uu_bulkintr.ubi_epdesc :
 1236                             urb->uu_pipe.upr_handle);
 1237                         if (ne == NULL)
 1238                                 goto exit;
 1239                         
 1240                         usbd_transfer_stop(ne->ne_xfer[0]);
 1241                         usbd_transfer_start(ne->ne_xfer[0]);
 1242                         break;
 1243                 case NDISUSB_TASK_VENDOR:
 1244                         ne = (urb->uu_vcreq.uvc_trans_flags &
 1245                             USBD_TRANSFER_DIRECTION_IN) ?
 1246                             &sc->ndisusb_dread_ep : &sc->ndisusb_dwrite_ep;
 1247                         usbd_transfer_start(ne->ne_xfer[0]);
 1248                         break;
 1249                 default:
 1250                         break;
 1251                 }
 1252 exit:
 1253                 NDISUSB_UNLOCK(sc);
 1254                 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock);
 1255 
 1256                 l = l->nle_flink;
 1257                 RemoveEntryList(&nt->nt_tasklist);
 1258                 free(nt, M_USBDEV);
 1259         }
 1260         KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock);
 1261 }
 1262 
 1263 static int32_t
 1264 usbd_func_bulkintr(irp *ip)
 1265 {
 1266         int32_t error;
 1267         struct ndisusb_ep *ne;
 1268         struct ndisusb_xfer *nx;
 1269         struct usbd_urb_bulk_or_intr_transfer *ubi;
 1270         union usbd_urb *urb;
 1271         usb_endpoint_descriptor_t *ep;
 1272 
 1273         urb = usbd_geturb(ip);
 1274         ubi = &urb->uu_bulkintr;
 1275         ep = ubi->ubi_epdesc;
 1276         if (ep == NULL)
 1277                 return (USBD_STATUS_INVALID_PIPE_HANDLE);
 1278 
 1279         ne = usbd_get_ndisep(ip, ep);
 1280         if (ne == NULL) {
 1281                 device_printf(IRP_NDIS_DEV(ip), "get NULL endpoint info.\n");
 1282                 return (USBD_STATUS_INVALID_PIPE_HANDLE);
 1283         }
 1284 
 1285         nx = malloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO);
 1286         if (nx == NULL) {
 1287                 device_printf(IRP_NDIS_DEV(ip), "out of memory\n");
 1288                 return (USBD_STATUS_NO_MEMORY);
 1289         }
 1290         nx->nx_ep = ne;
 1291         nx->nx_priv = ip;
 1292         KeAcquireSpinLockAtDpcLevel(&ne->ne_lock);
 1293         InsertTailList((&ne->ne_pending), (&nx->nx_next));
 1294         KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
 1295 
 1296         /* we've done to setup xfer.  Let's transfer it.  */
 1297         ip->irp_iostat.isb_status = STATUS_PENDING;
 1298         ip->irp_iostat.isb_info = 0;
 1299         USBD_URB_STATUS(urb) = USBD_STATUS_PENDING;
 1300         IoMarkIrpPending(ip);
 1301 
 1302         error = usbd_taskadd(ip, NDISUSB_TASK_TSTART);
 1303         if (error != USBD_STATUS_SUCCESS)
 1304                 return (error);
 1305 
 1306         return (USBD_STATUS_PENDING);
 1307 }
 1308 
 1309 static union usbd_urb *
 1310 USBD_CreateConfigurationRequest(usb_config_descriptor_t *conf, uint16_t *len)
 1311 {
 1312         struct usbd_interface_list_entry list[2];
 1313         union usbd_urb *urb;
 1314 
 1315         bzero(list, sizeof(struct usbd_interface_list_entry) * 2);
 1316         list[0].uil_intfdesc = USBD_ParseConfigurationDescriptorEx(conf, conf,
 1317             -1, -1, -1, -1, -1);
 1318         urb = USBD_CreateConfigurationRequestEx(conf, list);
 1319         if (urb == NULL)
 1320                 return (NULL);
 1321 
 1322         *len = urb->uu_selconf.usc_hdr.uuh_len;
 1323         return (urb);
 1324 }
 1325 
 1326 static union usbd_urb *
 1327 USBD_CreateConfigurationRequestEx(usb_config_descriptor_t *conf,
 1328     struct usbd_interface_list_entry *list)
 1329 {
 1330         int i, j, size;
 1331         struct usbd_interface_information *intf;
 1332         struct usbd_pipe_information *pipe;
 1333         struct usbd_urb_select_configuration *selconf;
 1334         usb_interface_descriptor_t *desc;
 1335 
 1336         for (i = 0, size = 0; i < conf->bNumInterface; i++) {
 1337                 j = list[i].uil_intfdesc->bNumEndpoints;
 1338                 size = size + sizeof(struct usbd_interface_information) +
 1339                     sizeof(struct usbd_pipe_information) * (j - 1);
 1340         }
 1341         size += sizeof(struct usbd_urb_select_configuration) -
 1342             sizeof(struct usbd_interface_information);
 1343 
 1344         selconf = ExAllocatePoolWithTag(NonPagedPool, size, 0);
 1345         if (selconf == NULL)
 1346                 return (NULL);
 1347         selconf->usc_hdr.uuh_func = URB_FUNCTION_SELECT_CONFIGURATION;
 1348         selconf->usc_hdr.uuh_len = size;
 1349         selconf->usc_handle = conf;
 1350         selconf->usc_conf = conf;
 1351 
 1352         intf = &selconf->usc_intf;
 1353         for (i = 0; i < conf->bNumInterface; i++) {
 1354                 if (list[i].uil_intfdesc == NULL)
 1355                         break;
 1356 
 1357                 list[i].uil_intf = intf;
 1358                 desc = list[i].uil_intfdesc;
 1359 
 1360                 intf->uii_len = sizeof(struct usbd_interface_information) +
 1361                     (desc->bNumEndpoints - 1) *
 1362                     sizeof(struct usbd_pipe_information);
 1363                 intf->uii_intfnum = desc->bInterfaceNumber;
 1364                 intf->uii_altset = desc->bAlternateSetting;
 1365                 intf->uii_intfclass = desc->bInterfaceClass;
 1366                 intf->uii_intfsubclass = desc->bInterfaceSubClass;
 1367                 intf->uii_intfproto = desc->bInterfaceProtocol;
 1368                 intf->uii_handle = desc;
 1369                 intf->uii_numeps = desc->bNumEndpoints;
 1370 
 1371                 pipe = &intf->uii_pipes[0];
 1372                 for (j = 0; j < intf->uii_numeps; j++)
 1373                         pipe[j].upi_maxtxsize =
 1374                             USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
 1375 
 1376                 intf = (struct usbd_interface_information *)((char *)intf +
 1377                     intf->uii_len);
 1378         }
 1379 
 1380         return ((union usbd_urb *)selconf);
 1381 }
 1382 
 1383 static void
 1384 USBD_GetUSBDIVersion(usbd_version_info *ui)
 1385 {
 1386 
 1387         /* Pretend to be Windows XP. */
 1388 
 1389         ui->uvi_usbdi_vers = USBDI_VERSION;
 1390         ui->uvi_supported_vers = USB_VER_2_0;
 1391 }
 1392 
 1393 static usb_interface_descriptor_t *
 1394 USBD_ParseConfigurationDescriptor(usb_config_descriptor_t *conf,
 1395         uint8_t intfnum, uint8_t altset)
 1396 {
 1397 
 1398         return USBD_ParseConfigurationDescriptorEx(conf, conf, intfnum, altset,
 1399             -1, -1, -1);
 1400 }
 1401 
 1402 static usb_interface_descriptor_t *
 1403 USBD_ParseConfigurationDescriptorEx(usb_config_descriptor_t *conf,
 1404     void *start, int32_t intfnum, int32_t altset, int32_t intfclass,
 1405     int32_t intfsubclass, int32_t intfproto)
 1406 {
 1407         struct usb_descriptor *next = NULL;
 1408         usb_interface_descriptor_t *desc;
 1409 
 1410         while ((next = usb_desc_foreach(conf, next)) != NULL) {
 1411                 desc = (usb_interface_descriptor_t *)next;
 1412                 if (desc->bDescriptorType != UDESC_INTERFACE)
 1413                         continue;
 1414                 if (!(intfnum == -1 || desc->bInterfaceNumber == intfnum))
 1415                         continue;
 1416                 if (!(altset == -1 || desc->bAlternateSetting == altset))
 1417                         continue;
 1418                 if (!(intfclass == -1 || desc->bInterfaceClass == intfclass))
 1419                         continue;
 1420                 if (!(intfsubclass == -1 ||
 1421                     desc->bInterfaceSubClass == intfsubclass))
 1422                         continue;
 1423                 if (!(intfproto == -1 || desc->bInterfaceProtocol == intfproto))
 1424                         continue;
 1425                 return (desc);
 1426         }
 1427 
 1428         return (NULL);
 1429 }
 1430 
 1431 static void
 1432 dummy(void)
 1433 {
 1434         printf("USBD dummy called\n");
 1435 }
 1436 
 1437 image_patch_table usbd_functbl[] = {
 1438         IMPORT_SFUNC(USBD_CreateConfigurationRequest, 2),
 1439         IMPORT_SFUNC(USBD_CreateConfigurationRequestEx, 2),
 1440         IMPORT_SFUNC_MAP(_USBD_CreateConfigurationRequestEx@8,
 1441             USBD_CreateConfigurationRequestEx, 2),
 1442         IMPORT_SFUNC(USBD_GetUSBDIVersion, 1),
 1443         IMPORT_SFUNC(USBD_ParseConfigurationDescriptor, 3),
 1444         IMPORT_SFUNC(USBD_ParseConfigurationDescriptorEx, 7),
 1445         IMPORT_SFUNC_MAP(_USBD_ParseConfigurationDescriptorEx@28,
 1446             USBD_ParseConfigurationDescriptorEx, 7),
 1447 
 1448         /*
 1449          * This last entry is a catch-all for any function we haven't
 1450          * implemented yet. The PE import list patching routine will
 1451          * use it for any function that doesn't have an explicit match
 1452          * in this table.
 1453          */
 1454 
 1455         { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL },
 1456 
 1457         /* End of list. */
 1458 
 1459         { NULL, NULL, NULL }
 1460 };
 1461 
 1462 MODULE_DEPEND(ndis, usb, 1, 1, 1);

Cache object: 241316411aacb2467ec9448f58847926


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