xref: /trueos/sys/compat/ndis/subr_usbd.c (revision 8fe640108653f13042f1b15213769e338aa524f6)
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 
77 static driver_object usbd_driver;
78 static usb_callback_t usbd_non_isoc_callback;
79 static 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)
90 static 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 
113 static int32_t		 usbd_func_bulkintr(irp *);
114 static int32_t		 usbd_func_vendorclass(irp *);
115 static int32_t		 usbd_func_selconf(irp *);
116 static int32_t		 usbd_func_abort_pipe(irp *);
117 static usb_error_t	 usbd_setup_endpoint(irp *, uint8_t,
118 			    struct usb_endpoint_descriptor	*);
119 static usb_error_t	 usbd_setup_endpoint_default(irp *, uint8_t);
120 static usb_error_t	 usbd_setup_endpoint_one(irp *, uint8_t,
121 			    struct ndisusb_ep *, struct usb_config *);
122 static int32_t		 usbd_func_getdesc(irp *);
123 static union usbd_urb	*usbd_geturb(irp *);
124 static struct ndisusb_ep*usbd_get_ndisep(irp *, usb_endpoint_descriptor_t *);
125 static int32_t		 usbd_iodispatch(device_object *, irp *);
126 static int32_t		 usbd_ioinvalid(device_object *, irp *);
127 static int32_t		 usbd_pnp(device_object *, irp *);
128 static int32_t		 usbd_power(device_object *, irp *);
129 static void		 usbd_irpcancel(device_object *, irp *);
130 static int32_t		 usbd_submit_urb(irp *);
131 static int32_t		 usbd_urb2nt(int32_t);
132 static void		 usbd_task(device_object *, void *);
133 static int32_t		 usbd_taskadd(irp *, unsigned);
134 static void		 usbd_xfertask(device_object *, void *);
135 static void		 dummy(void);
136 
137 static union usbd_urb	*USBD_CreateConfigurationRequestEx(
138 			    usb_config_descriptor_t *,
139 			    struct usbd_interface_list_entry *);
140 static union usbd_urb	*USBD_CreateConfigurationRequest(
141 			    usb_config_descriptor_t *,
142 			    uint16_t *);
143 static void		 USBD_GetUSBDIVersion(usbd_version_info *);
144 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptorEx(
145 			    usb_config_descriptor_t *, void *, int32_t, int32_t,
146 			    int32_t, int32_t, int32_t);
147 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptor(
148 		    usb_config_descriptor_t *, uint8_t, uint8_t);
149 
150 /*
151  * We need to wrap these functions because these need `context switch' from
152  * Windows to UNIX before it's called.
153  */
154 static funcptr usbd_iodispatch_wrap;
155 static funcptr usbd_ioinvalid_wrap;
156 static funcptr usbd_pnp_wrap;
157 static funcptr usbd_power_wrap;
158 static funcptr usbd_irpcancel_wrap;
159 static funcptr usbd_task_wrap;
160 static funcptr usbd_xfertask_wrap;
161 
162 int
usbd_libinit(void)163 usbd_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 
212 int
usbd_libfini(void)213 usbd_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 
236 static int32_t
usbd_iodispatch(device_object * dobj,irp * ip)237 usbd_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 
266 static int32_t
usbd_ioinvalid(device_object * dobj,irp * ip)267 usbd_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 
284 static int32_t
usbd_pnp(device_object * dobj,irp * ip)285 usbd_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 
302 static int32_t
usbd_power(device_object * dobj,irp * ip)303 usbd_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  */
321 static int32_t
usbd_urb2nt(int32_t status)322 usbd_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  */
348 static int32_t
usbd_usb2urb(int status)349 usbd_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 
380 static union usbd_urb *
usbd_geturb(irp * ip)381 usbd_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 
390 static int32_t
usbd_submit_urb(irp * ip)391 usbd_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 
443 static int32_t
usbd_func_getdesc(irp * ip)444 usbd_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 	}
490 exit:
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 
503 static int32_t
usbd_func_selconf(irp * ip)504 usbd_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 
582 static usb_error_t
usbd_setup_endpoint_one(irp * ip,uint8_t ifidx,struct ndisusb_ep * ne,struct usb_config * epconf)583 usbd_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 
608 static usb_error_t
usbd_setup_endpoint_default(irp * ip,uint8_t ifidx)609 usbd_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 
628 static usb_error_t
usbd_setup_endpoint(irp * ip,uint8_t ifidx,struct usb_endpoint_descriptor * ep)629 usbd_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 
684 static int32_t
usbd_func_abort_pipe(irp * ip)685 usbd_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 
707 static int32_t
usbd_func_vendorclass(irp * ip)708 usbd_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 
761 static void
usbd_irpcancel(device_object * dobj,irp * ip)762 usbd_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 
787 static void
usbd_xfer_complete(struct ndis_softc * sc,struct ndisusb_ep * ne,struct ndisusb_xfer * nx,usb_error_t status)788 usbd_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 
811 static struct ndisusb_xfer *
usbd_aq_getfirst(struct ndis_softc * sc,struct ndisusb_ep * ne)812 usbd_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 
831 static void
usbd_non_isoc_callback(struct usb_xfer * xfer,usb_error_t error)832 usbd_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:
885 next:
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;
909 extra:
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 
934 static void
usbd_ctrl_callback(struct usb_xfer * xfer,usb_error_t error)935 usbd_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:
969 next:
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 
1080 static struct ndisusb_ep *
usbd_get_ndisep(irp * ip,usb_endpoint_descriptor_t * ep)1081 usbd_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 
1095 static void
usbd_xfertask(device_object * dobj,void * arg)1096 usbd_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  */
1175 static int32_t
usbd_taskadd(irp * ip,unsigned type)1176 usbd_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 
1198 static void
usbd_task(device_object * dobj,void * arg)1199 usbd_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 		}
1248 exit:
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 
1259 static int32_t
usbd_func_bulkintr(irp * ip)1260 usbd_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 
1305 static union usbd_urb *
USBD_CreateConfigurationRequest(usb_config_descriptor_t * conf,uint16_t * len)1306 USBD_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 
1322 static union usbd_urb *
USBD_CreateConfigurationRequestEx(usb_config_descriptor_t * conf,struct usbd_interface_list_entry * list)1323 USBD_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 
1379 static void
USBD_GetUSBDIVersion(usbd_version_info * ui)1380 USBD_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 
1389 static usb_interface_descriptor_t *
USBD_ParseConfigurationDescriptor(usb_config_descriptor_t * conf,uint8_t intfnum,uint8_t altset)1390 USBD_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 
1398 static usb_interface_descriptor_t *
USBD_ParseConfigurationDescriptorEx(usb_config_descriptor_t * conf,void * start,int32_t intfnum,int32_t altset,int32_t intfclass,int32_t intfsubclass,int32_t intfproto)1399 USBD_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 
1427 static void
dummy(void)1428 dummy(void)
1429 {
1430 	printf("USBD dummy called\n");
1431 }
1432 
1433 image_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 
1458 MODULE_DEPEND(ndis, usb, 1, 1, 1);
1459