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.
32 * $FreeBSD: src/sys/compat/ndis/subr_usbd.c,v 1.22 2012/11/17 01:51:26 svnexp Exp $
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/unistd.h>
38 #include <sys/types.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
43 #include <sys/condvar.h>
44 #include <sys/module.h>
47 #include <sys/socket.h>
50 #include <sys/queue.h>
53 #include <net/if_var.h>
54 #include <net/if_media.h>
55 #include <netproto/802_11/ieee80211_var.h>
56 #include <netproto/802_11/ieee80211_ioctl.h>
58 #include <bus/u4b/usb.h>
59 #include <bus/u4b/usbdi.h>
60 #include <bus/u4b/usbdi_util.h>
61 #include <bus/u4b/usb_busdma.h>
62 #include <bus/u4b/usb_device.h>
63 #include <bus/u4b/usb_request.h>
65 #include <emulation/ndis/pe_var.h>
66 #include <emulation/ndis/cfg_var.h>
67 #include <emulation/ndis/resource_var.h>
68 #include <emulation/ndis/ntoskrnl_var.h>
69 #include <emulation/ndis/ndis_var.h>
70 #include <emulation/ndis/hal_var.h>
71 #include <emulation/ndis/u4bd_var.h>
72 #include <dev/netif/ndis/if_ndisvar.h>
74 static driver_object usbd_driver;
75 static usb_callback_t usbd_non_isoc_callback;
76 static usb_callback_t usbd_ctrl_callback;
78 #define USBD_CTRL_READ_PIPE 0
79 #define USBD_CTRL_WRITE_PIPE 1
80 #define USBD_CTRL_MAX_PIPE 2
81 #define USBD_CTRL_READ_BUFFER_SP 256
82 #define USBD_CTRL_WRITE_BUFFER_SP 256
83 #define USBD_CTRL_READ_BUFFER_SIZE \
84 (sizeof(struct usb_device_request) + USBD_CTRL_READ_BUFFER_SP)
85 #define USBD_CTRL_WRITE_BUFFER_SIZE \
86 (sizeof(struct usb_device_request) + USBD_CTRL_WRITE_BUFFER_SP)
87 static struct usb_config usbd_default_epconfig[USBD_CTRL_MAX_PIPE] = {
88 [USBD_CTRL_READ_PIPE] = {
90 .endpoint = 0x00, /* control pipe */
91 .direction = UE_DIR_ANY,
93 .bufsize = USBD_CTRL_READ_BUFFER_SIZE,
94 .flags = { .short_xfer_ok = 1, },
95 .callback = &usbd_ctrl_callback,
96 .timeout = 5000, /* 5 seconds */
98 [USBD_CTRL_WRITE_PIPE] = {
100 .endpoint = 0x00, /* control pipe */
101 .direction = UE_DIR_ANY,
103 .bufsize = USBD_CTRL_WRITE_BUFFER_SIZE,
104 .flags = { .proxy_buffer = 1, },
105 .callback = &usbd_ctrl_callback,
106 .timeout = 5000, /* 5 seconds */
110 static int32_t usbd_func_bulkintr(irp *);
111 static int32_t usbd_func_vendorclass(irp *);
112 static int32_t usbd_func_selconf(irp *);
113 static int32_t usbd_func_abort_pipe(irp *);
114 static usb_error_t usbd_setup_endpoint(irp *, uint8_t,
115 struct usb_endpoint_descriptor *);
116 static usb_error_t usbd_setup_endpoint_default(irp *, uint8_t);
117 static usb_error_t usbd_setup_endpoint_one(irp *, uint8_t,
118 struct ndisusb_ep *, struct usb_config *);
119 static int32_t usbd_func_getdesc(irp *);
120 static union usbd_urb *usbd_geturb(irp *);
121 static struct ndisusb_ep*usbd_get_ndisep(irp *, usb_endpoint_descriptor_t *);
122 static int32_t usbd_iodispatch(device_object *, irp *);
123 static int32_t usbd_ioinvalid(device_object *, irp *);
124 static int32_t usbd_pnp(device_object *, irp *);
125 static int32_t usbd_power(device_object *, irp *);
126 static void usbd_irpcancel(device_object *, irp *);
127 static int32_t usbd_submit_urb(irp *);
128 static int32_t usbd_urb2nt(int32_t);
129 static void usbd_task(device_object *, void *);
130 static int32_t usbd_taskadd(irp *, unsigned);
131 static void usbd_xfertask(device_object *, void *);
132 static void dummy(void);
134 static union usbd_urb *USBD_CreateConfigurationRequestEx(
135 usb_config_descriptor_t *,
136 struct usbd_interface_list_entry *);
137 static union usbd_urb *USBD_CreateConfigurationRequest(
138 usb_config_descriptor_t *,
140 static void USBD_GetUSBDIVersion(usbd_version_info *);
141 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptorEx(
142 usb_config_descriptor_t *, void *, int32_t, int32_t,
143 int32_t, int32_t, int32_t);
144 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptor(
145 usb_config_descriptor_t *, uint8_t, uint8_t);
148 * We need to wrap these functions because these need `context switch' from
149 * Windows to UNIX before it's called.
151 static funcptr usbd_iodispatch_wrap;
152 static funcptr usbd_ioinvalid_wrap;
153 static funcptr usbd_pnp_wrap;
154 static funcptr usbd_power_wrap;
155 static funcptr usbd_irpcancel_wrap;
156 static funcptr usbd_task_wrap;
157 static funcptr usbd_xfertask_wrap;
162 image_patch_table *patch;
165 patch = usbd_functbl;
166 while (patch->ipt_func != NULL) {
167 windrv_wrap((funcptr)patch->ipt_func,
168 (funcptr *)&patch->ipt_wrap,
169 patch->ipt_argcnt, patch->ipt_ftype);
173 windrv_wrap((funcptr)usbd_ioinvalid,
174 (funcptr *)&usbd_ioinvalid_wrap, 2, WINDRV_WRAP_STDCALL);
175 windrv_wrap((funcptr)usbd_iodispatch,
176 (funcptr *)&usbd_iodispatch_wrap, 2, WINDRV_WRAP_STDCALL);
177 windrv_wrap((funcptr)usbd_pnp,
178 (funcptr *)&usbd_pnp_wrap, 2, WINDRV_WRAP_STDCALL);
179 windrv_wrap((funcptr)usbd_power,
180 (funcptr *)&usbd_power_wrap, 2, WINDRV_WRAP_STDCALL);
181 windrv_wrap((funcptr)usbd_irpcancel,
182 (funcptr *)&usbd_irpcancel_wrap, 2, WINDRV_WRAP_STDCALL);
183 windrv_wrap((funcptr)usbd_task,
184 (funcptr *)&usbd_task_wrap, 2, WINDRV_WRAP_STDCALL);
185 windrv_wrap((funcptr)usbd_xfertask,
186 (funcptr *)&usbd_xfertask_wrap, 2, WINDRV_WRAP_STDCALL);
188 /* Create a fake USB driver instance. */
190 windrv_bus_attach(&usbd_driver, "USB Bus");
192 /* Set up our dipatch routine. */
193 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
194 usbd_driver.dro_dispatch[i] =
195 (driver_dispatch)usbd_ioinvalid_wrap;
197 usbd_driver.dro_dispatch[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
198 (driver_dispatch)usbd_iodispatch_wrap;
199 usbd_driver.dro_dispatch[IRP_MJ_DEVICE_CONTROL] =
200 (driver_dispatch)usbd_iodispatch_wrap;
201 usbd_driver.dro_dispatch[IRP_MJ_POWER] =
202 (driver_dispatch)usbd_power_wrap;
203 usbd_driver.dro_dispatch[IRP_MJ_PNP] =
204 (driver_dispatch)usbd_pnp_wrap;
212 image_patch_table *patch;
214 patch = usbd_functbl;
215 while (patch->ipt_func != NULL) {
216 windrv_unwrap(patch->ipt_wrap);
220 windrv_unwrap(usbd_ioinvalid_wrap);
221 windrv_unwrap(usbd_iodispatch_wrap);
222 windrv_unwrap(usbd_pnp_wrap);
223 windrv_unwrap(usbd_power_wrap);
224 windrv_unwrap(usbd_irpcancel_wrap);
225 windrv_unwrap(usbd_task_wrap);
226 windrv_unwrap(usbd_xfertask_wrap);
228 kfree(usbd_driver.dro_drivername.us_buf, M_DEVBUF);
234 usbd_iodispatch(device_object *dobj, irp *ip)
236 device_t dev = dobj->do_devext;
238 struct io_stack_location *irp_sl;
240 irp_sl = IoGetCurrentIrpStackLocation(ip);
241 switch (irp_sl->isl_parameters.isl_ioctl.isl_iocode) {
242 case IOCTL_INTERNAL_USB_SUBMIT_URB:
243 IRP_NDIS_DEV(ip) = dev;
245 status = usbd_submit_urb(ip);
248 device_printf(dev, "ioctl 0x%x isn't supported\n",
249 irp_sl->isl_parameters.isl_ioctl.isl_iocode);
250 status = USBD_STATUS_NOT_SUPPORTED;
254 if (status == USBD_STATUS_PENDING)
255 return (STATUS_PENDING);
257 ip->irp_iostat.isb_status = usbd_urb2nt(status);
258 if (status != USBD_STATUS_SUCCESS)
259 ip->irp_iostat.isb_info = 0;
260 return (ip->irp_iostat.isb_status);
264 usbd_ioinvalid(device_object *dobj, irp *ip)
266 device_t dev = dobj->do_devext;
267 struct io_stack_location *irp_sl;
269 irp_sl = IoGetCurrentIrpStackLocation(ip);
270 device_printf(dev, "invalid I/O dispatch %d:%d\n", irp_sl->isl_major,
273 ip->irp_iostat.isb_status = STATUS_FAILURE;
274 ip->irp_iostat.isb_info = 0;
276 IoCompleteRequest(ip, IO_NO_INCREMENT);
278 return (STATUS_FAILURE);
282 usbd_pnp(device_object *dobj, irp *ip)
284 device_t dev = dobj->do_devext;
285 struct io_stack_location *irp_sl;
287 irp_sl = IoGetCurrentIrpStackLocation(ip);
288 device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
289 __func__, irp_sl->isl_major, irp_sl->isl_minor);
291 ip->irp_iostat.isb_status = STATUS_FAILURE;
292 ip->irp_iostat.isb_info = 0;
294 IoCompleteRequest(ip, IO_NO_INCREMENT);
296 return (STATUS_FAILURE);
300 usbd_power(device_object *dobj, irp *ip)
302 device_t dev = dobj->do_devext;
303 struct io_stack_location *irp_sl;
305 irp_sl = IoGetCurrentIrpStackLocation(ip);
306 device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
307 __func__, irp_sl->isl_major, irp_sl->isl_minor);
309 ip->irp_iostat.isb_status = STATUS_FAILURE;
310 ip->irp_iostat.isb_info = 0;
312 IoCompleteRequest(ip, IO_NO_INCREMENT);
314 return (STATUS_FAILURE);
317 /* Convert USBD_STATUS to NTSTATUS */
319 usbd_urb2nt(int32_t status)
323 case USBD_STATUS_SUCCESS:
324 return (STATUS_SUCCESS);
325 case USBD_STATUS_DEVICE_GONE:
326 return (STATUS_DEVICE_NOT_CONNECTED);
327 case USBD_STATUS_PENDING:
328 return (STATUS_PENDING);
329 case USBD_STATUS_NOT_SUPPORTED:
330 return (STATUS_NOT_IMPLEMENTED);
331 case USBD_STATUS_NO_MEMORY:
332 return (STATUS_NO_MEMORY);
333 case USBD_STATUS_REQUEST_FAILED:
334 return (STATUS_NOT_SUPPORTED);
335 case USBD_STATUS_CANCELED:
336 return (STATUS_CANCELLED);
341 return (STATUS_FAILURE);
344 /* Convert FreeBSD's usb_error_t to USBD_STATUS */
346 usbd_usb2urb(int status)
350 case USB_ERR_NORMAL_COMPLETION:
351 return (USBD_STATUS_SUCCESS);
352 case USB_ERR_PENDING_REQUESTS:
353 return (USBD_STATUS_PENDING);
354 case USB_ERR_TIMEOUT:
355 return (USBD_STATUS_TIMEOUT);
356 case USB_ERR_SHORT_XFER:
357 return (USBD_STATUS_ERROR_SHORT_TRANSFER);
358 case USB_ERR_IOERROR:
359 return (USBD_STATUS_XACT_ERROR);
361 return (USBD_STATUS_NO_MEMORY);
363 return (USBD_STATUS_REQUEST_FAILED);
364 case USB_ERR_NOT_STARTED:
365 case USB_ERR_TOO_DEEP:
366 case USB_ERR_NO_POWER:
367 return (USBD_STATUS_DEVICE_GONE);
368 case USB_ERR_CANCELLED:
369 return (USBD_STATUS_CANCELED);
374 return (USBD_STATUS_NOT_SUPPORTED);
377 static union usbd_urb *
380 struct io_stack_location *irp_sl;
382 irp_sl = IoGetCurrentIrpStackLocation(ip);
384 return (irp_sl->isl_parameters.isl_others.isl_arg1);
388 usbd_submit_urb(irp *ip)
390 device_t dev = IRP_NDIS_DEV(ip);
394 urb = usbd_geturb(ip);
396 * In a case of URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
397 * USBD_URB_STATUS(urb) would be set at callback functions like
398 * usbd_intr() or usbd_xfereof().
400 switch (urb->uu_hdr.uuh_func) {
401 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
402 status = usbd_func_bulkintr(ip);
403 if (status != USBD_STATUS_SUCCESS &&
404 status != USBD_STATUS_PENDING)
405 USBD_URB_STATUS(urb) = status;
407 case URB_FUNCTION_VENDOR_DEVICE:
408 case URB_FUNCTION_VENDOR_INTERFACE:
409 case URB_FUNCTION_VENDOR_ENDPOINT:
410 case URB_FUNCTION_VENDOR_OTHER:
411 case URB_FUNCTION_CLASS_DEVICE:
412 case URB_FUNCTION_CLASS_INTERFACE:
413 case URB_FUNCTION_CLASS_ENDPOINT:
414 case URB_FUNCTION_CLASS_OTHER:
415 status = usbd_func_vendorclass(ip);
416 USBD_URB_STATUS(urb) = status;
418 case URB_FUNCTION_SELECT_CONFIGURATION:
419 status = usbd_func_selconf(ip);
420 USBD_URB_STATUS(urb) = status;
422 case URB_FUNCTION_ABORT_PIPE:
423 status = usbd_func_abort_pipe(ip);
424 USBD_URB_STATUS(urb) = status;
426 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
427 status = usbd_func_getdesc(ip);
428 USBD_URB_STATUS(urb) = status;
431 device_printf(dev, "func 0x%x isn't supported\n",
432 urb->uu_hdr.uuh_func);
433 USBD_URB_STATUS(urb) = status = USBD_STATUS_NOT_SUPPORTED;
441 usbd_func_getdesc(irp *ip)
443 #define NDISUSB_GETDESC_MAXRETRIES 3
444 device_t dev = IRP_NDIS_DEV(ip);
445 struct ndis_softc *sc = device_get_softc(dev);
446 struct usbd_urb_control_descriptor_request *ctldesc;
450 usb_config_descriptor_t *cdp;
453 urb = usbd_geturb(ip);
454 ctldesc = &urb->uu_ctldesc;
455 if (ctldesc->ucd_desctype == UDESC_CONFIG) {
457 * The NDIS driver is not allowed to change the
458 * config! There is only one choice!
460 cdp = usbd_get_config_descriptor(sc->ndisusb_dev);
462 status = USB_ERR_INVAL;
465 if (cdp->bDescriptorType != UDESC_CONFIG) {
466 device_printf(dev, "bad desc %d\n",
467 cdp->bDescriptorType);
468 status = USB_ERR_INVAL;
471 /* get minimum length */
472 len = MIN(UGETW(cdp->wTotalLength), ctldesc->ucd_trans_buflen);
473 /* copy out config descriptor */
474 memcpy(ctldesc->ucd_trans_buf, cdp, len);
475 /* set actual length */
477 status = USB_ERR_NORMAL_COMPLETION;
480 status = usbd_req_get_desc(sc->ndisusb_dev, &sc->ndisusb_lock,
481 &actlen, ctldesc->ucd_trans_buf, 2,
482 ctldesc->ucd_trans_buflen, ctldesc->ucd_langid,
483 ctldesc->ucd_desctype, ctldesc->ucd_idx,
484 NDISUSB_GETDESC_MAXRETRIES);
488 if (status != USB_ERR_NORMAL_COMPLETION) {
489 ctldesc->ucd_trans_buflen = 0;
490 return usbd_usb2urb(status);
493 ctldesc->ucd_trans_buflen = actlen;
494 ip->irp_iostat.isb_info = actlen;
496 return (USBD_STATUS_SUCCESS);
497 #undef NDISUSB_GETDESC_MAXRETRIES
501 usbd_func_selconf(irp *ip)
503 device_t dev = IRP_NDIS_DEV(ip);
505 struct ndis_softc *sc = device_get_softc(dev);
506 struct usb_device *udev = sc->ndisusb_dev;
507 struct usb_endpoint *ep = NULL;
508 struct usbd_interface_information *intf;
509 struct usbd_pipe_information *pipe;
510 struct usbd_urb_select_configuration *selconf;
512 usb_config_descriptor_t *conf;
513 usb_endpoint_descriptor_t *edesc;
516 urb = usbd_geturb(ip);
518 selconf = &urb->uu_selconf;
519 conf = selconf->usc_conf;
521 device_printf(dev, "select configuration is NULL\n");
522 return usbd_usb2urb(USB_ERR_NORMAL_COMPLETION);
525 intf = &selconf->usc_intf;
526 for (i = 0; i < conf->bNumInterface && intf->uii_len > 0; i++) {
527 ret = usbd_set_alt_interface_index(udev,
528 intf->uii_intfnum, intf->uii_altset);
529 if (ret != USB_ERR_NORMAL_COMPLETION && ret != USB_ERR_IN_USE) {
531 "setting alternate interface failed: %s\n",
533 return usbd_usb2urb(ret);
536 for (j = 0; (ep = usb_endpoint_foreach(udev, ep)); j++) {
537 if (j >= intf->uii_numeps) {
539 "endpoint %d and above are ignored",
544 pipe = &intf->uii_pipes[j];
545 pipe->upi_handle = edesc;
546 pipe->upi_epaddr = edesc->bEndpointAddress;
547 pipe->upi_maxpktsize = UGETW(edesc->wMaxPacketSize);
548 pipe->upi_type = UE_GET_XFERTYPE(edesc->bmAttributes);
550 ret = usbd_setup_endpoint(ip, intf->uii_intfnum, edesc);
551 if (ret != USB_ERR_NORMAL_COMPLETION)
552 return usbd_usb2urb(ret);
554 if (pipe->upi_type != UE_INTERRUPT)
557 /* XXX we're following linux USB's interval policy. */
558 if (udev->speed == USB_SPEED_LOW)
559 pipe->upi_interval = edesc->bInterval + 5;
560 else if (udev->speed == USB_SPEED_FULL)
561 pipe->upi_interval = edesc->bInterval;
567 } while (k1 < edesc->bInterval);
568 pipe->upi_interval = k0;
572 intf = (struct usbd_interface_information *)(((char *)intf) +
576 return (USBD_STATUS_SUCCESS);
580 usbd_setup_endpoint_one(irp *ip, uint8_t ifidx, struct ndisusb_ep *ne,
581 struct usb_config *epconf)
583 device_t dev = IRP_NDIS_DEV(ip);
584 struct ndis_softc *sc = device_get_softc(dev);
585 struct usb_xfer *xfer;
588 InitializeListHead(&ne->ne_active);
589 InitializeListHead(&ne->ne_pending);
590 KeInitializeSpinLock(&ne->ne_lock);
592 status = usbd_transfer_setup(sc->ndisusb_dev, &ifidx, ne->ne_xfer,
593 epconf, 1, sc, &sc->ndisusb_lock);
594 if (status != USB_ERR_NORMAL_COMPLETION) {
595 device_printf(dev, "couldn't setup xfer: %s\n",
596 usbd_errstr(status));
599 xfer = ne->ne_xfer[0];
600 usbd_xfer_set_priv(xfer, ne);
606 usbd_setup_endpoint_default(irp *ip, uint8_t ifidx)
608 device_t dev = IRP_NDIS_DEV(ip);
609 struct ndis_softc *sc = device_get_softc(dev);
613 device_printf(dev, "warning: ifidx > 0 isn't supported.\n");
615 status = usbd_setup_endpoint_one(ip, ifidx, &sc->ndisusb_dread_ep,
616 &usbd_default_epconfig[USBD_CTRL_READ_PIPE]);
617 if (status != USB_ERR_NORMAL_COMPLETION)
620 status = usbd_setup_endpoint_one(ip, ifidx, &sc->ndisusb_dwrite_ep,
621 &usbd_default_epconfig[USBD_CTRL_WRITE_PIPE]);
626 usbd_setup_endpoint(irp *ip, uint8_t ifidx,
627 struct usb_endpoint_descriptor *ep)
629 device_t dev = IRP_NDIS_DEV(ip);
630 struct ndis_softc *sc = device_get_softc(dev);
631 struct ndisusb_ep *ne;
632 struct usb_config cfg;
633 struct usb_xfer *xfer;
636 /* check for non-supported transfer types */
637 if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_CONTROL ||
638 UE_GET_XFERTYPE(ep->bmAttributes) == UE_ISOCHRONOUS) {
639 device_printf(dev, "%s: unsuppotted transfer types %#x\n",
640 __func__, UE_GET_XFERTYPE(ep->bmAttributes));
641 return (USB_ERR_INVAL);
644 ne = &sc->ndisusb_ep[NDISUSB_GET_ENDPT(ep->bEndpointAddress)];
645 InitializeListHead(&ne->ne_active);
646 InitializeListHead(&ne->ne_pending);
647 KeInitializeSpinLock(&ne->ne_lock);
648 ne->ne_dirin = UE_GET_DIR(ep->bEndpointAddress) >> 7;
650 memset(&cfg, 0, sizeof(struct usb_config));
651 cfg.type = UE_GET_XFERTYPE(ep->bmAttributes);
652 cfg.endpoint = UE_GET_ADDR(ep->bEndpointAddress);
653 cfg.direction = UE_GET_DIR(ep->bEndpointAddress);
654 cfg.callback = &usbd_non_isoc_callback;
655 cfg.bufsize = UGETW(ep->wMaxPacketSize);
656 cfg.flags.proxy_buffer = 1;
657 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
658 cfg.flags.short_xfer_ok = 1;
660 status = usbd_transfer_setup(sc->ndisusb_dev, &ifidx, ne->ne_xfer,
661 &cfg, 1, sc, &sc->ndisusb_lock);
662 if (status != USB_ERR_NORMAL_COMPLETION) {
663 device_printf(dev, "couldn't setup xfer: %s\n",
664 usbd_errstr(status));
667 xfer = ne->ne_xfer[0];
668 usbd_xfer_set_priv(xfer, ne);
669 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
670 usbd_xfer_set_timeout(xfer, NDISUSB_NO_TIMEOUT);
672 if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_BULK)
673 usbd_xfer_set_timeout(xfer, NDISUSB_TX_TIMEOUT);
675 usbd_xfer_set_timeout(xfer, NDISUSB_INTR_TIMEOUT);
682 usbd_func_abort_pipe(irp *ip)
684 device_t dev = IRP_NDIS_DEV(ip);
685 struct ndis_softc *sc = device_get_softc(dev);
686 struct ndisusb_ep *ne;
689 urb = usbd_geturb(ip);
690 ne = usbd_get_ndisep(ip, urb->uu_pipe.upr_handle);
692 device_printf(IRP_NDIS_DEV(ip), "get NULL endpoint info.\n");
693 return (USBD_STATUS_INVALID_PIPE_HANDLE);
697 usbd_transfer_stop(ne->ne_xfer[0]);
698 usbd_transfer_start(ne->ne_xfer[0]);
701 return (USBD_STATUS_SUCCESS);
705 usbd_func_vendorclass(irp *ip)
707 device_t dev = IRP_NDIS_DEV(ip);
709 struct ndis_softc *sc = device_get_softc(dev);
710 struct ndisusb_ep *ne;
711 struct ndisusb_xfer *nx;
712 struct usbd_urb_vendor_or_class_request *vcreq;
715 if (!(sc->ndisusb_status & NDISUSB_STATUS_SETUP_EP)) {
717 * XXX In some cases the interface number isn't 0. However
718 * some driver (eg. RTL8187L NDIS driver) calls this function
719 * before calling URB_FUNCTION_SELECT_CONFIGURATION.
721 error = usbd_setup_endpoint_default(ip, 0);
722 if (error != USB_ERR_NORMAL_COMPLETION)
723 return usbd_usb2urb(error);
724 sc->ndisusb_status |= NDISUSB_STATUS_SETUP_EP;
727 urb = usbd_geturb(ip);
728 vcreq = &urb->uu_vcreq;
729 ne = (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ?
730 &sc->ndisusb_dread_ep : &sc->ndisusb_dwrite_ep;
731 IRP_NDISUSB_EP(ip) = ne;
732 ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap;
734 nx = kmalloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO);
736 device_printf(IRP_NDIS_DEV(ip), "out of memory\n");
737 return (USBD_STATUS_NO_MEMORY);
741 KeAcquireSpinLockAtDpcLevel(&ne->ne_lock);
742 InsertTailList((&ne->ne_pending), (&nx->nx_next));
743 KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
745 /* we've done to setup xfer. Let's transfer it. */
746 ip->irp_iostat.isb_status = STATUS_PENDING;
747 ip->irp_iostat.isb_info = 0;
748 USBD_URB_STATUS(urb) = USBD_STATUS_PENDING;
749 IoMarkIrpPending(ip);
751 error = usbd_taskadd(ip, NDISUSB_TASK_VENDOR);
752 if (error != USBD_STATUS_SUCCESS)
755 return (USBD_STATUS_PENDING);
759 usbd_irpcancel(device_object *dobj, irp *ip)
761 device_t dev = IRP_NDIS_DEV(ip);
762 struct ndis_softc *sc = device_get_softc(dev);
763 struct ndisusb_ep *ne = IRP_NDISUSB_EP(ip);
766 ip->irp_cancel = TRUE;
767 IoReleaseCancelSpinLock(ip->irp_cancelirql);
772 * Make sure that the current USB transfer proxy is
773 * cancelled and then restarted.
776 usbd_transfer_stop(ne->ne_xfer[0]);
777 usbd_transfer_start(ne->ne_xfer[0]);
780 ip->irp_cancel = TRUE;
781 IoReleaseCancelSpinLock(ip->irp_cancelirql);
785 usbd_xfer_complete(struct ndis_softc *sc, struct ndisusb_ep *ne,
786 struct ndisusb_xfer *nx, usb_error_t status)
788 struct ndisusb_xferdone *nd;
791 nd = kmalloc(sizeof(struct ndisusb_xferdone), M_USBDEV,
794 device_printf(sc->ndis_dev, "out of memory");
798 nd->nd_status = status;
800 KeAcquireSpinLock(&sc->ndisusb_xferdonelock, &irql);
801 InsertTailList((&sc->ndisusb_xferdonelist), (&nd->nd_donelist));
802 KeReleaseSpinLock(&sc->ndisusb_xferdonelock, irql);
804 IoQueueWorkItem(sc->ndisusb_xferdoneitem,
805 (io_workitem_func)usbd_xfertask_wrap, WORKQUEUE_CRITICAL, sc);
808 static struct ndisusb_xfer *
809 usbd_aq_getfirst(struct ndis_softc *sc, struct ndisusb_ep *ne)
811 struct ndisusb_xfer *nx;
813 KeAcquireSpinLockAtDpcLevel(&ne->ne_lock);
814 if (IsListEmpty(&ne->ne_active)) {
815 device_printf(sc->ndis_dev,
816 "%s: the active queue can't be empty.\n", __func__);
817 KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
820 nx = CONTAINING_RECORD(ne->ne_active.nle_flink, struct ndisusb_xfer,
822 RemoveEntryList(&nx->nx_next);
823 KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
829 usbd_non_isoc_callback(struct usb_xfer *xfer, usb_error_t error)
832 struct ndis_softc *sc = usbd_xfer_softc(xfer);
833 struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer);
834 struct ndisusb_xfer *nx;
835 struct usbd_urb_bulk_or_intr_transfer *ubi;
836 struct usb_page_cache *pc;
840 usb_endpoint_descriptor_t *ep;
843 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
845 switch (USB_GET_STATE(xfer)) {
846 case USB_ST_TRANSFERRED:
847 nx = usbd_aq_getfirst(sc, ne);
848 pc = usbd_xfer_get_frame(xfer, 0);
852 /* copy in data with regard to the URB */
853 if (ne->ne_dirin != 0)
854 usbd_copy_out(pc, 0, nx->nx_urbbuf, actlen);
855 nx->nx_urbbuf += actlen;
856 nx->nx_urbactlen += actlen;
857 nx->nx_urblen -= actlen;
859 /* check for short transfer */
863 /* check remainder */
864 if (nx->nx_urblen > 0) {
865 KeAcquireSpinLock(&ne->ne_lock, &irql);
866 InsertHeadList((&ne->ne_active), (&nx->nx_next));
867 KeReleaseSpinLock(&ne->ne_lock, irql);
870 urb = usbd_geturb(ip);
871 ubi = &urb->uu_bulkintr;
872 ep = ubi->ubi_epdesc;
876 usbd_xfer_complete(sc, ne, nx,
877 ((actlen < sumlen) && (nx->nx_shortxfer == 0)) ?
878 USB_ERR_SHORT_XFER : USB_ERR_NORMAL_COMPLETION);
883 /* get next transfer */
884 KeAcquireSpinLock(&ne->ne_lock, &irql);
885 if (IsListEmpty(&ne->ne_pending)) {
886 KeReleaseSpinLock(&ne->ne_lock, irql);
889 nx = CONTAINING_RECORD(ne->ne_pending.nle_flink,
890 struct ndisusb_xfer, nx_next);
891 RemoveEntryList(&nx->nx_next);
892 /* add a entry to the active queue's tail. */
893 InsertTailList((&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;
901 nx->nx_urbbuf = ubi->ubi_trans_buf;
902 nx->nx_urbactlen = 0;
903 nx->nx_urblen = ubi->ubi_trans_buflen;
904 nx->nx_shortxfer = (ubi->ubi_trans_flags &
905 USBD_SHORT_TRANSFER_OK) ? 1 : 0;
907 len = MIN(usbd_xfer_max_len(xfer), nx->nx_urblen);
908 pc = usbd_xfer_get_frame(xfer, 0);
909 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_OUT)
910 usbd_copy_in(pc, 0, nx->nx_urbbuf, len);
911 usbd_xfer_set_frame_len(xfer, 0, len);
912 usbd_xfer_set_frames(xfer, 1);
913 usbd_transfer_submit(xfer);
916 nx = usbd_aq_getfirst(sc, ne);
919 if (error != USB_ERR_CANCELLED) {
920 usbd_xfer_set_stall(xfer);
921 device_printf(sc->ndis_dev, "usb xfer warning (%s)\n",
924 usbd_xfer_complete(sc, ne, nx, error);
925 if (error != USB_ERR_CANCELLED)
932 usbd_ctrl_callback(struct usb_xfer *xfer, usb_error_t error)
935 struct ndis_softc *sc = usbd_xfer_softc(xfer);
936 struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer);
937 struct ndisusb_xfer *nx;
940 struct usbd_urb_vendor_or_class_request *vcreq;
941 struct usb_page_cache *pc;
943 struct usb_device_request req;
946 switch (USB_GET_STATE(xfer)) {
947 case USB_ST_TRANSFERRED:
948 nx = usbd_aq_getfirst(sc, ne);
953 urb = usbd_geturb(ip);
954 vcreq = &urb->uu_vcreq;
956 if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
957 pc = usbd_xfer_get_frame(xfer, 1);
958 len = usbd_xfer_frame_len(xfer, 1);
959 usbd_copy_out(pc, 0, vcreq->uvc_trans_buf, len);
960 nx->nx_urbactlen += len;
963 usbd_xfer_complete(sc, ne, nx, USB_ERR_NORMAL_COMPLETION);
967 /* get next transfer */
968 KeAcquireSpinLock(&ne->ne_lock, &irql);
969 if (IsListEmpty(&ne->ne_pending)) {
970 KeReleaseSpinLock(&ne->ne_lock, irql);
973 nx = CONTAINING_RECORD(ne->ne_pending.nle_flink,
974 struct ndisusb_xfer, nx_next);
975 RemoveEntryList(&nx->nx_next);
976 /* add a entry to the active queue's tail. */
977 InsertTailList((&ne->ne_active), (&nx->nx_next));
978 KeReleaseSpinLock(&ne->ne_lock, irql);
981 urb = usbd_geturb(ip);
982 vcreq = &urb->uu_vcreq;
984 switch (urb->uu_hdr.uuh_func) {
985 case URB_FUNCTION_CLASS_DEVICE:
986 type = UT_CLASS | UT_DEVICE;
988 case URB_FUNCTION_CLASS_INTERFACE:
989 type = UT_CLASS | UT_INTERFACE;
991 case URB_FUNCTION_CLASS_OTHER:
992 type = UT_CLASS | UT_OTHER;
994 case URB_FUNCTION_CLASS_ENDPOINT:
995 type = UT_CLASS | UT_ENDPOINT;
997 case URB_FUNCTION_VENDOR_DEVICE:
998 type = UT_VENDOR | UT_DEVICE;
1000 case URB_FUNCTION_VENDOR_INTERFACE:
1001 type = UT_VENDOR | UT_INTERFACE;
1003 case URB_FUNCTION_VENDOR_OTHER:
1004 type = UT_VENDOR | UT_OTHER;
1006 case URB_FUNCTION_VENDOR_ENDPOINT:
1007 type = UT_VENDOR | UT_ENDPOINT;
1010 /* never reached. */
1014 type |= (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ?
1016 type |= vcreq->uvc_reserved1;
1018 req.bmRequestType = type;
1019 req.bRequest = vcreq->uvc_req;
1020 USETW(req.wIndex, vcreq->uvc_idx);
1021 USETW(req.wValue, vcreq->uvc_value);
1022 USETW(req.wLength, vcreq->uvc_trans_buflen);
1024 nx->nx_urbbuf = vcreq->uvc_trans_buf;
1025 nx->nx_urblen = vcreq->uvc_trans_buflen;
1026 nx->nx_urbactlen = 0;
1028 pc = usbd_xfer_get_frame(xfer, 0);
1029 usbd_copy_in(pc, 0, &req, sizeof(req));
1030 usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1031 usbd_xfer_set_frames(xfer, 1);
1032 if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
1033 if (vcreq->uvc_trans_buflen >= USBD_CTRL_READ_BUFFER_SP)
1034 device_printf(sc->ndis_dev,
1035 "warning: not enough buffer space (%d).\n",
1036 vcreq->uvc_trans_buflen);
1037 usbd_xfer_set_frame_len(xfer, 1,
1038 MIN(usbd_xfer_max_len(xfer),
1039 vcreq->uvc_trans_buflen));
1040 usbd_xfer_set_frames(xfer, 2);
1042 if (nx->nx_urblen > USBD_CTRL_WRITE_BUFFER_SP)
1043 device_printf(sc->ndis_dev,
1044 "warning: not enough write buffer space"
1045 " (%d).\n", nx->nx_urblen);
1047 * XXX with my local tests there was no cases to require
1048 * a extra buffer until now but it'd need to update in
1049 * the future if it needs to be.
1051 if (nx->nx_urblen > 0) {
1052 pc = usbd_xfer_get_frame(xfer, 1);
1053 usbd_copy_in(pc, 0, nx->nx_urbbuf,
1055 usbd_xfer_set_frame_len(xfer, 1, nx->nx_urblen);
1056 usbd_xfer_set_frames(xfer, 2);
1059 usbd_transfer_submit(xfer);
1062 nx = usbd_aq_getfirst(sc, ne);
1065 if (error != USB_ERR_CANCELLED) {
1066 usbd_xfer_set_stall(xfer);
1067 device_printf(sc->ndis_dev, "usb xfer warning (%s)\n",
1068 usbd_errstr(error));
1070 usbd_xfer_complete(sc, ne, nx, error);
1071 if (error != USB_ERR_CANCELLED)
1077 static struct ndisusb_ep *
1078 usbd_get_ndisep(irp *ip, usb_endpoint_descriptor_t *ep)
1080 device_t dev = IRP_NDIS_DEV(ip);
1081 struct ndis_softc *sc = device_get_softc(dev);
1082 struct ndisusb_ep *ne;
1084 ne = &sc->ndisusb_ep[NDISUSB_GET_ENDPT(ep->bEndpointAddress)];
1086 IRP_NDISUSB_EP(ip) = ne;
1087 ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap;
1093 usbd_xfertask(device_object *dobj, void *arg)
1098 struct ndis_softc *sc = arg;
1099 struct ndisusb_xferdone *nd;
1100 struct ndisusb_xfer *nq;
1101 struct usbd_urb_bulk_or_intr_transfer *ubi;
1102 struct usbd_urb_vendor_or_class_request *vcreq;
1103 union usbd_urb *urb;
1107 if (IsListEmpty(&sc->ndisusb_xferdonelist))
1110 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_xferdonelock);
1111 l = sc->ndisusb_xferdonelist.nle_flink;
1112 while (l != &sc->ndisusb_xferdonelist) {
1113 nd = CONTAINING_RECORD(l, struct ndisusb_xferdone, nd_donelist);
1116 status = nd->nd_status;
1119 urb = usbd_geturb(ip);
1121 ip->irp_cancelfunc = NULL;
1122 IRP_NDISUSB_EP(ip) = NULL;
1125 case USB_ERR_NORMAL_COMPLETION:
1126 if (urb->uu_hdr.uuh_func ==
1127 URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) {
1128 ubi = &urb->uu_bulkintr;
1129 ubi->ubi_trans_buflen = nq->nx_urbactlen;
1131 vcreq = &urb->uu_vcreq;
1132 vcreq->uvc_trans_buflen = nq->nx_urbactlen;
1134 ip->irp_iostat.isb_info = nq->nx_urbactlen;
1135 ip->irp_iostat.isb_status = STATUS_SUCCESS;
1136 USBD_URB_STATUS(urb) = USBD_STATUS_SUCCESS;
1138 case USB_ERR_CANCELLED:
1139 ip->irp_iostat.isb_info = 0;
1140 ip->irp_iostat.isb_status = STATUS_CANCELLED;
1141 USBD_URB_STATUS(urb) = USBD_STATUS_CANCELED;
1144 ip->irp_iostat.isb_info = 0;
1145 USBD_URB_STATUS(urb) = usbd_usb2urb(status);
1146 ip->irp_iostat.isb_status =
1147 usbd_urb2nt(USBD_URB_STATUS(urb));
1152 RemoveEntryList(&nd->nd_donelist);
1153 kfree(nq, M_USBDEV);
1154 kfree(nd, M_USBDEV);
1157 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_xferdonelock);
1158 /* NB: call after cleaning */
1159 IoCompleteRequest(ip, IO_NO_INCREMENT);
1160 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_xferdonelock);
1162 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_xferdonelock);
1166 * this function is for mainly deferring a task to the another thread because
1167 * we don't want to be in the scope of HAL lock.
1170 usbd_taskadd(irp *ip, unsigned type)
1172 device_t dev = IRP_NDIS_DEV(ip);
1173 struct ndis_softc *sc = device_get_softc(dev);
1174 struct ndisusb_task *nt;
1176 nt = kmalloc(sizeof(struct ndisusb_task), M_USBDEV, M_NOWAIT | M_ZERO);
1178 return (USBD_STATUS_NO_MEMORY);
1182 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock);
1183 InsertTailList((&sc->ndisusb_tasklist), (&nt->nt_tasklist));
1184 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock);
1186 IoQueueWorkItem(sc->ndisusb_taskitem,
1187 (io_workitem_func)usbd_task_wrap, WORKQUEUE_CRITICAL, sc);
1189 return (USBD_STATUS_SUCCESS);
1193 usbd_task(device_object *dobj, void *arg)
1197 struct ndis_softc *sc = arg;
1198 struct ndisusb_ep *ne;
1199 struct ndisusb_task *nt;
1200 union usbd_urb *urb;
1202 if (IsListEmpty(&sc->ndisusb_tasklist))
1205 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock);
1206 l = sc->ndisusb_tasklist.nle_flink;
1207 while (l != &sc->ndisusb_tasklist) {
1208 nt = CONTAINING_RECORD(l, struct ndisusb_task, nt_tasklist);
1211 urb = usbd_geturb(ip);
1213 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock);
1215 switch (nt->nt_type) {
1216 case NDISUSB_TASK_TSTART:
1217 ne = usbd_get_ndisep(ip, urb->uu_bulkintr.ubi_epdesc);
1220 usbd_transfer_start(ne->ne_xfer[0]);
1222 case NDISUSB_TASK_IRPCANCEL:
1223 ne = usbd_get_ndisep(ip,
1224 (nt->nt_type == NDISUSB_TASK_IRPCANCEL) ?
1225 urb->uu_bulkintr.ubi_epdesc :
1226 urb->uu_pipe.upr_handle);
1230 usbd_transfer_stop(ne->ne_xfer[0]);
1231 usbd_transfer_start(ne->ne_xfer[0]);
1233 case NDISUSB_TASK_VENDOR:
1234 ne = (urb->uu_vcreq.uvc_trans_flags &
1235 USBD_TRANSFER_DIRECTION_IN) ?
1236 &sc->ndisusb_dread_ep : &sc->ndisusb_dwrite_ep;
1237 usbd_transfer_start(ne->ne_xfer[0]);
1244 KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock);
1247 RemoveEntryList(&nt->nt_tasklist);
1248 kfree(nt, M_USBDEV);
1250 KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock);
1254 usbd_func_bulkintr(irp *ip)
1257 struct ndisusb_ep *ne;
1258 struct ndisusb_xfer *nx;
1259 struct usbd_urb_bulk_or_intr_transfer *ubi;
1260 union usbd_urb *urb;
1261 usb_endpoint_descriptor_t *ep;
1263 urb = usbd_geturb(ip);
1264 ubi = &urb->uu_bulkintr;
1265 ep = ubi->ubi_epdesc;
1267 return (USBD_STATUS_INVALID_PIPE_HANDLE);
1269 ne = usbd_get_ndisep(ip, ep);
1271 device_printf(IRP_NDIS_DEV(ip), "get NULL endpoint info.\n");
1272 return (USBD_STATUS_INVALID_PIPE_HANDLE);
1275 nx = kmalloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO);
1277 device_printf(IRP_NDIS_DEV(ip), "out of memory\n");
1278 return (USBD_STATUS_NO_MEMORY);
1282 KeAcquireSpinLockAtDpcLevel(&ne->ne_lock);
1283 InsertTailList((&ne->ne_pending), (&nx->nx_next));
1284 KeReleaseSpinLockFromDpcLevel(&ne->ne_lock);
1286 /* we've done to setup xfer. Let's transfer it. */
1287 ip->irp_iostat.isb_status = STATUS_PENDING;
1288 ip->irp_iostat.isb_info = 0;
1289 USBD_URB_STATUS(urb) = USBD_STATUS_PENDING;
1290 IoMarkIrpPending(ip);
1292 error = usbd_taskadd(ip, NDISUSB_TASK_TSTART);
1293 if (error != USBD_STATUS_SUCCESS)
1296 return (USBD_STATUS_PENDING);
1299 static union usbd_urb *
1300 USBD_CreateConfigurationRequest(usb_config_descriptor_t *conf, uint16_t *len)
1302 struct usbd_interface_list_entry list[2];
1303 union usbd_urb *urb;
1305 bzero(list, sizeof(struct usbd_interface_list_entry) * 2);
1306 list[0].uil_intfdesc = USBD_ParseConfigurationDescriptorEx(conf, conf,
1307 -1, -1, -1, -1, -1);
1308 urb = USBD_CreateConfigurationRequestEx(conf, list);
1312 *len = urb->uu_selconf.usc_hdr.uuh_len;
1316 static union usbd_urb *
1317 USBD_CreateConfigurationRequestEx(usb_config_descriptor_t *conf,
1318 struct usbd_interface_list_entry *list)
1321 struct usbd_interface_information *intf;
1322 struct usbd_pipe_information *pipe;
1323 struct usbd_urb_select_configuration *selconf;
1324 usb_interface_descriptor_t *desc;
1326 for (i = 0, size = 0; i < conf->bNumInterface; i++) {
1327 j = list[i].uil_intfdesc->bNumEndpoints;
1328 size = size + sizeof(struct usbd_interface_information) +
1329 sizeof(struct usbd_pipe_information) * (j - 1);
1331 size += sizeof(struct usbd_urb_select_configuration) -
1332 sizeof(struct usbd_interface_information);
1334 selconf = ExAllocatePoolWithTag(NonPagedPool, size, 0);
1335 if (selconf == NULL)
1337 selconf->usc_hdr.uuh_func = URB_FUNCTION_SELECT_CONFIGURATION;
1338 selconf->usc_hdr.uuh_len = size;
1339 selconf->usc_handle = conf;
1340 selconf->usc_conf = conf;
1342 intf = &selconf->usc_intf;
1343 for (i = 0; i < conf->bNumInterface; i++) {
1344 if (list[i].uil_intfdesc == NULL)
1347 list[i].uil_intf = intf;
1348 desc = list[i].uil_intfdesc;
1350 intf->uii_len = sizeof(struct usbd_interface_information) +
1351 (desc->bNumEndpoints - 1) *
1352 sizeof(struct usbd_pipe_information);
1353 intf->uii_intfnum = desc->bInterfaceNumber;
1354 intf->uii_altset = desc->bAlternateSetting;
1355 intf->uii_intfclass = desc->bInterfaceClass;
1356 intf->uii_intfsubclass = desc->bInterfaceSubClass;
1357 intf->uii_intfproto = desc->bInterfaceProtocol;
1358 intf->uii_handle = desc;
1359 intf->uii_numeps = desc->bNumEndpoints;
1361 pipe = &intf->uii_pipes[0];
1362 for (j = 0; j < intf->uii_numeps; j++)
1363 pipe[j].upi_maxtxsize =
1364 USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
1366 intf = (struct usbd_interface_information *)((char *)intf +
1370 return ((union usbd_urb *)selconf);
1374 USBD_GetUSBDIVersion(usbd_version_info *ui)
1377 /* Pretend to be Windows XP. */
1379 ui->uvi_usbdi_vers = USBDI_VERSION;
1380 ui->uvi_supported_vers = USB_VER_2_0;
1383 static usb_interface_descriptor_t *
1384 USBD_ParseConfigurationDescriptor(usb_config_descriptor_t *conf,
1385 uint8_t intfnum, uint8_t altset)
1388 return USBD_ParseConfigurationDescriptorEx(conf, conf, intfnum, altset,
1392 static usb_interface_descriptor_t *
1393 USBD_ParseConfigurationDescriptorEx(usb_config_descriptor_t *conf,
1394 void *start, int32_t intfnum, int32_t altset, int32_t intfclass,
1395 int32_t intfsubclass, int32_t intfproto)
1397 struct usb_descriptor *next = NULL;
1398 usb_interface_descriptor_t *desc;
1400 while ((next = usb_desc_foreach(conf, next)) != NULL) {
1401 desc = (usb_interface_descriptor_t *)next;
1402 if (desc->bDescriptorType != UDESC_INTERFACE)
1404 if (!(intfnum == -1 || desc->bInterfaceNumber == intfnum))
1406 if (!(altset == -1 || desc->bAlternateSetting == altset))
1408 if (!(intfclass == -1 || desc->bInterfaceClass == intfclass))
1410 if (!(intfsubclass == -1 ||
1411 desc->bInterfaceSubClass == intfsubclass))
1413 if (!(intfproto == -1 || desc->bInterfaceProtocol == intfproto))
1424 kprintf("USBD dummy called\n");
1427 image_patch_table usbd_functbl[] = {
1428 IMPORT_SFUNC(USBD_CreateConfigurationRequest, 2),
1429 IMPORT_SFUNC(USBD_CreateConfigurationRequestEx, 2),
1430 IMPORT_SFUNC_MAP(_USBD_CreateConfigurationRequestEx@8,
1431 USBD_CreateConfigurationRequestEx, 2),
1432 IMPORT_SFUNC(USBD_GetUSBDIVersion, 1),
1433 IMPORT_SFUNC(USBD_ParseConfigurationDescriptor, 3),
1434 IMPORT_SFUNC(USBD_ParseConfigurationDescriptorEx, 7),
1435 IMPORT_SFUNC_MAP(_USBD_ParseConfigurationDescriptorEx@28,
1436 USBD_ParseConfigurationDescriptorEx, 7),
1439 * This last entry is a catch-all for any function we haven't
1440 * implemented yet. The PE import list patching routine will
1441 * use it for any function that doesn't have an explicit match
1445 { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL },
1449 { NULL, NULL, NULL }
1452 MODULE_DEPEND(ndis, usb, 1, 1, 1);