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