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

Cache object: c7e9a873402d4307a0970b1431e2d30a


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