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_media.h>
54 #include <netproto/802_11/ieee80211_var.h>
55 #include <netproto/802_11/ieee80211_ioctl.h>
57 #include <bus/u4b/usb.h>
58 #include <bus/u4b/usbdi.h>
59 #include <bus/u4b/usbdi_util.h>
60 #include <bus/u4b/usb_busdma.h>
61 #include <bus/u4b/usb_device.h>
62 #include <bus/u4b/usb_request.h>
64 #include <emulation/ndis/pe_var.h>
65 #include <emulation/ndis/cfg_var.h>
66 #include <emulation/ndis/resource_var.h>
67 #include <emulation/ndis/ntoskrnl_var.h>
68 #include <emulation/ndis/ndis_var.h>
69 #include <emulation/ndis/hal_var.h>
70 #include <emulation/ndis/u4bd_var.h>
71 #include <dev/netif/ndis/if_ndisvar.h>
73 static driver_object usbd_driver
;
74 static usb_callback_t usbd_non_isoc_callback
;
75 static usb_callback_t usbd_ctrl_callback
;
77 #define USBD_CTRL_READ_PIPE 0
78 #define USBD_CTRL_WRITE_PIPE 1
79 #define USBD_CTRL_MAX_PIPE 2
80 #define USBD_CTRL_READ_BUFFER_SP 256
81 #define USBD_CTRL_WRITE_BUFFER_SP 256
82 #define USBD_CTRL_READ_BUFFER_SIZE \
83 (sizeof(struct usb_device_request) + USBD_CTRL_READ_BUFFER_SP)
84 #define USBD_CTRL_WRITE_BUFFER_SIZE \
85 (sizeof(struct usb_device_request) + USBD_CTRL_WRITE_BUFFER_SP)
86 static struct usb_config usbd_default_epconfig
[USBD_CTRL_MAX_PIPE
] = {
87 [USBD_CTRL_READ_PIPE
] = {
89 .endpoint
= 0x00, /* control pipe */
90 .direction
= UE_DIR_ANY
,
92 .bufsize
= USBD_CTRL_READ_BUFFER_SIZE
,
93 .flags
= { .short_xfer_ok
= 1, },
94 .callback
= &usbd_ctrl_callback
,
95 .timeout
= 5000, /* 5 seconds */
97 [USBD_CTRL_WRITE_PIPE
] = {
99 .endpoint
= 0x00, /* control pipe */
100 .direction
= UE_DIR_ANY
,
102 .bufsize
= USBD_CTRL_WRITE_BUFFER_SIZE
,
103 .flags
= { .proxy_buffer
= 1, },
104 .callback
= &usbd_ctrl_callback
,
105 .timeout
= 5000, /* 5 seconds */
109 static int32_t usbd_func_bulkintr(irp
*);
110 static int32_t usbd_func_vendorclass(irp
*);
111 static int32_t usbd_func_selconf(irp
*);
112 static int32_t usbd_func_abort_pipe(irp
*);
113 static usb_error_t
usbd_setup_endpoint(irp
*, uint8_t,
114 struct usb_endpoint_descriptor
*);
115 static usb_error_t
usbd_setup_endpoint_default(irp
*, uint8_t);
116 static usb_error_t
usbd_setup_endpoint_one(irp
*, uint8_t,
117 struct ndisusb_ep
*, struct usb_config
*);
118 static int32_t usbd_func_getdesc(irp
*);
119 static union usbd_urb
*usbd_geturb(irp
*);
120 static struct ndisusb_ep
*usbd_get_ndisep(irp
*, usb_endpoint_descriptor_t
*);
121 static int32_t usbd_iodispatch(device_object
*, irp
*);
122 static int32_t usbd_ioinvalid(device_object
*, irp
*);
123 static int32_t usbd_pnp(device_object
*, irp
*);
124 static int32_t usbd_power(device_object
*, irp
*);
125 static void usbd_irpcancel(device_object
*, irp
*);
126 static int32_t usbd_submit_urb(irp
*);
127 static int32_t usbd_urb2nt(int32_t);
128 static void usbd_task(device_object
*, void *);
129 static int32_t usbd_taskadd(irp
*, unsigned);
130 static void usbd_xfertask(device_object
*, void *);
131 static void dummy(void);
133 static union usbd_urb
*USBD_CreateConfigurationRequestEx(
134 usb_config_descriptor_t
*,
135 struct usbd_interface_list_entry
*);
136 static union usbd_urb
*USBD_CreateConfigurationRequest(
137 usb_config_descriptor_t
*,
139 static void USBD_GetUSBDIVersion(usbd_version_info
*);
140 static usb_interface_descriptor_t
*USBD_ParseConfigurationDescriptorEx(
141 usb_config_descriptor_t
*, void *, int32_t, int32_t,
142 int32_t, int32_t, int32_t);
143 static usb_interface_descriptor_t
*USBD_ParseConfigurationDescriptor(
144 usb_config_descriptor_t
*, uint8_t, uint8_t);
147 * We need to wrap these functions because these need `context switch' from
148 * Windows to UNIX before it's called.
150 static funcptr usbd_iodispatch_wrap
;
151 static funcptr usbd_ioinvalid_wrap
;
152 static funcptr usbd_pnp_wrap
;
153 static funcptr usbd_power_wrap
;
154 static funcptr usbd_irpcancel_wrap
;
155 static funcptr usbd_task_wrap
;
156 static funcptr usbd_xfertask_wrap
;
161 image_patch_table
*patch
;
164 patch
= usbd_functbl
;
165 while (patch
->ipt_func
!= NULL
) {
166 windrv_wrap((funcptr
)patch
->ipt_func
,
167 (funcptr
*)&patch
->ipt_wrap
,
168 patch
->ipt_argcnt
, patch
->ipt_ftype
);
172 windrv_wrap((funcptr
)usbd_ioinvalid
,
173 (funcptr
*)&usbd_ioinvalid_wrap
, 2, WINDRV_WRAP_STDCALL
);
174 windrv_wrap((funcptr
)usbd_iodispatch
,
175 (funcptr
*)&usbd_iodispatch_wrap
, 2, WINDRV_WRAP_STDCALL
);
176 windrv_wrap((funcptr
)usbd_pnp
,
177 (funcptr
*)&usbd_pnp_wrap
, 2, WINDRV_WRAP_STDCALL
);
178 windrv_wrap((funcptr
)usbd_power
,
179 (funcptr
*)&usbd_power_wrap
, 2, WINDRV_WRAP_STDCALL
);
180 windrv_wrap((funcptr
)usbd_irpcancel
,
181 (funcptr
*)&usbd_irpcancel_wrap
, 2, WINDRV_WRAP_STDCALL
);
182 windrv_wrap((funcptr
)usbd_task
,
183 (funcptr
*)&usbd_task_wrap
, 2, WINDRV_WRAP_STDCALL
);
184 windrv_wrap((funcptr
)usbd_xfertask
,
185 (funcptr
*)&usbd_xfertask_wrap
, 2, WINDRV_WRAP_STDCALL
);
187 /* Create a fake USB driver instance. */
189 windrv_bus_attach(&usbd_driver
, "USB Bus");
191 /* Set up our dipatch routine. */
192 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
193 usbd_driver
.dro_dispatch
[i
] =
194 (driver_dispatch
)usbd_ioinvalid_wrap
;
196 usbd_driver
.dro_dispatch
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] =
197 (driver_dispatch
)usbd_iodispatch_wrap
;
198 usbd_driver
.dro_dispatch
[IRP_MJ_DEVICE_CONTROL
] =
199 (driver_dispatch
)usbd_iodispatch_wrap
;
200 usbd_driver
.dro_dispatch
[IRP_MJ_POWER
] =
201 (driver_dispatch
)usbd_power_wrap
;
202 usbd_driver
.dro_dispatch
[IRP_MJ_PNP
] =
203 (driver_dispatch
)usbd_pnp_wrap
;
211 image_patch_table
*patch
;
213 patch
= usbd_functbl
;
214 while (patch
->ipt_func
!= NULL
) {
215 windrv_unwrap(patch
->ipt_wrap
);
219 windrv_unwrap(usbd_ioinvalid_wrap
);
220 windrv_unwrap(usbd_iodispatch_wrap
);
221 windrv_unwrap(usbd_pnp_wrap
);
222 windrv_unwrap(usbd_power_wrap
);
223 windrv_unwrap(usbd_irpcancel_wrap
);
224 windrv_unwrap(usbd_task_wrap
);
225 windrv_unwrap(usbd_xfertask_wrap
);
227 kfree(usbd_driver
.dro_drivername
.us_buf
, M_DEVBUF
);
233 usbd_iodispatch(device_object
*dobj
, irp
*ip
)
235 device_t dev
= dobj
->do_devext
;
237 struct io_stack_location
*irp_sl
;
239 irp_sl
= IoGetCurrentIrpStackLocation(ip
);
240 switch (irp_sl
->isl_parameters
.isl_ioctl
.isl_iocode
) {
241 case IOCTL_INTERNAL_USB_SUBMIT_URB
:
242 IRP_NDIS_DEV(ip
) = dev
;
244 status
= usbd_submit_urb(ip
);
247 device_printf(dev
, "ioctl 0x%x isn't supported\n",
248 irp_sl
->isl_parameters
.isl_ioctl
.isl_iocode
);
249 status
= USBD_STATUS_NOT_SUPPORTED
;
253 if (status
== USBD_STATUS_PENDING
)
254 return (STATUS_PENDING
);
256 ip
->irp_iostat
.isb_status
= usbd_urb2nt(status
);
257 if (status
!= USBD_STATUS_SUCCESS
)
258 ip
->irp_iostat
.isb_info
= 0;
259 return (ip
->irp_iostat
.isb_status
);
263 usbd_ioinvalid(device_object
*dobj
, irp
*ip
)
265 device_t dev
= dobj
->do_devext
;
266 struct io_stack_location
*irp_sl
;
268 irp_sl
= IoGetCurrentIrpStackLocation(ip
);
269 device_printf(dev
, "invalid I/O dispatch %d:%d\n", irp_sl
->isl_major
,
272 ip
->irp_iostat
.isb_status
= STATUS_FAILURE
;
273 ip
->irp_iostat
.isb_info
= 0;
275 IoCompleteRequest(ip
, IO_NO_INCREMENT
);
277 return (STATUS_FAILURE
);
281 usbd_pnp(device_object
*dobj
, irp
*ip
)
283 device_t dev
= dobj
->do_devext
;
284 struct io_stack_location
*irp_sl
;
286 irp_sl
= IoGetCurrentIrpStackLocation(ip
);
287 device_printf(dev
, "%s: unsupported I/O dispatch %d:%d\n",
288 __func__
, irp_sl
->isl_major
, irp_sl
->isl_minor
);
290 ip
->irp_iostat
.isb_status
= STATUS_FAILURE
;
291 ip
->irp_iostat
.isb_info
= 0;
293 IoCompleteRequest(ip
, IO_NO_INCREMENT
);
295 return (STATUS_FAILURE
);
299 usbd_power(device_object
*dobj
, irp
*ip
)
301 device_t dev
= dobj
->do_devext
;
302 struct io_stack_location
*irp_sl
;
304 irp_sl
= IoGetCurrentIrpStackLocation(ip
);
305 device_printf(dev
, "%s: unsupported I/O dispatch %d:%d\n",
306 __func__
, irp_sl
->isl_major
, irp_sl
->isl_minor
);
308 ip
->irp_iostat
.isb_status
= STATUS_FAILURE
;
309 ip
->irp_iostat
.isb_info
= 0;
311 IoCompleteRequest(ip
, IO_NO_INCREMENT
);
313 return (STATUS_FAILURE
);
316 /* Convert USBD_STATUS to NTSTATUS */
318 usbd_urb2nt(int32_t status
)
322 case USBD_STATUS_SUCCESS
:
323 return (STATUS_SUCCESS
);
324 case USBD_STATUS_DEVICE_GONE
:
325 return (STATUS_DEVICE_NOT_CONNECTED
);
326 case USBD_STATUS_PENDING
:
327 return (STATUS_PENDING
);
328 case USBD_STATUS_NOT_SUPPORTED
:
329 return (STATUS_NOT_IMPLEMENTED
);
330 case USBD_STATUS_NO_MEMORY
:
331 return (STATUS_NO_MEMORY
);
332 case USBD_STATUS_REQUEST_FAILED
:
333 return (STATUS_NOT_SUPPORTED
);
334 case USBD_STATUS_CANCELED
:
335 return (STATUS_CANCELLED
);
340 return (STATUS_FAILURE
);
343 /* Convert FreeBSD's usb_error_t to USBD_STATUS */
345 usbd_usb2urb(int status
)
349 case USB_ERR_NORMAL_COMPLETION
:
350 return (USBD_STATUS_SUCCESS
);
351 case USB_ERR_PENDING_REQUESTS
:
352 return (USBD_STATUS_PENDING
);
353 case USB_ERR_TIMEOUT
:
354 return (USBD_STATUS_TIMEOUT
);
355 case USB_ERR_SHORT_XFER
:
356 return (USBD_STATUS_ERROR_SHORT_TRANSFER
);
357 case USB_ERR_IOERROR
:
358 return (USBD_STATUS_XACT_ERROR
);
360 return (USBD_STATUS_NO_MEMORY
);
362 return (USBD_STATUS_REQUEST_FAILED
);
363 case USB_ERR_NOT_STARTED
:
364 case USB_ERR_TOO_DEEP
:
365 case USB_ERR_NO_POWER
:
366 return (USBD_STATUS_DEVICE_GONE
);
367 case USB_ERR_CANCELLED
:
368 return (USBD_STATUS_CANCELED
);
373 return (USBD_STATUS_NOT_SUPPORTED
);
376 static union usbd_urb
*
379 struct io_stack_location
*irp_sl
;
381 irp_sl
= IoGetCurrentIrpStackLocation(ip
);
383 return (irp_sl
->isl_parameters
.isl_others
.isl_arg1
);
387 usbd_submit_urb(irp
*ip
)
389 device_t dev
= IRP_NDIS_DEV(ip
);
393 urb
= usbd_geturb(ip
);
395 * In a case of URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
396 * USBD_URB_STATUS(urb) would be set at callback functions like
397 * usbd_intr() or usbd_xfereof().
399 switch (urb
->uu_hdr
.uuh_func
) {
400 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
:
401 status
= usbd_func_bulkintr(ip
);
402 if (status
!= USBD_STATUS_SUCCESS
&&
403 status
!= USBD_STATUS_PENDING
)
404 USBD_URB_STATUS(urb
) = status
;
406 case URB_FUNCTION_VENDOR_DEVICE
:
407 case URB_FUNCTION_VENDOR_INTERFACE
:
408 case URB_FUNCTION_VENDOR_ENDPOINT
:
409 case URB_FUNCTION_VENDOR_OTHER
:
410 case URB_FUNCTION_CLASS_DEVICE
:
411 case URB_FUNCTION_CLASS_INTERFACE
:
412 case URB_FUNCTION_CLASS_ENDPOINT
:
413 case URB_FUNCTION_CLASS_OTHER
:
414 status
= usbd_func_vendorclass(ip
);
415 USBD_URB_STATUS(urb
) = status
;
417 case URB_FUNCTION_SELECT_CONFIGURATION
:
418 status
= usbd_func_selconf(ip
);
419 USBD_URB_STATUS(urb
) = status
;
421 case URB_FUNCTION_ABORT_PIPE
:
422 status
= usbd_func_abort_pipe(ip
);
423 USBD_URB_STATUS(urb
) = status
;
425 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
:
426 status
= usbd_func_getdesc(ip
);
427 USBD_URB_STATUS(urb
) = status
;
430 device_printf(dev
, "func 0x%x isn't supported\n",
431 urb
->uu_hdr
.uuh_func
);
432 USBD_URB_STATUS(urb
) = status
= USBD_STATUS_NOT_SUPPORTED
;
440 usbd_func_getdesc(irp
*ip
)
442 #define NDISUSB_GETDESC_MAXRETRIES 3
443 device_t dev
= IRP_NDIS_DEV(ip
);
444 struct ndis_softc
*sc
= device_get_softc(dev
);
445 struct usbd_urb_control_descriptor_request
*ctldesc
;
449 usb_config_descriptor_t
*cdp
;
452 urb
= usbd_geturb(ip
);
453 ctldesc
= &urb
->uu_ctldesc
;
454 if (ctldesc
->ucd_desctype
== UDESC_CONFIG
) {
456 * The NDIS driver is not allowed to change the
457 * config! There is only one choice!
459 cdp
= usbd_get_config_descriptor(sc
->ndisusb_dev
);
461 status
= USB_ERR_INVAL
;
464 if (cdp
->bDescriptorType
!= UDESC_CONFIG
) {
465 device_printf(dev
, "bad desc %d\n",
466 cdp
->bDescriptorType
);
467 status
= USB_ERR_INVAL
;
470 /* get minimum length */
471 len
= MIN(UGETW(cdp
->wTotalLength
), ctldesc
->ucd_trans_buflen
);
472 /* copy out config descriptor */
473 memcpy(ctldesc
->ucd_trans_buf
, cdp
, len
);
474 /* set actual length */
476 status
= USB_ERR_NORMAL_COMPLETION
;
479 status
= usbd_req_get_desc(sc
->ndisusb_dev
, &sc
->ndisusb_lock
,
480 &actlen
, ctldesc
->ucd_trans_buf
, 2,
481 ctldesc
->ucd_trans_buflen
, ctldesc
->ucd_langid
,
482 ctldesc
->ucd_desctype
, ctldesc
->ucd_idx
,
483 NDISUSB_GETDESC_MAXRETRIES
);
487 if (status
!= USB_ERR_NORMAL_COMPLETION
) {
488 ctldesc
->ucd_trans_buflen
= 0;
489 return usbd_usb2urb(status
);
492 ctldesc
->ucd_trans_buflen
= actlen
;
493 ip
->irp_iostat
.isb_info
= actlen
;
495 return (USBD_STATUS_SUCCESS
);
496 #undef NDISUSB_GETDESC_MAXRETRIES
500 usbd_func_selconf(irp
*ip
)
502 device_t dev
= IRP_NDIS_DEV(ip
);
504 struct ndis_softc
*sc
= device_get_softc(dev
);
505 struct usb_device
*udev
= sc
->ndisusb_dev
;
506 struct usb_endpoint
*ep
= NULL
;
507 struct usbd_interface_information
*intf
;
508 struct usbd_pipe_information
*pipe
;
509 struct usbd_urb_select_configuration
*selconf
;
511 usb_config_descriptor_t
*conf
;
512 usb_endpoint_descriptor_t
*edesc
;
515 urb
= usbd_geturb(ip
);
517 selconf
= &urb
->uu_selconf
;
518 conf
= selconf
->usc_conf
;
520 device_printf(dev
, "select configuration is NULL\n");
521 return usbd_usb2urb(USB_ERR_NORMAL_COMPLETION
);
524 intf
= &selconf
->usc_intf
;
525 for (i
= 0; i
< conf
->bNumInterface
&& intf
->uii_len
> 0; i
++) {
526 ret
= usbd_set_alt_interface_index(udev
,
527 intf
->uii_intfnum
, intf
->uii_altset
);
528 if (ret
!= USB_ERR_NORMAL_COMPLETION
&& ret
!= USB_ERR_IN_USE
) {
530 "setting alternate interface failed: %s\n",
532 return usbd_usb2urb(ret
);
535 for (j
= 0; (ep
= usb_endpoint_foreach(udev
, ep
)); j
++) {
536 if (j
>= intf
->uii_numeps
) {
538 "endpoint %d and above are ignored",
543 pipe
= &intf
->uii_pipes
[j
];
544 pipe
->upi_handle
= edesc
;
545 pipe
->upi_epaddr
= edesc
->bEndpointAddress
;
546 pipe
->upi_maxpktsize
= UGETW(edesc
->wMaxPacketSize
);
547 pipe
->upi_type
= UE_GET_XFERTYPE(edesc
->bmAttributes
);
549 ret
= usbd_setup_endpoint(ip
, intf
->uii_intfnum
, edesc
);
550 if (ret
!= USB_ERR_NORMAL_COMPLETION
)
551 return usbd_usb2urb(ret
);
553 if (pipe
->upi_type
!= UE_INTERRUPT
)
556 /* XXX we're following linux USB's interval policy. */
557 if (udev
->speed
== USB_SPEED_LOW
)
558 pipe
->upi_interval
= edesc
->bInterval
+ 5;
559 else if (udev
->speed
== USB_SPEED_FULL
)
560 pipe
->upi_interval
= edesc
->bInterval
;
566 } while (k1
< edesc
->bInterval
);
567 pipe
->upi_interval
= k0
;
571 intf
= (struct usbd_interface_information
*)(((char *)intf
) +
575 return (USBD_STATUS_SUCCESS
);
579 usbd_setup_endpoint_one(irp
*ip
, uint8_t ifidx
, struct ndisusb_ep
*ne
,
580 struct usb_config
*epconf
)
582 device_t dev
= IRP_NDIS_DEV(ip
);
583 struct ndis_softc
*sc
= device_get_softc(dev
);
584 struct usb_xfer
*xfer
;
587 InitializeListHead(&ne
->ne_active
);
588 InitializeListHead(&ne
->ne_pending
);
589 KeInitializeSpinLock(&ne
->ne_lock
);
591 status
= usbd_transfer_setup(sc
->ndisusb_dev
, &ifidx
, ne
->ne_xfer
,
592 epconf
, 1, sc
, &sc
->ndisusb_lock
);
593 if (status
!= USB_ERR_NORMAL_COMPLETION
) {
594 device_printf(dev
, "couldn't setup xfer: %s\n",
595 usbd_errstr(status
));
598 xfer
= ne
->ne_xfer
[0];
599 usbd_xfer_set_priv(xfer
, ne
);
605 usbd_setup_endpoint_default(irp
*ip
, uint8_t ifidx
)
607 device_t dev
= IRP_NDIS_DEV(ip
);
608 struct ndis_softc
*sc
= device_get_softc(dev
);
612 device_printf(dev
, "warning: ifidx > 0 isn't supported.\n");
614 status
= usbd_setup_endpoint_one(ip
, ifidx
, &sc
->ndisusb_dread_ep
,
615 &usbd_default_epconfig
[USBD_CTRL_READ_PIPE
]);
616 if (status
!= USB_ERR_NORMAL_COMPLETION
)
619 status
= usbd_setup_endpoint_one(ip
, ifidx
, &sc
->ndisusb_dwrite_ep
,
620 &usbd_default_epconfig
[USBD_CTRL_WRITE_PIPE
]);
625 usbd_setup_endpoint(irp
*ip
, uint8_t ifidx
,
626 struct usb_endpoint_descriptor
*ep
)
628 device_t dev
= IRP_NDIS_DEV(ip
);
629 struct ndis_softc
*sc
= device_get_softc(dev
);
630 struct ndisusb_ep
*ne
;
631 struct usb_config cfg
;
632 struct usb_xfer
*xfer
;
635 /* check for non-supported transfer types */
636 if (UE_GET_XFERTYPE(ep
->bmAttributes
) == UE_CONTROL
||
637 UE_GET_XFERTYPE(ep
->bmAttributes
) == UE_ISOCHRONOUS
) {
638 device_printf(dev
, "%s: unsuppotted transfer types %#x\n",
639 __func__
, UE_GET_XFERTYPE(ep
->bmAttributes
));
640 return (USB_ERR_INVAL
);
643 ne
= &sc
->ndisusb_ep
[NDISUSB_GET_ENDPT(ep
->bEndpointAddress
)];
644 InitializeListHead(&ne
->ne_active
);
645 InitializeListHead(&ne
->ne_pending
);
646 KeInitializeSpinLock(&ne
->ne_lock
);
647 ne
->ne_dirin
= UE_GET_DIR(ep
->bEndpointAddress
) >> 7;
649 memset(&cfg
, 0, sizeof(struct usb_config
));
650 cfg
.type
= UE_GET_XFERTYPE(ep
->bmAttributes
);
651 cfg
.endpoint
= UE_GET_ADDR(ep
->bEndpointAddress
);
652 cfg
.direction
= UE_GET_DIR(ep
->bEndpointAddress
);
653 cfg
.callback
= &usbd_non_isoc_callback
;
654 cfg
.bufsize
= UGETW(ep
->wMaxPacketSize
);
655 cfg
.flags
.proxy_buffer
= 1;
656 if (UE_GET_DIR(ep
->bEndpointAddress
) == UE_DIR_IN
)
657 cfg
.flags
.short_xfer_ok
= 1;
659 status
= usbd_transfer_setup(sc
->ndisusb_dev
, &ifidx
, ne
->ne_xfer
,
660 &cfg
, 1, sc
, &sc
->ndisusb_lock
);
661 if (status
!= USB_ERR_NORMAL_COMPLETION
) {
662 device_printf(dev
, "couldn't setup xfer: %s\n",
663 usbd_errstr(status
));
666 xfer
= ne
->ne_xfer
[0];
667 usbd_xfer_set_priv(xfer
, ne
);
668 if (UE_GET_DIR(ep
->bEndpointAddress
) == UE_DIR_IN
)
669 usbd_xfer_set_timeout(xfer
, NDISUSB_NO_TIMEOUT
);
671 if (UE_GET_XFERTYPE(ep
->bmAttributes
) == UE_BULK
)
672 usbd_xfer_set_timeout(xfer
, NDISUSB_TX_TIMEOUT
);
674 usbd_xfer_set_timeout(xfer
, NDISUSB_INTR_TIMEOUT
);
681 usbd_func_abort_pipe(irp
*ip
)
683 device_t dev
= IRP_NDIS_DEV(ip
);
684 struct ndis_softc
*sc
= device_get_softc(dev
);
685 struct ndisusb_ep
*ne
;
688 urb
= usbd_geturb(ip
);
689 ne
= usbd_get_ndisep(ip
, urb
->uu_pipe
.upr_handle
);
691 device_printf(IRP_NDIS_DEV(ip
), "get NULL endpoint info.\n");
692 return (USBD_STATUS_INVALID_PIPE_HANDLE
);
696 usbd_transfer_stop(ne
->ne_xfer
[0]);
697 usbd_transfer_start(ne
->ne_xfer
[0]);
700 return (USBD_STATUS_SUCCESS
);
704 usbd_func_vendorclass(irp
*ip
)
706 device_t dev
= IRP_NDIS_DEV(ip
);
708 struct ndis_softc
*sc
= device_get_softc(dev
);
709 struct ndisusb_ep
*ne
;
710 struct ndisusb_xfer
*nx
;
711 struct usbd_urb_vendor_or_class_request
*vcreq
;
714 if (!(sc
->ndisusb_status
& NDISUSB_STATUS_SETUP_EP
)) {
716 * XXX In some cases the interface number isn't 0. However
717 * some driver (eg. RTL8187L NDIS driver) calls this function
718 * before calling URB_FUNCTION_SELECT_CONFIGURATION.
720 error
= usbd_setup_endpoint_default(ip
, 0);
721 if (error
!= USB_ERR_NORMAL_COMPLETION
)
722 return usbd_usb2urb(error
);
723 sc
->ndisusb_status
|= NDISUSB_STATUS_SETUP_EP
;
726 urb
= usbd_geturb(ip
);
727 vcreq
= &urb
->uu_vcreq
;
728 ne
= (vcreq
->uvc_trans_flags
& USBD_TRANSFER_DIRECTION_IN
) ?
729 &sc
->ndisusb_dread_ep
: &sc
->ndisusb_dwrite_ep
;
730 IRP_NDISUSB_EP(ip
) = ne
;
731 ip
->irp_cancelfunc
= (cancel_func
)usbd_irpcancel_wrap
;
733 nx
= kmalloc(sizeof(struct ndisusb_xfer
), M_USBDEV
, M_NOWAIT
| M_ZERO
);
735 device_printf(IRP_NDIS_DEV(ip
), "out of memory\n");
736 return (USBD_STATUS_NO_MEMORY
);
740 KeAcquireSpinLockAtDpcLevel(&ne
->ne_lock
);
741 InsertTailList((&ne
->ne_pending
), (&nx
->nx_next
));
742 KeReleaseSpinLockFromDpcLevel(&ne
->ne_lock
);
744 /* we've done to setup xfer. Let's transfer it. */
745 ip
->irp_iostat
.isb_status
= STATUS_PENDING
;
746 ip
->irp_iostat
.isb_info
= 0;
747 USBD_URB_STATUS(urb
) = USBD_STATUS_PENDING
;
748 IoMarkIrpPending(ip
);
750 error
= usbd_taskadd(ip
, NDISUSB_TASK_VENDOR
);
751 if (error
!= USBD_STATUS_SUCCESS
)
754 return (USBD_STATUS_PENDING
);
758 usbd_irpcancel(device_object
*dobj
, irp
*ip
)
760 device_t dev
= IRP_NDIS_DEV(ip
);
761 struct ndis_softc
*sc
= device_get_softc(dev
);
762 struct ndisusb_ep
*ne
= IRP_NDISUSB_EP(ip
);
765 ip
->irp_cancel
= TRUE
;
766 IoReleaseCancelSpinLock(ip
->irp_cancelirql
);
771 * Make sure that the current USB transfer proxy is
772 * cancelled and then restarted.
775 usbd_transfer_stop(ne
->ne_xfer
[0]);
776 usbd_transfer_start(ne
->ne_xfer
[0]);
779 ip
->irp_cancel
= TRUE
;
780 IoReleaseCancelSpinLock(ip
->irp_cancelirql
);
784 usbd_xfer_complete(struct ndis_softc
*sc
, struct ndisusb_ep
*ne
,
785 struct ndisusb_xfer
*nx
, usb_error_t status
)
787 struct ndisusb_xferdone
*nd
;
790 nd
= kmalloc(sizeof(struct ndisusb_xferdone
), M_USBDEV
,
793 device_printf(sc
->ndis_dev
, "out of memory");
797 nd
->nd_status
= status
;
799 KeAcquireSpinLock(&sc
->ndisusb_xferdonelock
, &irql
);
800 InsertTailList((&sc
->ndisusb_xferdonelist
), (&nd
->nd_donelist
));
801 KeReleaseSpinLock(&sc
->ndisusb_xferdonelock
, irql
);
803 IoQueueWorkItem(sc
->ndisusb_xferdoneitem
,
804 (io_workitem_func
)usbd_xfertask_wrap
, WORKQUEUE_CRITICAL
, sc
);
807 static struct ndisusb_xfer
*
808 usbd_aq_getfirst(struct ndis_softc
*sc
, struct ndisusb_ep
*ne
)
810 struct ndisusb_xfer
*nx
;
812 KeAcquireSpinLockAtDpcLevel(&ne
->ne_lock
);
813 if (IsListEmpty(&ne
->ne_active
)) {
814 device_printf(sc
->ndis_dev
,
815 "%s: the active queue can't be empty.\n", __func__
);
816 KeReleaseSpinLockFromDpcLevel(&ne
->ne_lock
);
819 nx
= CONTAINING_RECORD(ne
->ne_active
.nle_flink
, struct ndisusb_xfer
,
821 RemoveEntryList(&nx
->nx_next
);
822 KeReleaseSpinLockFromDpcLevel(&ne
->ne_lock
);
828 usbd_non_isoc_callback(struct usb_xfer
*xfer
, usb_error_t error
)
831 struct ndis_softc
*sc
= usbd_xfer_softc(xfer
);
832 struct ndisusb_ep
*ne
= usbd_xfer_get_priv(xfer
);
833 struct ndisusb_xfer
*nx
;
834 struct usbd_urb_bulk_or_intr_transfer
*ubi
;
835 struct usb_page_cache
*pc
;
839 usb_endpoint_descriptor_t
*ep
;
842 usbd_xfer_status(xfer
, &actlen
, &sumlen
, NULL
, NULL
);
844 switch (USB_GET_STATE(xfer
)) {
845 case USB_ST_TRANSFERRED
:
846 nx
= usbd_aq_getfirst(sc
, ne
);
847 pc
= usbd_xfer_get_frame(xfer
, 0);
851 /* copy in data with regard to the URB */
852 if (ne
->ne_dirin
!= 0)
853 usbd_copy_out(pc
, 0, nx
->nx_urbbuf
, actlen
);
854 nx
->nx_urbbuf
+= actlen
;
855 nx
->nx_urbactlen
+= actlen
;
856 nx
->nx_urblen
-= actlen
;
858 /* check for short transfer */
862 /* check remainder */
863 if (nx
->nx_urblen
> 0) {
864 KeAcquireSpinLock(&ne
->ne_lock
, &irql
);
865 InsertHeadList((&ne
->ne_active
), (&nx
->nx_next
));
866 KeReleaseSpinLock(&ne
->ne_lock
, irql
);
869 urb
= usbd_geturb(ip
);
870 ubi
= &urb
->uu_bulkintr
;
871 ep
= ubi
->ubi_epdesc
;
875 usbd_xfer_complete(sc
, ne
, nx
,
876 ((actlen
< sumlen
) && (nx
->nx_shortxfer
== 0)) ?
877 USB_ERR_SHORT_XFER
: USB_ERR_NORMAL_COMPLETION
);
882 /* get next transfer */
883 KeAcquireSpinLock(&ne
->ne_lock
, &irql
);
884 if (IsListEmpty(&ne
->ne_pending
)) {
885 KeReleaseSpinLock(&ne
->ne_lock
, irql
);
888 nx
= CONTAINING_RECORD(ne
->ne_pending
.nle_flink
,
889 struct ndisusb_xfer
, nx_next
);
890 RemoveEntryList(&nx
->nx_next
);
891 /* add a entry to the active queue's tail. */
892 InsertTailList((&ne
->ne_active
), (&nx
->nx_next
));
893 KeReleaseSpinLock(&ne
->ne_lock
, irql
);
896 urb
= usbd_geturb(ip
);
897 ubi
= &urb
->uu_bulkintr
;
898 ep
= ubi
->ubi_epdesc
;
900 nx
->nx_urbbuf
= ubi
->ubi_trans_buf
;
901 nx
->nx_urbactlen
= 0;
902 nx
->nx_urblen
= ubi
->ubi_trans_buflen
;
903 nx
->nx_shortxfer
= (ubi
->ubi_trans_flags
&
904 USBD_SHORT_TRANSFER_OK
) ? 1 : 0;
906 len
= MIN(usbd_xfer_max_len(xfer
), nx
->nx_urblen
);
907 pc
= usbd_xfer_get_frame(xfer
, 0);
908 if (UE_GET_DIR(ep
->bEndpointAddress
) == UE_DIR_OUT
)
909 usbd_copy_in(pc
, 0, nx
->nx_urbbuf
, len
);
910 usbd_xfer_set_frame_len(xfer
, 0, len
);
911 usbd_xfer_set_frames(xfer
, 1);
912 usbd_transfer_submit(xfer
);
915 nx
= usbd_aq_getfirst(sc
, ne
);
918 if (error
!= USB_ERR_CANCELLED
) {
919 usbd_xfer_set_stall(xfer
);
920 device_printf(sc
->ndis_dev
, "usb xfer warning (%s)\n",
923 usbd_xfer_complete(sc
, ne
, nx
, error
);
924 if (error
!= USB_ERR_CANCELLED
)
931 usbd_ctrl_callback(struct usb_xfer
*xfer
, usb_error_t error
)
934 struct ndis_softc
*sc
= usbd_xfer_softc(xfer
);
935 struct ndisusb_ep
*ne
= usbd_xfer_get_priv(xfer
);
936 struct ndisusb_xfer
*nx
;
939 struct usbd_urb_vendor_or_class_request
*vcreq
;
940 struct usb_page_cache
*pc
;
942 struct usb_device_request req
;
945 switch (USB_GET_STATE(xfer
)) {
946 case USB_ST_TRANSFERRED
:
947 nx
= usbd_aq_getfirst(sc
, ne
);
952 urb
= usbd_geturb(ip
);
953 vcreq
= &urb
->uu_vcreq
;
955 if (vcreq
->uvc_trans_flags
& USBD_TRANSFER_DIRECTION_IN
) {
956 pc
= usbd_xfer_get_frame(xfer
, 1);
957 len
= usbd_xfer_frame_len(xfer
, 1);
958 usbd_copy_out(pc
, 0, vcreq
->uvc_trans_buf
, len
);
959 nx
->nx_urbactlen
+= len
;
962 usbd_xfer_complete(sc
, ne
, nx
, USB_ERR_NORMAL_COMPLETION
);
966 /* get next transfer */
967 KeAcquireSpinLock(&ne
->ne_lock
, &irql
);
968 if (IsListEmpty(&ne
->ne_pending
)) {
969 KeReleaseSpinLock(&ne
->ne_lock
, irql
);
972 nx
= CONTAINING_RECORD(ne
->ne_pending
.nle_flink
,
973 struct ndisusb_xfer
, nx_next
);
974 RemoveEntryList(&nx
->nx_next
);
975 /* add a entry to the active queue's tail. */
976 InsertTailList((&ne
->ne_active
), (&nx
->nx_next
));
977 KeReleaseSpinLock(&ne
->ne_lock
, irql
);
980 urb
= usbd_geturb(ip
);
981 vcreq
= &urb
->uu_vcreq
;
983 switch (urb
->uu_hdr
.uuh_func
) {
984 case URB_FUNCTION_CLASS_DEVICE
:
985 type
= UT_CLASS
| UT_DEVICE
;
987 case URB_FUNCTION_CLASS_INTERFACE
:
988 type
= UT_CLASS
| UT_INTERFACE
;
990 case URB_FUNCTION_CLASS_OTHER
:
991 type
= UT_CLASS
| UT_OTHER
;
993 case URB_FUNCTION_CLASS_ENDPOINT
:
994 type
= UT_CLASS
| UT_ENDPOINT
;
996 case URB_FUNCTION_VENDOR_DEVICE
:
997 type
= UT_VENDOR
| UT_DEVICE
;
999 case URB_FUNCTION_VENDOR_INTERFACE
:
1000 type
= UT_VENDOR
| UT_INTERFACE
;
1002 case URB_FUNCTION_VENDOR_OTHER
:
1003 type
= UT_VENDOR
| UT_OTHER
;
1005 case URB_FUNCTION_VENDOR_ENDPOINT
:
1006 type
= UT_VENDOR
| UT_ENDPOINT
;
1009 /* never reached. */
1013 type
|= (vcreq
->uvc_trans_flags
& USBD_TRANSFER_DIRECTION_IN
) ?
1015 type
|= vcreq
->uvc_reserved1
;
1017 req
.bmRequestType
= type
;
1018 req
.bRequest
= vcreq
->uvc_req
;
1019 USETW(req
.wIndex
, vcreq
->uvc_idx
);
1020 USETW(req
.wValue
, vcreq
->uvc_value
);
1021 USETW(req
.wLength
, vcreq
->uvc_trans_buflen
);
1023 nx
->nx_urbbuf
= vcreq
->uvc_trans_buf
;
1024 nx
->nx_urblen
= vcreq
->uvc_trans_buflen
;
1025 nx
->nx_urbactlen
= 0;
1027 pc
= usbd_xfer_get_frame(xfer
, 0);
1028 usbd_copy_in(pc
, 0, &req
, sizeof(req
));
1029 usbd_xfer_set_frame_len(xfer
, 0, sizeof(req
));
1030 usbd_xfer_set_frames(xfer
, 1);
1031 if (vcreq
->uvc_trans_flags
& USBD_TRANSFER_DIRECTION_IN
) {
1032 if (vcreq
->uvc_trans_buflen
>= USBD_CTRL_READ_BUFFER_SP
)
1033 device_printf(sc
->ndis_dev
,
1034 "warning: not enough buffer space (%d).\n",
1035 vcreq
->uvc_trans_buflen
);
1036 usbd_xfer_set_frame_len(xfer
, 1,
1037 MIN(usbd_xfer_max_len(xfer
),
1038 vcreq
->uvc_trans_buflen
));
1039 usbd_xfer_set_frames(xfer
, 2);
1041 if (nx
->nx_urblen
> USBD_CTRL_WRITE_BUFFER_SP
)
1042 device_printf(sc
->ndis_dev
,
1043 "warning: not enough write buffer space"
1044 " (%d).\n", nx
->nx_urblen
);
1046 * XXX with my local tests there was no cases to require
1047 * a extra buffer until now but it'd need to update in
1048 * the future if it needs to be.
1050 if (nx
->nx_urblen
> 0) {
1051 pc
= usbd_xfer_get_frame(xfer
, 1);
1052 usbd_copy_in(pc
, 0, nx
->nx_urbbuf
,
1054 usbd_xfer_set_frame_len(xfer
, 1, nx
->nx_urblen
);
1055 usbd_xfer_set_frames(xfer
, 2);
1058 usbd_transfer_submit(xfer
);
1061 nx
= usbd_aq_getfirst(sc
, ne
);
1064 if (error
!= USB_ERR_CANCELLED
) {
1065 usbd_xfer_set_stall(xfer
);
1066 device_printf(sc
->ndis_dev
, "usb xfer warning (%s)\n",
1067 usbd_errstr(error
));
1069 usbd_xfer_complete(sc
, ne
, nx
, error
);
1070 if (error
!= USB_ERR_CANCELLED
)
1076 static struct ndisusb_ep
*
1077 usbd_get_ndisep(irp
*ip
, usb_endpoint_descriptor_t
*ep
)
1079 device_t dev
= IRP_NDIS_DEV(ip
);
1080 struct ndis_softc
*sc
= device_get_softc(dev
);
1081 struct ndisusb_ep
*ne
;
1083 ne
= &sc
->ndisusb_ep
[NDISUSB_GET_ENDPT(ep
->bEndpointAddress
)];
1085 IRP_NDISUSB_EP(ip
) = ne
;
1086 ip
->irp_cancelfunc
= (cancel_func
)usbd_irpcancel_wrap
;
1092 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
;
1109 if (IsListEmpty(&sc
->ndisusb_xferdonelist
))
1112 KeAcquireSpinLockAtDpcLevel(&sc
->ndisusb_xferdonelock
);
1113 l
= sc
->ndisusb_xferdonelist
.nle_flink
;
1114 while (l
!= &sc
->ndisusb_xferdonelist
) {
1115 nd
= CONTAINING_RECORD(l
, struct ndisusb_xferdone
, nd_donelist
);
1118 status
= nd
->nd_status
;
1121 urb
= usbd_geturb(ip
);
1123 ip
->irp_cancelfunc
= NULL
;
1124 IRP_NDISUSB_EP(ip
) = NULL
;
1127 case USB_ERR_NORMAL_COMPLETION
:
1128 if (urb
->uu_hdr
.uuh_func
==
1129 URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
) {
1130 ubi
= &urb
->uu_bulkintr
;
1131 ubi
->ubi_trans_buflen
= nq
->nx_urbactlen
;
1133 vcreq
= &urb
->uu_vcreq
;
1134 vcreq
->uvc_trans_buflen
= nq
->nx_urbactlen
;
1136 ip
->irp_iostat
.isb_info
= nq
->nx_urbactlen
;
1137 ip
->irp_iostat
.isb_status
= STATUS_SUCCESS
;
1138 USBD_URB_STATUS(urb
) = USBD_STATUS_SUCCESS
;
1140 case USB_ERR_CANCELLED
:
1141 ip
->irp_iostat
.isb_info
= 0;
1142 ip
->irp_iostat
.isb_status
= STATUS_CANCELLED
;
1143 USBD_URB_STATUS(urb
) = USBD_STATUS_CANCELED
;
1146 ip
->irp_iostat
.isb_info
= 0;
1147 USBD_URB_STATUS(urb
) = usbd_usb2urb(status
);
1148 ip
->irp_iostat
.isb_status
=
1149 usbd_urb2nt(USBD_URB_STATUS(urb
));
1154 RemoveEntryList(&nd
->nd_donelist
);
1155 kfree(nq
, M_USBDEV
);
1156 kfree(nd
, M_USBDEV
);
1159 KeReleaseSpinLockFromDpcLevel(&sc
->ndisusb_xferdonelock
);
1160 /* NB: call after cleaning */
1161 IoCompleteRequest(ip
, IO_NO_INCREMENT
);
1162 KeAcquireSpinLockAtDpcLevel(&sc
->ndisusb_xferdonelock
);
1164 KeReleaseSpinLockFromDpcLevel(&sc
->ndisusb_xferdonelock
);
1168 * this function is for mainly deferring a task to the another thread because
1169 * we don't want to be in the scope of HAL lock.
1172 usbd_taskadd(irp
*ip
, unsigned type
)
1174 device_t dev
= IRP_NDIS_DEV(ip
);
1175 struct ndis_softc
*sc
= device_get_softc(dev
);
1176 struct ndisusb_task
*nt
;
1178 nt
= kmalloc(sizeof(struct ndisusb_task
), M_USBDEV
, M_NOWAIT
| M_ZERO
);
1180 return (USBD_STATUS_NO_MEMORY
);
1184 KeAcquireSpinLockAtDpcLevel(&sc
->ndisusb_tasklock
);
1185 InsertTailList((&sc
->ndisusb_tasklist
), (&nt
->nt_tasklist
));
1186 KeReleaseSpinLockFromDpcLevel(&sc
->ndisusb_tasklock
);
1188 IoQueueWorkItem(sc
->ndisusb_taskitem
,
1189 (io_workitem_func
)usbd_task_wrap
, WORKQUEUE_CRITICAL
, sc
);
1191 return (USBD_STATUS_SUCCESS
);
1195 usbd_task(device_object
*dobj
, void *arg
)
1199 struct ndis_softc
*sc
= arg
;
1200 struct ndisusb_ep
*ne
;
1201 struct ndisusb_task
*nt
;
1202 union usbd_urb
*urb
;
1204 if (IsListEmpty(&sc
->ndisusb_tasklist
))
1207 KeAcquireSpinLockAtDpcLevel(&sc
->ndisusb_tasklock
);
1208 l
= sc
->ndisusb_tasklist
.nle_flink
;
1209 while (l
!= &sc
->ndisusb_tasklist
) {
1210 nt
= CONTAINING_RECORD(l
, struct ndisusb_task
, nt_tasklist
);
1213 urb
= usbd_geturb(ip
);
1215 KeReleaseSpinLockFromDpcLevel(&sc
->ndisusb_tasklock
);
1217 switch (nt
->nt_type
) {
1218 case NDISUSB_TASK_TSTART
:
1219 ne
= usbd_get_ndisep(ip
, urb
->uu_bulkintr
.ubi_epdesc
);
1222 usbd_transfer_start(ne
->ne_xfer
[0]);
1224 case NDISUSB_TASK_IRPCANCEL
:
1225 ne
= usbd_get_ndisep(ip
,
1226 (nt
->nt_type
== NDISUSB_TASK_IRPCANCEL
) ?
1227 urb
->uu_bulkintr
.ubi_epdesc
:
1228 urb
->uu_pipe
.upr_handle
);
1232 usbd_transfer_stop(ne
->ne_xfer
[0]);
1233 usbd_transfer_start(ne
->ne_xfer
[0]);
1235 case NDISUSB_TASK_VENDOR
:
1236 ne
= (urb
->uu_vcreq
.uvc_trans_flags
&
1237 USBD_TRANSFER_DIRECTION_IN
) ?
1238 &sc
->ndisusb_dread_ep
: &sc
->ndisusb_dwrite_ep
;
1239 usbd_transfer_start(ne
->ne_xfer
[0]);
1246 KeAcquireSpinLockAtDpcLevel(&sc
->ndisusb_tasklock
);
1249 RemoveEntryList(&nt
->nt_tasklist
);
1250 kfree(nt
, M_USBDEV
);
1252 KeReleaseSpinLockFromDpcLevel(&sc
->ndisusb_tasklock
);
1256 usbd_func_bulkintr(irp
*ip
)
1259 struct ndisusb_ep
*ne
;
1260 struct ndisusb_xfer
*nx
;
1261 struct usbd_urb_bulk_or_intr_transfer
*ubi
;
1262 union usbd_urb
*urb
;
1263 usb_endpoint_descriptor_t
*ep
;
1265 urb
= usbd_geturb(ip
);
1266 ubi
= &urb
->uu_bulkintr
;
1267 ep
= ubi
->ubi_epdesc
;
1269 return (USBD_STATUS_INVALID_PIPE_HANDLE
);
1271 ne
= usbd_get_ndisep(ip
, ep
);
1273 device_printf(IRP_NDIS_DEV(ip
), "get NULL endpoint info.\n");
1274 return (USBD_STATUS_INVALID_PIPE_HANDLE
);
1277 nx
= kmalloc(sizeof(struct ndisusb_xfer
), M_USBDEV
, M_NOWAIT
| M_ZERO
);
1279 device_printf(IRP_NDIS_DEV(ip
), "out of memory\n");
1280 return (USBD_STATUS_NO_MEMORY
);
1284 KeAcquireSpinLockAtDpcLevel(&ne
->ne_lock
);
1285 InsertTailList((&ne
->ne_pending
), (&nx
->nx_next
));
1286 KeReleaseSpinLockFromDpcLevel(&ne
->ne_lock
);
1288 /* we've done to setup xfer. Let's transfer it. */
1289 ip
->irp_iostat
.isb_status
= STATUS_PENDING
;
1290 ip
->irp_iostat
.isb_info
= 0;
1291 USBD_URB_STATUS(urb
) = USBD_STATUS_PENDING
;
1292 IoMarkIrpPending(ip
);
1294 error
= usbd_taskadd(ip
, NDISUSB_TASK_TSTART
);
1295 if (error
!= USBD_STATUS_SUCCESS
)
1298 return (USBD_STATUS_PENDING
);
1301 static union usbd_urb
*
1302 USBD_CreateConfigurationRequest(usb_config_descriptor_t
*conf
, uint16_t *len
)
1304 struct usbd_interface_list_entry list
[2];
1305 union usbd_urb
*urb
;
1307 bzero(list
, sizeof(struct usbd_interface_list_entry
) * 2);
1308 list
[0].uil_intfdesc
= USBD_ParseConfigurationDescriptorEx(conf
, conf
,
1309 -1, -1, -1, -1, -1);
1310 urb
= USBD_CreateConfigurationRequestEx(conf
, list
);
1314 *len
= urb
->uu_selconf
.usc_hdr
.uuh_len
;
1318 static union usbd_urb
*
1319 USBD_CreateConfigurationRequestEx(usb_config_descriptor_t
*conf
,
1320 struct usbd_interface_list_entry
*list
)
1323 struct usbd_interface_information
*intf
;
1324 struct usbd_pipe_information
*pipe
;
1325 struct usbd_urb_select_configuration
*selconf
;
1326 usb_interface_descriptor_t
*desc
;
1328 for (i
= 0, size
= 0; i
< conf
->bNumInterface
; i
++) {
1329 j
= list
[i
].uil_intfdesc
->bNumEndpoints
;
1330 size
= size
+ sizeof(struct usbd_interface_information
) +
1331 sizeof(struct usbd_pipe_information
) * (j
- 1);
1333 size
+= sizeof(struct usbd_urb_select_configuration
) -
1334 sizeof(struct usbd_interface_information
);
1336 selconf
= ExAllocatePoolWithTag(NonPagedPool
, size
, 0);
1337 if (selconf
== NULL
)
1339 selconf
->usc_hdr
.uuh_func
= URB_FUNCTION_SELECT_CONFIGURATION
;
1340 selconf
->usc_hdr
.uuh_len
= size
;
1341 selconf
->usc_handle
= conf
;
1342 selconf
->usc_conf
= conf
;
1344 intf
= &selconf
->usc_intf
;
1345 for (i
= 0; i
< conf
->bNumInterface
; i
++) {
1346 if (list
[i
].uil_intfdesc
== NULL
)
1349 list
[i
].uil_intf
= intf
;
1350 desc
= list
[i
].uil_intfdesc
;
1352 intf
->uii_len
= sizeof(struct usbd_interface_information
) +
1353 (desc
->bNumEndpoints
- 1) *
1354 sizeof(struct usbd_pipe_information
);
1355 intf
->uii_intfnum
= desc
->bInterfaceNumber
;
1356 intf
->uii_altset
= desc
->bAlternateSetting
;
1357 intf
->uii_intfclass
= desc
->bInterfaceClass
;
1358 intf
->uii_intfsubclass
= desc
->bInterfaceSubClass
;
1359 intf
->uii_intfproto
= desc
->bInterfaceProtocol
;
1360 intf
->uii_handle
= desc
;
1361 intf
->uii_numeps
= desc
->bNumEndpoints
;
1363 pipe
= &intf
->uii_pipes
[0];
1364 for (j
= 0; j
< intf
->uii_numeps
; j
++)
1365 pipe
[j
].upi_maxtxsize
=
1366 USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE
;
1368 intf
= (struct usbd_interface_information
*)((char *)intf
+
1372 return ((union usbd_urb
*)selconf
);
1376 USBD_GetUSBDIVersion(usbd_version_info
*ui
)
1379 /* Pretend to be Windows XP. */
1381 ui
->uvi_usbdi_vers
= USBDI_VERSION
;
1382 ui
->uvi_supported_vers
= USB_VER_2_0
;
1385 static usb_interface_descriptor_t
*
1386 USBD_ParseConfigurationDescriptor(usb_config_descriptor_t
*conf
,
1387 uint8_t intfnum
, uint8_t altset
)
1390 return USBD_ParseConfigurationDescriptorEx(conf
, conf
, intfnum
, altset
,
1394 static usb_interface_descriptor_t
*
1395 USBD_ParseConfigurationDescriptorEx(usb_config_descriptor_t
*conf
,
1396 void *start
, int32_t intfnum
, int32_t altset
, int32_t intfclass
,
1397 int32_t intfsubclass
, int32_t intfproto
)
1399 struct usb_descriptor
*next
= NULL
;
1400 usb_interface_descriptor_t
*desc
;
1402 while ((next
= usb_desc_foreach(conf
, next
)) != NULL
) {
1403 desc
= (usb_interface_descriptor_t
*)next
;
1404 if (desc
->bDescriptorType
!= UDESC_INTERFACE
)
1406 if (!(intfnum
== -1 || desc
->bInterfaceNumber
== intfnum
))
1408 if (!(altset
== -1 || desc
->bAlternateSetting
== altset
))
1410 if (!(intfclass
== -1 || desc
->bInterfaceClass
== intfclass
))
1412 if (!(intfsubclass
== -1 ||
1413 desc
->bInterfaceSubClass
== intfsubclass
))
1415 if (!(intfproto
== -1 || desc
->bInterfaceProtocol
== intfproto
))
1426 kprintf("USBD dummy called\n");
1429 image_patch_table usbd_functbl
[] = {
1430 IMPORT_SFUNC(USBD_CreateConfigurationRequest
, 2),
1431 IMPORT_SFUNC(USBD_CreateConfigurationRequestEx
, 2),
1432 IMPORT_SFUNC_MAP(_USBD_CreateConfigurationRequestEx@
8,
1433 USBD_CreateConfigurationRequestEx
, 2),
1434 IMPORT_SFUNC(USBD_GetUSBDIVersion
, 1),
1435 IMPORT_SFUNC(USBD_ParseConfigurationDescriptor
, 3),
1436 IMPORT_SFUNC(USBD_ParseConfigurationDescriptorEx
, 7),
1437 IMPORT_SFUNC_MAP(_USBD_ParseConfigurationDescriptorEx@
28,
1438 USBD_ParseConfigurationDescriptorEx
, 7),
1441 * This last entry is a catch-all for any function we haven't
1442 * implemented yet. The PE import list patching routine will
1443 * use it for any function that doesn't have an explicit match
1447 { NULL
, (FUNC
)dummy
, NULL
, 0, WINDRV_WRAP_STDCALL
},
1451 { NULL
, NULL
, NULL
}
1454 MODULE_DEPEND(ndis
, usb
, 1, 1, 1);