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