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