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