1 /* $NetBSD: ugenhc.c,v 1.10 2012/06/10 06:15:55 mrg 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.10 2012/06/10 06:15:55 mrg 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 /* XXX locking */ 316 usb_transfer_complete(xfer); 317 return (USBD_IN_PROGRESS); 318 } 319 320 static usbd_status 321 rumpusb_root_ctrl_transfer(usbd_xfer_handle xfer) 322 { 323 usbd_status err; 324 325 err = usb_insert_transfer(xfer); 326 if (err) 327 return (err); 328 329 return (rumpusb_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); 330 } 331 332 static void 333 rumpusb_root_ctrl_abort(usbd_xfer_handle xfer) 334 { 335 336 } 337 338 static void 339 rumpusb_root_ctrl_close(usbd_pipe_handle pipe) 340 { 341 342 } 343 344 static void 345 rumpusb_root_ctrl_cleartoggle(usbd_pipe_handle pipe) 346 { 347 348 } 349 350 static void 351 rumpusb_root_ctrl_done(usbd_xfer_handle xfer) 352 { 353 354 } 355 356 static const struct usbd_pipe_methods rumpusb_root_ctrl_methods = { 357 .transfer = rumpusb_root_ctrl_transfer, 358 .start = rumpusb_root_ctrl_start, 359 .abort = rumpusb_root_ctrl_abort, 360 .close = rumpusb_root_ctrl_close, 361 .cleartoggle = rumpusb_root_ctrl_cleartoggle, 362 .done = rumpusb_root_ctrl_done, 363 }; 364 365 static usbd_status 366 rumpusb_device_ctrl_start(usbd_xfer_handle xfer) 367 { 368 usb_device_request_t *req = &xfer->request; 369 struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private; 370 uint8_t *buf = NULL; 371 int len, totlen; 372 int value; 373 int err = 0; 374 int ru_error, mightfail = 0; 375 376 len = totlen = UGETW(req->wLength); 377 if (len) 378 buf = KERNADDR(&xfer->dmabuf, 0); 379 value = UGETW(req->wValue); 380 381 #define C(x,y) ((x) | ((y) << 8)) 382 switch(C(req->bRequest, req->bmRequestType)) { 383 case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): 384 switch (value>>8) { 385 case UDESC_DEVICE: 386 { 387 usb_device_descriptor_t uddesc; 388 totlen = min(len, USB_DEVICE_DESCRIPTOR_SIZE); 389 memset(buf, 0, totlen); 390 if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 391 USB_GET_DEVICE_DESC, &uddesc, &ru_error) == -1) { 392 err = EIO; 393 goto ret; 394 } 395 memcpy(buf, &uddesc, totlen); 396 } 397 398 break; 399 case UDESC_CONFIG: 400 { 401 struct usb_full_desc ufdesc; 402 ufdesc.ufd_config_index = value & 0xff; 403 ufdesc.ufd_size = len; 404 ufdesc.ufd_data = buf; 405 memset(buf, 0, len); 406 if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 407 USB_GET_FULL_DESC, &ufdesc, &ru_error) == -1) { 408 err = USBD_IOERROR; 409 goto ret; 410 } 411 totlen = ufdesc.ufd_size; 412 } 413 break; 414 415 case UDESC_STRING: 416 { 417 struct usb_device_info udi; 418 419 if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 420 USB_GET_DEVICEINFO, &udi, &ru_error) == -1) { 421 printf("ugenhc: get dev info failed: %d\n", 422 ru_error); 423 err = USBD_IOERROR; 424 goto ret; 425 } 426 427 switch (value & 0xff) { 428 #define sd ((usb_string_descriptor_t *)buf) 429 case 0: /* language table */ 430 break; 431 case 1: /* vendor */ 432 totlen = usb_makestrdesc(sd, len, 433 udi.udi_vendor); 434 break; 435 case 2: /* product */ 436 totlen = usb_makestrdesc(sd, len, 437 udi.udi_product); 438 break; 439 } 440 #undef sd 441 } 442 break; 443 444 default: 445 panic("not handled"); 446 } 447 break; 448 449 case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): 450 /* ignored, ugen won't let us */ 451 break; 452 453 case C(UR_SET_CONFIG, UT_WRITE_DEVICE): 454 if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 455 USB_SET_CONFIG, &value, &ru_error) == -1) { 456 printf("ugenhc: set config failed: %d\n", 457 ru_error); 458 err = USBD_IOERROR; 459 goto ret; 460 } 461 break; 462 463 case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): 464 { 465 struct usb_alt_interface uai; 466 467 totlen = 0; 468 uai.uai_interface_index = UGETW(req->wIndex); 469 uai.uai_alt_no = value; 470 if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 471 USB_SET_ALTINTERFACE, &uai, &ru_error) == -1) { 472 printf("ugenhc: set alt interface failed: %d\n", 473 ru_error); 474 err = USBD_IOERROR; 475 goto ret; 476 } 477 break; 478 } 479 480 /* 481 * This request might fail unknown reasons. "EIO" doesn't 482 * give much help, and debugging the host ugen would be 483 * necessary. However, since it doesn't seem to really 484 * affect anything, just let it fail for now. 485 */ 486 case C(0x00, UT_WRITE_CLASS_INTERFACE): 487 mightfail = 1; 488 /*FALLTHROUGH*/ 489 490 /* 491 * XXX: don't wildcard these yet. I want to better figure 492 * out what to trap here. This is kinda silly, though ... 493 */ 494 495 case C(0x01, UT_WRITE_VENDOR_DEVICE): 496 case C(0x06, UT_WRITE_VENDOR_DEVICE): 497 case C(0x07, UT_READ_VENDOR_DEVICE): 498 case C(0x09, UT_READ_VENDOR_DEVICE): 499 case C(0xfe, UT_READ_CLASS_INTERFACE): 500 case C(0x01, UT_READ_CLASS_INTERFACE): 501 case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): 502 case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): 503 case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): 504 case C(UR_GET_DESCRIPTOR, UT_READ_INTERFACE): 505 case C(0xff, UT_WRITE_CLASS_INTERFACE): 506 case C(0x20, UT_WRITE_CLASS_INTERFACE): 507 case C(0x22, UT_WRITE_CLASS_INTERFACE): 508 case C(0x0a, UT_WRITE_CLASS_INTERFACE): 509 case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): 510 case C(0x00, UT_WRITE_CLASS_DEVICE): 511 case C(UR_SET_FEATURE, UT_WRITE_DEVICE): 512 case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): 513 case C(UR_SET_REPORT, UT_WRITE_CLASS_INTERFACE): 514 case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): 515 { 516 struct usb_ctl_request ucr; 517 518 memcpy(&ucr.ucr_request, req, sizeof(ucr.ucr_request)); 519 ucr.ucr_data = buf; 520 if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 521 USB_DO_REQUEST, &ucr, &ru_error) == -1) { 522 if (!mightfail) { 523 panic("request failed: %d", ru_error); 524 } else { 525 err = ru_error; 526 } 527 } 528 } 529 break; 530 531 default: 532 panic("unhandled request"); 533 break; 534 } 535 xfer->actlen = totlen; 536 err = USBD_NORMAL_COMPLETION; 537 538 ret: 539 xfer->status = err; 540 usb_transfer_complete(xfer); 541 return (USBD_IN_PROGRESS); 542 } 543 544 static usbd_status 545 rumpusb_device_ctrl_transfer(usbd_xfer_handle xfer) 546 { 547 usbd_status err; 548 549 err = usb_insert_transfer(xfer); 550 if (err) 551 return (err); 552 553 return (rumpusb_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); 554 } 555 556 static void 557 rumpusb_device_ctrl_abort(usbd_xfer_handle xfer) 558 { 559 560 } 561 562 static void 563 rumpusb_device_ctrl_close(usbd_pipe_handle pipe) 564 { 565 566 } 567 568 static void 569 rumpusb_device_ctrl_cleartoggle(usbd_pipe_handle pipe) 570 { 571 572 } 573 574 static void 575 rumpusb_device_ctrl_done(usbd_xfer_handle xfer) 576 { 577 578 } 579 580 static const struct usbd_pipe_methods rumpusb_device_ctrl_methods = { 581 .transfer = rumpusb_device_ctrl_transfer, 582 .start = rumpusb_device_ctrl_start, 583 .abort = rumpusb_device_ctrl_abort, 584 .close = rumpusb_device_ctrl_close, 585 .cleartoggle = rumpusb_device_ctrl_cleartoggle, 586 .done = rumpusb_device_ctrl_done, 587 }; 588 589 static void 590 rhscintr(void *arg) 591 { 592 char buf[UGENDEV_BUFSIZE]; 593 struct ugenhc_softc *sc = arg; 594 usbd_xfer_handle xfer; 595 int fd, error; 596 597 makeugendevstr(sc->sc_devnum, 0, buf); 598 599 for (;;) { 600 /* 601 * Detect device attach. 602 */ 603 604 for (;;) { 605 fd = rumpuser_open(buf, O_RDWR, &error); 606 if (fd != -1) 607 break; 608 kpause("ugwait", false, hz/4, NULL); 609 } 610 611 sc->sc_ugenfd[UGEN_EPT_CTRL] = fd; 612 sc->sc_port_status = UPS_CURRENT_CONNECT_STATUS 613 | UPS_PORT_ENABLED | UPS_PORT_POWER; 614 sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET; 615 616 xfer = sc->sc_intrxfer; 617 memset(xfer->buffer, 0xff, xfer->length); 618 xfer->actlen = xfer->length; 619 xfer->status = USBD_NORMAL_COMPLETION; 620 621 usb_transfer_complete(xfer); 622 623 kpause("ugwait2", false, hz, NULL); 624 625 /* 626 * Detect device detach. 627 */ 628 629 for (;;) { 630 fd = rumpuser_open(buf, O_RDWR, &error); 631 if (fd == -1) 632 break; 633 634 rumpuser_close(fd, &error); 635 kpause("ugwait2", false, hz/4, NULL); 636 } 637 638 sc->sc_port_status = ~(UPS_CURRENT_CONNECT_STATUS 639 | UPS_PORT_ENABLED | UPS_PORT_POWER); 640 sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET; 641 642 rumpuser_close(sc->sc_ugenfd[UGEN_EPT_CTRL], &error); 643 sc->sc_ugenfd[UGEN_EPT_CTRL] = -1; 644 645 xfer = sc->sc_intrxfer; 646 memset(xfer->buffer, 0xff, xfer->length); 647 xfer->actlen = xfer->length; 648 xfer->status = USBD_NORMAL_COMPLETION; 649 usb_transfer_complete(xfer); 650 651 kpause("ugwait3", false, hz, NULL); 652 } 653 654 kthread_exit(0); 655 } 656 657 static usbd_status 658 rumpusb_root_intr_start(usbd_xfer_handle xfer) 659 { 660 struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private; 661 int error; 662 663 sc->sc_intrxfer = xfer; 664 if (!sc->sc_rhintr) { 665 error = kthread_create(PRI_NONE, 0, NULL, 666 rhscintr, sc, &sc->sc_rhintr, "ugenrhi"); 667 if (error) 668 xfer->status = error; 669 } 670 671 return (USBD_IN_PROGRESS); 672 } 673 674 static usbd_status 675 rumpusb_root_intr_transfer(usbd_xfer_handle xfer) 676 { 677 usbd_status err; 678 679 err = usb_insert_transfer(xfer); 680 if (err) 681 return (err); 682 683 return (rumpusb_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); 684 } 685 686 static void 687 rumpusb_root_intr_abort(usbd_xfer_handle xfer) 688 { 689 690 } 691 692 static void 693 rumpusb_root_intr_close(usbd_pipe_handle pipe) 694 { 695 696 } 697 698 static void 699 rumpusb_root_intr_cleartoggle(usbd_pipe_handle pipe) 700 { 701 702 } 703 704 static void 705 rumpusb_root_intr_done(usbd_xfer_handle xfer) 706 { 707 708 } 709 710 static const struct usbd_pipe_methods rumpusb_root_intr_methods = { 711 .transfer = rumpusb_root_intr_transfer, 712 .start = rumpusb_root_intr_start, 713 .abort = rumpusb_root_intr_abort, 714 .close = rumpusb_root_intr_close, 715 .cleartoggle = rumpusb_root_intr_cleartoggle, 716 .done = rumpusb_root_intr_done, 717 }; 718 719 static usbd_status 720 rumpusb_device_bulk_start(usbd_xfer_handle xfer) 721 { 722 struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private; 723 usb_endpoint_descriptor_t *ed = xfer->pipe->endpoint->edesc; 724 ssize_t n; 725 ssize_t done; 726 bool isread; 727 int len, error, endpt; 728 uint8_t *buf; 729 int xfererr = USBD_NORMAL_COMPLETION; 730 int shortval, i; 731 732 ed = xfer->pipe->endpoint->edesc; 733 endpt = ed->bEndpointAddress; 734 isread = UE_GET_DIR(endpt) == UE_DIR_IN; 735 endpt = UE_GET_ADDR(endpt); 736 KASSERT(endpt < UGEN_NEPTS); 737 738 buf = KERNADDR(&xfer->dmabuf, 0); 739 done = 0; 740 if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) { 741 for (i = 0, len = 0; i < xfer->nframes; i++) 742 len += xfer->frlengths[i]; 743 } else { 744 KASSERT(xfer->length); 745 len = xfer->length; 746 } 747 shortval = (xfer->flags & USBD_SHORT_XFER_OK) != 0; 748 749 while (RUSB(xfer)->rusb_status == 0) { 750 if (isread) { 751 rumpuser_ioctl(sc->sc_ugenfd[endpt], 752 USB_SET_SHORT_XFER, &shortval, &error); 753 n = rumpuser_read(sc->sc_ugenfd[endpt], 754 buf+done, len-done, &error); 755 if (n == -1) { 756 n = 0; 757 if (done == 0) { 758 if (error == ETIMEDOUT) 759 continue; 760 xfererr = USBD_IOERROR; 761 goto out; 762 } 763 } 764 done += n; 765 if (done == len) 766 break; 767 } else { 768 n = rumpuser_write(sc->sc_ugenfd[endpt], 769 buf, len, &error); 770 done = n; 771 if (done == len) 772 break; 773 else if (n != -1) 774 panic("short write"); 775 776 xfererr = USBD_IOERROR; 777 goto out; 778 } 779 780 if (shortval) { 781 /* 782 * Holy XXX, bitman. I get >16byte interrupt 783 * transfers from ugen in 16 byte chunks. 784 * Don't know how to better fix this for now. 785 * Of course this hack will fail e.g. if someone 786 * sports other magic values or if the transfer 787 * happens to be an integral multiple of 16 788 * in size .... 789 */ 790 if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT 791 && n == 16) { 792 continue; 793 } else { 794 break; 795 } 796 } 797 } 798 799 if (RUSB(xfer)->rusb_status == 0) { 800 xfer->actlen = done; 801 } else { 802 xfererr = USBD_CANCELLED; 803 RUSB(xfer)->rusb_status = 2; 804 } 805 out: 806 if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) 807 if (done != len) 808 panic("lazy bum"); 809 xfer->status = xfererr; 810 usb_transfer_complete(xfer); 811 return (USBD_IN_PROGRESS); 812 } 813 814 static void 815 doxfer_kth(void *arg) 816 { 817 usbd_xfer_handle xfer = arg; 818 819 do { 820 rumpusb_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue)); 821 } while (!SIMPLEQ_EMPTY(&xfer->pipe->queue)); 822 kthread_exit(0); 823 } 824 825 static usbd_status 826 rumpusb_device_bulk_transfer(usbd_xfer_handle xfer) 827 { 828 usbd_status err; 829 830 if (!rump_threads) { 831 /* XXX: lie about supporting async transfers */ 832 if ((xfer->flags & USBD_SYNCHRONOUS) == 0) { 833 printf("non-threaded rump does not support " 834 "async transfers.\n"); 835 return USBD_IN_PROGRESS; 836 } 837 838 err = usb_insert_transfer(xfer); 839 if (err) 840 return err; 841 842 return rumpusb_device_bulk_start( 843 SIMPLEQ_FIRST(&xfer->pipe->queue)); 844 } else { 845 /* biglocked */ 846 /* XXX locking */ 847 err = usb_insert_transfer(xfer); 848 if (err) 849 return err; 850 kthread_create(PRI_NONE, 0, NULL, doxfer_kth, xfer, NULL, 851 "rusbhcxf"); 852 853 return USBD_IN_PROGRESS; 854 } 855 } 856 857 /* wait for transfer to abort. yea, this is cheesy (from a spray can) */ 858 static void 859 rumpusb_device_bulk_abort(usbd_xfer_handle xfer) 860 { 861 struct rusb_xfer *rx = RUSB(xfer); 862 863 rx->rusb_status = 1; 864 while (rx->rusb_status < 2) { 865 kpause("jopo", false, hz/10, NULL); 866 } 867 } 868 869 static void 870 rumpusb_device_bulk_close(usbd_pipe_handle pipe) 871 { 872 struct ugenhc_softc *sc = pipe->device->bus->hci_private; 873 int endpt = pipe->endpoint->edesc->bEndpointAddress; 874 usbd_xfer_handle xfer; 875 int error; 876 877 endpt = UE_GET_ADDR(endpt); 878 879 while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL) 880 rumpusb_device_bulk_abort(xfer); 881 882 rumpuser_close(sc->sc_ugenfd[endpt], &error); 883 sc->sc_ugenfd[endpt] = -1; 884 sc->sc_fdmodes[endpt] = -1; 885 } 886 887 static void 888 rumpusb_device_bulk_cleartoggle(usbd_pipe_handle pipe) 889 { 890 891 } 892 893 static void 894 rumpusb_device_bulk_done(usbd_xfer_handle xfer) 895 { 896 897 } 898 899 static const struct usbd_pipe_methods rumpusb_device_bulk_methods = { 900 .transfer = rumpusb_device_bulk_transfer, 901 .start = rumpusb_device_bulk_start, 902 .abort = rumpusb_device_bulk_abort, 903 .close = rumpusb_device_bulk_close, 904 .cleartoggle = rumpusb_device_bulk_cleartoggle, 905 .done = rumpusb_device_bulk_done, 906 }; 907 908 static const struct usbd_pipe_methods rumpusb_device_intr_methods = { 909 .transfer = rumpusb_root_intr_transfer, 910 .start = rumpusb_root_intr_start, 911 .abort = rumpusb_root_intr_abort, 912 .close = rumpusb_root_intr_close, 913 .cleartoggle = rumpusb_root_intr_cleartoggle, 914 .done = rumpusb_root_intr_done, 915 }; 916 917 static usbd_status 918 ugenhc_open(struct usbd_pipe *pipe) 919 { 920 usbd_device_handle dev = pipe->device; 921 struct ugenhc_softc *sc = dev->bus->hci_private; 922 usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc; 923 u_int8_t addr = dev->address; 924 u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE; 925 char buf[UGENDEV_BUFSIZE]; 926 int endpt, oflags, error; 927 int fd, val; 928 929 if (addr == sc->sc_addr) { 930 switch (xfertype) { 931 case UE_CONTROL: 932 pipe->methods = &rumpusb_root_ctrl_methods; 933 break; 934 case UE_INTERRUPT: 935 pipe->methods = &rumpusb_root_intr_methods; 936 break; 937 default: 938 panic("%d not supported", xfertype); 939 break; 940 } 941 } else { 942 switch (xfertype) { 943 case UE_CONTROL: 944 pipe->methods = &rumpusb_device_ctrl_methods; 945 break; 946 case UE_INTERRUPT: 947 case UE_BULK: 948 case UE_ISOCHRONOUS: 949 pipe->methods = &rumpusb_device_bulk_methods; 950 endpt = pipe->endpoint->edesc->bEndpointAddress; 951 if (UE_GET_DIR(endpt) == UE_DIR_IN) { 952 oflags = O_RDONLY; 953 } else { 954 oflags = O_WRONLY; 955 } 956 endpt = UE_GET_ADDR(endpt); 957 958 if (oflags != O_RDONLY && xfertype == UE_ISOCHRONOUS) { 959 printf("WARNING: faking isoc write open\n"); 960 oflags = O_RDONLY; 961 } 962 963 if (sc->sc_fdmodes[endpt] == oflags 964 || sc->sc_fdmodes[endpt] == O_RDWR) 965 break; 966 967 if (sc->sc_fdmodes[endpt] != -1) { 968 /* XXX: closing from under someone? */ 969 rumpuser_close(sc->sc_ugenfd[endpt], &error); 970 oflags = O_RDWR; 971 } 972 973 makeugendevstr(sc->sc_devnum, endpt, buf); 974 fd = rumpuser_open(buf, oflags, &error); 975 if (fd == -1) { 976 return USBD_INVAL; /* XXX: no mapping */ 977 } 978 val = 100; 979 if (rumpuser_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(struct device *parent, struct cfdata *match, void *aux) 1057 { 1058 char buf[UGENDEV_BUFSIZE]; 1059 int error; 1060 1061 makeugendevstr(match->cf_unit, 0, buf); 1062 if (rumpuser_getfileinfo(buf, NULL, NULL, &error) == -1) 1063 return 0; 1064 1065 return 1; 1066 } 1067 1068 static void 1069 ugenhc_attach(struct device *parent, struct device *self, void *aux) 1070 { 1071 struct mainbus_attach_args *maa = aux; 1072 struct ugenhc_softc *sc = device_private(self); 1073 1074 aprint_normal("\n"); 1075 1076 memset(sc, 0, sizeof(*sc)); 1077 memset(&sc->sc_ugenfd, -1, sizeof(sc->sc_ugenfd)); 1078 memset(&sc->sc_fdmodes, -1, sizeof(sc->sc_fdmodes)); 1079 1080 sc->sc_bus.usbrev = USBREV_2_0; 1081 sc->sc_bus.methods = &ugenhc_bus_methods; 1082 sc->sc_bus.hci_private = sc; 1083 sc->sc_bus.pipe_size = sizeof(struct ugenhc_pipe); 1084 sc->sc_devnum = maa->maa_unit; 1085 1086 config_found(self, &sc->sc_bus, usbctlprint); 1087 } 1088