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