1 /* $NetBSD: ugenhc.c,v 1.22 2014/08/02 12:38:01 skrll Exp $ */ 2 3 /* 4 * Copyright (c) 2009, 2010 Antti Kantee. All Rights Reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 /* 29 * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. 30 * All rights reserved. 31 * 32 * This code is derived from software contributed to The NetBSD Foundation 33 * by Lennart Augustsson (lennart@augustsson.net) at 34 * Carlstedt Research & Technology. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 46 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 47 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 48 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 49 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 50 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 51 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 52 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 53 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 55 * POSSIBILITY OF SUCH DAMAGE. 56 */ 57 58 /* 59 * This rump driver attaches ugen as a kernel usb host controller. 60 * It's still somewhat under the hammer .... 61 */ 62 63 #include <sys/cdefs.h> 64 __KERNEL_RCSID(0, "$NetBSD: ugenhc.c,v 1.22 2014/08/02 12:38:01 skrll Exp $"); 65 66 #include <sys/param.h> 67 #include <sys/bus.h> 68 #include <sys/conf.h> 69 #include <sys/device.h> 70 #include <sys/fcntl.h> 71 #include <sys/kmem.h> 72 #include <sys/kernel.h> 73 #include <sys/kthread.h> 74 #include <sys/mutex.h> 75 76 #include <dev/usb/usb.h> 77 #include <dev/usb/usbdi.h> 78 #include <dev/usb/usbhid.h> 79 #include <dev/usb/usbdivar.h> 80 #include <dev/usb/usb_mem.h> 81 #include <dev/usb/usbroothub_subr.h> 82 83 #include <rump/rumpuser.h> 84 85 #include "ugenhc_user.h" 86 87 #include "rump_private.h" 88 #include "rump_dev_private.h" 89 90 #define UGEN_NEPTS 16 91 #define UGEN_EPT_CTRL 0 /* ugenx.00 is the control endpoint */ 92 93 struct ugenhc_softc { 94 struct usbd_bus sc_bus; 95 int sc_devnum; 96 97 int sc_ugenfd[UGEN_NEPTS]; 98 int sc_fdmodes[UGEN_NEPTS]; 99 100 int sc_port_status; 101 int sc_port_change; 102 int sc_addr; 103 int sc_conf; 104 105 struct lwp *sc_rhintr; 106 usbd_xfer_handle sc_intrxfer; 107 108 kmutex_t sc_lock; 109 }; 110 111 static int ugenhc_probe(device_t, cfdata_t, void *); 112 static void ugenhc_attach(device_t, device_t, void *); 113 114 CFATTACH_DECL_NEW(ugenhc, sizeof(struct ugenhc_softc), 115 ugenhc_probe, ugenhc_attach, NULL, NULL); 116 117 struct rusb_xfer { 118 struct usbd_xfer rusb_xfer; 119 int rusb_status; /* now this is a cheap trick */ 120 }; 121 #define RUSB(x) ((struct rusb_xfer *)x) 122 123 #define UGENDEV_BASESTR "/dev/ugen" 124 #define UGENDEV_BUFSIZE 32 125 static void 126 makeugendevstr(int devnum, int endpoint, char *buf, size_t len) 127 { 128 129 CTASSERT(UGENDEV_BUFSIZE > sizeof(UGENDEV_BASESTR)+sizeof("0.00")+1); 130 snprintf(buf, len, "%s%d.%02d", UGENDEV_BASESTR, devnum, endpoint); 131 } 132 133 /* 134 * Our fictional hubbie. 135 */ 136 137 static const usb_device_descriptor_t rumphub_udd = { 138 .bLength = USB_DEVICE_DESCRIPTOR_SIZE, 139 .bDescriptorType = UDESC_DEVICE, 140 .bDeviceClass = UDCLASS_HUB, 141 .bDeviceSubClass = UDSUBCLASS_HUB, 142 .bDeviceProtocol = UDPROTO_FSHUB, 143 .bMaxPacketSize = 64, 144 .idVendor = { 0x75, 0x72 }, 145 .idProduct = { 0x70, 0x6d }, 146 .bNumConfigurations = 1, 147 }; 148 149 static const usb_config_descriptor_t rumphub_ucd = { 150 .bLength = USB_CONFIG_DESCRIPTOR_SIZE, 151 .bDescriptorType = UDESC_CONFIG, 152 .wTotalLength = { USB_CONFIG_DESCRIPTOR_SIZE 153 + USB_INTERFACE_DESCRIPTOR_SIZE 154 + USB_ENDPOINT_DESCRIPTOR_SIZE }, 155 .bNumInterface = 1, 156 .bmAttributes = UC_SELF_POWERED | UC_ATTR_MBO, 157 }; 158 159 static const usb_interface_descriptor_t rumphub_uid = { 160 .bLength = USB_INTERFACE_DESCRIPTOR_SIZE, 161 .bDescriptorType = UDESC_INTERFACE, 162 .bInterfaceNumber = 0, 163 .bNumEndpoints = 1, 164 .bInterfaceClass = UICLASS_HUB, 165 .bInterfaceSubClass = UISUBCLASS_HUB, 166 .bInterfaceProtocol = UIPROTO_FSHUB, 167 }; 168 169 static const usb_endpoint_descriptor_t rumphub_epd = { 170 .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE, 171 .bDescriptorType = UDESC_ENDPOINT, 172 .bmAttributes = UE_INTERRUPT, 173 .wMaxPacketSize = {64, 0}, 174 }; 175 176 static const usb_hub_descriptor_t rumphub_hdd = { 177 .bDescLength = USB_HUB_DESCRIPTOR_SIZE, 178 .bDescriptorType = UDESC_HUB, 179 .bNbrPorts = 1, 180 }; 181 182 static usbd_status 183 rumpusb_root_ctrl_start(usbd_xfer_handle xfer) 184 { 185 usb_device_request_t *req = &xfer->request; 186 struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private; 187 int len, totlen, value, curlen, err; 188 uint8_t *buf = NULL; 189 190 len = totlen = UGETW(req->wLength); 191 if (len) 192 buf = KERNADDR(&xfer->dmabuf, 0); 193 value = UGETW(req->wValue); 194 195 #define C(x,y) ((x) | ((y) << 8)) 196 switch(C(req->bRequest, req->bmRequestType)) { 197 198 case C(UR_GET_CONFIG, UT_READ_DEVICE): 199 if (len > 0) { 200 *buf = sc->sc_conf; 201 totlen = 1; 202 } 203 break; 204 205 case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): 206 switch (value >> 8) { 207 case UDESC_DEVICE: 208 totlen = min(len, USB_DEVICE_DESCRIPTOR_SIZE); 209 memcpy(buf, &rumphub_udd, totlen); 210 break; 211 212 case UDESC_CONFIG: 213 totlen = 0; 214 curlen = min(len, USB_CONFIG_DESCRIPTOR_SIZE); 215 memcpy(buf, &rumphub_ucd, curlen); 216 len -= curlen; 217 buf += curlen; 218 totlen += curlen; 219 220 curlen = min(len, USB_INTERFACE_DESCRIPTOR_SIZE); 221 memcpy(buf, &rumphub_uid, curlen); 222 len -= curlen; 223 buf += curlen; 224 totlen += curlen; 225 226 curlen = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE); 227 memcpy(buf, &rumphub_epd, curlen); 228 len -= curlen; 229 buf += curlen; 230 totlen += curlen; 231 break; 232 233 case UDESC_STRING: 234 #define sd ((usb_string_descriptor_t *)buf) 235 switch (value & 0xff) { 236 case 0: /* Language table */ 237 totlen = usb_makelangtbl(sd, len); 238 break; 239 case 1: /* Vendor */ 240 totlen = usb_makestrdesc(sd, len, "rod nevada"); 241 break; 242 case 2: /* Product */ 243 totlen = usb_makestrdesc(sd, len, 244 "RUMPUSBHC root hub"); 245 break; 246 } 247 #undef sd 248 break; 249 250 default: 251 panic("unhandled read device request"); 252 break; 253 } 254 break; 255 256 case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): 257 if (value >= USB_MAX_DEVICES) { 258 err = USBD_IOERROR; 259 goto ret; 260 } 261 sc->sc_addr = value; 262 break; 263 264 case C(UR_SET_CONFIG, UT_WRITE_DEVICE): 265 if (value != 0 && value != 1) { 266 err = USBD_IOERROR; 267 goto ret; 268 } 269 sc->sc_conf = value; 270 break; 271 272 case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): 273 switch (value) { 274 case UHF_PORT_RESET: 275 sc->sc_port_change |= UPS_C_PORT_RESET; 276 break; 277 case UHF_PORT_POWER: 278 break; 279 default: 280 panic("unhandled"); 281 } 282 break; 283 284 case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): 285 sc->sc_port_change &= ~value; 286 break; 287 288 case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): 289 totlen = min(len, USB_HUB_DESCRIPTOR_SIZE); 290 memcpy(buf, &rumphub_hdd, totlen); 291 break; 292 293 case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): 294 /* huh? other hc's do this */ 295 memset(buf, 0, len); 296 totlen = len; 297 break; 298 299 case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): 300 { 301 usb_port_status_t ps; 302 303 USETW(ps.wPortStatus, sc->sc_port_status); 304 USETW(ps.wPortChange, sc->sc_port_change); 305 totlen = min(len, sizeof(ps)); 306 memcpy(buf, &ps, totlen); 307 break; 308 } 309 310 default: 311 panic("unhandled request"); 312 break; 313 } 314 err = USBD_NORMAL_COMPLETION; 315 xfer->actlen = totlen; 316 317 ret: 318 xfer->status = err; 319 mutex_enter(&sc->sc_lock); 320 usb_transfer_complete(xfer); 321 mutex_exit(&sc->sc_lock); 322 323 return (USBD_IN_PROGRESS); 324 } 325 326 static usbd_status 327 rumpusb_root_ctrl_transfer(usbd_xfer_handle xfer) 328 { 329 struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private; 330 usbd_status err; 331 332 mutex_enter(&sc->sc_lock); 333 err = usb_insert_transfer(xfer); 334 mutex_exit(&sc->sc_lock); 335 if (err) 336 return (err); 337 338 return (rumpusb_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); 339 } 340 341 static void 342 rumpusb_root_ctrl_abort(usbd_xfer_handle xfer) 343 { 344 345 } 346 347 static void 348 rumpusb_root_ctrl_close(usbd_pipe_handle pipe) 349 { 350 351 } 352 353 static void 354 rumpusb_root_ctrl_cleartoggle(usbd_pipe_handle pipe) 355 { 356 357 } 358 359 static void 360 rumpusb_root_ctrl_done(usbd_xfer_handle xfer) 361 { 362 363 } 364 365 static const struct usbd_pipe_methods rumpusb_root_ctrl_methods = { 366 .transfer = rumpusb_root_ctrl_transfer, 367 .start = rumpusb_root_ctrl_start, 368 .abort = rumpusb_root_ctrl_abort, 369 .close = rumpusb_root_ctrl_close, 370 .cleartoggle = rumpusb_root_ctrl_cleartoggle, 371 .done = rumpusb_root_ctrl_done, 372 }; 373 374 static usbd_status 375 rumpusb_device_ctrl_start(usbd_xfer_handle xfer) 376 { 377 usb_device_request_t *req = &xfer->request; 378 struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private; 379 uint8_t *buf = NULL; 380 int len, totlen; 381 int value; 382 int err = 0; 383 int ru_error, mightfail = 0; 384 385 len = totlen = UGETW(req->wLength); 386 if (len) 387 buf = KERNADDR(&xfer->dmabuf, 0); 388 value = UGETW(req->wValue); 389 390 #define C(x,y) ((x) | ((y) << 8)) 391 switch(C(req->bRequest, req->bmRequestType)) { 392 case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): 393 switch (value>>8) { 394 case UDESC_DEVICE: 395 { 396 usb_device_descriptor_t uddesc; 397 totlen = min(len, USB_DEVICE_DESCRIPTOR_SIZE); 398 memset(buf, 0, totlen); 399 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 400 USB_GET_DEVICE_DESC, &uddesc, &ru_error) == -1) { 401 err = EIO; 402 goto ret; 403 } 404 memcpy(buf, &uddesc, totlen); 405 } 406 407 break; 408 case UDESC_CONFIG: 409 { 410 struct usb_full_desc ufdesc; 411 ufdesc.ufd_config_index = value & 0xff; 412 ufdesc.ufd_size = len; 413 ufdesc.ufd_data = buf; 414 memset(buf, 0, len); 415 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 416 USB_GET_FULL_DESC, &ufdesc, &ru_error) == -1) { 417 err = USBD_IOERROR; 418 goto ret; 419 } 420 totlen = ufdesc.ufd_size; 421 } 422 break; 423 424 case UDESC_STRING: 425 { 426 struct usb_device_info udi; 427 428 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 429 USB_GET_DEVICEINFO, &udi, &ru_error) == -1) { 430 printf("ugenhc: get dev info failed: %d\n", 431 ru_error); 432 err = USBD_IOERROR; 433 goto ret; 434 } 435 436 switch (value & 0xff) { 437 #define sd ((usb_string_descriptor_t *)buf) 438 case 0: /* language table */ 439 break; 440 case 1: /* vendor */ 441 totlen = usb_makestrdesc(sd, len, 442 udi.udi_vendor); 443 break; 444 case 2: /* product */ 445 totlen = usb_makestrdesc(sd, len, 446 udi.udi_product); 447 break; 448 } 449 #undef sd 450 } 451 break; 452 453 default: 454 panic("not handled"); 455 } 456 break; 457 458 case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): 459 /* ignored, ugen won't let us */ 460 break; 461 462 case C(UR_SET_CONFIG, UT_WRITE_DEVICE): 463 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 464 USB_SET_CONFIG, &value, &ru_error) == -1) { 465 printf("ugenhc: set config failed: %d\n", 466 ru_error); 467 err = USBD_IOERROR; 468 goto ret; 469 } 470 break; 471 472 case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): 473 { 474 struct usb_alt_interface uai; 475 476 totlen = 0; 477 uai.uai_interface_index = UGETW(req->wIndex); 478 uai.uai_alt_no = value; 479 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 480 USB_SET_ALTINTERFACE, &uai, &ru_error) == -1) { 481 printf("ugenhc: set alt interface failed: %d\n", 482 ru_error); 483 err = USBD_IOERROR; 484 goto ret; 485 } 486 break; 487 } 488 489 /* 490 * This request might fail unknown reasons. "EIO" doesn't 491 * give much help, and debugging the host ugen would be 492 * necessary. However, since it doesn't seem to really 493 * affect anything, just let it fail for now. 494 */ 495 case C(0x00, UT_WRITE_CLASS_INTERFACE): 496 mightfail = 1; 497 /*FALLTHROUGH*/ 498 499 /* 500 * XXX: don't wildcard these yet. I want to better figure 501 * out what to trap here. This is kinda silly, though ... 502 */ 503 504 case C(0x01, UT_WRITE_VENDOR_DEVICE): 505 case C(0x06, UT_WRITE_VENDOR_DEVICE): 506 case C(0x07, UT_READ_VENDOR_DEVICE): 507 case C(0x09, UT_READ_VENDOR_DEVICE): 508 case C(0xfe, UT_READ_CLASS_INTERFACE): 509 case C(0x01, UT_READ_CLASS_INTERFACE): 510 case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): 511 case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): 512 case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): 513 case C(UR_GET_DESCRIPTOR, UT_READ_INTERFACE): 514 case C(0xff, UT_WRITE_CLASS_INTERFACE): 515 case C(0x20, UT_WRITE_CLASS_INTERFACE): 516 case C(0x22, UT_WRITE_CLASS_INTERFACE): 517 case C(0x0a, UT_WRITE_CLASS_INTERFACE): 518 case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): 519 case C(0x00, UT_WRITE_CLASS_DEVICE): 520 case C(UR_SET_FEATURE, UT_WRITE_DEVICE): 521 case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): 522 case C(UR_SET_REPORT, UT_WRITE_CLASS_INTERFACE): 523 case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): 524 { 525 struct usb_ctl_request ucr; 526 527 memcpy(&ucr.ucr_request, req, sizeof(ucr.ucr_request)); 528 ucr.ucr_data = buf; 529 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 530 USB_DO_REQUEST, &ucr, &ru_error) == -1) { 531 if (!mightfail) { 532 panic("request failed: %d", ru_error); 533 } else { 534 err = ru_error; 535 } 536 } 537 } 538 break; 539 540 default: 541 panic("unhandled request"); 542 break; 543 } 544 xfer->actlen = totlen; 545 err = USBD_NORMAL_COMPLETION; 546 547 ret: 548 xfer->status = err; 549 mutex_enter(&sc->sc_lock); 550 usb_transfer_complete(xfer); 551 mutex_exit(&sc->sc_lock); 552 553 return (USBD_IN_PROGRESS); 554 } 555 556 static usbd_status 557 rumpusb_device_ctrl_transfer(usbd_xfer_handle xfer) 558 { 559 struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private; 560 usbd_status err; 561 562 mutex_enter(&sc->sc_lock); 563 err = usb_insert_transfer(xfer); 564 mutex_exit(&sc->sc_lock); 565 if (err) 566 return (err); 567 568 return (rumpusb_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); 569 } 570 571 static void 572 rumpusb_device_ctrl_abort(usbd_xfer_handle xfer) 573 { 574 575 } 576 577 static void 578 rumpusb_device_ctrl_close(usbd_pipe_handle pipe) 579 { 580 581 } 582 583 static void 584 rumpusb_device_ctrl_cleartoggle(usbd_pipe_handle pipe) 585 { 586 587 } 588 589 static void 590 rumpusb_device_ctrl_done(usbd_xfer_handle xfer) 591 { 592 593 } 594 595 static const struct usbd_pipe_methods rumpusb_device_ctrl_methods = { 596 .transfer = rumpusb_device_ctrl_transfer, 597 .start = rumpusb_device_ctrl_start, 598 .abort = rumpusb_device_ctrl_abort, 599 .close = rumpusb_device_ctrl_close, 600 .cleartoggle = rumpusb_device_ctrl_cleartoggle, 601 .done = rumpusb_device_ctrl_done, 602 }; 603 604 static void 605 rhscintr(void *arg) 606 { 607 char buf[UGENDEV_BUFSIZE]; 608 struct ugenhc_softc *sc = arg; 609 usbd_xfer_handle xfer; 610 int fd, error; 611 612 makeugendevstr(sc->sc_devnum, 0, buf, sizeof(buf)); 613 614 for (;;) { 615 /* 616 * Detect device attach. 617 */ 618 619 for (;;) { 620 error = rumpuser_open(buf, RUMPUSER_OPEN_RDWR, &fd); 621 if (error == 0) 622 break; 623 kpause("ugwait", false, hz/4, NULL); 624 } 625 626 sc->sc_ugenfd[UGEN_EPT_CTRL] = fd; 627 sc->sc_port_status = UPS_CURRENT_CONNECT_STATUS 628 | UPS_PORT_ENABLED | UPS_PORT_POWER; 629 sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET; 630 631 xfer = sc->sc_intrxfer; 632 memset(xfer->buffer, 0xff, xfer->length); 633 xfer->actlen = xfer->length; 634 xfer->status = USBD_NORMAL_COMPLETION; 635 636 mutex_enter(&sc->sc_lock); 637 usb_transfer_complete(xfer); 638 mutex_exit(&sc->sc_lock); 639 640 kpause("ugwait2", false, hz, NULL); 641 642 /* 643 * Detect device detach. 644 */ 645 646 for (;;) { 647 fd = rumpuser_open(buf, RUMPUSER_OPEN_RDWR, &error); 648 if (fd == -1) 649 break; 650 651 error = rumpuser_close(fd); 652 kpause("ugwait2", false, hz/4, NULL); 653 } 654 655 sc->sc_port_status = ~(UPS_CURRENT_CONNECT_STATUS 656 | UPS_PORT_ENABLED | UPS_PORT_POWER); 657 sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET; 658 659 error = rumpuser_close(sc->sc_ugenfd[UGEN_EPT_CTRL]); 660 sc->sc_ugenfd[UGEN_EPT_CTRL] = -1; 661 662 xfer = sc->sc_intrxfer; 663 memset(xfer->buffer, 0xff, xfer->length); 664 xfer->actlen = xfer->length; 665 xfer->status = USBD_NORMAL_COMPLETION; 666 mutex_enter(&sc->sc_lock); 667 usb_transfer_complete(xfer); 668 mutex_exit(&sc->sc_lock); 669 670 kpause("ugwait3", false, hz, NULL); 671 } 672 673 kthread_exit(0); 674 } 675 676 static usbd_status 677 rumpusb_root_intr_start(usbd_xfer_handle xfer) 678 { 679 struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private; 680 int error; 681 682 mutex_enter(&sc->sc_lock); 683 sc->sc_intrxfer = xfer; 684 if (!sc->sc_rhintr) { 685 error = kthread_create(PRI_NONE, 0, NULL, 686 rhscintr, sc, &sc->sc_rhintr, "ugenrhi"); 687 if (error) 688 xfer->status = USBD_IOERROR; 689 } 690 mutex_exit(&sc->sc_lock); 691 692 return (USBD_IN_PROGRESS); 693 } 694 695 static usbd_status 696 rumpusb_root_intr_transfer(usbd_xfer_handle xfer) 697 { 698 struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private; 699 usbd_status err; 700 701 mutex_enter(&sc->sc_lock); 702 err = usb_insert_transfer(xfer); 703 mutex_exit(&sc->sc_lock); 704 if (err) 705 return (err); 706 707 return (rumpusb_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); 708 } 709 710 static void 711 rumpusb_root_intr_abort(usbd_xfer_handle xfer) 712 { 713 714 } 715 716 static void 717 rumpusb_root_intr_close(usbd_pipe_handle pipe) 718 { 719 720 } 721 722 static void 723 rumpusb_root_intr_cleartoggle(usbd_pipe_handle pipe) 724 { 725 726 } 727 728 static void 729 rumpusb_root_intr_done(usbd_xfer_handle xfer) 730 { 731 732 } 733 734 static const struct usbd_pipe_methods rumpusb_root_intr_methods = { 735 .transfer = rumpusb_root_intr_transfer, 736 .start = rumpusb_root_intr_start, 737 .abort = rumpusb_root_intr_abort, 738 .close = rumpusb_root_intr_close, 739 .cleartoggle = rumpusb_root_intr_cleartoggle, 740 .done = rumpusb_root_intr_done, 741 }; 742 743 static usbd_status 744 rumpusb_device_bulk_start(usbd_xfer_handle xfer) 745 { 746 struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private; 747 usb_endpoint_descriptor_t *ed = xfer->pipe->endpoint->edesc; 748 size_t n, done; 749 bool isread; 750 int len, error, endpt; 751 uint8_t *buf; 752 int xfererr = USBD_NORMAL_COMPLETION; 753 int shortval, i; 754 755 ed = xfer->pipe->endpoint->edesc; 756 endpt = ed->bEndpointAddress; 757 isread = UE_GET_DIR(endpt) == UE_DIR_IN; 758 endpt = UE_GET_ADDR(endpt); 759 KASSERT(endpt < UGEN_NEPTS); 760 761 buf = KERNADDR(&xfer->dmabuf, 0); 762 done = 0; 763 if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) { 764 for (i = 0, len = 0; i < xfer->nframes; i++) 765 len += xfer->frlengths[i]; 766 } else { 767 KASSERT(xfer->length); 768 len = xfer->length; 769 } 770 shortval = (xfer->flags & USBD_SHORT_XFER_OK) != 0; 771 772 while (RUSB(xfer)->rusb_status == 0) { 773 if (isread) { 774 struct rumpuser_iovec iov; 775 776 rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[endpt], 777 USB_SET_SHORT_XFER, &shortval, &error); 778 iov.iov_base = buf+done; 779 iov.iov_len = len-done; 780 error = rumpuser_iovread(sc->sc_ugenfd[endpt], &iov, 1, 781 RUMPUSER_IOV_NOSEEK, &n); 782 if (error) { 783 n = 0; 784 if (done == 0) { 785 if (error == ETIMEDOUT) 786 continue; 787 xfererr = USBD_IOERROR; 788 goto out; 789 } 790 } 791 done += n; 792 if (done == len) 793 break; 794 } else { 795 struct rumpuser_iovec iov; 796 797 iov.iov_base = buf; 798 iov.iov_len = len; 799 error = rumpuser_iovwrite(sc->sc_ugenfd[endpt], &iov, 1, 800 RUMPUSER_IOV_NOSEEK, &n); 801 done = n; 802 if (done == len) 803 break; 804 else if (!error) 805 panic("short write"); 806 807 xfererr = USBD_IOERROR; 808 goto out; 809 } 810 811 if (shortval) { 812 /* 813 * Holy XXX, bitman. I get >16byte interrupt 814 * transfers from ugen in 16 byte chunks. 815 * Don't know how to better fix this for now. 816 * Of course this hack will fail e.g. if someone 817 * sports other magic values or if the transfer 818 * happens to be an integral multiple of 16 819 * in size .... 820 */ 821 if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT 822 && n == 16) { 823 continue; 824 } else { 825 break; 826 } 827 } 828 } 829 830 if (RUSB(xfer)->rusb_status == 0) { 831 xfer->actlen = done; 832 } else { 833 xfererr = USBD_CANCELLED; 834 RUSB(xfer)->rusb_status = 2; 835 } 836 out: 837 if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) 838 if (done != len) 839 panic("lazy bum"); 840 xfer->status = xfererr; 841 mutex_enter(&sc->sc_lock); 842 usb_transfer_complete(xfer); 843 mutex_exit(&sc->sc_lock); 844 return (USBD_IN_PROGRESS); 845 } 846 847 static void 848 doxfer_kth(void *arg) 849 { 850 usbd_pipe_handle pipe = arg; 851 struct ugenhc_softc *sc = pipe->device->bus->hci_private; 852 853 mutex_enter(&sc->sc_lock); 854 do { 855 usbd_xfer_handle xfer = SIMPLEQ_FIRST(&pipe->queue); 856 mutex_exit(&sc->sc_lock); 857 rumpusb_device_bulk_start(xfer); 858 mutex_enter(&sc->sc_lock); 859 } while (!SIMPLEQ_EMPTY(&pipe->queue)); 860 mutex_exit(&sc->sc_lock); 861 kthread_exit(0); 862 } 863 864 static usbd_status 865 rumpusb_device_bulk_transfer(usbd_xfer_handle xfer) 866 { 867 struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private; 868 usbd_status err; 869 870 if (!rump_threads) { 871 /* XXX: lie about supporting async transfers */ 872 if ((xfer->flags & USBD_SYNCHRONOUS) == 0) { 873 printf("non-threaded rump does not support " 874 "async transfers.\n"); 875 return USBD_IN_PROGRESS; 876 } 877 878 mutex_enter(&sc->sc_lock); 879 err = usb_insert_transfer(xfer); 880 mutex_exit(&sc->sc_lock); 881 if (err) 882 return err; 883 884 return rumpusb_device_bulk_start( 885 SIMPLEQ_FIRST(&xfer->pipe->queue)); 886 } else { 887 mutex_enter(&sc->sc_lock); 888 err = usb_insert_transfer(xfer); 889 mutex_exit(&sc->sc_lock); 890 if (err) 891 return err; 892 kthread_create(PRI_NONE, 0, NULL, doxfer_kth, xfer->pipe, NULL, 893 "rusbhcxf"); 894 895 return USBD_IN_PROGRESS; 896 } 897 } 898 899 /* wait for transfer to abort. yea, this is cheesy (from a spray can) */ 900 static void 901 rumpusb_device_bulk_abort(usbd_xfer_handle xfer) 902 { 903 struct rusb_xfer *rx = RUSB(xfer); 904 905 rx->rusb_status = 1; 906 while (rx->rusb_status < 2) { 907 kpause("jopo", false, hz/10, NULL); 908 } 909 } 910 911 static void 912 rumpusb_device_bulk_close(usbd_pipe_handle pipe) 913 { 914 struct ugenhc_softc *sc = pipe->device->bus->hci_private; 915 int endpt = pipe->endpoint->edesc->bEndpointAddress; 916 usbd_xfer_handle xfer; 917 918 KASSERT(mutex_owned(&sc->sc_lock)); 919 920 endpt = UE_GET_ADDR(endpt); 921 922 while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL) 923 rumpusb_device_bulk_abort(xfer); 924 925 rumpuser_close(sc->sc_ugenfd[endpt]); 926 sc->sc_ugenfd[endpt] = -1; 927 sc->sc_fdmodes[endpt] = -1; 928 } 929 930 static void 931 rumpusb_device_bulk_cleartoggle(usbd_pipe_handle pipe) 932 { 933 934 } 935 936 static void 937 rumpusb_device_bulk_done(usbd_xfer_handle xfer) 938 { 939 940 } 941 942 static const struct usbd_pipe_methods rumpusb_device_bulk_methods = { 943 .transfer = rumpusb_device_bulk_transfer, 944 .start = rumpusb_device_bulk_start, 945 .abort = rumpusb_device_bulk_abort, 946 .close = rumpusb_device_bulk_close, 947 .cleartoggle = rumpusb_device_bulk_cleartoggle, 948 .done = rumpusb_device_bulk_done, 949 }; 950 951 static usbd_status 952 ugenhc_open(struct usbd_pipe *pipe) 953 { 954 usbd_device_handle dev = pipe->device; 955 struct ugenhc_softc *sc = dev->bus->hci_private; 956 usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc; 957 u_int8_t addr = dev->address; 958 u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE; 959 char buf[UGENDEV_BUFSIZE]; 960 int endpt, oflags, error; 961 int fd, val; 962 963 if (addr == sc->sc_addr) { 964 switch (xfertype) { 965 case UE_CONTROL: 966 pipe->methods = &rumpusb_root_ctrl_methods; 967 break; 968 case UE_INTERRUPT: 969 pipe->methods = &rumpusb_root_intr_methods; 970 break; 971 default: 972 panic("%d not supported", xfertype); 973 break; 974 } 975 } else { 976 switch (xfertype) { 977 case UE_CONTROL: 978 pipe->methods = &rumpusb_device_ctrl_methods; 979 break; 980 case UE_INTERRUPT: 981 case UE_BULK: 982 case UE_ISOCHRONOUS: 983 pipe->methods = &rumpusb_device_bulk_methods; 984 endpt = pipe->endpoint->edesc->bEndpointAddress; 985 if (UE_GET_DIR(endpt) == UE_DIR_IN) { 986 oflags = O_RDONLY; 987 } else { 988 oflags = O_WRONLY; 989 } 990 endpt = UE_GET_ADDR(endpt); 991 992 if (oflags != O_RDONLY && xfertype == UE_ISOCHRONOUS) { 993 printf("WARNING: faking isoc write open\n"); 994 oflags = O_RDONLY; 995 } 996 997 if (sc->sc_fdmodes[endpt] == oflags 998 || sc->sc_fdmodes[endpt] == O_RDWR) 999 break; 1000 1001 if (sc->sc_fdmodes[endpt] != -1) { 1002 /* XXX: closing from under someone? */ 1003 error = rumpuser_close(sc->sc_ugenfd[endpt]); 1004 oflags = O_RDWR; 1005 } 1006 1007 makeugendevstr(sc->sc_devnum, endpt, buf, sizeof(buf)); 1008 /* XXX: theoretically should convert oflags */ 1009 error = rumpuser_open(buf, oflags, &fd); 1010 if (error != 0) { 1011 return USBD_INVAL; /* XXX: no mapping */ 1012 } 1013 val = 100; 1014 if (rumpcomp_ugenhc_ioctl(fd, USB_SET_TIMEOUT, &val, 1015 &error) == -1) 1016 panic("timeout set failed"); 1017 sc->sc_ugenfd[endpt] = fd; 1018 sc->sc_fdmodes[endpt] = oflags; 1019 1020 break; 1021 default: 1022 panic("%d not supported", xfertype); 1023 break; 1024 1025 } 1026 } 1027 return 0; 1028 } 1029 1030 static void 1031 ugenhc_softint(void *arg) 1032 { 1033 1034 } 1035 1036 static void 1037 ugenhc_poll(struct usbd_bus *ubus) 1038 { 1039 1040 } 1041 1042 static usbd_status 1043 ugenhc_allocm(struct usbd_bus *bus, usb_dma_t *dma, uint32_t size) 1044 { 1045 struct ugenhc_softc *sc = bus->hci_private; 1046 1047 return usb_allocmem(&sc->sc_bus, size, 0, dma); 1048 } 1049 1050 static void 1051 ugenhc_freem(struct usbd_bus *bus, usb_dma_t *dma) 1052 { 1053 struct ugenhc_softc *sc = bus->hci_private; 1054 1055 usb_freemem(&sc->sc_bus, dma); 1056 } 1057 1058 static struct usbd_xfer * 1059 ugenhc_allocx(struct usbd_bus *bus) 1060 { 1061 usbd_xfer_handle xfer; 1062 1063 xfer = kmem_zalloc(sizeof(struct usbd_xfer), KM_SLEEP); 1064 xfer->busy_free = XFER_BUSY; 1065 1066 return xfer; 1067 } 1068 1069 static void 1070 ugenhc_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) 1071 { 1072 1073 kmem_free(xfer, sizeof(struct usbd_xfer)); 1074 } 1075 1076 1077 static void 1078 ugenhc_getlock(struct usbd_bus *bus, kmutex_t **lock) 1079 { 1080 struct ugenhc_softc *sc = bus->hci_private; 1081 1082 *lock = &sc->sc_lock; 1083 } 1084 1085 struct ugenhc_pipe { 1086 struct usbd_pipe pipe; 1087 }; 1088 1089 static const struct usbd_bus_methods ugenhc_bus_methods = { 1090 .open_pipe = ugenhc_open, 1091 .soft_intr = ugenhc_softint, 1092 .do_poll = ugenhc_poll, 1093 .allocm = ugenhc_allocm, 1094 .freem = ugenhc_freem, 1095 .allocx = ugenhc_allocx, 1096 .freex = ugenhc_freex, 1097 .get_lock = ugenhc_getlock 1098 }; 1099 1100 static int 1101 ugenhc_probe(device_t parent, cfdata_t match, void *aux) 1102 { 1103 char buf[UGENDEV_BUFSIZE]; 1104 1105 makeugendevstr(match->cf_unit, 0, buf, sizeof(buf)); 1106 if (rumpuser_getfileinfo(buf, NULL, NULL) != 0) 1107 return 0; 1108 1109 return 1; 1110 } 1111 1112 static void 1113 ugenhc_attach(device_t parent, device_t self, void *aux) 1114 { 1115 struct mainbus_attach_args *maa = aux; 1116 struct ugenhc_softc *sc = device_private(self); 1117 1118 aprint_normal("\n"); 1119 1120 memset(sc, 0, sizeof(*sc)); 1121 memset(&sc->sc_ugenfd, -1, sizeof(sc->sc_ugenfd)); 1122 memset(&sc->sc_fdmodes, -1, sizeof(sc->sc_fdmodes)); 1123 1124 sc->sc_bus.usbrev = USBREV_2_0; 1125 sc->sc_bus.methods = &ugenhc_bus_methods; 1126 sc->sc_bus.hci_private = sc; 1127 sc->sc_bus.pipe_size = sizeof(struct ugenhc_pipe); 1128 sc->sc_devnum = maa->maa_unit; 1129 1130 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 1131 1132 config_found(self, &sc->sc_bus, usbctlprint); 1133 } 1134