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

Cache object: feffa6abcee7aef25460f21227bdc282


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