3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/unistd.h>
39 #include <sys/types.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
44 #include <sys/mutex.h>
46 #include <sys/condvar.h>
47 #include <sys/module.h>
50 #include <sys/socket.h>
51 #include <machine/bus.h>
54 #include <sys/queue.h>
57 #include <net/if_var.h>
58 #include <net/if_media.h>
59 #include <net80211/ieee80211_var.h>
60 #include <net80211/ieee80211_ioctl.h>
62 #include <dev/usb/usb.h>
63 #include <dev/usb/usbdi.h>
64 #include <dev/usb/usbdi_util.h>
65 #include <dev/usb/usb_busdma.h>
66 #include <dev/usb/usb_device.h>
67 #include <dev/usb/usb_request.h>
69 #include <compat/ndis/pe_var.h>
70 #include <compat/ndis/cfg_var.h>
71 #include <compat/ndis/resource_var.h>
72 #include <compat/ndis/ntoskrnl_var.h>
73 #include <compat/ndis/ndis_var.h>
74 #include <compat/ndis/hal_var.h>
75 #include <compat/ndis/usbd_var.h>
76 #include <dev/if_ndis/if_ndisvar.h>
78 static driver_object usbd_driver;
79 static usb_callback_t usbd_non_isoc_callback;
80 static usb_callback_t usbd_ctrl_callback;
82 #define USBD_CTRL_READ_PIPE 0
83 #define USBD_CTRL_WRITE_PIPE 1
84 #define USBD_CTRL_MAX_PIPE 2
85 #define USBD_CTRL_READ_BUFFER_SP 256
86 #define USBD_CTRL_WRITE_BUFFER_SP 256
87 #define USBD_CTRL_READ_BUFFER_SIZE \
88 (sizeof(struct usb_device_request) + USBD_CTRL_READ_BUFFER_SP)
89 #define USBD_CTRL_WRITE_BUFFER_SIZE \
90 (sizeof(struct usb_device_request) + USBD_CTRL_WRITE_BUFFER_SP)
91 static struct usb_config usbd_default_epconfig[USBD_CTRL_MAX_PIPE] = {
92 [USBD_CTRL_READ_PIPE] = {
94 .endpoint = 0x00, /* control pipe */
95 .direction = UE_DIR_ANY,
97 .bufsize = USBD_CTRL_READ_BUFFER_SIZE,
98 .flags = { .short_xfer_ok = 1, },
99 .callback = &usbd_ctrl_callback,
100 .timeout = 5000, /* 5 seconds */
102 [USBD_CTRL_WRITE_PIPE] = {
104 .endpoint = 0x00, /* control pipe */
105 .direction = UE_DIR_ANY,
107 .bufsize = USBD_CTRL_WRITE_BUFFER_SIZE,
108 .flags = { .proxy_buffer = 1, },
109 .callback = &usbd_ctrl_callback,
110 .timeout = 5000, /* 5 seconds */
114 static int32_t usbd_func_bulkintr(irp *);
115 static int32_t usbd_func_vendorclass(irp *);
116 static int32_t usbd_func_selconf(irp *);
117 static int32_t usbd_func_abort_pipe(irp *);
118 static usb_error_t usbd_setup_endpoint(irp *, uint8_t,
119 struct usb_endpoint_descriptor *);
120 static usb_error_t usbd_setup_endpoint_default(irp *, uint8_t);
121 static usb_error_t usbd_setup_endpoint_one(irp *, uint8_t,
122 struct ndisusb_ep *, struct usb_config *);
123 static int32_t usbd_func_getdesc(irp *);
124 static union usbd_urb *usbd_geturb(irp *);
125 static struct ndisusb_ep*usbd_get_ndisep(irp *, usb_endpoint_descriptor_t *);
126 static int32_t usbd_iodispatch(device_object *, irp *);
127 static int32_t usbd_ioinvalid(device_object *, irp *);
128 static int32_t usbd_pnp(device_object *, irp *);
129 static int32_t usbd_power(device_object *, irp *);
130 static void usbd_irpcancel(device_object *, irp *);
131 static int32_t usbd_submit_urb(irp *);
132 static int32_t usbd_urb2nt(int32_t);
133 static void usbd_task(device_object *, void *);
134 static int32_t usbd_taskadd(irp *, unsigned);
135 static void usbd_xfertask(device_object *, void *);
136 static void dummy(void);
138 static union usbd_urb *USBD_CreateConfigurationRequestEx(
139 usb_config_descriptor_t *,
140 struct usbd_interface_list_entry *);
141 static union usbd_urb *USBD_CreateConfigurationRequest(
142 usb_config_descriptor_t *,
144 static void USBD_GetUSBDIVersion(usbd_version_info *);
145 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptorEx(
146 usb_config_descriptor_t *, void *, int32_t, int32_t,
147 int32_t, int32_t, int32_t);
148 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptor(
149 usb_config_descriptor_t *, uint8_t, uint8_t);
152 * We need to wrap these functions because these need `context switch' from
153 * Windows to UNIX before it's called.
155 static funcptr usbd_iodispatch_wrap;
156 static funcptr usbd_ioinvalid_wrap;
157 static funcptr usbd_pnp_wrap;
158 static funcptr usbd_power_wrap;
159 static funcptr usbd_irpcancel_wrap;
160 static funcptr usbd_task_wrap;
161 static funcptr usbd_xfertask_wrap;
166 image_patch_table *patch;
169 patch = usbd_functbl;
170 while (patch->ipt_func != NULL) {
171 windrv_wrap((funcptr)patch->ipt_func,
172 (funcptr *)&patch->ipt_wrap,
173 patch->ipt_argcnt, patch->ipt_ftype);
177 windrv_wrap((funcptr)usbd_ioinvalid,
178 (funcptr *)&usbd_ioinvalid_wrap, 2, WINDRV_WRAP_STDCALL);
179 windrv_wrap((funcptr)usbd_iodispatch,
180 (funcptr *)&usbd_iodispatch_wrap, 2, WINDRV_WRAP_STDCALL);
181 windrv_wrap((funcptr)usbd_pnp,
182 (funcptr *)&usbd_pnp_wrap, 2, WINDRV_WRAP_STDCALL);
183 windrv_wrap((funcptr)usbd_power,
184 (funcptr *)&usbd_power_wrap, 2, WINDRV_WRAP_STDCALL);
185 windrv_wrap((funcptr)usbd_irpcancel,
186 (funcptr *)&usbd_irpcancel_wrap, 2, WINDRV_WRAP_STDCALL);
187 windrv_wrap((funcptr)usbd_task,
188 (funcptr *)&usbd_task_wrap, 2, WINDRV_WRAP_STDCALL);
189 windrv_wrap((funcptr)usbd_xfertask,
190 (funcptr *)&usbd_xfertask_wrap, 2, WINDRV_WRAP_STDCALL);
192 /* Create a fake USB driver instance. */
194 windrv_bus_attach(&usbd_driver, "USB Bus");
196 /* Set up our dipatch routine. */
197 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
198 usbd_driver.dro_dispatch[i] =
199 (driver_dispatch)usbd_ioinvalid_wrap;
201 usbd_driver.dro_dispatch[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
202 (driver_dispatch)usbd_iodispatch_wrap;
203 usbd_driver.dro_dispatch[IRP_MJ_DEVICE_CONTROL] =
204 (driver_dispatch)usbd_iodispatch_wrap;
205 usbd_driver.dro_dispatch[IRP_MJ_POWER] =
206 (driver_dispatch)usbd_power_wrap;
207 usbd_driver.dro_dispatch[IRP_MJ_PNP] =
208 (driver_dispatch)usbd_pnp_wrap;
216 image_patch_table *patch;
218 patch = usbd_functbl;
219 while (patch->ipt_func != NULL) {
220 windrv_unwrap(patch->ipt_wrap);
224 windrv_unwrap(usbd_ioinvalid_wrap);
225 windrv_unwrap(usbd_iodispatch_wrap);
226 windrv_unwrap(usbd_pnp_wrap);
227 windrv_unwrap(usbd_power_wrap);
228 windrv_unwrap(usbd_irpcancel_wrap);
229 windrv_unwrap(usbd_task_wrap);
230 windrv_unwrap(usbd_xfertask_wrap);
232 free(usbd_driver.dro_drivername.us_buf, M_DEVBUF);
238 usbd_iodispatch(device_object *dobj, irp *ip)
240 device_t dev = dobj->do_devext;
242 struct io_stack_location *irp_sl;
244 irp_sl = IoGetCurrentIrpStackLocation(ip);
245 switch (irp_sl->isl_parameters.isl_ioctl.isl_iocode) {
246 case IOCTL_INTERNAL_USB_SUBMIT_URB:
247 IRP_NDIS_DEV(ip) = dev;
249 status = usbd_submit_urb(ip);
252 device_printf(dev, "ioctl 0x%x isn't supported\n",
253 irp_sl->isl_parameters.isl_ioctl.isl_iocode);
254 status = USBD_STATUS_NOT_SUPPORTED;
258 if (status == USBD_STATUS_PENDING)
259 return (STATUS_PENDING);
261 ip->irp_iostat.isb_status = usbd_urb2nt(status);
262 if (status != USBD_STATUS_SUCCESS)
263 ip->irp_iostat.isb_info = 0;
264 return (ip->irp_iostat.isb_status);
268 usbd_ioinvalid(device_object *dobj, irp *ip)
270 device_t dev = dobj->do_devext;
271 struct io_stack_location *irp_sl;
273 irp_sl = IoGetCurrentIrpStackLocation(ip);
274 device_printf(dev, "invalid I/O dispatch %d:%d\n", irp_sl->isl_major,
277 ip->irp_iostat.isb_status = STATUS_FAILURE;
278 ip->irp_iostat.isb_info = 0;
280 IoCompleteRequest(ip, IO_NO_INCREMENT);
282 return (STATUS_FAILURE);
286 usbd_pnp(device_object *dobj, irp *ip)
288 device_t dev = dobj->do_devext;
289 struct io_stack_location *irp_sl;
291 irp_sl = IoGetCurrentIrpStackLocation(ip);
292 device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
293 __func__, irp_sl->isl_major, irp_sl->isl_minor);
295 ip->irp_iostat.isb_status = STATUS_FAILURE;
296 ip->irp_iostat.isb_info = 0;
298 IoCompleteRequest(ip, IO_NO_INCREMENT);
300 return (STATUS_FAILURE);
304 usbd_power(device_object *dobj, irp *ip)
306 device_t dev = dobj->do_devext;
307 struct io_stack_location *irp_sl;
309 irp_sl = IoGetCurrentIrpStackLocation(ip);
310 device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
311 __func__, irp_sl->isl_major, irp_sl->isl_minor);
313 ip->irp_iostat.isb_status = STATUS_FAILURE;
314 ip->irp_iostat.isb_info = 0;
316 IoCompleteRequest(ip, IO_NO_INCREMENT);
318 return (STATUS_FAILURE);
321 /* Convert USBD_STATUS to NTSTATUS */
323 usbd_urb2nt(int32_t status)
327 case USBD_STATUS_SUCCESS:
328 return (STATUS_SUCCESS);
329 case USBD_STATUS_DEVICE_GONE:
330 return (STATUS_DEVICE_NOT_CONNECTED);
331 case USBD_STATUS_PENDING:
332 return (STATUS_PENDING);
333 case USBD_STATUS_NOT_SUPPORTED:
334 return (STATUS_NOT_IMPLEMENTED);
335 case USBD_STATUS_NO_MEMORY:
336 return (STATUS_NO_MEMORY);
337 case USBD_STATUS_REQUEST_FAILED:
338 return (STATUS_NOT_SUPPORTED);
339 case USBD_STATUS_CANCELED:
340 return (STATUS_CANCELLED);
345 return (STATUS_FAILURE);
348 /* Convert FreeBSD's usb_error_t to USBD_STATUS */
350 usbd_usb2urb(int status)
354 case USB_ERR_NORMAL_COMPLETION:
355 return (USBD_STATUS_SUCCESS);
356 case USB_ERR_PENDING_REQUESTS:
357 return (USBD_STATUS_PENDING);
358 case USB_ERR_TIMEOUT:
359 return (USBD_STATUS_TIMEOUT);
360 case USB_ERR_SHORT_XFER:
361 return (USBD_STATUS_ERROR_SHORT_TRANSFER);
362 case USB_ERR_IOERROR:
363 return (USBD_STATUS_XACT_ERROR);
365 return (USBD_STATUS_NO_MEMORY);
367 return (USBD_STATUS_REQUEST_FAILED);
368 case USB_ERR_NOT_STARTED:
369 case USB_ERR_TOO_DEEP:
370 case USB_ERR_NO_POWER:
371 return (USBD_STATUS_DEVICE_GONE);
372 case USB_ERR_CANCELLED:
373 return (USBD_STATUS_CANCELED);
378 return (USBD_STATUS_NOT_SUPPORTED);
381 static union usbd_urb *
384 struct io_stack_location *irp_sl;
386 irp_sl = IoGetCurrentIrpStackLocation(ip);
388 return (irp_sl->isl_parameters.isl_others.isl_arg1);
392 usbd_submit_urb(irp *ip)
394 device_t dev = IRP_NDIS_DEV(ip);
398 urb = usbd_geturb(ip);
400 * In a case of URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
401 * USBD_URB_STATUS(urb) would be set at callback functions like
402 * usbd_intr() or usbd_xfereof().
404 switch (urb->uu_hdr.uuh_func) {
405 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
406 status = usbd_func_bulkintr(ip);
407 if (status != USBD_STATUS_SUCCESS &&
408 status != USBD_STATUS_PENDING)
409 USBD_URB_STATUS(urb) = status;
411 case URB_FUNCTION_VENDOR_DEVICE:
412 case URB_FUNCTION_VENDOR_INTERFACE:
413 case URB_FUNCTION_VENDOR_ENDPOINT:
414 case URB_FUNCTION_VENDOR_OTHER:
415 case URB_FUNCTION_CLASS_DEVICE:
416 case URB_FUNCTION_CLASS_INTERFACE:
417 case URB_FUNCTION_CLASS_ENDPOINT:
418 case URB_FUNCTION_CLASS_OTHER:
419 status = usbd_func_vendorclass(ip);
420 USBD_URB_STATUS(urb) = status;
422 case URB_FUNCTION_SELECT_CONFIGURATION:
423 status = usbd_func_selconf(ip);
424 USBD_URB_STATUS(urb) = status;
426 case URB_FUNCTION_ABORT_PIPE:
427 status = usbd_func_abort_pipe(ip);
428 USBD_URB_STATUS(urb) = status;
430 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
431 status = usbd_func_getdesc(ip);
432 USBD_URB_STATUS(urb) = status;
435 device_printf(dev, "func 0x%x isn't supported\n",
436 urb->uu_hdr.uuh_func);
437 USBD_URB_STATUS(urb) = status = USBD_STATUS_NOT_SUPPORTED;
445 usbd_func_getdesc(irp *ip)
447 #define NDISUSB_GETDESC_MAXRETRIES 3
448 device_t dev = IRP_NDIS_DEV(ip);
449 struct ndis_softc *sc = device_get_softc(dev);
450 struct usbd_urb_control_descriptor_request *ctldesc;
454 usb_config_descriptor_t *cdp;
457 urb = usbd_geturb(ip);
458 ctldesc = &urb->uu_ctldesc;
459 if (ctldesc->ucd_desctype == UDESC_CONFIG) {
461 * The NDIS driver is not allowed to change the
462 * config! There is only one choice!
464 cdp = usbd_get_config_descriptor(sc->ndisusb_dev);
466 status = USB_ERR_INVAL;
469 if (cdp->bDescriptorType != UDESC_CONFIG) {
470 device_printf(dev, "bad desc %d\n",
471 cdp->bDescriptorType);
472 status = USB_ERR_INVAL;
475 /* get minimum length */
476 len = MIN(UGETW(cdp->wTotalLength), ctldesc->ucd_trans_buflen);
477 /* copy out config descriptor */
478 memcpy(ctldesc->ucd_trans_buf, cdp, len);
479 /* set actual length */
481 status = USB_ERR_NORMAL_COMPLETION;
484 status = usbd_req_get_desc(sc->ndisusb_dev, &sc->ndisusb_mtx,
485 &actlen, ctldesc->ucd_trans_buf, 2,
486 ctldesc->ucd_trans_buflen, ctldesc->ucd_langid,
487 ctldesc->ucd_desctype, ctldesc->ucd_idx,
488 NDISUSB_GETDESC_MAXRETRIES);
492 if (status != USB_ERR_NORMAL_COMPLETION) {
493 ctldesc->ucd_trans_buflen = 0;
494 return usbd_usb2urb(status);
497 ctldesc->ucd_trans_buflen = actlen;
498 ip->irp_iostat.isb_info = actlen;
500 return (USBD_STATUS_SUCCESS);
501 #undef NDISUSB_GETDESC_MAXRETRIES
505 usbd_func_selconf(irp *ip)
507 device_t dev = IRP_NDIS_DEV(ip);
509 struct ndis_softc *sc = device_get_softc(dev);
510 struct usb_device *udev = sc->ndisusb_dev;
511 struct usb_endpoint *ep = NULL;
512 struct usbd_interface_information *intf;
513 struct usbd_pipe_information *pipe;
514 struct usbd_urb_select_configuration *selconf;
516 usb_config_descriptor_t *conf;
517 usb_endpoint_descriptor_t *edesc;
520 urb = usbd_geturb(ip);
522 selconf = &urb->uu_selconf;
523 conf = selconf->usc_conf;
525 device_printf(dev, "select configuration is NULL\n");
526 return usbd_usb2urb(USB_ERR_NORMAL_COMPLETION);
529 intf = &selconf->usc_intf;
530 for (i = 0; i < conf->bNumInterface && intf->uii_len > 0; i++) {
531 ret = usbd_set_alt_interface_index(udev,
532 intf->uii_intfnum, intf->uii_altset);
533 if (ret != USB_ERR_NORMAL_COMPLETION && ret != USB_ERR_IN_USE) {
535 "setting alternate interface failed: %s\n",
537 return usbd_usb2urb(ret);
540 for (j = 0; (ep = usb_endpoint_foreach(udev, ep)); j++) {
541 if (j >= intf->uii_numeps) {
543 "endpoint %d and above are ignored",
548 pipe = &intf->uii_pipes[j];
549 pipe->upi_handle = edesc;
550 pipe->upi_epaddr = edesc->bEndpointAddress;
551 pipe->upi_maxpktsize = UGETW(edesc->wMaxPacketSize);
552 pipe->upi_type = UE_GET_XFERTYPE(edesc->bmAttributes);
554 ret = usbd_setup_endpoint(ip, intf->uii_intfnum, edesc);
555 if (ret != USB_ERR_NORMAL_COMPLETION)
556 return usbd_usb2urb(ret);
558 if (pipe->upi_type != UE_INTERRUPT)
561 /* XXX we're following linux USB's interval policy. */
562 if (udev->speed == USB_SPEED_LOW)
563 pipe->upi_interval = edesc->bInterval + 5;
564 else if (udev->speed == USB_SPEED_FULL)
565 pipe->upi_interval = edesc->bInterval;
571 } while (k1 < edesc->bInterval);
572 pipe->upi_interval = k0;
576 intf = (struct usbd_interface_information *)(((char *)intf) +
580 return (USBD_STATUS_SUCCESS);
584 usbd_setup_endpoint_one(irp *ip, uint8_t ifidx, struct ndisusb_ep *ne,
585 struct usb_config *epconf)
587 device_t dev = IRP_NDIS_DEV(ip);
588 struct ndis_softc *sc = device_get_softc(dev);
589 struct usb_xfer *xfer;
592 InitializeListHead(&ne->ne_active);
593 InitializeListHead(&ne->ne_pending);
594 KeInitializeSpinLock(&ne->ne_lock);
596 status = usbd_transfer_setup(sc->ndisusb_dev, &ifidx, ne->ne_xfer,
597 epconf, 1, sc, &sc->ndisusb_mtx);
598 if (status != USB_ERR_NORMAL_COMPLETION) {
599 device_printf(dev, "couldn't setup xfer: %s\n",
600 usbd_errstr(status));
603 xfer = ne->ne_xfer[0];
604 usbd_xfer_set_priv(xfer, ne);
610 usbd_setup_endpoint_default(irp *ip, uint8_t ifidx)
612 device_t dev = IRP_NDIS_DEV(ip);
613 struct ndis_softc *sc = device_get_softc(dev);
617 device_printf(dev, "warning: ifidx > 0 isn't supported.\n");
619 status = usbd_setup_endpoint_one(ip, ifidx, &sc->ndisusb_dread_ep,
620 &usbd_default_epconfig[USBD_CTRL_READ_PIPE]);
621 if (status != USB_ERR_NORMAL_COMPLETION)
624 status = usbd_setup_endpoint_one(ip, ifidx, &sc->ndisusb_dwrite_ep,
625 &usbd_default_epconfig[USBD_CTRL_WRITE_PIPE]);
630 usbd_setup_endpoint(irp *ip, uint8_t ifidx,
631 struct usb_endpoint_descriptor *ep)
633 device_t dev = IRP_NDIS_DEV(ip);
634 struct ndis_softc *sc = device_get_softc(dev);
635 struct ndisusb_ep *ne;
636 struct usb_config cfg;
637 struct usb_xfer *xfer;
640 /* check for non-supported transfer types */
641 if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_CONTROL ||
642 UE_GET_XFERTYPE(ep->bmAttributes) == UE_ISOCHRONOUS) {
643 device_printf(dev, "%s: unsuppotted transfer types %#x\n",
644 __func__, UE_GET_XFERTYPE(ep->bmAttributes));
645 return (USB_ERR_INVAL);
648 ne = &sc->ndisusb_ep[NDISUSB_GET_ENDPT(ep->bEndpointAddress)];
649 InitializeListHead(&ne->ne_active);
650 InitializeListHead(&ne->ne_pending);
651 KeInitializeSpinLock(&ne->ne_lock);
652 ne->ne_dirin = UE_GET_DIR(ep->bEndpointAddress) >> 7;
654 memset(&cfg, 0, sizeof(struct usb_config));
655 cfg.type = UE_GET_XFERTYPE(ep->bmAttributes);
656 cfg.endpoint = UE_GET_ADDR(ep->bEndpointAddress);
657 cfg.direction = UE_GET_DIR(ep->bEndpointAddress);
658 cfg.callback = &usbd_non_isoc_callback;
659 cfg.bufsize = UGETW(ep->wMaxPacketSize);
660 cfg.flags.proxy_buffer = 1;
661 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
662 cfg.flags.short_xfer_ok = 1;
664 status = usbd_transfer_setup(sc->ndisusb_dev, &ifidx, ne->ne_xfer,
665 &cfg, 1, sc, &sc->ndisusb_mtx);
666 if (status != USB_ERR_NORMAL_COMPLETION) {
667 device_printf(dev, "couldn't setup xfer: %s\n",
668 usbd_errstr(status));
671 xfer = ne->ne_xfer[0];
672 usbd_xfer_set_priv(xfer, ne);
673 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
674 usbd_xfer_set_timeout(xfer, NDISUSB_NO_TIMEOUT);
676 if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_BULK)
677 usbd_xfer_set_timeout(xfer, NDISUSB_TX_TIMEOUT);
679 usbd_xfer_set_timeout(xfer, NDISUSB_INTR_TIMEOUT);
686 usbd_func_abort_pipe(irp *ip)
688 device_t dev = IRP_NDIS_DEV(ip);
689 struct ndis_softc *sc = device_get_softc(dev);
690 struct ndisusb_ep *ne;
693 urb = usbd_geturb(ip);
694 ne = usbd_get_ndisep(ip, urb->uu_pipe.upr_handle);
696 device_printf(IRP_NDIS_DEV(ip), "get NULL endpoint info.\n");
697 return (USBD_STATUS_INVALID_PIPE_HANDLE);
701 usbd_transfer_stop(ne->ne_xfer[0]);
702 usbd_transfer_start(ne->ne_xfer[0]);
705 return (USBD_STATUS_SUCCESS);
709 usbd_func_vendorclass(irp *ip)
711 device_t dev = IRP_NDIS_DEV(ip);
713 struct ndis_softc *sc = device_get_softc(dev);
714 struct ndisusb_ep *ne;
715 struct ndisusb_xfer *nx;
716 struct usbd_urb_vendor_or_class_request *vcreq;
719 if (!(sc->ndisusb_status & NDISUSB_STATUS_SETUP_EP)) {
721 * XXX In some cases the interface number isn't 0. However
722 * some driver (eg. RTL8187L NDIS driver) calls this function
723 * before calling URB_FUNCTION_SELECT_CONFIGURATION.
725 error = usbd_setup_endpoint_default(ip, 0);
726 if (error != USB_ERR_NORMAL_COMPLETION)
727 return usbd_usb2urb(error);
728 sc->ndisusb_status |= NDISUSB_STATUS_SETUP_EP;
731 urb = usbd_geturb(ip);
732 vcreq = &urb->uu_vcreq;
733 ne = (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ?
734 &sc->ndisusb_dread_ep : &sc->ndisusb_dwrite_ep;
735 IRP_NDISUSB_EP(ip) = ne;
736 ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap;
738 nx = malloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO);
740 device_printf(IRP_NDIS_DEV(ip), "out of memory\n");
741 return (USBD_STATUS_NO_MEMORY);
745 KeAcquireSpinLockAtDpcLevel(&ne->ne_lock);
746 InsertTailList((&ne->ne_pending), (&nx->nx_next));
747 KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
749 /* we've done to setup xfer. Let's transfer it. */
750 ip->irp_iostat.isb_status = STATUS_PENDING;
751 ip->irp_iostat.isb_info = 0;
752 USBD_URB_STATUS(urb) = USBD_STATUS_PENDING;
753 IoMarkIrpPending(ip);
755 error = usbd_taskadd(ip, NDISUSB_TASK_VENDOR);
756 if (error != USBD_STATUS_SUCCESS)
759 return (USBD_STATUS_PENDING);
763 usbd_irpcancel(device_object *dobj, irp *ip)
765 device_t dev = IRP_NDIS_DEV(ip);
766 struct ndis_softc *sc = device_get_softc(dev);
767 struct ndisusb_ep *ne = IRP_NDISUSB_EP(ip);
770 ip->irp_cancel = TRUE;
771 IoReleaseCancelSpinLock(ip->irp_cancelirql);
776 * Make sure that the current USB transfer proxy is
777 * cancelled and then restarted.
780 usbd_transfer_stop(ne->ne_xfer[0]);
781 usbd_transfer_start(ne->ne_xfer[0]);
784 ip->irp_cancel = TRUE;
785 IoReleaseCancelSpinLock(ip->irp_cancelirql);
789 usbd_xfer_complete(struct ndis_softc *sc, struct ndisusb_ep *ne,
790 struct ndisusb_xfer *nx, usb_error_t status)
792 struct ndisusb_xferdone *nd;
795 nd = malloc(sizeof(struct ndisusb_xferdone), M_USBDEV,
798 device_printf(sc->ndis_dev, "out of memory");
802 nd->nd_status = status;
804 KeAcquireSpinLock(&sc->ndisusb_xferdonelock, &irql);
805 InsertTailList((&sc->ndisusb_xferdonelist), (&nd->nd_donelist));
806 KeReleaseSpinLock(&sc->ndisusb_xferdonelock, irql);
808 IoQueueWorkItem(sc->ndisusb_xferdoneitem,
809 (io_workitem_func)usbd_xfertask_wrap, WORKQUEUE_CRITICAL, sc);
812 static struct ndisusb_xfer *
813 usbd_aq_getfirst(struct ndis_softc *sc, struct ndisusb_ep *ne)
815 struct ndisusb_xfer *nx;
817 KeAcquireSpinLockAtDpcLevel(&ne->ne_lock);
818 if (IsListEmpty(&ne->ne_active)) {
819 device_printf(sc->ndis_dev,
820 "%s: the active queue can't be empty.\n", __func__);
821 KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
824 nx = CONTAINING_RECORD(ne->ne_active.nle_flink, struct ndisusb_xfer,
826 RemoveEntryList(&nx->nx_next);
827 KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
833 usbd_non_isoc_callback(struct usb_xfer *xfer, usb_error_t error)
836 struct ndis_softc *sc = usbd_xfer_softc(xfer);
837 struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer);
838 struct ndisusb_xfer *nx;
839 struct usbd_urb_bulk_or_intr_transfer *ubi;
840 struct usb_page_cache *pc;
844 usb_endpoint_descriptor_t *ep;
847 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
849 switch (USB_GET_STATE(xfer)) {
850 case USB_ST_TRANSFERRED:
851 nx = usbd_aq_getfirst(sc, ne);
852 pc = usbd_xfer_get_frame(xfer, 0);
856 /* copy in data with regard to the URB */
857 if (ne->ne_dirin != 0)
858 usbd_copy_out(pc, 0, nx->nx_urbbuf, actlen);
859 nx->nx_urbbuf += actlen;
860 nx->nx_urbactlen += actlen;
861 nx->nx_urblen -= actlen;
863 /* check for short transfer */
867 /* check remainder */
868 if (nx->nx_urblen > 0) {
869 KeAcquireSpinLock(&ne->ne_lock, &irql);
870 InsertHeadList((&ne->ne_active), (&nx->nx_next));
871 KeReleaseSpinLock(&ne->ne_lock, irql);
874 urb = usbd_geturb(ip);
875 ubi = &urb->uu_bulkintr;
876 ep = ubi->ubi_epdesc;
880 usbd_xfer_complete(sc, ne, nx,
881 ((actlen < sumlen) && (nx->nx_shortxfer == 0)) ?
882 USB_ERR_SHORT_XFER : USB_ERR_NORMAL_COMPLETION);
887 /* get next transfer */
888 KeAcquireSpinLock(&ne->ne_lock, &irql);
889 if (IsListEmpty(&ne->ne_pending)) {
890 KeReleaseSpinLock(&ne->ne_lock, irql);
893 nx = CONTAINING_RECORD(ne->ne_pending.nle_flink,
894 struct ndisusb_xfer, nx_next);
895 RemoveEntryList(&nx->nx_next);
896 /* add a entry to the active queue's tail. */
897 InsertTailList((&ne->ne_active), (&nx->nx_next));
898 KeReleaseSpinLock(&ne->ne_lock, irql);
901 urb = usbd_geturb(ip);
902 ubi = &urb->uu_bulkintr;
903 ep = ubi->ubi_epdesc;
905 nx->nx_urbbuf = ubi->ubi_trans_buf;
906 nx->nx_urbactlen = 0;
907 nx->nx_urblen = ubi->ubi_trans_buflen;
908 nx->nx_shortxfer = (ubi->ubi_trans_flags &
909 USBD_SHORT_TRANSFER_OK) ? 1 : 0;
911 len = MIN(usbd_xfer_max_len(xfer), nx->nx_urblen);
912 pc = usbd_xfer_get_frame(xfer, 0);
913 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_OUT)
914 usbd_copy_in(pc, 0, nx->nx_urbbuf, len);
915 usbd_xfer_set_frame_len(xfer, 0, len);
916 usbd_xfer_set_frames(xfer, 1);
917 usbd_transfer_submit(xfer);
920 nx = usbd_aq_getfirst(sc, ne);
923 if (error != USB_ERR_CANCELLED) {
924 usbd_xfer_set_stall(xfer);
925 device_printf(sc->ndis_dev, "usb xfer warning (%s)\n",
928 usbd_xfer_complete(sc, ne, nx, error);
929 if (error != USB_ERR_CANCELLED)
936 usbd_ctrl_callback(struct usb_xfer *xfer, usb_error_t error)
939 struct ndis_softc *sc = usbd_xfer_softc(xfer);
940 struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer);
941 struct ndisusb_xfer *nx;
944 struct usbd_urb_vendor_or_class_request *vcreq;
945 struct usb_page_cache *pc;
947 struct usb_device_request req;
950 switch (USB_GET_STATE(xfer)) {
951 case USB_ST_TRANSFERRED:
952 nx = usbd_aq_getfirst(sc, ne);
957 urb = usbd_geturb(ip);
958 vcreq = &urb->uu_vcreq;
960 if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
961 pc = usbd_xfer_get_frame(xfer, 1);
962 len = usbd_xfer_frame_len(xfer, 1);
963 usbd_copy_out(pc, 0, vcreq->uvc_trans_buf, len);
964 nx->nx_urbactlen += len;
967 usbd_xfer_complete(sc, ne, nx, USB_ERR_NORMAL_COMPLETION);
971 /* get next transfer */
972 KeAcquireSpinLock(&ne->ne_lock, &irql);
973 if (IsListEmpty(&ne->ne_pending)) {
974 KeReleaseSpinLock(&ne->ne_lock, irql);
977 nx = CONTAINING_RECORD(ne->ne_pending.nle_flink,
978 struct ndisusb_xfer, nx_next);
979 RemoveEntryList(&nx->nx_next);
980 /* add a entry to the active queue's tail. */
981 InsertTailList((&ne->ne_active), (&nx->nx_next));
982 KeReleaseSpinLock(&ne->ne_lock, irql);
985 urb = usbd_geturb(ip);
986 vcreq = &urb->uu_vcreq;
988 switch (urb->uu_hdr.uuh_func) {
989 case URB_FUNCTION_CLASS_DEVICE:
990 type = UT_CLASS | UT_DEVICE;
992 case URB_FUNCTION_CLASS_INTERFACE:
993 type = UT_CLASS | UT_INTERFACE;
995 case URB_FUNCTION_CLASS_OTHER:
996 type = UT_CLASS | UT_OTHER;
998 case URB_FUNCTION_CLASS_ENDPOINT:
999 type = UT_CLASS | UT_ENDPOINT;
1001 case URB_FUNCTION_VENDOR_DEVICE:
1002 type = UT_VENDOR | UT_DEVICE;
1004 case URB_FUNCTION_VENDOR_INTERFACE:
1005 type = UT_VENDOR | UT_INTERFACE;
1007 case URB_FUNCTION_VENDOR_OTHER:
1008 type = UT_VENDOR | UT_OTHER;
1010 case URB_FUNCTION_VENDOR_ENDPOINT:
1011 type = UT_VENDOR | UT_ENDPOINT;
1014 /* never reached. */
1018 type |= (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ?
1020 type |= vcreq->uvc_reserved1;
1022 req.bmRequestType = type;
1023 req.bRequest = vcreq->uvc_req;
1024 USETW(req.wIndex, vcreq->uvc_idx);
1025 USETW(req.wValue, vcreq->uvc_value);
1026 USETW(req.wLength, vcreq->uvc_trans_buflen);
1028 nx->nx_urbbuf = vcreq->uvc_trans_buf;
1029 nx->nx_urblen = vcreq->uvc_trans_buflen;
1030 nx->nx_urbactlen = 0;
1032 pc = usbd_xfer_get_frame(xfer, 0);
1033 usbd_copy_in(pc, 0, &req, sizeof(req));
1034 usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1035 usbd_xfer_set_frames(xfer, 1);
1036 if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
1037 if (vcreq->uvc_trans_buflen >= USBD_CTRL_READ_BUFFER_SP)
1038 device_printf(sc->ndis_dev,
1039 "warning: not enough buffer space (%d).\n",
1040 vcreq->uvc_trans_buflen);
1041 usbd_xfer_set_frame_len(xfer, 1,
1042 MIN(usbd_xfer_max_len(xfer),
1043 vcreq->uvc_trans_buflen));
1044 usbd_xfer_set_frames(xfer, 2);
1046 if (nx->nx_urblen > USBD_CTRL_WRITE_BUFFER_SP)
1047 device_printf(sc->ndis_dev,
1048 "warning: not enough write buffer space"
1049 " (%d).\n", nx->nx_urblen);
1051 * XXX with my local tests there was no cases to require
1052 * a extra buffer until now but it'd need to update in
1053 * the future if it needs to be.
1055 if (nx->nx_urblen > 0) {
1056 pc = usbd_xfer_get_frame(xfer, 1);
1057 usbd_copy_in(pc, 0, nx->nx_urbbuf,
1059 usbd_xfer_set_frame_len(xfer, 1, nx->nx_urblen);
1060 usbd_xfer_set_frames(xfer, 2);
1063 usbd_transfer_submit(xfer);
1066 nx = usbd_aq_getfirst(sc, ne);
1069 if (error != USB_ERR_CANCELLED) {
1070 usbd_xfer_set_stall(xfer);
1071 device_printf(sc->ndis_dev, "usb xfer warning (%s)\n",
1072 usbd_errstr(error));
1074 usbd_xfer_complete(sc, ne, nx, error);
1075 if (error != USB_ERR_CANCELLED)
1081 static struct ndisusb_ep *
1082 usbd_get_ndisep(irp *ip, usb_endpoint_descriptor_t *ep)
1084 device_t dev = IRP_NDIS_DEV(ip);
1085 struct ndis_softc *sc = device_get_softc(dev);
1086 struct ndisusb_ep *ne;
1088 ne = &sc->ndisusb_ep[NDISUSB_GET_ENDPT(ep->bEndpointAddress)];
1090 IRP_NDISUSB_EP(ip) = ne;
1091 ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap;
1097 usbd_xfertask(device_object *dobj, void *arg)
1103 struct ndis_softc *sc = arg;
1104 struct ndisusb_xferdone *nd;
1105 struct ndisusb_xfer *nq;
1106 struct usbd_urb_bulk_or_intr_transfer *ubi;
1107 struct usbd_urb_vendor_or_class_request *vcreq;
1108 union usbd_urb *urb;
1114 if (IsListEmpty(&sc->ndisusb_xferdonelist))
1117 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_xferdonelock);
1118 l = sc->ndisusb_xferdonelist.nle_flink;
1119 while (l != &sc->ndisusb_xferdonelist) {
1120 nd = CONTAINING_RECORD(l, struct ndisusb_xferdone, nd_donelist);
1123 status = nd->nd_status;
1126 urb = usbd_geturb(ip);
1128 ip->irp_cancelfunc = NULL;
1129 IRP_NDISUSB_EP(ip) = NULL;
1132 case USB_ERR_NORMAL_COMPLETION:
1133 if (urb->uu_hdr.uuh_func ==
1134 URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) {
1135 ubi = &urb->uu_bulkintr;
1136 ubi->ubi_trans_buflen = nq->nx_urbactlen;
1138 vcreq = &urb->uu_vcreq;
1139 vcreq->uvc_trans_buflen = nq->nx_urbactlen;
1141 ip->irp_iostat.isb_info = nq->nx_urbactlen;
1142 ip->irp_iostat.isb_status = STATUS_SUCCESS;
1143 USBD_URB_STATUS(urb) = USBD_STATUS_SUCCESS;
1145 case USB_ERR_CANCELLED:
1146 ip->irp_iostat.isb_info = 0;
1147 ip->irp_iostat.isb_status = STATUS_CANCELLED;
1148 USBD_URB_STATUS(urb) = USBD_STATUS_CANCELED;
1151 ip->irp_iostat.isb_info = 0;
1152 USBD_URB_STATUS(urb) = usbd_usb2urb(status);
1153 ip->irp_iostat.isb_status =
1154 usbd_urb2nt(USBD_URB_STATUS(urb));
1159 RemoveEntryList(&nd->nd_donelist);
1164 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_xferdonelock);
1165 /* NB: call after cleaning */
1166 IoCompleteRequest(ip, IO_NO_INCREMENT);
1167 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_xferdonelock);
1169 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_xferdonelock);
1173 * this function is for mainly deferring a task to the another thread because
1174 * we don't want to be in the scope of HAL lock.
1177 usbd_taskadd(irp *ip, unsigned type)
1179 device_t dev = IRP_NDIS_DEV(ip);
1180 struct ndis_softc *sc = device_get_softc(dev);
1181 struct ndisusb_task *nt;
1183 nt = malloc(sizeof(struct ndisusb_task), M_USBDEV, M_NOWAIT | M_ZERO);
1185 return (USBD_STATUS_NO_MEMORY);
1189 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock);
1190 InsertTailList((&sc->ndisusb_tasklist), (&nt->nt_tasklist));
1191 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock);
1193 IoQueueWorkItem(sc->ndisusb_taskitem,
1194 (io_workitem_func)usbd_task_wrap, WORKQUEUE_CRITICAL, sc);
1196 return (USBD_STATUS_SUCCESS);
1200 usbd_task(device_object *dobj, void *arg)
1204 struct ndis_softc *sc = arg;
1205 struct ndisusb_ep *ne;
1206 struct ndisusb_task *nt;
1207 union usbd_urb *urb;
1209 if (IsListEmpty(&sc->ndisusb_tasklist))
1212 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock);
1213 l = sc->ndisusb_tasklist.nle_flink;
1214 while (l != &sc->ndisusb_tasklist) {
1215 nt = CONTAINING_RECORD(l, struct ndisusb_task, nt_tasklist);
1218 urb = usbd_geturb(ip);
1220 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock);
1222 switch (nt->nt_type) {
1223 case NDISUSB_TASK_TSTART:
1224 ne = usbd_get_ndisep(ip, urb->uu_bulkintr.ubi_epdesc);
1227 usbd_transfer_start(ne->ne_xfer[0]);
1229 case NDISUSB_TASK_IRPCANCEL:
1230 ne = usbd_get_ndisep(ip,
1231 (nt->nt_type == NDISUSB_TASK_IRPCANCEL) ?
1232 urb->uu_bulkintr.ubi_epdesc :
1233 urb->uu_pipe.upr_handle);
1237 usbd_transfer_stop(ne->ne_xfer[0]);
1238 usbd_transfer_start(ne->ne_xfer[0]);
1240 case NDISUSB_TASK_VENDOR:
1241 ne = (urb->uu_vcreq.uvc_trans_flags &
1242 USBD_TRANSFER_DIRECTION_IN) ?
1243 &sc->ndisusb_dread_ep : &sc->ndisusb_dwrite_ep;
1244 usbd_transfer_start(ne->ne_xfer[0]);
1251 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock);
1254 RemoveEntryList(&nt->nt_tasklist);
1257 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock);
1261 usbd_func_bulkintr(irp *ip)
1264 struct ndisusb_ep *ne;
1265 struct ndisusb_xfer *nx;
1266 struct usbd_urb_bulk_or_intr_transfer *ubi;
1267 union usbd_urb *urb;
1268 usb_endpoint_descriptor_t *ep;
1270 urb = usbd_geturb(ip);
1271 ubi = &urb->uu_bulkintr;
1272 ep = ubi->ubi_epdesc;
1274 return (USBD_STATUS_INVALID_PIPE_HANDLE);
1276 ne = usbd_get_ndisep(ip, ep);
1278 device_printf(IRP_NDIS_DEV(ip), "get NULL endpoint info.\n");
1279 return (USBD_STATUS_INVALID_PIPE_HANDLE);
1282 nx = malloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO);
1284 device_printf(IRP_NDIS_DEV(ip), "out of memory\n");
1285 return (USBD_STATUS_NO_MEMORY);
1289 KeAcquireSpinLockAtDpcLevel(&ne->ne_lock);
1290 InsertTailList((&ne->ne_pending), (&nx->nx_next));
1291 KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
1293 /* we've done to setup xfer. Let's transfer it. */
1294 ip->irp_iostat.isb_status = STATUS_PENDING;
1295 ip->irp_iostat.isb_info = 0;
1296 USBD_URB_STATUS(urb) = USBD_STATUS_PENDING;
1297 IoMarkIrpPending(ip);
1299 error = usbd_taskadd(ip, NDISUSB_TASK_TSTART);
1300 if (error != USBD_STATUS_SUCCESS)
1303 return (USBD_STATUS_PENDING);
1306 static union usbd_urb *
1307 USBD_CreateConfigurationRequest(usb_config_descriptor_t *conf, uint16_t *len)
1309 struct usbd_interface_list_entry list[2];
1310 union usbd_urb *urb;
1312 bzero(list, sizeof(struct usbd_interface_list_entry) * 2);
1313 list[0].uil_intfdesc = USBD_ParseConfigurationDescriptorEx(conf, conf,
1314 -1, -1, -1, -1, -1);
1315 urb = USBD_CreateConfigurationRequestEx(conf, list);
1319 *len = urb->uu_selconf.usc_hdr.uuh_len;
1323 static union usbd_urb *
1324 USBD_CreateConfigurationRequestEx(usb_config_descriptor_t *conf,
1325 struct usbd_interface_list_entry *list)
1328 struct usbd_interface_information *intf;
1329 struct usbd_pipe_information *pipe;
1330 struct usbd_urb_select_configuration *selconf;
1331 usb_interface_descriptor_t *desc;
1333 for (i = 0, size = 0; i < conf->bNumInterface; i++) {
1334 j = list[i].uil_intfdesc->bNumEndpoints;
1335 size = size + sizeof(struct usbd_interface_information) +
1336 sizeof(struct usbd_pipe_information) * (j - 1);
1338 size += sizeof(struct usbd_urb_select_configuration) -
1339 sizeof(struct usbd_interface_information);
1341 selconf = ExAllocatePoolWithTag(NonPagedPool, size, 0);
1342 if (selconf == NULL)
1344 selconf->usc_hdr.uuh_func = URB_FUNCTION_SELECT_CONFIGURATION;
1345 selconf->usc_hdr.uuh_len = size;
1346 selconf->usc_handle = conf;
1347 selconf->usc_conf = conf;
1349 intf = &selconf->usc_intf;
1350 for (i = 0; i < conf->bNumInterface; i++) {
1351 if (list[i].uil_intfdesc == NULL)
1354 list[i].uil_intf = intf;
1355 desc = list[i].uil_intfdesc;
1357 intf->uii_len = sizeof(struct usbd_interface_information) +
1358 (desc->bNumEndpoints - 1) *
1359 sizeof(struct usbd_pipe_information);
1360 intf->uii_intfnum = desc->bInterfaceNumber;
1361 intf->uii_altset = desc->bAlternateSetting;
1362 intf->uii_intfclass = desc->bInterfaceClass;
1363 intf->uii_intfsubclass = desc->bInterfaceSubClass;
1364 intf->uii_intfproto = desc->bInterfaceProtocol;
1365 intf->uii_handle = desc;
1366 intf->uii_numeps = desc->bNumEndpoints;
1368 pipe = &intf->uii_pipes[0];
1369 for (j = 0; j < intf->uii_numeps; j++)
1370 pipe[j].upi_maxtxsize =
1371 USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
1373 intf = (struct usbd_interface_information *)((char *)intf +
1377 return ((union usbd_urb *)selconf);
1381 USBD_GetUSBDIVersion(usbd_version_info *ui)
1384 /* Pretend to be Windows XP. */
1386 ui->uvi_usbdi_vers = USBDI_VERSION;
1387 ui->uvi_supported_vers = USB_VER_2_0;
1390 static usb_interface_descriptor_t *
1391 USBD_ParseConfigurationDescriptor(usb_config_descriptor_t *conf,
1392 uint8_t intfnum, uint8_t altset)
1395 return USBD_ParseConfigurationDescriptorEx(conf, conf, intfnum, altset,
1399 static usb_interface_descriptor_t *
1400 USBD_ParseConfigurationDescriptorEx(usb_config_descriptor_t *conf,
1401 void *start, int32_t intfnum, int32_t altset, int32_t intfclass,
1402 int32_t intfsubclass, int32_t intfproto)
1404 struct usb_descriptor *next = NULL;
1405 usb_interface_descriptor_t *desc;
1407 while ((next = usb_desc_foreach(conf, next)) != NULL) {
1408 desc = (usb_interface_descriptor_t *)next;
1409 if (desc->bDescriptorType != UDESC_INTERFACE)
1411 if (!(intfnum == -1 || desc->bInterfaceNumber == intfnum))
1413 if (!(altset == -1 || desc->bAlternateSetting == altset))
1415 if (!(intfclass == -1 || desc->bInterfaceClass == intfclass))
1417 if (!(intfsubclass == -1 ||
1418 desc->bInterfaceSubClass == intfsubclass))
1420 if (!(intfproto == -1 || desc->bInterfaceProtocol == intfproto))
1431 printf("USBD dummy called\n");
1434 image_patch_table usbd_functbl[] = {
1435 IMPORT_SFUNC(USBD_CreateConfigurationRequest, 2),
1436 IMPORT_SFUNC(USBD_CreateConfigurationRequestEx, 2),
1437 IMPORT_SFUNC_MAP(_USBD_CreateConfigurationRequestEx@8,
1438 USBD_CreateConfigurationRequestEx, 2),
1439 IMPORT_SFUNC(USBD_GetUSBDIVersion, 1),
1440 IMPORT_SFUNC(USBD_ParseConfigurationDescriptor, 3),
1441 IMPORT_SFUNC(USBD_ParseConfigurationDescriptorEx, 7),
1442 IMPORT_SFUNC_MAP(_USBD_ParseConfigurationDescriptorEx@28,
1443 USBD_ParseConfigurationDescriptorEx, 7),
1446 * This last entry is a catch-all for any function we haven't
1447 * implemented yet. The PE import list patching routine will
1448 * use it for any function that doesn't have an explicit match
1452 { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL },
1456 { NULL, NULL, NULL }
1459 MODULE_DEPEND(ndis, usb, 1, 1, 1);