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