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