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