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