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