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


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

FreeBSD/Linux Kernel Cross Reference
sys/emulation/ndis/subr_u4bd.c

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

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

Cache object: dcae5a5d46a4a5ed748639ffbc7587d3


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