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_media.h>
58 #include <net80211/ieee80211_var.h>
59 #include <net80211/ieee80211_ioctl.h>
61 #include <dev/usb/usb.h>
62 #include <dev/usb/usbdi.h>
63 #include <dev/usb/usbdi_util.h>
64 #include <dev/usb/usb_busdma.h>
65 #include <dev/usb/usb_device.h>
66 #include <dev/usb/usb_request.h>
68 #include <compat/ndis/pe_var.h>
69 #include <compat/ndis/cfg_var.h>
70 #include <compat/ndis/resource_var.h>
71 #include <compat/ndis/ntoskrnl_var.h>
72 #include <compat/ndis/ndis_var.h>
73 #include <compat/ndis/hal_var.h>
74 #include <compat/ndis/usbd_var.h>
75 #include <dev/if_ndis/if_ndisvar.h>
77 static driver_object usbd_driver;
78 static usb_callback_t usbd_non_isoc_callback;
79 static usb_callback_t usbd_ctrl_callback;
81 #define USBD_CTRL_READ_PIPE 0
82 #define USBD_CTRL_WRITE_PIPE 1
83 #define USBD_CTRL_MAX_PIPE 2
84 #define USBD_CTRL_READ_BUFFER_SP 256
85 #define USBD_CTRL_WRITE_BUFFER_SP 256
86 #define USBD_CTRL_READ_BUFFER_SIZE \
87 (sizeof(struct usb_device_request) + USBD_CTRL_READ_BUFFER_SP)
88 #define USBD_CTRL_WRITE_BUFFER_SIZE \
89 (sizeof(struct usb_device_request) + USBD_CTRL_WRITE_BUFFER_SP)
90 static struct usb_config usbd_default_epconfig[USBD_CTRL_MAX_PIPE] = {
91 [USBD_CTRL_READ_PIPE] = {
93 .endpoint = 0x00, /* control pipe */
94 .direction = UE_DIR_ANY,
96 .bufsize = USBD_CTRL_READ_BUFFER_SIZE,
97 .flags = { .short_xfer_ok = 1, },
98 .callback = &usbd_ctrl_callback,
99 .timeout = 5000, /* 5 seconds */
101 [USBD_CTRL_WRITE_PIPE] = {
103 .endpoint = 0x00, /* control pipe */
104 .direction = UE_DIR_ANY,
106 .bufsize = USBD_CTRL_WRITE_BUFFER_SIZE,
107 .flags = { .proxy_buffer = 1, },
108 .callback = &usbd_ctrl_callback,
109 .timeout = 5000, /* 5 seconds */
113 static int32_t usbd_func_bulkintr(irp *);
114 static int32_t usbd_func_vendorclass(irp *);
115 static int32_t usbd_func_selconf(irp *);
116 static int32_t usbd_func_abort_pipe(irp *);
117 static usb_error_t usbd_setup_endpoint(irp *, uint8_t,
118 struct usb_endpoint_descriptor *);
119 static usb_error_t usbd_setup_endpoint_default(irp *, uint8_t);
120 static usb_error_t usbd_setup_endpoint_one(irp *, uint8_t,
121 struct ndisusb_ep *, struct usb_config *);
122 static int32_t usbd_func_getdesc(irp *);
123 static union usbd_urb *usbd_geturb(irp *);
124 static struct ndisusb_ep*usbd_get_ndisep(irp *, usb_endpoint_descriptor_t *);
125 static int32_t usbd_iodispatch(device_object *, irp *);
126 static int32_t usbd_ioinvalid(device_object *, irp *);
127 static int32_t usbd_pnp(device_object *, irp *);
128 static int32_t usbd_power(device_object *, irp *);
129 static void usbd_irpcancel(device_object *, irp *);
130 static int32_t usbd_submit_urb(irp *);
131 static int32_t usbd_urb2nt(int32_t);
132 static void usbd_task(device_object *, void *);
133 static int32_t usbd_taskadd(irp *, unsigned);
134 static void usbd_xfertask(device_object *, void *);
135 static void dummy(void);
137 static union usbd_urb *USBD_CreateConfigurationRequestEx(
138 usb_config_descriptor_t *,
139 struct usbd_interface_list_entry *);
140 static union usbd_urb *USBD_CreateConfigurationRequest(
141 usb_config_descriptor_t *,
143 static void USBD_GetUSBDIVersion(usbd_version_info *);
144 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptorEx(
145 usb_config_descriptor_t *, void *, int32_t, int32_t,
146 int32_t, int32_t, int32_t);
147 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptor(
148 usb_config_descriptor_t *, uint8_t, uint8_t);
151 * We need to wrap these functions because these need `context switch' from
152 * Windows to UNIX before it's called.
154 static funcptr usbd_iodispatch_wrap;
155 static funcptr usbd_ioinvalid_wrap;
156 static funcptr usbd_pnp_wrap;
157 static funcptr usbd_power_wrap;
158 static funcptr usbd_irpcancel_wrap;
159 static funcptr usbd_task_wrap;
160 static funcptr usbd_xfertask_wrap;
165 image_patch_table *patch;
168 patch = usbd_functbl;
169 while (patch->ipt_func != NULL) {
170 windrv_wrap((funcptr)patch->ipt_func,
171 (funcptr *)&patch->ipt_wrap,
172 patch->ipt_argcnt, patch->ipt_ftype);
176 windrv_wrap((funcptr)usbd_ioinvalid,
177 (funcptr *)&usbd_ioinvalid_wrap, 2, WINDRV_WRAP_STDCALL);
178 windrv_wrap((funcptr)usbd_iodispatch,
179 (funcptr *)&usbd_iodispatch_wrap, 2, WINDRV_WRAP_STDCALL);
180 windrv_wrap((funcptr)usbd_pnp,
181 (funcptr *)&usbd_pnp_wrap, 2, WINDRV_WRAP_STDCALL);
182 windrv_wrap((funcptr)usbd_power,
183 (funcptr *)&usbd_power_wrap, 2, WINDRV_WRAP_STDCALL);
184 windrv_wrap((funcptr)usbd_irpcancel,
185 (funcptr *)&usbd_irpcancel_wrap, 2, WINDRV_WRAP_STDCALL);
186 windrv_wrap((funcptr)usbd_task,
187 (funcptr *)&usbd_task_wrap, 2, WINDRV_WRAP_STDCALL);
188 windrv_wrap((funcptr)usbd_xfertask,
189 (funcptr *)&usbd_xfertask_wrap, 2, WINDRV_WRAP_STDCALL);
191 /* Create a fake USB driver instance. */
193 windrv_bus_attach(&usbd_driver, "USB Bus");
195 /* Set up our dipatch routine. */
196 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
197 usbd_driver.dro_dispatch[i] =
198 (driver_dispatch)usbd_ioinvalid_wrap;
200 usbd_driver.dro_dispatch[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
201 (driver_dispatch)usbd_iodispatch_wrap;
202 usbd_driver.dro_dispatch[IRP_MJ_DEVICE_CONTROL] =
203 (driver_dispatch)usbd_iodispatch_wrap;
204 usbd_driver.dro_dispatch[IRP_MJ_POWER] =
205 (driver_dispatch)usbd_power_wrap;
206 usbd_driver.dro_dispatch[IRP_MJ_PNP] =
207 (driver_dispatch)usbd_pnp_wrap;
215 image_patch_table *patch;
217 patch = usbd_functbl;
218 while (patch->ipt_func != NULL) {
219 windrv_unwrap(patch->ipt_wrap);
223 windrv_unwrap(usbd_ioinvalid_wrap);
224 windrv_unwrap(usbd_iodispatch_wrap);
225 windrv_unwrap(usbd_pnp_wrap);
226 windrv_unwrap(usbd_power_wrap);
227 windrv_unwrap(usbd_irpcancel_wrap);
228 windrv_unwrap(usbd_task_wrap);
229 windrv_unwrap(usbd_xfertask_wrap);
231 free(usbd_driver.dro_drivername.us_buf, M_DEVBUF);
237 usbd_iodispatch(dobj, ip)
241 device_t dev = dobj->do_devext;
243 struct io_stack_location *irp_sl;
245 irp_sl = IoGetCurrentIrpStackLocation(ip);
246 switch (irp_sl->isl_parameters.isl_ioctl.isl_iocode) {
247 case IOCTL_INTERNAL_USB_SUBMIT_URB:
248 IRP_NDIS_DEV(ip) = dev;
250 status = usbd_submit_urb(ip);
253 device_printf(dev, "ioctl 0x%x isn't supported\n",
254 irp_sl->isl_parameters.isl_ioctl.isl_iocode);
255 status = USBD_STATUS_NOT_SUPPORTED;
259 if (status == USBD_STATUS_PENDING)
260 return (STATUS_PENDING);
262 ip->irp_iostat.isb_status = usbd_urb2nt(status);
263 if (status != USBD_STATUS_SUCCESS)
264 ip->irp_iostat.isb_info = 0;
265 return (ip->irp_iostat.isb_status);
269 usbd_ioinvalid(dobj, ip)
273 device_t dev = dobj->do_devext;
274 struct io_stack_location *irp_sl;
276 irp_sl = IoGetCurrentIrpStackLocation(ip);
277 device_printf(dev, "invalid I/O dispatch %d:%d\n", irp_sl->isl_major,
280 ip->irp_iostat.isb_status = STATUS_FAILURE;
281 ip->irp_iostat.isb_info = 0;
283 IoCompleteRequest(ip, IO_NO_INCREMENT);
285 return (STATUS_FAILURE);
293 device_t dev = dobj->do_devext;
294 struct io_stack_location *irp_sl;
296 irp_sl = IoGetCurrentIrpStackLocation(ip);
297 device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
298 __func__, irp_sl->isl_major, irp_sl->isl_minor);
300 ip->irp_iostat.isb_status = STATUS_FAILURE;
301 ip->irp_iostat.isb_info = 0;
303 IoCompleteRequest(ip, IO_NO_INCREMENT);
305 return (STATUS_FAILURE);
313 device_t dev = dobj->do_devext;
314 struct io_stack_location *irp_sl;
316 irp_sl = IoGetCurrentIrpStackLocation(ip);
317 device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
318 __func__, irp_sl->isl_major, irp_sl->isl_minor);
320 ip->irp_iostat.isb_status = STATUS_FAILURE;
321 ip->irp_iostat.isb_info = 0;
323 IoCompleteRequest(ip, IO_NO_INCREMENT);
325 return (STATUS_FAILURE);
328 /* Convert USBD_STATUS to NTSTATUS */
335 case USBD_STATUS_SUCCESS:
336 return (STATUS_SUCCESS);
337 case USBD_STATUS_DEVICE_GONE:
338 return (STATUS_DEVICE_NOT_CONNECTED);
339 case USBD_STATUS_PENDING:
340 return (STATUS_PENDING);
341 case USBD_STATUS_NOT_SUPPORTED:
342 return (STATUS_NOT_IMPLEMENTED);
343 case USBD_STATUS_NO_MEMORY:
344 return (STATUS_NO_MEMORY);
345 case USBD_STATUS_REQUEST_FAILED:
346 return (STATUS_NOT_SUPPORTED);
347 case USBD_STATUS_CANCELED:
348 return (STATUS_CANCELLED);
353 return (STATUS_FAILURE);
356 /* Convert FreeBSD's usb_error_t to USBD_STATUS */
358 usbd_usb2urb(int status)
362 case USB_ERR_NORMAL_COMPLETION:
363 return (USBD_STATUS_SUCCESS);
364 case USB_ERR_PENDING_REQUESTS:
365 return (USBD_STATUS_PENDING);
366 case USB_ERR_TIMEOUT:
367 return (USBD_STATUS_TIMEOUT);
368 case USB_ERR_SHORT_XFER:
369 return (USBD_STATUS_ERROR_SHORT_TRANSFER);
370 case USB_ERR_IOERROR:
371 return (USBD_STATUS_XACT_ERROR);
373 return (USBD_STATUS_NO_MEMORY);
375 return (USBD_STATUS_REQUEST_FAILED);
376 case USB_ERR_NOT_STARTED:
377 case USB_ERR_TOO_DEEP:
378 case USB_ERR_NO_POWER:
379 return (USBD_STATUS_DEVICE_GONE);
380 case USB_ERR_CANCELLED:
381 return (USBD_STATUS_CANCELED);
386 return (USBD_STATUS_NOT_SUPPORTED);
389 static union usbd_urb *
393 struct io_stack_location *irp_sl;
395 irp_sl = IoGetCurrentIrpStackLocation(ip);
397 return (irp_sl->isl_parameters.isl_others.isl_arg1);
404 device_t dev = IRP_NDIS_DEV(ip);
408 urb = usbd_geturb(ip);
410 * In a case of URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
411 * USBD_URB_STATUS(urb) would be set at callback functions like
412 * usbd_intr() or usbd_xfereof().
414 switch (urb->uu_hdr.uuh_func) {
415 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
416 status = usbd_func_bulkintr(ip);
417 if (status != USBD_STATUS_SUCCESS &&
418 status != USBD_STATUS_PENDING)
419 USBD_URB_STATUS(urb) = status;
421 case URB_FUNCTION_VENDOR_DEVICE:
422 case URB_FUNCTION_VENDOR_INTERFACE:
423 case URB_FUNCTION_VENDOR_ENDPOINT:
424 case URB_FUNCTION_VENDOR_OTHER:
425 case URB_FUNCTION_CLASS_DEVICE:
426 case URB_FUNCTION_CLASS_INTERFACE:
427 case URB_FUNCTION_CLASS_ENDPOINT:
428 case URB_FUNCTION_CLASS_OTHER:
429 status = usbd_func_vendorclass(ip);
430 USBD_URB_STATUS(urb) = status;
432 case URB_FUNCTION_SELECT_CONFIGURATION:
433 status = usbd_func_selconf(ip);
434 USBD_URB_STATUS(urb) = status;
436 case URB_FUNCTION_ABORT_PIPE:
437 status = usbd_func_abort_pipe(ip);
438 USBD_URB_STATUS(urb) = status;
440 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
441 status = usbd_func_getdesc(ip);
442 USBD_URB_STATUS(urb) = status;
445 device_printf(dev, "func 0x%x isn't supported\n",
446 urb->uu_hdr.uuh_func);
447 USBD_URB_STATUS(urb) = status = USBD_STATUS_NOT_SUPPORTED;
455 usbd_func_getdesc(ip)
458 #define NDISUSB_GETDESC_MAXRETRIES 3
459 device_t dev = IRP_NDIS_DEV(ip);
460 struct ndis_softc *sc = device_get_softc(dev);
461 struct usbd_urb_control_descriptor_request *ctldesc;
465 usb_config_descriptor_t *cdp;
468 urb = usbd_geturb(ip);
469 ctldesc = &urb->uu_ctldesc;
470 if (ctldesc->ucd_desctype == UDESC_CONFIG) {
472 * The NDIS driver is not allowed to change the
473 * config! There is only one choice!
475 cdp = usbd_get_config_descriptor(sc->ndisusb_dev);
477 status = USB_ERR_INVAL;
480 if (cdp->bDescriptorType != UDESC_CONFIG) {
481 device_printf(dev, "bad desc %d\n",
482 cdp->bDescriptorType);
483 status = USB_ERR_INVAL;
486 /* get minimum length */
487 len = MIN(UGETW(cdp->wTotalLength), ctldesc->ucd_trans_buflen);
488 /* copy out config descriptor */
489 memcpy(ctldesc->ucd_trans_buf, cdp, len);
490 /* set actual length */
492 status = USB_ERR_NORMAL_COMPLETION;
495 status = usbd_req_get_desc(sc->ndisusb_dev, &sc->ndisusb_mtx,
496 &actlen, ctldesc->ucd_trans_buf, 2,
497 ctldesc->ucd_trans_buflen, ctldesc->ucd_langid,
498 ctldesc->ucd_desctype, ctldesc->ucd_idx,
499 NDISUSB_GETDESC_MAXRETRIES);
503 if (status != USB_ERR_NORMAL_COMPLETION) {
504 ctldesc->ucd_trans_buflen = 0;
505 return usbd_usb2urb(status);
508 ctldesc->ucd_trans_buflen = actlen;
509 ip->irp_iostat.isb_info = actlen;
511 return (USBD_STATUS_SUCCESS);
512 #undef NDISUSB_GETDESC_MAXRETRIES
516 usbd_func_selconf(ip)
519 device_t dev = IRP_NDIS_DEV(ip);
521 struct ndis_softc *sc = device_get_softc(dev);
522 struct usb_device *udev = sc->ndisusb_dev;
523 struct usb_endpoint *ep = NULL;
524 struct usbd_interface_information *intf;
525 struct usbd_pipe_information *pipe;
526 struct usbd_urb_select_configuration *selconf;
528 usb_config_descriptor_t *conf;
529 usb_endpoint_descriptor_t *edesc;
532 urb = usbd_geturb(ip);
534 selconf = &urb->uu_selconf;
535 conf = selconf->usc_conf;
537 device_printf(dev, "select configuration is NULL\n");
538 return usbd_usb2urb(USB_ERR_NORMAL_COMPLETION);
541 intf = &selconf->usc_intf;
542 for (i = 0; i < conf->bNumInterface && intf->uii_len > 0; i++) {
543 ret = usbd_set_alt_interface_index(udev,
544 intf->uii_intfnum, intf->uii_altset);
545 if (ret != USB_ERR_NORMAL_COMPLETION && ret != USB_ERR_IN_USE) {
547 "setting alternate interface failed: %s\n",
549 return usbd_usb2urb(ret);
552 for (j = 0; (ep = usb_endpoint_foreach(udev, ep)); j++) {
553 if (j >= intf->uii_numeps) {
555 "endpoint %d and above are ignored",
560 pipe = &intf->uii_pipes[j];
561 pipe->upi_handle = edesc;
562 pipe->upi_epaddr = edesc->bEndpointAddress;
563 pipe->upi_maxpktsize = UGETW(edesc->wMaxPacketSize);
564 pipe->upi_type = UE_GET_XFERTYPE(edesc->bmAttributes);
566 ret = usbd_setup_endpoint(ip, intf->uii_intfnum, edesc);
567 if (ret != USB_ERR_NORMAL_COMPLETION)
568 return usbd_usb2urb(ret);
570 if (pipe->upi_type != UE_INTERRUPT)
573 /* XXX we're following linux USB's interval policy. */
574 if (udev->speed == USB_SPEED_LOW)
575 pipe->upi_interval = edesc->bInterval + 5;
576 else if (udev->speed == USB_SPEED_FULL)
577 pipe->upi_interval = edesc->bInterval;
583 } while (k1 < edesc->bInterval);
584 pipe->upi_interval = k0;
588 intf = (struct usbd_interface_information *)(((char *)intf) +
592 return USBD_STATUS_SUCCESS;
596 usbd_setup_endpoint_one(ip, ifidx, ne, epconf)
599 struct ndisusb_ep *ne;
600 struct usb_config *epconf;
602 device_t dev = IRP_NDIS_DEV(ip);
603 struct ndis_softc *sc = device_get_softc(dev);
604 struct usb_xfer *xfer;
607 InitializeListHead(&ne->ne_active);
608 InitializeListHead(&ne->ne_pending);
609 KeInitializeSpinLock(&ne->ne_lock);
611 status = usbd_transfer_setup(sc->ndisusb_dev, &ifidx, ne->ne_xfer,
612 epconf, 1, sc, &sc->ndisusb_mtx);
613 if (status != USB_ERR_NORMAL_COMPLETION) {
614 device_printf(dev, "couldn't setup xfer: %s\n",
615 usbd_errstr(status));
618 xfer = ne->ne_xfer[0];
619 usbd_xfer_set_priv(xfer, ne);
625 usbd_setup_endpoint_default(ip, ifidx)
629 device_t dev = IRP_NDIS_DEV(ip);
630 struct ndis_softc *sc = device_get_softc(dev);
634 device_printf(dev, "warning: ifidx > 0 isn't supported.\n");
636 status = usbd_setup_endpoint_one(ip, ifidx, &sc->ndisusb_dread_ep,
637 &usbd_default_epconfig[USBD_CTRL_READ_PIPE]);
638 if (status != USB_ERR_NORMAL_COMPLETION)
641 status = usbd_setup_endpoint_one(ip, ifidx, &sc->ndisusb_dwrite_ep,
642 &usbd_default_epconfig[USBD_CTRL_WRITE_PIPE]);
647 usbd_setup_endpoint(ip, ifidx, ep)
650 struct usb_endpoint_descriptor *ep;
652 device_t dev = IRP_NDIS_DEV(ip);
653 struct ndis_softc *sc = device_get_softc(dev);
654 struct ndisusb_ep *ne;
655 struct usb_config cfg;
656 struct usb_xfer *xfer;
659 /* check for non-supported transfer types */
660 if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_CONTROL ||
661 UE_GET_XFERTYPE(ep->bmAttributes) == UE_ISOCHRONOUS) {
662 device_printf(dev, "%s: unsuppotted transfer types %#x\n",
663 __func__, UE_GET_XFERTYPE(ep->bmAttributes));
664 return (USB_ERR_INVAL);
667 ne = &sc->ndisusb_ep[NDISUSB_GET_ENDPT(ep->bEndpointAddress)];
668 InitializeListHead(&ne->ne_active);
669 InitializeListHead(&ne->ne_pending);
670 KeInitializeSpinLock(&ne->ne_lock);
671 ne->ne_dirin = UE_GET_DIR(ep->bEndpointAddress) >> 7;
673 memset(&cfg, 0, sizeof(struct usb_config));
674 cfg.type = UE_GET_XFERTYPE(ep->bmAttributes);
675 cfg.endpoint = UE_GET_ADDR(ep->bEndpointAddress);
676 cfg.direction = UE_GET_DIR(ep->bEndpointAddress);
677 cfg.callback = &usbd_non_isoc_callback;
678 cfg.bufsize = UGETW(ep->wMaxPacketSize);
679 cfg.flags.proxy_buffer = 1;
680 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
681 cfg.flags.short_xfer_ok = 1;
683 status = usbd_transfer_setup(sc->ndisusb_dev, &ifidx, ne->ne_xfer,
684 &cfg, 1, sc, &sc->ndisusb_mtx);
685 if (status != USB_ERR_NORMAL_COMPLETION) {
686 device_printf(dev, "couldn't setup xfer: %s\n",
687 usbd_errstr(status));
690 xfer = ne->ne_xfer[0];
691 usbd_xfer_set_priv(xfer, ne);
692 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
693 usbd_xfer_set_timeout(xfer, NDISUSB_NO_TIMEOUT);
695 if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_BULK)
696 usbd_xfer_set_timeout(xfer, NDISUSB_TX_TIMEOUT);
698 usbd_xfer_set_timeout(xfer, NDISUSB_INTR_TIMEOUT);
705 usbd_func_abort_pipe(ip)
708 device_t dev = IRP_NDIS_DEV(ip);
709 struct ndis_softc *sc = device_get_softc(dev);
710 struct ndisusb_ep *ne;
713 urb = usbd_geturb(ip);
714 ne = usbd_get_ndisep(ip, urb->uu_pipe.upr_handle);
716 device_printf(IRP_NDIS_DEV(ip), "get NULL endpoint info.\n");
717 return (USBD_STATUS_INVALID_PIPE_HANDLE);
721 usbd_transfer_stop(ne->ne_xfer[0]);
722 usbd_transfer_start(ne->ne_xfer[0]);
725 return (USBD_STATUS_SUCCESS);
729 usbd_func_vendorclass(ip)
732 device_t dev = IRP_NDIS_DEV(ip);
734 struct ndis_softc *sc = device_get_softc(dev);
735 struct ndisusb_ep *ne;
736 struct ndisusb_xfer *nx;
737 struct usbd_urb_vendor_or_class_request *vcreq;
740 if (!(sc->ndisusb_status & NDISUSB_STATUS_SETUP_EP)) {
742 * XXX In some cases the interface number isn't 0. However
743 * some driver (eg. RTL8187L NDIS driver) calls this function
744 * before calling URB_FUNCTION_SELECT_CONFIGURATION.
746 error = usbd_setup_endpoint_default(ip, 0);
747 if (error != USB_ERR_NORMAL_COMPLETION)
748 return usbd_usb2urb(error);
749 sc->ndisusb_status |= NDISUSB_STATUS_SETUP_EP;
752 urb = usbd_geturb(ip);
753 vcreq = &urb->uu_vcreq;
754 ne = (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ?
755 &sc->ndisusb_dread_ep : &sc->ndisusb_dwrite_ep;
756 IRP_NDISUSB_EP(ip) = ne;
757 ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap;
759 nx = malloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO);
761 device_printf(IRP_NDIS_DEV(ip), "out of memory\n");
762 return (USBD_STATUS_NO_MEMORY);
766 KeAcquireSpinLockAtDpcLevel(&ne->ne_lock);
767 InsertTailList((&ne->ne_pending), (&nx->nx_next));
768 KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
770 /* we've done to setup xfer. Let's transfer it. */
771 ip->irp_iostat.isb_status = STATUS_PENDING;
772 ip->irp_iostat.isb_info = 0;
773 USBD_URB_STATUS(urb) = USBD_STATUS_PENDING;
774 IoMarkIrpPending(ip);
776 error = usbd_taskadd(ip, NDISUSB_TASK_VENDOR);
777 if (error != USBD_STATUS_SUCCESS)
780 return (USBD_STATUS_PENDING);
784 usbd_irpcancel(dobj, ip)
788 device_t dev = IRP_NDIS_DEV(ip);
789 struct ndis_softc *sc = device_get_softc(dev);
790 struct ndisusb_ep *ne = IRP_NDISUSB_EP(ip);
793 ip->irp_cancel = TRUE;
794 IoReleaseCancelSpinLock(ip->irp_cancelirql);
799 * Make sure that the current USB transfer proxy is
800 * cancelled and then restarted.
803 usbd_transfer_stop(ne->ne_xfer[0]);
804 usbd_transfer_start(ne->ne_xfer[0]);
807 ip->irp_cancel = TRUE;
808 IoReleaseCancelSpinLock(ip->irp_cancelirql);
812 usbd_xfer_complete(struct ndis_softc *sc, struct ndisusb_ep *ne,
813 struct ndisusb_xfer *nx, usb_error_t status)
815 struct ndisusb_xferdone *nd;
818 nd = malloc(sizeof(struct ndisusb_xferdone), M_USBDEV,
821 device_printf(sc->ndis_dev, "out of memory");
825 nd->nd_status = status;
827 KeAcquireSpinLock(&sc->ndisusb_xferdonelock, &irql);
828 InsertTailList((&sc->ndisusb_xferdonelist), (&nd->nd_donelist));
829 KeReleaseSpinLock(&sc->ndisusb_xferdonelock, irql);
831 IoQueueWorkItem(sc->ndisusb_xferdoneitem,
832 (io_workitem_func)usbd_xfertask_wrap, WORKQUEUE_CRITICAL, sc);
835 static struct ndisusb_xfer *
836 usbd_aq_getfirst(struct ndis_softc *sc, struct ndisusb_ep *ne)
838 struct ndisusb_xfer *nx;
840 KeAcquireSpinLockAtDpcLevel(&ne->ne_lock);
841 if (IsListEmpty(&ne->ne_active)) {
842 device_printf(sc->ndis_dev,
843 "%s: the active queue can't be empty.\n", __func__);
844 KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
847 nx = CONTAINING_RECORD(ne->ne_active.nle_flink, struct ndisusb_xfer,
849 RemoveEntryList(&nx->nx_next);
850 KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
856 usbd_non_isoc_callback(struct usb_xfer *xfer, usb_error_t error)
859 struct ndis_softc *sc = usbd_xfer_softc(xfer);
860 struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer);
861 struct ndisusb_xfer *nx;
862 struct usbd_urb_bulk_or_intr_transfer *ubi;
863 struct usb_page_cache *pc;
867 usb_endpoint_descriptor_t *ep;
870 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
872 switch (USB_GET_STATE(xfer)) {
873 case USB_ST_TRANSFERRED:
874 nx = usbd_aq_getfirst(sc, ne);
875 pc = usbd_xfer_get_frame(xfer, 0);
879 /* copy in data with regard to the URB */
880 if (ne->ne_dirin != 0)
881 usbd_copy_out(pc, 0, nx->nx_urbbuf, actlen);
882 nx->nx_urbbuf += actlen;
883 nx->nx_urbactlen += actlen;
884 nx->nx_urblen -= actlen;
886 /* check for short transfer */
890 /* check remainder */
891 if (nx->nx_urblen > 0) {
892 KeAcquireSpinLock(&ne->ne_lock, &irql);
893 InsertHeadList((&ne->ne_active), (&nx->nx_next));
894 KeReleaseSpinLock(&ne->ne_lock, irql);
897 urb = usbd_geturb(ip);
898 ubi = &urb->uu_bulkintr;
899 ep = ubi->ubi_epdesc;
903 usbd_xfer_complete(sc, ne, nx,
904 ((actlen < sumlen) && (nx->nx_shortxfer == 0)) ?
905 USB_ERR_SHORT_XFER : USB_ERR_NORMAL_COMPLETION);
910 /* get next transfer */
911 KeAcquireSpinLock(&ne->ne_lock, &irql);
912 if (IsListEmpty(&ne->ne_pending)) {
913 KeReleaseSpinLock(&ne->ne_lock, irql);
916 nx = CONTAINING_RECORD(ne->ne_pending.nle_flink,
917 struct ndisusb_xfer, nx_next);
918 RemoveEntryList(&nx->nx_next);
919 /* add a entry to the active queue's tail. */
920 InsertTailList((&ne->ne_active), (&nx->nx_next));
921 KeReleaseSpinLock(&ne->ne_lock, irql);
924 urb = usbd_geturb(ip);
925 ubi = &urb->uu_bulkintr;
926 ep = ubi->ubi_epdesc;
928 nx->nx_urbbuf = ubi->ubi_trans_buf;
929 nx->nx_urbactlen = 0;
930 nx->nx_urblen = ubi->ubi_trans_buflen;
931 nx->nx_shortxfer = (ubi->ubi_trans_flags &
932 USBD_SHORT_TRANSFER_OK) ? 1 : 0;
934 len = MIN(usbd_xfer_max_len(xfer), nx->nx_urblen);
935 pc = usbd_xfer_get_frame(xfer, 0);
936 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_OUT)
937 usbd_copy_in(pc, 0, nx->nx_urbbuf, len);
938 usbd_xfer_set_frame_len(xfer, 0, len);
939 usbd_xfer_set_frames(xfer, 1);
940 usbd_transfer_submit(xfer);
943 nx = usbd_aq_getfirst(sc, ne);
946 if (error != USB_ERR_CANCELLED) {
947 usbd_xfer_set_stall(xfer);
948 device_printf(sc->ndis_dev, "usb xfer warning (%s)\n",
951 usbd_xfer_complete(sc, ne, nx, error);
952 if (error != USB_ERR_CANCELLED)
959 usbd_ctrl_callback(struct usb_xfer *xfer, usb_error_t error)
962 struct ndis_softc *sc = usbd_xfer_softc(xfer);
963 struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer);
964 struct ndisusb_xfer *nx;
967 struct usbd_urb_vendor_or_class_request *vcreq;
968 struct usb_page_cache *pc;
970 struct usb_device_request req;
973 switch (USB_GET_STATE(xfer)) {
974 case USB_ST_TRANSFERRED:
975 nx = usbd_aq_getfirst(sc, ne);
980 urb = usbd_geturb(ip);
981 vcreq = &urb->uu_vcreq;
983 if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
984 pc = usbd_xfer_get_frame(xfer, 1);
985 len = usbd_xfer_frame_len(xfer, 1);
986 usbd_copy_out(pc, 0, vcreq->uvc_trans_buf, len);
987 nx->nx_urbactlen += len;
990 usbd_xfer_complete(sc, ne, nx, USB_ERR_NORMAL_COMPLETION);
994 /* get next transfer */
995 KeAcquireSpinLock(&ne->ne_lock, &irql);
996 if (IsListEmpty(&ne->ne_pending)) {
997 KeReleaseSpinLock(&ne->ne_lock, irql);
1000 nx = CONTAINING_RECORD(ne->ne_pending.nle_flink,
1001 struct ndisusb_xfer, nx_next);
1002 RemoveEntryList(&nx->nx_next);
1003 /* add a entry to the active queue's tail. */
1004 InsertTailList((&ne->ne_active), (&nx->nx_next));
1005 KeReleaseSpinLock(&ne->ne_lock, irql);
1008 urb = usbd_geturb(ip);
1009 vcreq = &urb->uu_vcreq;
1011 switch (urb->uu_hdr.uuh_func) {
1012 case URB_FUNCTION_CLASS_DEVICE:
1013 type = UT_CLASS | UT_DEVICE;
1015 case URB_FUNCTION_CLASS_INTERFACE:
1016 type = UT_CLASS | UT_INTERFACE;
1018 case URB_FUNCTION_CLASS_OTHER:
1019 type = UT_CLASS | UT_OTHER;
1021 case URB_FUNCTION_CLASS_ENDPOINT:
1022 type = UT_CLASS | UT_ENDPOINT;
1024 case URB_FUNCTION_VENDOR_DEVICE:
1025 type = UT_VENDOR | UT_DEVICE;
1027 case URB_FUNCTION_VENDOR_INTERFACE:
1028 type = UT_VENDOR | UT_INTERFACE;
1030 case URB_FUNCTION_VENDOR_OTHER:
1031 type = UT_VENDOR | UT_OTHER;
1033 case URB_FUNCTION_VENDOR_ENDPOINT:
1034 type = UT_VENDOR | UT_ENDPOINT;
1037 /* never reached. */
1041 type |= (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ?
1043 type |= vcreq->uvc_reserved1;
1045 req.bmRequestType = type;
1046 req.bRequest = vcreq->uvc_req;
1047 USETW(req.wIndex, vcreq->uvc_idx);
1048 USETW(req.wValue, vcreq->uvc_value);
1049 USETW(req.wLength, vcreq->uvc_trans_buflen);
1051 nx->nx_urbbuf = vcreq->uvc_trans_buf;
1052 nx->nx_urblen = vcreq->uvc_trans_buflen;
1053 nx->nx_urbactlen = 0;
1055 pc = usbd_xfer_get_frame(xfer, 0);
1056 usbd_copy_in(pc, 0, &req, sizeof(req));
1057 usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1058 usbd_xfer_set_frames(xfer, 1);
1059 if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
1060 if (vcreq->uvc_trans_buflen >= USBD_CTRL_READ_BUFFER_SP)
1061 device_printf(sc->ndis_dev,
1062 "warning: not enough buffer space (%d).\n",
1063 vcreq->uvc_trans_buflen);
1064 usbd_xfer_set_frame_len(xfer, 1,
1065 MIN(usbd_xfer_max_len(xfer),
1066 vcreq->uvc_trans_buflen));
1067 usbd_xfer_set_frames(xfer, 2);
1069 if (nx->nx_urblen > USBD_CTRL_WRITE_BUFFER_SP)
1070 device_printf(sc->ndis_dev,
1071 "warning: not enough write buffer space"
1072 " (%d).\n", nx->nx_urblen);
1074 * XXX with my local tests there was no cases to require
1075 * a extra buffer until now but it'd need to update in
1076 * the future if it needs to be.
1078 if (nx->nx_urblen > 0) {
1079 pc = usbd_xfer_get_frame(xfer, 1);
1080 usbd_copy_in(pc, 0, nx->nx_urbbuf,
1082 usbd_xfer_set_frame_len(xfer, 1, nx->nx_urblen);
1083 usbd_xfer_set_frames(xfer, 2);
1086 usbd_transfer_submit(xfer);
1089 nx = usbd_aq_getfirst(sc, ne);
1092 if (error != USB_ERR_CANCELLED) {
1093 usbd_xfer_set_stall(xfer);
1094 device_printf(sc->ndis_dev, "usb xfer warning (%s)\n",
1095 usbd_errstr(error));
1097 usbd_xfer_complete(sc, ne, nx, error);
1098 if (error != USB_ERR_CANCELLED)
1104 static struct ndisusb_ep *
1105 usbd_get_ndisep(ip, ep)
1107 usb_endpoint_descriptor_t *ep;
1109 device_t dev = IRP_NDIS_DEV(ip);
1110 struct ndis_softc *sc = device_get_softc(dev);
1111 struct ndisusb_ep *ne;
1113 ne = &sc->ndisusb_ep[NDISUSB_GET_ENDPT(ep->bEndpointAddress)];
1115 IRP_NDISUSB_EP(ip) = ne;
1116 ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap;
1122 usbd_xfertask(dobj, arg)
1123 device_object *dobj;
1130 struct ndis_softc *sc = arg;
1131 struct ndisusb_xferdone *nd;
1132 struct ndisusb_xfer *nq;
1133 struct usbd_urb_bulk_or_intr_transfer *ubi;
1134 struct usbd_urb_vendor_or_class_request *vcreq;
1135 union usbd_urb *urb;
1141 if (IsListEmpty(&sc->ndisusb_xferdonelist))
1144 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_xferdonelock);
1145 l = sc->ndisusb_xferdonelist.nle_flink;
1146 while (l != &sc->ndisusb_xferdonelist) {
1147 nd = CONTAINING_RECORD(l, struct ndisusb_xferdone, nd_donelist);
1150 status = nd->nd_status;
1153 urb = usbd_geturb(ip);
1155 ip->irp_cancelfunc = NULL;
1156 IRP_NDISUSB_EP(ip) = NULL;
1159 case USB_ERR_NORMAL_COMPLETION:
1160 if (urb->uu_hdr.uuh_func ==
1161 URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) {
1162 ubi = &urb->uu_bulkintr;
1163 ubi->ubi_trans_buflen = nq->nx_urbactlen;
1165 vcreq = &urb->uu_vcreq;
1166 vcreq->uvc_trans_buflen = nq->nx_urbactlen;
1168 ip->irp_iostat.isb_info = nq->nx_urbactlen;
1169 ip->irp_iostat.isb_status = STATUS_SUCCESS;
1170 USBD_URB_STATUS(urb) = USBD_STATUS_SUCCESS;
1172 case USB_ERR_CANCELLED:
1173 ip->irp_iostat.isb_info = 0;
1174 ip->irp_iostat.isb_status = STATUS_CANCELLED;
1175 USBD_URB_STATUS(urb) = USBD_STATUS_CANCELED;
1178 ip->irp_iostat.isb_info = 0;
1179 USBD_URB_STATUS(urb) = usbd_usb2urb(status);
1180 ip->irp_iostat.isb_status =
1181 usbd_urb2nt(USBD_URB_STATUS(urb));
1186 RemoveEntryList(&nd->nd_donelist);
1191 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_xferdonelock);
1192 /* NB: call after cleaning */
1193 IoCompleteRequest(ip, IO_NO_INCREMENT);
1194 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_xferdonelock);
1196 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_xferdonelock);
1200 * this function is for mainly deferring a task to the another thread because
1201 * we don't want to be in the scope of HAL lock.
1204 usbd_taskadd(ip, type)
1208 device_t dev = IRP_NDIS_DEV(ip);
1209 struct ndis_softc *sc = device_get_softc(dev);
1210 struct ndisusb_task *nt;
1212 nt = malloc(sizeof(struct ndisusb_task), M_USBDEV, M_NOWAIT | M_ZERO);
1214 return (USBD_STATUS_NO_MEMORY);
1218 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock);
1219 InsertTailList((&sc->ndisusb_tasklist), (&nt->nt_tasklist));
1220 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock);
1222 IoQueueWorkItem(sc->ndisusb_taskitem,
1223 (io_workitem_func)usbd_task_wrap, WORKQUEUE_CRITICAL, sc);
1225 return (USBD_STATUS_SUCCESS);
1229 usbd_task(dobj, arg)
1230 device_object *dobj;
1235 struct ndis_softc *sc = arg;
1236 struct ndisusb_ep *ne;
1237 struct ndisusb_task *nt;
1238 union usbd_urb *urb;
1240 if (IsListEmpty(&sc->ndisusb_tasklist))
1243 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock);
1244 l = sc->ndisusb_tasklist.nle_flink;
1245 while (l != &sc->ndisusb_tasklist) {
1246 nt = CONTAINING_RECORD(l, struct ndisusb_task, nt_tasklist);
1249 urb = usbd_geturb(ip);
1251 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock);
1253 switch (nt->nt_type) {
1254 case NDISUSB_TASK_TSTART:
1255 ne = usbd_get_ndisep(ip, urb->uu_bulkintr.ubi_epdesc);
1258 usbd_transfer_start(ne->ne_xfer[0]);
1260 case NDISUSB_TASK_IRPCANCEL:
1261 ne = usbd_get_ndisep(ip,
1262 (nt->nt_type == NDISUSB_TASK_IRPCANCEL) ?
1263 urb->uu_bulkintr.ubi_epdesc :
1264 urb->uu_pipe.upr_handle);
1268 usbd_transfer_stop(ne->ne_xfer[0]);
1269 usbd_transfer_start(ne->ne_xfer[0]);
1271 case NDISUSB_TASK_VENDOR:
1272 ne = (urb->uu_vcreq.uvc_trans_flags &
1273 USBD_TRANSFER_DIRECTION_IN) ?
1274 &sc->ndisusb_dread_ep : &sc->ndisusb_dwrite_ep;
1275 usbd_transfer_start(ne->ne_xfer[0]);
1282 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock);
1285 RemoveEntryList(&nt->nt_tasklist);
1288 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock);
1292 usbd_func_bulkintr(ip)
1296 struct ndisusb_ep *ne;
1297 struct ndisusb_xfer *nx;
1298 struct usbd_urb_bulk_or_intr_transfer *ubi;
1299 union usbd_urb *urb;
1300 usb_endpoint_descriptor_t *ep;
1302 urb = usbd_geturb(ip);
1303 ubi = &urb->uu_bulkintr;
1304 ep = ubi->ubi_epdesc;
1306 return (USBD_STATUS_INVALID_PIPE_HANDLE);
1308 ne = usbd_get_ndisep(ip, ep);
1310 device_printf(IRP_NDIS_DEV(ip), "get NULL endpoint info.\n");
1311 return (USBD_STATUS_INVALID_PIPE_HANDLE);
1314 nx = malloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO);
1316 device_printf(IRP_NDIS_DEV(ip), "out of memory\n");
1317 return (USBD_STATUS_NO_MEMORY);
1321 KeAcquireSpinLockAtDpcLevel(&ne->ne_lock);
1322 InsertTailList((&ne->ne_pending), (&nx->nx_next));
1323 KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
1325 /* we've done to setup xfer. Let's transfer it. */
1326 ip->irp_iostat.isb_status = STATUS_PENDING;
1327 ip->irp_iostat.isb_info = 0;
1328 USBD_URB_STATUS(urb) = USBD_STATUS_PENDING;
1329 IoMarkIrpPending(ip);
1331 error = usbd_taskadd(ip, NDISUSB_TASK_TSTART);
1332 if (error != USBD_STATUS_SUCCESS)
1335 return (USBD_STATUS_PENDING);
1338 static union usbd_urb *
1339 USBD_CreateConfigurationRequest(conf, len)
1340 usb_config_descriptor_t *conf;
1343 struct usbd_interface_list_entry list[2];
1344 union usbd_urb *urb;
1346 bzero(list, sizeof(struct usbd_interface_list_entry) * 2);
1347 list[0].uil_intfdesc = USBD_ParseConfigurationDescriptorEx(conf, conf,
1348 -1, -1, -1, -1, -1);
1349 urb = USBD_CreateConfigurationRequestEx(conf, list);
1353 *len = urb->uu_selconf.usc_hdr.uuh_len;
1357 static union usbd_urb *
1358 USBD_CreateConfigurationRequestEx(conf, list)
1359 usb_config_descriptor_t *conf;
1360 struct usbd_interface_list_entry *list;
1363 struct usbd_interface_information *intf;
1364 struct usbd_pipe_information *pipe;
1365 struct usbd_urb_select_configuration *selconf;
1366 usb_interface_descriptor_t *desc;
1368 for (i = 0, size = 0; i < conf->bNumInterface; i++) {
1369 j = list[i].uil_intfdesc->bNumEndpoints;
1370 size = size + sizeof(struct usbd_interface_information) +
1371 sizeof(struct usbd_pipe_information) * (j - 1);
1373 size += sizeof(struct usbd_urb_select_configuration) -
1374 sizeof(struct usbd_interface_information);
1376 selconf = ExAllocatePoolWithTag(NonPagedPool, size, 0);
1377 if (selconf == NULL)
1379 selconf->usc_hdr.uuh_func = URB_FUNCTION_SELECT_CONFIGURATION;
1380 selconf->usc_hdr.uuh_len = size;
1381 selconf->usc_handle = conf;
1382 selconf->usc_conf = conf;
1384 intf = &selconf->usc_intf;
1385 for (i = 0; i < conf->bNumInterface; i++) {
1386 if (list[i].uil_intfdesc == NULL)
1389 list[i].uil_intf = intf;
1390 desc = list[i].uil_intfdesc;
1392 intf->uii_len = sizeof(struct usbd_interface_information) +
1393 (desc->bNumEndpoints - 1) *
1394 sizeof(struct usbd_pipe_information);
1395 intf->uii_intfnum = desc->bInterfaceNumber;
1396 intf->uii_altset = desc->bAlternateSetting;
1397 intf->uii_intfclass = desc->bInterfaceClass;
1398 intf->uii_intfsubclass = desc->bInterfaceSubClass;
1399 intf->uii_intfproto = desc->bInterfaceProtocol;
1400 intf->uii_handle = desc;
1401 intf->uii_numeps = desc->bNumEndpoints;
1403 pipe = &intf->uii_pipes[0];
1404 for (j = 0; j < intf->uii_numeps; j++)
1405 pipe[j].upi_maxtxsize =
1406 USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
1408 intf = (struct usbd_interface_information *)((char *)intf +
1412 return ((union usbd_urb *)selconf);
1416 USBD_GetUSBDIVersion(ui)
1417 usbd_version_info *ui;
1420 /* Pretend to be Windows XP. */
1422 ui->uvi_usbdi_vers = USBDI_VERSION;
1423 ui->uvi_supported_vers = USB_VER_2_0;
1428 static usb_interface_descriptor_t *
1429 USBD_ParseConfigurationDescriptor(usb_config_descriptor_t *conf,
1430 uint8_t intfnum, uint8_t altset)
1433 return USBD_ParseConfigurationDescriptorEx(conf, conf, intfnum, altset,
1437 static usb_interface_descriptor_t *
1438 USBD_ParseConfigurationDescriptorEx(conf, start, intfnum,
1439 altset, intfclass, intfsubclass, intfproto)
1440 usb_config_descriptor_t *conf;
1445 int32_t intfsubclass;
1448 struct usb_descriptor *next = NULL;
1449 usb_interface_descriptor_t *desc;
1451 while ((next = usb_desc_foreach(conf, next)) != NULL) {
1452 desc = (usb_interface_descriptor_t *)next;
1453 if (desc->bDescriptorType != UDESC_INTERFACE)
1455 if (!(intfnum == -1 || desc->bInterfaceNumber == intfnum))
1457 if (!(altset == -1 || desc->bAlternateSetting == altset))
1459 if (!(intfclass == -1 || desc->bInterfaceClass == intfclass))
1461 if (!(intfsubclass == -1 ||
1462 desc->bInterfaceSubClass == intfsubclass))
1464 if (!(intfproto == -1 || desc->bInterfaceProtocol == intfproto))
1475 printf("USBD dummy called\n");
1479 image_patch_table usbd_functbl[] = {
1480 IMPORT_SFUNC(USBD_CreateConfigurationRequest, 2),
1481 IMPORT_SFUNC(USBD_CreateConfigurationRequestEx, 2),
1482 IMPORT_SFUNC_MAP(_USBD_CreateConfigurationRequestEx@8,
1483 USBD_CreateConfigurationRequestEx, 2),
1484 IMPORT_SFUNC(USBD_GetUSBDIVersion, 1),
1485 IMPORT_SFUNC(USBD_ParseConfigurationDescriptor, 3),
1486 IMPORT_SFUNC(USBD_ParseConfigurationDescriptorEx, 7),
1487 IMPORT_SFUNC_MAP(_USBD_ParseConfigurationDescriptorEx@28,
1488 USBD_ParseConfigurationDescriptorEx, 7),
1491 * This last entry is a catch-all for any function we haven't
1492 * implemented yet. The PE import list patching routine will
1493 * use it for any function that doesn't have an explicit match
1497 { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL },
1501 { NULL, NULL, NULL }
1504 MODULE_DEPEND(ndis, usb, 1, 1, 1);