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 * $FreeBSD: src/sys/compat/ndis/subr_usbd.c,v 1.6 2009/02/24 18:09:31 rdivacky Exp $
33 */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/unistd.h>
38 #include <sys/types.h>
39
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 #include <sys/lock.h>
43 #include <sys/mutex.h>
44 #include <sys/module.h>
45 #include <sys/conf.h>
46 #include <sys/mbuf.h>
47 #include <sys/socket.h>
48 #include <sys/bus.h>
49
50 #include <sys/queue.h>
51 #include <sys/mplock2.h>
52
53 #include <net/if.h>
54 #include <net/if_media.h>
55 #include <netproto/802_11/ieee80211_var.h>
56 #include <netproto/802_11/ieee80211_ioctl.h>
57
58 #include <bus/usb/usb.h>
59 #include <bus/usb/usbdi.h>
60 #include <bus/usb/usbdi_util.h>
61 #include <bus/usb/usbdivar.h>
62 #include <bus/usb/usb_quirks.h>
63
64 #include <emulation/ndis/pe_var.h>
65 #include <emulation/ndis/cfg_var.h>
66 #include <emulation/ndis/resource_var.h>
67 #include <emulation/ndis/ntoskrnl_var.h>
68 #include <emulation/ndis/ndis_var.h>
69 #include <emulation/ndis/hal_var.h>
70 #include <emulation/ndis/usbd_var.h>
71 #include <dev/netif/ndis/if_ndisvar.h>
72
73 static driver_object usbd_driver;
74
75 static int32_t usbd_func_bulkintr(irp *);
76 static int32_t usbd_func_vendorclass(irp *);
77 static int32_t usbd_func_selconf(irp *);
78 static int32_t usbd_func_abort_pipe(irp *);
79 static int32_t usbd_func_getdesc(irp *);
80 static usbd_status usbd_get_desc_ndis(usbd_device_handle, int, int, int,
81 void *, int *);
82 static union usbd_urb *usbd_geturb(irp *);
83 static usbd_status usbd_init_ndispipe(irp *, usb_endpoint_descriptor_t *);
84 static usbd_xfer_handle usbd_init_ndisxfer(irp *, usb_endpoint_descriptor_t *,
85 void *, uint32_t);
86 static int32_t usbd_iodispatch(device_object *, irp *);
87 static int32_t usbd_ioinvalid(device_object *, irp *);
88 static int32_t usbd_pnp(device_object *, irp *);
89 static int32_t usbd_power(device_object *, irp *);
90 static void usbd_irpcancel(device_object *, irp *);
91 static void usbd_irpcancel_cb(void *);
92 static int32_t usbd_submit_urb(irp *);
93 static int32_t usbd_urb2nt(int32_t);
94 static void usbd_xfereof(usbd_xfer_handle, usbd_private_handle,
95 usbd_status);
96 static void usbd_xferadd(usbd_xfer_handle, usbd_private_handle,
97 usbd_status);
98 static void usbd_xfertask(device_object *, void *);
99 static void dummy(void);
100
101 static union usbd_urb *USBD_CreateConfigurationRequestEx(
102 usb_config_descriptor_t *,
103 struct usbd_interface_list_entry *);
104 static union usbd_urb *USBD_CreateConfigurationRequest(
105 usb_config_descriptor_t *,
106 uint16_t *);
107 static void USBD_GetUSBDIVersion(usbd_version_info *);
108 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptorEx(
109 usb_config_descriptor_t *, void *, int32_t, int32_t,
110 int32_t, int32_t, int32_t);
111 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptor(
112 usb_config_descriptor_t *, uint8_t, uint8_t);
113
114 /*
115 * We need to wrap these functions because these need `context switch' from
116 * Windows to UNIX before it's called.
117 */
118 static funcptr usbd_iodispatch_wrap;
119 static funcptr usbd_ioinvalid_wrap;
120 static funcptr usbd_pnp_wrap;
121 static funcptr usbd_power_wrap;
122 static funcptr usbd_irpcancel_wrap;
123 static funcptr usbd_xfertask_wrap;
124
125 int
126 usbd_libinit(void)
127 {
128 image_patch_table *patch;
129 int i;
130
131 patch = usbd_functbl;
132 while (patch->ipt_func != NULL) {
133 windrv_wrap((funcptr)patch->ipt_func,
134 (funcptr *)&patch->ipt_wrap,
135 patch->ipt_argcnt, patch->ipt_ftype);
136 patch++;
137 }
138
139 windrv_wrap((funcptr)usbd_ioinvalid,
140 &usbd_ioinvalid_wrap, 2, WINDRV_WRAP_STDCALL);
141 windrv_wrap((funcptr)usbd_iodispatch,
142 &usbd_iodispatch_wrap, 2, WINDRV_WRAP_STDCALL);
143 windrv_wrap((funcptr)usbd_pnp,
144 &usbd_pnp_wrap, 2, WINDRV_WRAP_STDCALL);
145 windrv_wrap((funcptr)usbd_power,
146 &usbd_power_wrap, 2, WINDRV_WRAP_STDCALL);
147 windrv_wrap((funcptr)usbd_irpcancel,
148 &usbd_irpcancel_wrap, 2, WINDRV_WRAP_STDCALL);
149 windrv_wrap((funcptr)usbd_xfertask,
150 &usbd_xfertask_wrap, 2, WINDRV_WRAP_STDCALL);
151
152 /* Create a fake USB driver instance. */
153
154 windrv_bus_attach(&usbd_driver, "USB Bus");
155
156 /* Set up our dipatch routine. */
157 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
158 usbd_driver.dro_dispatch[i] =
159 (driver_dispatch)usbd_ioinvalid_wrap;
160
161 usbd_driver.dro_dispatch[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
162 (driver_dispatch)usbd_iodispatch_wrap;
163 usbd_driver.dro_dispatch[IRP_MJ_DEVICE_CONTROL] =
164 (driver_dispatch)usbd_iodispatch_wrap;
165 usbd_driver.dro_dispatch[IRP_MJ_POWER] =
166 (driver_dispatch)usbd_power_wrap;
167 usbd_driver.dro_dispatch[IRP_MJ_PNP] =
168 (driver_dispatch)usbd_pnp_wrap;
169
170 return(0);
171 }
172
173 int
174 usbd_libfini(void)
175 {
176 image_patch_table *patch;
177
178 patch = usbd_functbl;
179 while (patch->ipt_func != NULL) {
180 windrv_unwrap(patch->ipt_wrap);
181 patch++;
182 }
183
184 windrv_unwrap(usbd_ioinvalid_wrap);
185 windrv_unwrap(usbd_iodispatch_wrap);
186 windrv_unwrap(usbd_pnp_wrap);
187 windrv_unwrap(usbd_power_wrap);
188 windrv_unwrap(usbd_irpcancel_wrap);
189 windrv_unwrap(usbd_xfertask_wrap);
190
191 kfree(usbd_driver.dro_drivername.us_buf, M_DEVBUF);
192
193 return (0);
194 }
195
196 static int32_t
197 usbd_iodispatch(device_object *dobj, irp *ip)
198 {
199 device_t dev = dobj->do_devext;
200 int32_t status;
201 struct io_stack_location *irp_sl;
202
203 irp_sl = IoGetCurrentIrpStackLocation(ip);
204 switch (irp_sl->isl_parameters.isl_ioctl.isl_iocode) {
205 case IOCTL_INTERNAL_USB_SUBMIT_URB:
206 IRP_NDIS_DEV(ip) = dev;
207
208 status = usbd_submit_urb(ip);
209 break;
210 default:
211 device_printf(dev, "ioctl 0x%x isn't supported\n",
212 irp_sl->isl_parameters.isl_ioctl.isl_iocode);
213 status = USBD_STATUS_NOT_SUPPORTED;
214 break;
215 }
216
217 if (status == USBD_STATUS_PENDING)
218 return (STATUS_PENDING);
219
220 ip->irp_iostat.isb_status = usbd_urb2nt(status);
221 if (status != USBD_STATUS_SUCCESS)
222 ip->irp_iostat.isb_info = 0;
223 return (ip->irp_iostat.isb_status);
224 }
225
226 static int32_t
227 usbd_ioinvalid(device_object *dobj, irp *ip)
228 {
229 device_t dev = dobj->do_devext;
230 struct io_stack_location *irp_sl;
231
232 irp_sl = IoGetCurrentIrpStackLocation(ip);
233 device_printf(dev, "invalid I/O dispatch %d:%d\n", irp_sl->isl_major,
234 irp_sl->isl_minor);
235
236 ip->irp_iostat.isb_status = STATUS_FAILURE;
237 ip->irp_iostat.isb_info = 0;
238
239 IoCompleteRequest(ip, IO_NO_INCREMENT);
240
241 return (STATUS_FAILURE);
242 }
243
244 static int32_t
245 usbd_pnp(device_object *dobj, irp *ip)
246 {
247 device_t dev = dobj->do_devext;
248 struct io_stack_location *irp_sl;
249
250 irp_sl = IoGetCurrentIrpStackLocation(ip);
251 device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
252 __func__, irp_sl->isl_major, irp_sl->isl_minor);
253
254 ip->irp_iostat.isb_status = STATUS_FAILURE;
255 ip->irp_iostat.isb_info = 0;
256
257 IoCompleteRequest(ip, IO_NO_INCREMENT);
258
259 return (STATUS_FAILURE);
260 }
261
262 static int32_t
263 usbd_power(device_object *dobj, irp *ip)
264 {
265 device_t dev = dobj->do_devext;
266 struct io_stack_location *irp_sl;
267
268 irp_sl = IoGetCurrentIrpStackLocation(ip);
269 device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
270 __func__, irp_sl->isl_major, irp_sl->isl_minor);
271
272 ip->irp_iostat.isb_status = STATUS_FAILURE;
273 ip->irp_iostat.isb_info = 0;
274
275 IoCompleteRequest(ip, IO_NO_INCREMENT);
276
277 return (STATUS_FAILURE);
278 }
279
280 /* Convert USBD_STATUS to NTSTATUS */
281 static int32_t
282 usbd_urb2nt(int32_t status)
283 {
284
285 switch (status) {
286 case USBD_STATUS_SUCCESS:
287 return (STATUS_SUCCESS);
288 case USBD_STATUS_DEVICE_GONE:
289 return (STATUS_DEVICE_NOT_CONNECTED);
290 case USBD_STATUS_PENDING:
291 return (STATUS_PENDING);
292 case USBD_STATUS_NOT_SUPPORTED:
293 return (STATUS_NOT_IMPLEMENTED);
294 case USBD_STATUS_NO_MEMORY:
295 return (STATUS_NO_MEMORY);
296 case USBD_STATUS_REQUEST_FAILED:
297 return (STATUS_NOT_SUPPORTED);
298 case USBD_STATUS_CANCELED:
299 return (STATUS_CANCELLED);
300 default:
301 break;
302 }
303
304 return (STATUS_FAILURE);
305 }
306
307 /* Convert FreeBSD's usbd_status to USBD_STATUS */
308 static int32_t
309 usbd_usb2urb(int status)
310 {
311
312 switch (status) {
313 case USBD_NORMAL_COMPLETION:
314 return (USBD_STATUS_SUCCESS);
315 case USBD_IN_PROGRESS:
316 return (USBD_STATUS_PENDING);
317 case USBD_TIMEOUT:
318 return (USBD_STATUS_TIMEOUT);
319 case USBD_SHORT_XFER:
320 return (USBD_STATUS_ERROR_SHORT_TRANSFER);
321 case USBD_IOERROR:
322 return (USBD_STATUS_XACT_ERROR);
323 case USBD_NOMEM:
324 return (USBD_STATUS_NO_MEMORY);
325 case USBD_INVAL:
326 return (USBD_STATUS_REQUEST_FAILED);
327 case USBD_NOT_STARTED:
328 case USBD_TOO_DEEP:
329 case USBD_NO_POWER:
330 return (USBD_STATUS_DEVICE_GONE);
331 case USBD_CANCELLED:
332 return (USBD_STATUS_CANCELED);
333 default:
334 break;
335 }
336
337 return (USBD_STATUS_NOT_SUPPORTED);
338 }
339
340 static union usbd_urb *
341 usbd_geturb(irp *ip)
342 {
343 struct io_stack_location *irp_sl;
344
345 irp_sl = IoGetCurrentIrpStackLocation(ip);
346
347 return (irp_sl->isl_parameters.isl_others.isl_arg1);
348 }
349
350 static int32_t
351 usbd_submit_urb(irp *ip)
352 {
353 device_t dev = IRP_NDIS_DEV(ip);
354 int32_t status;
355 union usbd_urb *urb;
356
357 urb = usbd_geturb(ip);
358 /*
359 * In a case of URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
360 * USBD_URB_STATUS(urb) would be set at callback functions like
361 * usbd_intr() or usbd_xfereof().
362 */
363 switch (urb->uu_hdr.uuh_func) {
364 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
365 status = usbd_func_bulkintr(ip);
366 if (status != USBD_STATUS_SUCCESS &&
367 status != USBD_STATUS_PENDING)
368 USBD_URB_STATUS(urb) = status;
369 break;
370 case URB_FUNCTION_VENDOR_DEVICE:
371 case URB_FUNCTION_VENDOR_INTERFACE:
372 case URB_FUNCTION_VENDOR_ENDPOINT:
373 case URB_FUNCTION_VENDOR_OTHER:
374 case URB_FUNCTION_CLASS_DEVICE:
375 case URB_FUNCTION_CLASS_INTERFACE:
376 case URB_FUNCTION_CLASS_ENDPOINT:
377 case URB_FUNCTION_CLASS_OTHER:
378 status = usbd_func_vendorclass(ip);
379 USBD_URB_STATUS(urb) = status;
380 break;
381 case URB_FUNCTION_SELECT_CONFIGURATION:
382 status = usbd_func_selconf(ip);
383 USBD_URB_STATUS(urb) = status;
384 break;
385 case URB_FUNCTION_ABORT_PIPE:
386 status = usbd_func_abort_pipe(ip);
387 USBD_URB_STATUS(urb) = status;
388 break;
389 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
390 status = usbd_func_getdesc(ip);
391 USBD_URB_STATUS(urb) = status;
392 break;
393 default:
394 device_printf(dev, "func 0x%x isn't supported\n",
395 urb->uu_hdr.uuh_func);
396 USBD_URB_STATUS(urb) = status = USBD_STATUS_NOT_SUPPORTED;
397 break;
398 }
399
400 return (status);
401 }
402
403 static int32_t
404 usbd_func_getdesc(irp *ip)
405 {
406 device_t dev = IRP_NDIS_DEV(ip);
407 int actlen, i;
408 struct usb_attach_arg *uaa = device_get_ivars(dev);
409 struct usbd_urb_control_descriptor_request *ctldesc;
410 uint32_t len;
411 union usbd_urb *urb;
412 usb_config_descriptor_t cd, *cdp;
413 usbd_status status;
414
415 get_mplock();
416
417 urb = usbd_geturb(ip);
418 ctldesc = &urb->uu_ctldesc;
419 if (ctldesc->ucd_desctype == UDESC_CONFIG) {
420 /* Get the short config descriptor. */
421 status = usbd_get_config_desc(uaa->device, ctldesc->ucd_idx,
422 &cd);
423 if (status != USBD_NORMAL_COMPLETION) {
424 ctldesc->ucd_trans_buflen = 0;
425 rel_mplock();
426 return usbd_usb2urb(status);
427 }
428 /* Get the full descriptor. Try a few times for slow devices. */
429 len = MIN(ctldesc->ucd_trans_buflen, UGETW(cd.wTotalLength));
430 for (i = 0; i < 3; i++) {
431 status = usbd_get_desc_ndis(uaa->device,
432 ctldesc->ucd_desctype, ctldesc->ucd_idx,
433 len, ctldesc->ucd_trans_buf, &actlen);
434 if (status == USBD_NORMAL_COMPLETION)
435 break;
436 usbd_delay_ms(uaa->device, 200);
437 }
438 if (status != USBD_NORMAL_COMPLETION) {
439 ctldesc->ucd_trans_buflen = 0;
440 rel_mplock();
441 return usbd_usb2urb(status);
442 }
443
444 cdp = (usb_config_descriptor_t *)ctldesc->ucd_trans_buf;
445 if (cdp->bDescriptorType != UDESC_CONFIG) {
446 device_printf(dev, "bad desc %d\n",
447 cdp->bDescriptorType);
448 status = USBD_INVAL;
449 }
450 } else if (ctldesc->ucd_desctype == UDESC_STRING) {
451 /* Try a few times for slow devices. */
452 for (i = 0; i < 3; i++) {
453 status = usbd_get_string_desc(uaa->device,
454 (UDESC_STRING << 8) + ctldesc->ucd_idx,
455 ctldesc->ucd_langid, ctldesc->ucd_trans_buf,
456 &actlen);
457 if (actlen > ctldesc->ucd_trans_buflen)
458 panic("small string buffer for UDESC_STRING");
459 if (status == USBD_NORMAL_COMPLETION)
460 break;
461 usbd_delay_ms(uaa->device, 200);
462 }
463 } else
464 status = usbd_get_desc_ndis(uaa->device, ctldesc->ucd_desctype,
465 ctldesc->ucd_idx, ctldesc->ucd_trans_buflen,
466 ctldesc->ucd_trans_buf, &actlen);
467
468 if (status != USBD_NORMAL_COMPLETION) {
469 ctldesc->ucd_trans_buflen = 0;
470 rel_mplock();
471 return usbd_usb2urb(status);
472 }
473
474 ctldesc->ucd_trans_buflen = actlen;
475 ip->irp_iostat.isb_info = actlen;
476
477 rel_mplock();
478
479 return (USBD_STATUS_SUCCESS);
480 }
481
482 /*
483 * FIXME: at USB1, not USB2, framework, there's no a interface to get `actlen'.
484 * However, we need it!!!
485 */
486 static usbd_status
487 usbd_get_desc_ndis(usbd_device_handle dev, int type, int index, int len,
488 void *desc, int *actlen)
489 {
490 usb_device_request_t req;
491
492 req.bmRequestType = UT_READ_DEVICE;
493 req.bRequest = UR_GET_DESCRIPTOR;
494 USETW2(req.wValue, type, index);
495 USETW(req.wIndex, 0);
496 USETW(req.wLength, len);
497 return usbd_do_request_flags_pipe(dev, dev->default_pipe, &req, desc,
498 0, actlen, USBD_DEFAULT_TIMEOUT);
499 }
500
501 static int32_t
502 usbd_func_selconf(irp *ip)
503 {
504 device_t dev = IRP_NDIS_DEV(ip);
505 int i, j;
506 struct usb_attach_arg *uaa = device_get_ivars(dev);
507 struct usbd_interface_information *intf;
508 struct usbd_pipe_information *pipe;
509 struct usbd_urb_select_configuration *selconf;
510 union usbd_urb *urb;
511 usb_config_descriptor_t *conf;
512 usb_endpoint_descriptor_t *edesc;
513 usbd_device_handle udev = uaa->device;
514 usbd_interface_handle iface;
515 usbd_status ret;
516
517 urb = usbd_geturb(ip);
518
519 selconf = &urb->uu_selconf;
520 conf = selconf->usc_conf;
521 if (conf == NULL) {
522 device_printf(dev, "select configuration is NULL\n");
523 return usbd_usb2urb(USBD_NORMAL_COMPLETION);
524 }
525
526 if (conf->bConfigurationValue > NDISUSB_CONFIG_NO)
527 device_printf(dev, "warning: config_no is larger than default");
528
529 intf = &selconf->usc_intf;
530 for (i = 0; i < conf->bNumInterface && intf->uii_len > 0; i++) {
531 ret = usbd_device2interface_handle(uaa->device,
532 intf->uii_intfnum, &iface);
533 if (ret != USBD_NORMAL_COMPLETION) {
534 device_printf(dev,
535 "getting interface handle failed: %s\n",
536 usbd_errstr(ret));
537 return usbd_usb2urb(ret);
538 }
539
540 ret = usbd_set_interface(iface, intf->uii_altset);
541 if (ret != USBD_NORMAL_COMPLETION && ret != USBD_IN_USE) {
542 device_printf(dev,
543 "setting alternate interface failed: %s\n",
544 usbd_errstr(ret));
545 return usbd_usb2urb(ret);
546 }
547
548 for (j = 0; j < iface->idesc->bNumEndpoints; j++) {
549 if (j >= intf->uii_numeps) {
550 device_printf(dev,
551 "endpoint %d and above are ignored",
552 intf->uii_numeps);
553 break;
554 }
555 edesc = iface->endpoints[j].edesc;
556 pipe = &intf->uii_pipes[j];
557 pipe->upi_handle = edesc;
558 pipe->upi_epaddr = edesc->bEndpointAddress;
559 pipe->upi_maxpktsize = UGETW(edesc->wMaxPacketSize);
560 pipe->upi_type = UE_GET_XFERTYPE(edesc->bmAttributes);
561 if (pipe->upi_type != UE_INTERRUPT)
562 continue;
563
564 /* XXX we're following linux USB's interval policy. */
565 if (udev->speed == USB_SPEED_LOW)
566 pipe->upi_interval = edesc->bInterval + 5;
567 else if (udev->speed == USB_SPEED_FULL)
568 pipe->upi_interval = edesc->bInterval;
569 else {
570 int k0 = 0, k1 = 1;
571 do {
572 k1 = k1 * 2;
573 k0 = k0 + 1;
574 } while (k1 < edesc->bInterval);
575 pipe->upi_interval = k0;
576 }
577 }
578
579 intf = (struct usbd_interface_information *)(((char *)intf) +
580 intf->uii_len);
581 }
582
583 return (USBD_STATUS_SUCCESS);
584 }
585
586 static int32_t
587 usbd_func_abort_pipe(irp *ip)
588 {
589 device_t dev = IRP_NDIS_DEV(ip);
590 struct ndis_softc *sc = device_get_softc(dev);
591 union usbd_urb *urb;
592 struct usbd_urb_bulk_or_intr_transfer *ubi;
593 usb_endpoint_descriptor_t *ep;
594 uint8_t irql;
595 usbd_status status;
596
597 urb = usbd_geturb(ip);
598 ubi = &urb->uu_bulkintr;
599 ep = ubi->ubi_epdesc;
600 if (ep == NULL)
601 return (USBD_STATUS_INVALID_PIPE_HANDLE);
602
603 KeRaiseIrql(DISPATCH_LEVEL, &irql);
604 status = usbd_abort_pipe(sc->ndisusb_ep[NDISUSB_ENDPT_BIN]);
605 if (status != USBD_NORMAL_COMPLETION)
606 device_printf(dev, "can't be canceld");
607 KeLowerIrql(irql);
608
609 return (USBD_STATUS_SUCCESS);
610 }
611
612 static int32_t
613 usbd_func_vendorclass(irp *ip)
614 {
615 device_t dev = IRP_NDIS_DEV(ip);
616 struct usb_attach_arg *uaa = device_get_ivars(dev);
617 struct usbd_urb_vendor_or_class_request *vcreq;
618 uint8_t type = 0;
619 union usbd_urb *urb;
620 usb_device_request_t req;
621 usbd_status status;
622
623 urb = usbd_geturb(ip);
624 vcreq = &urb->uu_vcreq;
625
626 switch (urb->uu_hdr.uuh_func) {
627 case URB_FUNCTION_CLASS_DEVICE:
628 type = UT_CLASS | UT_DEVICE;
629 break;
630 case URB_FUNCTION_CLASS_INTERFACE:
631 type = UT_CLASS | UT_INTERFACE;
632 break;
633 case URB_FUNCTION_CLASS_OTHER:
634 type = UT_CLASS | UT_OTHER;
635 break;
636 case URB_FUNCTION_CLASS_ENDPOINT:
637 type = UT_CLASS | UT_ENDPOINT;
638 break;
639 case URB_FUNCTION_VENDOR_DEVICE:
640 type = UT_VENDOR | UT_DEVICE;
641 break;
642 case URB_FUNCTION_VENDOR_INTERFACE:
643 type = UT_VENDOR | UT_INTERFACE;
644 break;
645 case URB_FUNCTION_VENDOR_OTHER:
646 type = UT_VENDOR | UT_OTHER;
647 break;
648 case URB_FUNCTION_VENDOR_ENDPOINT:
649 type = UT_VENDOR | UT_ENDPOINT;
650 break;
651 default:
652 /* never reach. */
653 break;
654 }
655
656 type |= (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ?
657 UT_READ : UT_WRITE;
658 type |= vcreq->uvc_reserved1;
659
660 req.bmRequestType = type;
661 req.bRequest = vcreq->uvc_req;
662 USETW(req.wIndex, vcreq->uvc_idx);
663 USETW(req.wValue, vcreq->uvc_value);
664 USETW(req.wLength, vcreq->uvc_trans_buflen);
665
666 if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
667 get_mplock();
668 status = usbd_do_request(uaa->device, &req,
669 vcreq->uvc_trans_buf);
670 rel_mplock();
671 } else
672 status = usbd_do_request_async(uaa->device, &req,
673 vcreq->uvc_trans_buf);
674
675 return usbd_usb2urb(status);
676 }
677
678 static usbd_status
679 usbd_init_ndispipe(irp *ip, usb_endpoint_descriptor_t *ep)
680 {
681 device_t dev = IRP_NDIS_DEV(ip);
682 struct ndis_softc *sc = device_get_softc(dev);
683 struct usb_attach_arg *uaa = device_get_ivars(dev);
684 usbd_interface_handle iface;
685 usbd_status status;
686
687 status = usbd_device2interface_handle(uaa->device, NDISUSB_IFACE_INDEX,
688 &iface);
689 if (status != USBD_NORMAL_COMPLETION) {
690 device_printf(dev, "could not get interface handle\n");
691 return (status);
692 }
693
694 switch (UE_GET_XFERTYPE(ep->bmAttributes)) {
695 case UE_BULK:
696 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) {
697 /* RX (bulk IN) */
698 if (sc->ndisusb_ep[NDISUSB_ENDPT_BIN] != NULL)
699 return (USBD_NORMAL_COMPLETION);
700
701 status = usbd_open_pipe(iface, ep->bEndpointAddress,
702 USBD_EXCLUSIVE_USE,
703 &sc->ndisusb_ep[NDISUSB_ENDPT_BIN]);
704 break;
705 }
706
707 /* TX (bulk OUT) */
708 if (sc->ndisusb_ep[NDISUSB_ENDPT_BOUT] != NULL)
709 return (USBD_NORMAL_COMPLETION);
710
711 status = usbd_open_pipe(iface, ep->bEndpointAddress,
712 USBD_EXCLUSIVE_USE, &sc->ndisusb_ep[NDISUSB_ENDPT_BOUT]);
713 break;
714 case UE_INTERRUPT:
715 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) {
716 /* Interrupt IN. */
717 if (sc->ndisusb_ep[NDISUSB_ENDPT_IIN] != NULL)
718 return (USBD_NORMAL_COMPLETION);
719
720 status = usbd_open_pipe(iface, ep->bEndpointAddress,
721 USBD_EXCLUSIVE_USE,
722 &sc->ndisusb_ep[NDISUSB_ENDPT_IIN]);
723 break;
724 }
725
726 /* Interrupt OUT. */
727 if (sc->ndisusb_ep[NDISUSB_ENDPT_IOUT] != NULL)
728 return (USBD_NORMAL_COMPLETION);
729
730 status = usbd_open_pipe(iface, ep->bEndpointAddress,
731 USBD_EXCLUSIVE_USE, &sc->ndisusb_ep[NDISUSB_ENDPT_IOUT]);
732 break;
733 default:
734 device_printf(dev, "can't handle xfertype 0x%x\n",
735 UE_GET_XFERTYPE(ep->bmAttributes));
736 return (USBD_INVAL);
737 }
738
739 if (status != USBD_NORMAL_COMPLETION)
740 device_printf(dev, "open pipe failed: (0x%x) %s\n",
741 ep->bEndpointAddress, usbd_errstr(status));
742
743 return (status);
744 }
745
746 static void
747 usbd_irpcancel_cb(void *priv)
748 {
749 struct ndisusb_cancel *nc = priv;
750 struct ndis_softc *sc = device_get_softc(nc->dev);
751 usbd_status status;
752 usbd_xfer_handle xfer = nc->xfer;
753
754 if (sc->ndisusb_status & NDISUSB_STATUS_DETACH)
755 goto exit;
756
757 status = usbd_abort_pipe(xfer->pipe);
758 if (status != USBD_NORMAL_COMPLETION)
759 device_printf(nc->dev, "can't be canceld");
760 exit:
761 kfree(nc, M_USBDEV);
762 }
763
764 static void
765 usbd_irpcancel(device_object *dobj, irp *ip)
766 {
767 device_t dev = IRP_NDIS_DEV(ip);
768 struct ndisusb_cancel *nc;
769 struct usb_attach_arg *uaa = device_get_ivars(dev);
770
771 if (IRP_NDISUSB_XFER(ip) == NULL) {
772 ip->irp_cancel = TRUE;
773 IoReleaseCancelSpinLock(ip->irp_cancelirql);
774 return;
775 }
776
777 /*
778 * XXX Since we're under DISPATCH_LEVEL during calling usbd_irpcancel(),
779 * we can't sleep at all. However, currently FreeBSD's USB stack
780 * requires a sleep to abort a transfer. It's inevitable! so it causes
781 * serveral fatal problems (e.g. kernel hangups or crashes). I think
782 * that there are no ways to make this reliable. In this implementation,
783 * I used usb_add_task() but it's not a perfect method to solve this
784 * because of as follows: NDIS drivers would expect that IRP's
785 * completely canceld when usbd_irpcancel() is returned but we need
786 * a sleep to do it. During canceling XFERs, usbd_intr() would be
787 * called with a status, USBD_CANCELLED.
788 */
789 nc = kmalloc(sizeof(struct ndisusb_cancel), M_USBDEV, M_NOWAIT | M_ZERO);
790 if (nc == NULL) {
791 ip->irp_cancel = FALSE;
792 IoReleaseCancelSpinLock(ip->irp_cancelirql);
793 return;
794 }
795
796 nc->dev = dev;
797 nc->xfer = IRP_NDISUSB_XFER(ip);
798 usb_init_task(&nc->task, usbd_irpcancel_cb, nc);
799
800 IRP_NDISUSB_XFER(ip) = NULL;
801 usb_add_task(uaa->device, &nc->task, USB_TASKQ_DRIVER);
802
803 ip->irp_cancel = TRUE;
804 IoReleaseCancelSpinLock(ip->irp_cancelirql);
805 }
806
807 static usbd_xfer_handle
808 usbd_init_ndisxfer(irp *ip, usb_endpoint_descriptor_t *ep, void *buf,
809 uint32_t buflen)
810 {
811 device_t dev = IRP_NDIS_DEV(ip);
812 struct usb_attach_arg *uaa = device_get_ivars(dev);
813 usbd_xfer_handle xfer;
814
815 xfer = usbd_alloc_xfer(uaa->device);
816 if (xfer == NULL)
817 return (NULL);
818
819 if (buf != NULL && MmIsAddressValid(buf) == FALSE && buflen > 0) {
820 xfer->buffer = usbd_alloc_buffer(xfer, buflen);
821 if (xfer->buffer == NULL)
822 return (NULL);
823
824 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_OUT)
825 memcpy(xfer->buffer, buf, buflen);
826 } else
827 xfer->buffer = buf;
828
829 xfer->length = buflen;
830
831 IoAcquireCancelSpinLock(&ip->irp_cancelirql);
832 IRP_NDISUSB_XFER(ip) = xfer;
833 ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap;
834 IoReleaseCancelSpinLock(ip->irp_cancelirql);
835
836 return (xfer);
837 }
838
839 static void
840 usbd_xferadd(usbd_xfer_handle xfer, usbd_private_handle priv,
841 usbd_status status)
842 {
843 irp *ip = priv;
844 device_t dev = IRP_NDIS_DEV(ip);
845 struct ndis_softc *sc = device_get_softc(dev);
846 struct ndisusb_xfer *nx;
847 uint8_t irql;
848
849 nx = kmalloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO);
850 if (nx == NULL) {
851 device_printf(dev, "out of memory");
852 return;
853 }
854 nx->nx_xfer = xfer;
855 nx->nx_priv = priv;
856 nx->nx_status = status;
857
858 KeAcquireSpinLock(&sc->ndisusb_xferlock, &irql);
859 InsertTailList((&sc->ndisusb_xferlist), (&nx->nx_xferlist));
860 KeReleaseSpinLock(&sc->ndisusb_xferlock, irql);
861
862 IoQueueWorkItem(sc->ndisusb_xferitem,
863 (io_workitem_func)usbd_xfertask_wrap, WORKQUEUE_CRITICAL, sc);
864 }
865
866 static void
867 usbd_xfereof(usbd_xfer_handle xfer, usbd_private_handle priv,
868 usbd_status status)
869 {
870
871 usbd_xferadd(xfer, priv, status);
872 }
873
874 static void
875 usbd_xfertask(device_object *dobj, void *arg)
876 {
877 int error;
878 irp *ip;
879 device_t dev;
880 list_entry *l;
881 struct ndis_softc *sc = arg;
882 struct ndisusb_xfer *nx;
883 struct usbd_urb_bulk_or_intr_transfer *ubi;
884 uint8_t irql;
885 union usbd_urb *urb;
886 usbd_private_handle priv;
887 usbd_status status;
888 usbd_xfer_handle xfer;
889
890 dev = sc->ndis_dev;
891
892 if (IsListEmpty(&sc->ndisusb_xferlist))
893 return;
894
895 KeAcquireSpinLock(&sc->ndisusb_xferlock, &irql);
896 l = sc->ndisusb_xferlist.nle_flink;
897 while (l != &sc->ndisusb_xferlist) {
898 nx = CONTAINING_RECORD(l, struct ndisusb_xfer, nx_xferlist);
899 xfer = nx->nx_xfer;
900 priv = nx->nx_priv;
901 status = nx->nx_status;
902 error = 0;
903 ip = priv;
904
905 if (status != USBD_NORMAL_COMPLETION) {
906 if (status == USBD_NOT_STARTED) {
907 error = 1;
908 goto next;
909 }
910 if (status == USBD_STALLED)
911 usbd_clear_endpoint_stall_async(xfer->pipe);
912 /*
913 * NB: just for notice. We must handle error cases also
914 * because if we just return without notifying to the
915 * NDIS driver the driver never knows about that there
916 * was a error. This can cause a lot of problems like
917 * system hangs.
918 */
919 device_printf(dev, "usb xfer warning (%s)\n",
920 usbd_errstr(status));
921 }
922
923 urb = usbd_geturb(ip);
924
925 KASSERT(urb->uu_hdr.uuh_func ==
926 URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
927 ("function(%d) isn't for bulk or interrupt",
928 urb->uu_hdr.uuh_func));
929
930 IoAcquireCancelSpinLock(&ip->irp_cancelirql);
931
932 ip->irp_cancelfunc = NULL;
933 IRP_NDISUSB_XFER(ip) = NULL;
934
935 switch (status) {
936 case USBD_NORMAL_COMPLETION:
937 ubi = &urb->uu_bulkintr;
938 ubi->ubi_trans_buflen = xfer->actlen;
939 if (ubi->ubi_trans_flags & USBD_TRANSFER_DIRECTION_IN)
940 memcpy(ubi->ubi_trans_buf, xfer->buffer,
941 xfer->actlen);
942
943 ip->irp_iostat.isb_info = xfer->actlen;
944 ip->irp_iostat.isb_status = STATUS_SUCCESS;
945 USBD_URB_STATUS(urb) = USBD_STATUS_SUCCESS;
946 break;
947 case USBD_CANCELLED:
948 ip->irp_iostat.isb_info = 0;
949 ip->irp_iostat.isb_status = STATUS_CANCELLED;
950 USBD_URB_STATUS(urb) = USBD_STATUS_CANCELED;
951 break;
952 default:
953 ip->irp_iostat.isb_info = 0;
954 USBD_URB_STATUS(urb) = usbd_usb2urb(status);
955 ip->irp_iostat.isb_status =
956 usbd_urb2nt(USBD_URB_STATUS(urb));
957 break;
958 }
959
960 IoReleaseCancelSpinLock(ip->irp_cancelirql);
961 next:
962 l = l->nle_flink;
963 RemoveEntryList(&nx->nx_xferlist);
964 usbd_free_xfer(nx->nx_xfer);
965 kfree(nx, M_USBDEV);
966 if (error)
967 continue;
968 /* NB: call after cleaning */
969 IoCompleteRequest(ip, IO_NO_INCREMENT);
970 }
971 KeReleaseSpinLock(&sc->ndisusb_xferlock, irql);
972 }
973
974 static int32_t
975 usbd_func_bulkintr(irp *ip)
976 {
977 device_t dev = IRP_NDIS_DEV(ip);
978 struct ndis_softc *sc = device_get_softc(dev);
979 struct usbd_urb_bulk_or_intr_transfer *ubi;
980 union usbd_urb *urb;
981 usb_endpoint_descriptor_t *ep;
982 usbd_status status;
983 usbd_xfer_handle xfer;
984
985 urb = usbd_geturb(ip);
986 ubi = &urb->uu_bulkintr;
987 ep = ubi->ubi_epdesc;
988 if (ep == NULL)
989 return (USBD_STATUS_INVALID_PIPE_HANDLE);
990
991 status = usbd_init_ndispipe(ip, ep);
992 if (status != USBD_NORMAL_COMPLETION)
993 return usbd_usb2urb(status);
994
995 xfer = usbd_init_ndisxfer(ip, ep, ubi->ubi_trans_buf,
996 ubi->ubi_trans_buflen);
997 if (xfer == NULL) {
998 device_printf(IRP_NDIS_DEV(ip), "can't allocate xfer\n");
999 return (USBD_STATUS_NO_MEMORY);
1000 }
1001
1002 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) {
1003 xfer->flags |= USBD_SHORT_XFER_OK;
1004 if (!(ubi->ubi_trans_flags & USBD_SHORT_TRANSFER_OK))
1005 xfer->flags &= ~USBD_SHORT_XFER_OK;
1006 }
1007
1008 if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_BULK) {
1009 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
1010 /* RX (bulk IN) */
1011 usbd_setup_xfer(xfer, sc->ndisusb_ep[NDISUSB_ENDPT_BIN],
1012 ip, xfer->buffer, xfer->length, xfer->flags,
1013 USBD_NO_TIMEOUT, usbd_xfereof);
1014 else {
1015 /* TX (bulk OUT) */
1016 xfer->flags |= USBD_NO_COPY;
1017
1018 usbd_setup_xfer(xfer, sc->ndisusb_ep[NDISUSB_ENDPT_BOUT],
1019 ip, xfer->buffer, xfer->length, xfer->flags,
1020 NDISUSB_TX_TIMEOUT, usbd_xfereof);
1021 }
1022 } else {
1023 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
1024 /* Interrupt IN */
1025 usbd_setup_xfer(xfer, sc->ndisusb_ep[NDISUSB_ENDPT_IIN],
1026 ip, xfer->buffer, xfer->length, xfer->flags,
1027 USBD_NO_TIMEOUT, usbd_xfereof);
1028 else
1029 /* Interrupt OUT */
1030 usbd_setup_xfer(xfer, sc->ndisusb_ep[NDISUSB_ENDPT_IOUT],
1031 ip, xfer->buffer, xfer->length, xfer->flags,
1032 NDISUSB_INTR_TIMEOUT, usbd_xfereof);
1033 }
1034
1035 /* we've done to setup xfer. Let's transfer it. */
1036 ip->irp_iostat.isb_status = STATUS_PENDING;
1037 ip->irp_iostat.isb_info = 0;
1038 USBD_URB_STATUS(urb) = USBD_STATUS_PENDING;
1039 IoMarkIrpPending(ip);
1040
1041 status = usbd_transfer(xfer);
1042 if (status == USBD_IN_PROGRESS)
1043 return (USBD_STATUS_PENDING);
1044
1045 usbd_free_xfer(xfer);
1046 IRP_NDISUSB_XFER(ip) = NULL;
1047 IoUnmarkIrpPending(ip);
1048 USBD_URB_STATUS(urb) = usbd_usb2urb(status);
1049
1050 return USBD_URB_STATUS(urb);
1051 }
1052
1053 static union usbd_urb *
1054 USBD_CreateConfigurationRequest(usb_config_descriptor_t *conf, uint16_t *len)
1055 {
1056 struct usbd_interface_list_entry list[2];
1057 union usbd_urb *urb;
1058
1059 bzero(list, sizeof(struct usbd_interface_list_entry) * 2);
1060 list[0].uil_intfdesc = USBD_ParseConfigurationDescriptorEx(conf, conf,
1061 -1, -1, -1, -1, -1);
1062 urb = USBD_CreateConfigurationRequestEx(conf, list);
1063 if (urb == NULL)
1064 return (NULL);
1065
1066 *len = urb->uu_selconf.usc_hdr.uuh_len;
1067 return (urb);
1068 }
1069
1070 static union usbd_urb *
1071 USBD_CreateConfigurationRequestEx(usb_config_descriptor_t *conf,
1072 struct usbd_interface_list_entry *list)
1073 {
1074 int i, j, size;
1075 struct usbd_interface_information *intf;
1076 struct usbd_pipe_information *pipe;
1077 struct usbd_urb_select_configuration *selconf;
1078 usb_interface_descriptor_t *desc;
1079
1080 for (i = 0, size = 0; i < conf->bNumInterface; i++) {
1081 j = list[i].uil_intfdesc->bNumEndpoints;
1082 size = size + sizeof(struct usbd_interface_information) +
1083 sizeof(struct usbd_pipe_information) * (j - 1);
1084 }
1085 size += sizeof(struct usbd_urb_select_configuration) -
1086 sizeof(struct usbd_interface_information);
1087
1088 selconf = ExAllocatePoolWithTag(NonPagedPool, size, 0);
1089 if (selconf == NULL)
1090 return (NULL);
1091 selconf->usc_hdr.uuh_func = URB_FUNCTION_SELECT_CONFIGURATION;
1092 selconf->usc_hdr.uuh_len = size;
1093 selconf->usc_handle = conf;
1094 selconf->usc_conf = conf;
1095
1096 intf = &selconf->usc_intf;
1097 for (i = 0; i < conf->bNumInterface; i++) {
1098 if (list[i].uil_intfdesc == NULL)
1099 break;
1100
1101 list[i].uil_intf = intf;
1102 desc = list[i].uil_intfdesc;
1103
1104 intf->uii_len = sizeof(struct usbd_interface_information) +
1105 (desc->bNumEndpoints - 1) *
1106 sizeof(struct usbd_pipe_information);
1107 intf->uii_intfnum = desc->bInterfaceNumber;
1108 intf->uii_altset = desc->bAlternateSetting;
1109 intf->uii_intfclass = desc->bInterfaceClass;
1110 intf->uii_intfsubclass = desc->bInterfaceSubClass;
1111 intf->uii_intfproto = desc->bInterfaceProtocol;
1112 intf->uii_handle = desc;
1113 intf->uii_numeps = desc->bNumEndpoints;
1114
1115 pipe = &intf->uii_pipes[0];
1116 for (j = 0; j < intf->uii_numeps; j++)
1117 pipe[j].upi_maxtxsize =
1118 USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
1119
1120 intf = (struct usbd_interface_information *)((char *)intf +
1121 intf->uii_len);
1122 }
1123
1124 return ((union usbd_urb *)selconf);
1125 }
1126
1127 static void
1128 USBD_GetUSBDIVersion(usbd_version_info *ui)
1129 {
1130
1131 /* Pretend to be Windows XP. */
1132
1133 ui->uvi_usbdi_vers = USBDI_VERSION;
1134 ui->uvi_supported_vers = USB_VER_2_0;
1135 }
1136
1137 static usb_interface_descriptor_t *
1138 USBD_ParseConfigurationDescriptor(usb_config_descriptor_t *conf,
1139 uint8_t intfnum, uint8_t altset)
1140 {
1141
1142 return USBD_ParseConfigurationDescriptorEx(conf, conf, intfnum, altset,
1143 -1, -1, -1);
1144 }
1145
1146 static usb_interface_descriptor_t *
1147 USBD_ParseConfigurationDescriptorEx(usb_config_descriptor_t *conf,
1148 void *start, int32_t intfnum, int32_t altset, int32_t intfclass,
1149 int32_t intfsubclass, int32_t intfproto)
1150 {
1151 char *pos;
1152 usb_interface_descriptor_t *desc;
1153
1154 for (pos = start; pos < ((char *)conf + UGETW(conf->wTotalLength));
1155 pos += desc->bLength) {
1156 desc = (usb_interface_descriptor_t *)pos;
1157 if (desc->bDescriptorType != UDESC_INTERFACE)
1158 continue;
1159 if (!(intfnum == -1 || desc->bInterfaceNumber == intfnum))
1160 continue;
1161 if (!(altset == -1 || desc->bAlternateSetting == altset))
1162 continue;
1163 if (!(intfclass == -1 || desc->bInterfaceClass == intfclass))
1164 continue;
1165 if (!(intfsubclass == -1 ||
1166 desc->bInterfaceSubClass == intfsubclass))
1167 continue;
1168 if (!(intfproto == -1 || desc->bInterfaceProtocol == intfproto))
1169 continue;
1170 return (desc);
1171 }
1172
1173 return (NULL);
1174 }
1175
1176 static void
1177 dummy(void)
1178 {
1179 kprintf("USBD dummy called\n");
1180 }
1181
1182 image_patch_table usbd_functbl[] = {
1183 IMPORT_SFUNC(USBD_CreateConfigurationRequest, 2),
1184 IMPORT_SFUNC(USBD_CreateConfigurationRequestEx, 2),
1185 IMPORT_SFUNC_MAP(_USBD_CreateConfigurationRequestEx@8,
1186 USBD_CreateConfigurationRequestEx, 2),
1187 IMPORT_SFUNC(USBD_GetUSBDIVersion, 1),
1188 IMPORT_SFUNC(USBD_ParseConfigurationDescriptor, 3),
1189 IMPORT_SFUNC(USBD_ParseConfigurationDescriptorEx, 7),
1190 IMPORT_SFUNC_MAP(_USBD_ParseConfigurationDescriptorEx@28,
1191 USBD_ParseConfigurationDescriptorEx, 7),
1192
1193 /*
1194 * This last entry is a catch-all for any function we haven't
1195 * implemented yet. The PE import list patching routine will
1196 * use it for any function that doesn't have an explicit match
1197 * in this table.
1198 */
1199
1200 { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL },
1201
1202 /* End of list. */
1203
1204 { NULL, NULL, NULL }
1205 };
1206
1207 MODULE_DEPEND(ndis, usb, 1, 1, 1);
Cache object: 4c5b7271b4615df65d761ef59b95b607
|