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: src/sys/compat/ndis/subr_usbd.c,v 1.4 2008/12/27 08:03:32 weongyo Exp $");
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/module.h>
46 #include <sys/conf.h>
47 #include <sys/mbuf.h>
48 #include <sys/socket.h>
49 #include <machine/bus.h>
50 #include <sys/bus.h>
51
52 #include <sys/queue.h>
53
54 #include <net/if.h>
55 #include <net/if_media.h>
56 #include <net80211/ieee80211_var.h>
57 #include <net80211/ieee80211_ioctl.h>
58
59 #include <dev/usb/usb.h>
60 #include <dev/usb/usbdi.h>
61 #include <dev/usb/usbdi_util.h>
62 #include <dev/usb/usbdivar.h>
63 #include <dev/usb/usb_quirks.h>
64 #include "usbdevs.h"
65
66 #include <compat/ndis/pe_var.h>
67 #include <compat/ndis/cfg_var.h>
68 #include <compat/ndis/resource_var.h>
69 #include <compat/ndis/ntoskrnl_var.h>
70 #include <compat/ndis/ndis_var.h>
71 #include <compat/ndis/hal_var.h>
72 #include <compat/ndis/usbd_var.h>
73 #include <dev/if_ndis/if_ndisvar.h>
74
75 static driver_object usbd_driver;
76
77 static int32_t usbd_func_bulkintr(irp *);
78 static int32_t usbd_func_vendorclass(irp *);
79 static int32_t usbd_func_selconf(irp *);
80 static int32_t usbd_func_getdesc(irp *);
81 static usbd_status usbd_get_desc_ndis(usbd_device_handle, int, int, int,
82 void *, int *);
83 static union usbd_urb *usbd_geturb(irp *);
84 static usbd_status usbd_init_ndispipe(irp *, usb_endpoint_descriptor_t *);
85 static usbd_xfer_handle usbd_init_ndisxfer(irp *, usb_endpoint_descriptor_t *,
86 void *, uint32_t);
87 static int32_t usbd_iodispatch(device_object *, irp *);
88 static int32_t usbd_ioinvalid(device_object *, irp *);
89 static int32_t usbd_pnp(device_object *, irp *);
90 static int32_t usbd_power(device_object *, irp *);
91 static void usbd_irpcancel(device_object *, irp *);
92 static void usbd_irpcancel_cb(void *);
93 static int32_t usbd_submit_urb(irp *);
94 static int32_t usbd_urb2nt(int32_t);
95 static void usbd_xfereof(usbd_xfer_handle, usbd_private_handle,
96 usbd_status);
97 static void usbd_xferadd(usbd_xfer_handle, usbd_private_handle,
98 usbd_status);
99 static void usbd_xfertask(device_object *, void *);
100 static void dummy(void);
101
102 static union usbd_urb *USBD_CreateConfigurationRequestEx(
103 usb_config_descriptor_t *,
104 struct usbd_interface_list_entry *);
105 static union usbd_urb *USBD_CreateConfigurationRequest(
106 usb_config_descriptor_t *,
107 uint16_t *);
108 static void USBD_GetUSBDIVersion(usbd_version_info *);
109 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptorEx(
110 usb_config_descriptor_t *, void *, int32_t, int32_t,
111 int32_t, int32_t, int32_t);
112 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptor(
113 usb_config_descriptor_t *, uint8_t, uint8_t);
114
115 /*
116 * We need to wrap these functions because these need `context switch' from
117 * Windows to UNIX before it's called.
118 */
119 static funcptr usbd_iodispatch_wrap;
120 static funcptr usbd_ioinvalid_wrap;
121 static funcptr usbd_pnp_wrap;
122 static funcptr usbd_power_wrap;
123 static funcptr usbd_irpcancel_wrap;
124 static funcptr usbd_xfertask_wrap;
125
126 int
127 usbd_libinit(void)
128 {
129 image_patch_table *patch;
130 int i;
131
132 patch = usbd_functbl;
133 while (patch->ipt_func != NULL) {
134 windrv_wrap((funcptr)patch->ipt_func,
135 (funcptr *)&patch->ipt_wrap,
136 patch->ipt_argcnt, patch->ipt_ftype);
137 patch++;
138 }
139
140 windrv_wrap((funcptr)usbd_ioinvalid,
141 (funcptr *)&usbd_ioinvalid_wrap, 2, WINDRV_WRAP_STDCALL);
142 windrv_wrap((funcptr)usbd_iodispatch,
143 (funcptr *)&usbd_iodispatch_wrap, 2, WINDRV_WRAP_STDCALL);
144 windrv_wrap((funcptr)usbd_pnp,
145 (funcptr *)&usbd_pnp_wrap, 2, WINDRV_WRAP_STDCALL);
146 windrv_wrap((funcptr)usbd_power,
147 (funcptr *)&usbd_power_wrap, 2, WINDRV_WRAP_STDCALL);
148 windrv_wrap((funcptr)usbd_irpcancel,
149 (funcptr *)&usbd_irpcancel_wrap, 2, WINDRV_WRAP_STDCALL);
150 windrv_wrap((funcptr)usbd_xfertask,
151 (funcptr *)&usbd_xfertask_wrap, 2, WINDRV_WRAP_STDCALL);
152
153 /* Create a fake USB driver instance. */
154
155 windrv_bus_attach(&usbd_driver, "USB Bus");
156
157 /* Set up our dipatch routine. */
158 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
159 usbd_driver.dro_dispatch[i] =
160 (driver_dispatch)usbd_ioinvalid_wrap;
161
162 usbd_driver.dro_dispatch[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
163 (driver_dispatch)usbd_iodispatch_wrap;
164 usbd_driver.dro_dispatch[IRP_MJ_DEVICE_CONTROL] =
165 (driver_dispatch)usbd_iodispatch_wrap;
166 usbd_driver.dro_dispatch[IRP_MJ_POWER] =
167 (driver_dispatch)usbd_power_wrap;
168 usbd_driver.dro_dispatch[IRP_MJ_PNP] =
169 (driver_dispatch)usbd_pnp_wrap;
170
171 return(0);
172 }
173
174 int
175 usbd_libfini(void)
176 {
177 image_patch_table *patch;
178
179 patch = usbd_functbl;
180 while (patch->ipt_func != NULL) {
181 windrv_unwrap(patch->ipt_wrap);
182 patch++;
183 }
184
185 windrv_unwrap(usbd_ioinvalid_wrap);
186 windrv_unwrap(usbd_iodispatch_wrap);
187 windrv_unwrap(usbd_pnp_wrap);
188 windrv_unwrap(usbd_power_wrap);
189 windrv_unwrap(usbd_irpcancel_wrap);
190 windrv_unwrap(usbd_xfertask_wrap);
191
192 free(usbd_driver.dro_drivername.us_buf, M_DEVBUF);
193
194 return(0);
195 }
196
197 static int32_t
198 usbd_iodispatch(dobj, ip)
199 device_object *dobj;
200 irp *ip;
201 {
202 device_t dev = dobj->do_devext;
203 int32_t status;
204 struct io_stack_location *irp_sl;
205
206 irp_sl = IoGetCurrentIrpStackLocation(ip);
207 switch (irp_sl->isl_parameters.isl_ioctl.isl_iocode) {
208 case IOCTL_INTERNAL_USB_SUBMIT_URB:
209 IRP_NDIS_DEV(ip) = dev;
210
211 status = usbd_submit_urb(ip);
212 break;
213 default:
214 device_printf(dev, "ioctl 0x%x isn't supported\n",
215 irp_sl->isl_parameters.isl_ioctl.isl_iocode);
216 status = USBD_STATUS_NOT_SUPPORTED;
217 break;
218 }
219
220 if (status == USBD_STATUS_PENDING)
221 return (STATUS_PENDING);
222
223 ip->irp_iostat.isb_status = usbd_urb2nt(status);
224 if (status != USBD_STATUS_SUCCESS)
225 ip->irp_iostat.isb_info = 0;
226 return (ip->irp_iostat.isb_status);
227 }
228
229 static int32_t
230 usbd_ioinvalid(dobj, ip)
231 device_object *dobj;
232 irp *ip;
233 {
234 device_t dev = dobj->do_devext;
235 struct io_stack_location *irp_sl;
236
237 irp_sl = IoGetCurrentIrpStackLocation(ip);
238 device_printf(dev, "invalid I/O dispatch %d:%d\n", irp_sl->isl_major,
239 irp_sl->isl_minor);
240
241 ip->irp_iostat.isb_status = STATUS_FAILURE;
242 ip->irp_iostat.isb_info = 0;
243
244 IoCompleteRequest(ip, IO_NO_INCREMENT);
245
246 return (STATUS_FAILURE);
247 }
248
249 static int32_t
250 usbd_pnp(dobj, ip)
251 device_object *dobj;
252 irp *ip;
253 {
254 device_t dev = dobj->do_devext;
255 struct io_stack_location *irp_sl;
256
257 irp_sl = IoGetCurrentIrpStackLocation(ip);
258 device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
259 __func__, irp_sl->isl_major, irp_sl->isl_minor);
260
261 ip->irp_iostat.isb_status = STATUS_FAILURE;
262 ip->irp_iostat.isb_info = 0;
263
264 IoCompleteRequest(ip, IO_NO_INCREMENT);
265
266 return (STATUS_FAILURE);
267 }
268
269 static int32_t
270 usbd_power(dobj, ip)
271 device_object *dobj;
272 irp *ip;
273 {
274 device_t dev = dobj->do_devext;
275 struct io_stack_location *irp_sl;
276
277 irp_sl = IoGetCurrentIrpStackLocation(ip);
278 device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
279 __func__, irp_sl->isl_major, irp_sl->isl_minor);
280
281 ip->irp_iostat.isb_status = STATUS_FAILURE;
282 ip->irp_iostat.isb_info = 0;
283
284 IoCompleteRequest(ip, IO_NO_INCREMENT);
285
286 return (STATUS_FAILURE);
287 }
288
289 /* Convert USBD_STATUS to NTSTATUS */
290 static int32_t
291 usbd_urb2nt(status)
292 int32_t status;
293 {
294
295 switch (status) {
296 case USBD_STATUS_SUCCESS:
297 return (STATUS_SUCCESS);
298 case USBD_STATUS_DEVICE_GONE:
299 return (STATUS_DEVICE_NOT_CONNECTED);
300 case USBD_STATUS_PENDING:
301 return (STATUS_PENDING);
302 case USBD_STATUS_NOT_SUPPORTED:
303 return (STATUS_NOT_IMPLEMENTED);
304 case USBD_STATUS_NO_MEMORY:
305 return (STATUS_NO_MEMORY);
306 case USBD_STATUS_REQUEST_FAILED:
307 return (STATUS_NOT_SUPPORTED);
308 case USBD_STATUS_CANCELED:
309 return (STATUS_CANCELLED);
310 default:
311 break;
312 }
313
314 return (STATUS_FAILURE);
315 }
316
317 /* Convert FreeBSD's usbd_status to USBD_STATUS */
318 static int32_t
319 usbd_usb2urb(int status)
320 {
321
322 switch (status) {
323 case USBD_NORMAL_COMPLETION:
324 return (USBD_STATUS_SUCCESS);
325 case USBD_IN_PROGRESS:
326 return (USBD_STATUS_PENDING);
327 case USBD_TIMEOUT:
328 return (USBD_STATUS_TIMEOUT);
329 case USBD_SHORT_XFER:
330 return (USBD_STATUS_ERROR_SHORT_TRANSFER);
331 case USBD_IOERROR:
332 return (USBD_STATUS_XACT_ERROR);
333 case USBD_NOMEM:
334 return (USBD_STATUS_NO_MEMORY);
335 case USBD_INVAL:
336 return (USBD_STATUS_REQUEST_FAILED);
337 case USBD_NOT_STARTED:
338 case USBD_TOO_DEEP:
339 case USBD_NO_POWER:
340 return (USBD_STATUS_DEVICE_GONE);
341 case USBD_CANCELLED:
342 return (USBD_STATUS_CANCELED);
343 default:
344 break;
345 }
346
347 return (USBD_STATUS_NOT_SUPPORTED);
348 }
349
350 static union usbd_urb *
351 usbd_geturb(ip)
352 irp *ip;
353 {
354 struct io_stack_location *irp_sl;
355
356 irp_sl = IoGetCurrentIrpStackLocation(ip);
357
358 return (irp_sl->isl_parameters.isl_others.isl_arg1);
359 }
360
361 static int32_t
362 usbd_submit_urb(ip)
363 irp *ip;
364 {
365 device_t dev = IRP_NDIS_DEV(ip);
366 int32_t status;
367 union usbd_urb *urb;
368
369 urb = usbd_geturb(ip);
370 /*
371 * In a case of URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
372 * USBD_URB_STATUS(urb) would be set at callback functions like
373 * usbd_intr() or usbd_xfereof().
374 */
375 switch (urb->uu_hdr.uuh_func) {
376 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
377 status = usbd_func_bulkintr(ip);
378 if (status != USBD_STATUS_SUCCESS &&
379 status != USBD_STATUS_PENDING)
380 USBD_URB_STATUS(urb) = status;
381 break;
382 case URB_FUNCTION_VENDOR_DEVICE:
383 case URB_FUNCTION_VENDOR_INTERFACE:
384 case URB_FUNCTION_VENDOR_ENDPOINT:
385 case URB_FUNCTION_VENDOR_OTHER:
386 case URB_FUNCTION_CLASS_DEVICE:
387 case URB_FUNCTION_CLASS_INTERFACE:
388 case URB_FUNCTION_CLASS_ENDPOINT:
389 case URB_FUNCTION_CLASS_OTHER:
390 status = usbd_func_vendorclass(ip);
391 USBD_URB_STATUS(urb) = status;
392 break;
393 case URB_FUNCTION_SELECT_CONFIGURATION:
394 status = usbd_func_selconf(ip);
395 USBD_URB_STATUS(urb) = status;
396 break;
397 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
398 status = usbd_func_getdesc(ip);
399 USBD_URB_STATUS(urb) = status;
400 break;
401 default:
402 device_printf(dev, "func 0x%x isn't supported\n",
403 urb->uu_hdr.uuh_func);
404 USBD_URB_STATUS(urb) = status = USBD_STATUS_NOT_SUPPORTED;
405 break;
406 }
407
408 return (status);
409 }
410
411 static int32_t
412 usbd_func_getdesc(ip)
413 irp *ip;
414 {
415 device_t dev = IRP_NDIS_DEV(ip);
416 int actlen, i;
417 struct usb_attach_arg *uaa = device_get_ivars(dev);
418 struct usbd_urb_control_descriptor_request *ctldesc;
419 uint32_t len;
420 union usbd_urb *urb;
421 usb_config_descriptor_t cd, *cdp;
422 usbd_status status;
423
424 mtx_lock(&Giant);
425
426 urb = usbd_geturb(ip);
427 ctldesc = &urb->uu_ctldesc;
428 if (ctldesc->ucd_desctype == UDESC_CONFIG) {
429 /* Get the short config descriptor. */
430 status = usbd_get_config_desc(uaa->device, ctldesc->ucd_idx,
431 &cd);
432 if (status != USBD_NORMAL_COMPLETION) {
433 ctldesc->ucd_trans_buflen = 0;
434 mtx_unlock(&Giant);
435 return usbd_usb2urb(status);
436 }
437 /* Get the full descriptor. Try a few times for slow devices. */
438 len = MIN(ctldesc->ucd_trans_buflen, UGETW(cd.wTotalLength));
439 for (i = 0; i < 3; i++) {
440 status = usbd_get_desc_ndis(uaa->device,
441 ctldesc->ucd_desctype, ctldesc->ucd_idx,
442 len, ctldesc->ucd_trans_buf, &actlen);
443 if (status == USBD_NORMAL_COMPLETION)
444 break;
445 usbd_delay_ms(uaa->device, 200);
446 }
447 if (status != USBD_NORMAL_COMPLETION) {
448 ctldesc->ucd_trans_buflen = 0;
449 mtx_unlock(&Giant);
450 return usbd_usb2urb(status);
451 }
452
453 cdp = (usb_config_descriptor_t *)ctldesc->ucd_trans_buf;
454 if (cdp->bDescriptorType != UDESC_CONFIG) {
455 device_printf(dev, "bad desc %d\n",
456 cdp->bDescriptorType);
457 status = USBD_INVAL;
458 }
459 } else if (ctldesc->ucd_desctype == UDESC_STRING) {
460 /* Try a few times for slow devices. */
461 for (i = 0; i < 3; i++) {
462 status = usbd_get_string_desc(uaa->device,
463 (UDESC_STRING << 8) + ctldesc->ucd_idx,
464 ctldesc->ucd_langid, ctldesc->ucd_trans_buf,
465 &actlen);
466 if (actlen > ctldesc->ucd_trans_buflen)
467 panic("small string buffer for UDESC_STRING");
468 if (status == USBD_NORMAL_COMPLETION)
469 break;
470 usbd_delay_ms(uaa->device, 200);
471 }
472 } else
473 status = usbd_get_desc_ndis(uaa->device, ctldesc->ucd_desctype,
474 ctldesc->ucd_idx, ctldesc->ucd_trans_buflen,
475 ctldesc->ucd_trans_buf, &actlen);
476
477 if (status != USBD_NORMAL_COMPLETION) {
478 ctldesc->ucd_trans_buflen = 0;
479 mtx_unlock(&Giant);
480 return usbd_usb2urb(status);
481 }
482
483 ctldesc->ucd_trans_buflen = actlen;
484 ip->irp_iostat.isb_info = actlen;
485
486 mtx_unlock(&Giant);
487
488 return (USBD_STATUS_SUCCESS);
489 }
490
491 /*
492 * FIXME: at USB1, not USB2, framework, there's no a interface to get `actlen'.
493 * However, we need it!!!
494 */
495 static usbd_status
496 usbd_get_desc_ndis(usbd_device_handle dev, int type, int index, int len,
497 void *desc, int *actlen)
498 {
499 usb_device_request_t req;
500
501 req.bmRequestType = UT_READ_DEVICE;
502 req.bRequest = UR_GET_DESCRIPTOR;
503 USETW2(req.wValue, type, index);
504 USETW(req.wIndex, 0);
505 USETW(req.wLength, len);
506 return usbd_do_request_flags_pipe(dev, dev->default_pipe, &req, desc,
507 0, actlen, USBD_DEFAULT_TIMEOUT);
508 }
509
510 static int32_t
511 usbd_func_selconf(ip)
512 irp *ip;
513 {
514 device_t dev = IRP_NDIS_DEV(ip);
515 int i, j;
516 struct usb_attach_arg *uaa = device_get_ivars(dev);
517 struct usbd_interface_information *intf;
518 struct usbd_pipe_information *pipe;
519 struct usbd_urb_select_configuration *selconf;
520 union usbd_urb *urb;
521 usb_config_descriptor_t *conf;
522 usb_endpoint_descriptor_t *edesc;
523 usbd_device_handle udev = uaa->device;
524 usbd_interface_handle iface;
525 usbd_status ret;
526
527 urb = usbd_geturb(ip);
528
529 selconf = &urb->uu_selconf;
530 conf = selconf->usc_conf;
531 if (conf == NULL) {
532 device_printf(dev, "select configuration is NULL\n");
533 return usbd_usb2urb(USBD_NORMAL_COMPLETION);
534 }
535
536 if (conf->bConfigurationValue > NDISUSB_CONFIG_NO)
537 device_printf(dev, "warning: config_no is larger than default");
538
539 intf = &selconf->usc_intf;
540 for (i = 0; i < conf->bNumInterface && intf->uii_len > 0; i++) {
541 ret = usbd_device2interface_handle(uaa->device,
542 intf->uii_intfnum, &iface);
543 if (ret != USBD_NORMAL_COMPLETION) {
544 device_printf(dev,
545 "getting interface handle failed: %s\n",
546 usbd_errstr(ret));
547 return usbd_usb2urb(ret);
548 }
549
550 ret = usbd_set_interface(iface, intf->uii_altset);
551 if (ret != USBD_NORMAL_COMPLETION && ret != USBD_IN_USE) {
552 device_printf(dev,
553 "setting alternate interface failed: %s\n",
554 usbd_errstr(ret));
555 return usbd_usb2urb(ret);
556 }
557
558 for (j = 0; j < iface->idesc->bNumEndpoints; j++) {
559 if (j >= intf->uii_numeps) {
560 device_printf(dev,
561 "endpoint %d and above are ignored",
562 intf->uii_numeps);
563 break;
564 }
565 edesc = iface->endpoints[j].edesc;
566 pipe = &intf->uii_pipes[j];
567 pipe->upi_handle = edesc;
568 pipe->upi_epaddr = edesc->bEndpointAddress;
569 pipe->upi_maxpktsize = UGETW(edesc->wMaxPacketSize);
570 pipe->upi_type = UE_GET_XFERTYPE(edesc->bmAttributes);
571 if (pipe->upi_type != UE_INTERRUPT)
572 continue;
573
574 /* XXX we're following linux USB's interval policy. */
575 if (udev->speed == USB_SPEED_LOW)
576 pipe->upi_interval = edesc->bInterval + 5;
577 else if (udev->speed == USB_SPEED_FULL)
578 pipe->upi_interval = edesc->bInterval;
579 else {
580 int k0 = 0, k1 = 1;
581 do {
582 k1 = k1 * 2;
583 k0 = k0 + 1;
584 } while (k1 < edesc->bInterval);
585 pipe->upi_interval = k0;
586 }
587 }
588
589 intf = (struct usbd_interface_information *)(((char *)intf) +
590 intf->uii_len);
591 }
592
593 return USBD_STATUS_SUCCESS;
594 }
595
596 static int32_t
597 usbd_func_vendorclass(ip)
598 irp *ip;
599 {
600 device_t dev = IRP_NDIS_DEV(ip);
601 struct usb_attach_arg *uaa = device_get_ivars(dev);
602 struct usbd_urb_vendor_or_class_request *vcreq;
603 uint8_t type = 0;
604 union usbd_urb *urb;
605 usb_device_request_t req;
606 usbd_status status;
607
608 urb = usbd_geturb(ip);
609 vcreq = &urb->uu_vcreq;
610
611 switch (urb->uu_hdr.uuh_func) {
612 case URB_FUNCTION_CLASS_DEVICE:
613 type = UT_CLASS | UT_DEVICE;
614 break;
615 case URB_FUNCTION_CLASS_INTERFACE:
616 type = UT_CLASS | UT_INTERFACE;
617 break;
618 case URB_FUNCTION_CLASS_OTHER:
619 type = UT_CLASS | UT_OTHER;
620 break;
621 case URB_FUNCTION_CLASS_ENDPOINT:
622 type = UT_CLASS | UT_ENDPOINT;
623 break;
624 case URB_FUNCTION_VENDOR_DEVICE:
625 type = UT_VENDOR | UT_DEVICE;
626 break;
627 case URB_FUNCTION_VENDOR_INTERFACE:
628 type = UT_VENDOR | UT_INTERFACE;
629 break;
630 case URB_FUNCTION_VENDOR_OTHER:
631 type = UT_VENDOR | UT_OTHER;
632 break;
633 case URB_FUNCTION_VENDOR_ENDPOINT:
634 type = UT_VENDOR | UT_ENDPOINT;
635 break;
636 default:
637 /* never reach. */
638 break;
639 }
640
641 type |= (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ?
642 UT_READ : UT_WRITE;
643 type |= vcreq->uvc_reserved1;
644
645 req.bmRequestType = type;
646 req.bRequest = vcreq->uvc_req;
647 USETW(req.wIndex, vcreq->uvc_idx);
648 USETW(req.wValue, vcreq->uvc_value);
649 USETW(req.wLength, vcreq->uvc_trans_buflen);
650
651 if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
652 mtx_lock(&Giant);
653 status = usbd_do_request(uaa->device, &req,
654 vcreq->uvc_trans_buf);
655 mtx_unlock(&Giant);
656 } else
657 status = usbd_do_request_async(uaa->device, &req,
658 vcreq->uvc_trans_buf);
659
660 return usbd_usb2urb(status);
661 }
662
663 static usbd_status
664 usbd_init_ndispipe(ip, ep)
665 irp *ip;
666 usb_endpoint_descriptor_t *ep;
667 {
668 device_t dev = IRP_NDIS_DEV(ip);
669 struct ndis_softc *sc = device_get_softc(dev);
670 struct usb_attach_arg *uaa = device_get_ivars(dev);
671 usbd_interface_handle iface;
672 usbd_status status;
673
674 status = usbd_device2interface_handle(uaa->device, NDISUSB_IFACE_INDEX,
675 &iface);
676 if (status != USBD_NORMAL_COMPLETION) {
677 device_printf(dev, "could not get interface handle\n");
678 return (status);
679 }
680
681 switch (UE_GET_XFERTYPE(ep->bmAttributes)) {
682 case UE_BULK:
683 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) {
684 /* RX (bulk IN) */
685 if (sc->ndisusb_ep[NDISUSB_ENDPT_BIN] != NULL)
686 return (USBD_NORMAL_COMPLETION);
687
688 status = usbd_open_pipe(iface, ep->bEndpointAddress,
689 USBD_EXCLUSIVE_USE,
690 &sc->ndisusb_ep[NDISUSB_ENDPT_BIN]);
691 break;
692 }
693
694 /* TX (bulk OUT) */
695 if (sc->ndisusb_ep[NDISUSB_ENDPT_BOUT] != NULL)
696 return (USBD_NORMAL_COMPLETION);
697
698 status = usbd_open_pipe(iface, ep->bEndpointAddress,
699 USBD_EXCLUSIVE_USE, &sc->ndisusb_ep[NDISUSB_ENDPT_BOUT]);
700 break;
701 case UE_INTERRUPT:
702 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) {
703 /* Interrupt IN. */
704 if (sc->ndisusb_ep[NDISUSB_ENDPT_IIN] != NULL)
705 return (USBD_NORMAL_COMPLETION);
706
707 status = usbd_open_pipe(iface, ep->bEndpointAddress,
708 USBD_EXCLUSIVE_USE,
709 &sc->ndisusb_ep[NDISUSB_ENDPT_IIN]);
710 break;
711 }
712
713 /* Interrupt OUT. */
714 if (sc->ndisusb_ep[NDISUSB_ENDPT_IOUT] != NULL)
715 return (USBD_NORMAL_COMPLETION);
716
717 status = usbd_open_pipe(iface, ep->bEndpointAddress,
718 USBD_EXCLUSIVE_USE, &sc->ndisusb_ep[NDISUSB_ENDPT_IOUT]);
719 break;
720 default:
721 device_printf(dev, "can't handle xfertype 0x%x\n",
722 UE_GET_XFERTYPE(ep->bmAttributes));
723 return (USBD_INVAL);
724 }
725
726 if (status != USBD_NORMAL_COMPLETION)
727 device_printf(dev, "open pipe failed: (0x%x) %s\n",
728 ep->bEndpointAddress, usbd_errstr(status));
729
730 return (status);
731 }
732
733 static void
734 usbd_irpcancel_cb(priv)
735 void *priv;
736 {
737 struct ndisusb_cancel *nc = priv;
738 struct ndis_softc *sc = device_get_softc(nc->dev);
739 usbd_status status;
740 usbd_xfer_handle xfer = nc->xfer;
741
742 if (sc->ndisusb_status & NDISUSB_STATUS_DETACH)
743 goto exit;
744
745 status = usbd_abort_pipe(xfer->pipe);
746 if (status != USBD_NORMAL_COMPLETION)
747 device_printf(nc->dev, "can't be canceld");
748 exit:
749 free(nc, M_USBDEV);
750 }
751
752 static void
753 usbd_irpcancel(dobj, ip)
754 device_object *dobj;
755 irp *ip;
756 {
757 device_t dev = IRP_NDIS_DEV(ip);
758 struct ndisusb_cancel *nc;
759 struct usb_attach_arg *uaa = device_get_ivars(dev);
760
761 if (IRP_NDISUSB_XFER(ip) == NULL) {
762 ip->irp_cancel = TRUE;
763 IoReleaseCancelSpinLock(ip->irp_cancelirql);
764 return;
765 }
766
767 /*
768 * XXX Since we're under DISPATCH_LEVEL during calling usbd_irpcancel(),
769 * we can't sleep at all. However, currently FreeBSD's USB stack
770 * requires a sleep to abort a transfer. It's inevitable! so it causes
771 * serveral fatal problems (e.g. kernel hangups or crashes). I think
772 * that there are no ways to make this reliable. In this implementation,
773 * I used usb_add_task() but it's not a perfect method to solve this
774 * because of as follows: NDIS drivers would expect that IRP's
775 * completely canceld when usbd_irpcancel() is returned but we need
776 * a sleep to do it. During canceling XFERs, usbd_intr() would be
777 * called with a status, USBD_CANCELLED.
778 */
779 nc = malloc(sizeof(struct ndisusb_cancel), M_USBDEV, M_NOWAIT | M_ZERO);
780 if (nc == NULL) {
781 ip->irp_cancel = FALSE;
782 IoReleaseCancelSpinLock(ip->irp_cancelirql);
783 return;
784 }
785
786 nc->dev = dev;
787 nc->xfer = IRP_NDISUSB_XFER(ip);
788 usb_init_task(&nc->task, usbd_irpcancel_cb, nc);
789
790 IRP_NDISUSB_XFER(ip) = NULL;
791 usb_add_task(uaa->device, &nc->task, USB_TASKQ_DRIVER);
792
793 ip->irp_cancel = TRUE;
794 IoReleaseCancelSpinLock(ip->irp_cancelirql);
795 }
796
797 static usbd_xfer_handle
798 usbd_init_ndisxfer(ip, ep, buf, buflen)
799 irp *ip;
800 usb_endpoint_descriptor_t *ep;
801 void *buf;
802 uint32_t buflen;
803 {
804 device_t dev = IRP_NDIS_DEV(ip);
805 struct usb_attach_arg *uaa = device_get_ivars(dev);
806 usbd_xfer_handle xfer;
807
808 xfer = usbd_alloc_xfer(uaa->device);
809 if (xfer == NULL)
810 return (NULL);
811
812 if (buf != NULL && MmIsAddressValid(buf) == FALSE && buflen > 0) {
813 xfer->buffer = usbd_alloc_buffer(xfer, buflen);
814 if (xfer->buffer == NULL)
815 return (NULL);
816
817 if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_OUT)
818 memcpy(xfer->buffer, buf, buflen);
819 } else
820 xfer->buffer = buf;
821
822 xfer->length = buflen;
823
824 IoAcquireCancelSpinLock(&ip->irp_cancelirql);
825 IRP_NDISUSB_XFER(ip) = xfer;
826 ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap;
827 IoReleaseCancelSpinLock(ip->irp_cancelirql);
828
829 return (xfer);
830 }
831
832 static void
833 usbd_xferadd(xfer, priv, status)
834 usbd_xfer_handle xfer;
835 usbd_private_handle priv;
836 usbd_status status;
837 {
838 irp *ip = priv;
839 device_t dev = IRP_NDIS_DEV(ip);
840 struct ndis_softc *sc = device_get_softc(dev);
841 struct ndisusb_xfer *nx;
842 uint8_t irql;
843
844 nx = malloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO);
845 if (nx == NULL) {
846 device_printf(dev, "out of memory");
847 return;
848 }
849 nx->nx_xfer = xfer;
850 nx->nx_priv = priv;
851 nx->nx_status = status;
852
853 KeAcquireSpinLock(&sc->ndisusb_xferlock, &irql);
854 InsertTailList((&sc->ndisusb_xferlist), (&nx->nx_xferlist));
855 KeReleaseSpinLock(&sc->ndisusb_xferlock, irql);
856
857 IoQueueWorkItem(sc->ndisusb_xferitem,
858 (io_workitem_func)usbd_xfertask_wrap, WORKQUEUE_CRITICAL, sc);
859 }
860
861 static void
862 usbd_xfereof(xfer, priv, status)
863 usbd_xfer_handle xfer;
864 usbd_private_handle priv;
865 usbd_status status;
866 {
867
868 usbd_xferadd(xfer, priv, status);
869 }
870
871 static void
872 usbd_xfertask(dobj, arg)
873 device_object *dobj;
874 void *arg;
875 {
876 int error;
877 irp *ip;
878 device_t dev;
879 list_entry *l;
880 struct ndis_softc *sc = arg;
881 struct ndisusb_xfer *nx;
882 struct usbd_urb_bulk_or_intr_transfer *ubi;
883 uint8_t irql;
884 union usbd_urb *urb;
885 usbd_private_handle priv;
886 usbd_status status;
887 usbd_xfer_handle xfer;
888
889 dev = sc->ndis_dev;
890
891 if (IsListEmpty(&sc->ndisusb_xferlist))
892 return;
893
894 KeAcquireSpinLock(&sc->ndisusb_xferlock, &irql);
895 l = sc->ndisusb_xferlist.nle_flink;
896 while (l != &sc->ndisusb_xferlist) {
897 nx = CONTAINING_RECORD(l, struct ndisusb_xfer, nx_xferlist);
898 xfer = nx->nx_xfer;
899 priv = nx->nx_priv;
|