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