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