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