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