1 /* $NetBSD: ugenhc.c,v 1.29 2021/08/07 16:19:18 thorpej 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.29 2021/08/07 16:19:18 thorpej 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.h> 82 83 #include <rump/rumpuser.h> 84 85 #include <rump-sys/kern.h> 86 #include <rump-sys/dev.h> 87 88 #include "ugenhc_user.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 103 struct lwp *sc_rhintr; 104 struct usbd_xfer *sc_intrxfer; 105 106 kmutex_t sc_lock; 107 }; 108 109 static int ugenhc_probe(device_t, cfdata_t, void *); 110 static void ugenhc_attach(device_t, device_t, void *); 111 112 CFATTACH_DECL_NEW(ugenhc, sizeof(struct ugenhc_softc), 113 ugenhc_probe, ugenhc_attach, NULL, NULL); 114 115 struct rusb_xfer { 116 struct usbd_xfer rusb_xfer; 117 int rusb_status; /* now this is a cheap trick */ 118 }; 119 #define RUSB(x) ((struct rusb_xfer *)x) 120 121 #define UGENHC_BUS2SC(bus) ((bus)->ub_hcpriv) 122 #define UGENHC_PIPE2SC(pipe) UGENHC_BUS2SC((pipe)->up_dev->ud_bus) 123 #define UGENHC_XFER2SC(pipe) UGENHC_BUS2SC((xfer)->ux_bus) 124 125 #define UGENDEV_BASESTR "/dev/ugen" 126 #define UGENDEV_BUFSIZE 32 127 static void 128 makeugendevstr(int devnum, int endpoint, char *buf, size_t len) 129 { 130 131 CTASSERT(UGENDEV_BUFSIZE > sizeof(UGENDEV_BASESTR)+sizeof("0.00")+1); 132 snprintf(buf, len, "%s%d.%02d", UGENDEV_BASESTR, devnum, endpoint); 133 } 134 135 static int 136 ugenhc_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req, 137 void *buf, int buflen) 138 { 139 struct ugenhc_softc *sc = UGENHC_BUS2SC(bus); 140 int totlen = 0; 141 uint16_t len, value; 142 143 len = UGETW(req->wLength); 144 value = UGETW(req->wValue); 145 146 #define C(x,y) ((x) | ((y) << 8)) 147 switch (C(req->bRequest, req->bmRequestType)) { 148 case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): 149 switch (value) { 150 case C(0, UDESC_DEVICE): { 151 usb_device_descriptor_t devd; 152 153 totlen = uimin(buflen, sizeof(devd)); 154 memcpy(&devd, buf, totlen); 155 USETW(devd.idVendor, 0x7275); 156 USETW(devd.idProduct, 0x6d72); 157 memcpy(buf, &devd, totlen); 158 break; 159 } 160 #define sd ((usb_string_descriptor_t *)buf) 161 case C(1, UDESC_STRING): 162 /* Vendor */ 163 totlen = usb_makestrdesc(sd, len, "rod nevada"); 164 break; 165 case C(2, UDESC_STRING): 166 /* Product */ 167 totlen = usb_makestrdesc(sd, len, "RUMPUSBHC root hub"); 168 break; 169 #undef sd 170 default: 171 /* default from usbroothub */ 172 return buflen; 173 } 174 break; 175 176 case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): 177 switch (value) { 178 case UHF_PORT_RESET: 179 sc->sc_port_change |= UPS_C_PORT_RESET; 180 break; 181 case UHF_PORT_POWER: 182 break; 183 default: 184 return -1; 185 } 186 break; 187 188 case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): 189 sc->sc_port_change &= ~value; 190 break; 191 192 case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): 193 totlen = buflen; 194 break; 195 196 case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): 197 /* huh? other hc's do this */ 198 memset(buf, 0, len); 199 totlen = len; 200 break; 201 202 case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): { 203 usb_port_status_t ps; 204 205 USETW(ps.wPortStatus, sc->sc_port_status); 206 USETW(ps.wPortChange, sc->sc_port_change); 207 totlen = uimin(len, sizeof(ps)); 208 memcpy(buf, &ps, totlen); 209 break; 210 } 211 default: 212 /* default from usbroothub */ 213 return buflen; 214 } 215 216 return totlen; 217 } 218 219 static usbd_status 220 rumpusb_device_ctrl_start(struct usbd_xfer *xfer) 221 { 222 usb_device_request_t *req = &xfer->ux_request; 223 struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer); 224 uint8_t *buf = NULL; 225 int len, totlen; 226 int value; 227 int err = 0; 228 int ru_error, mightfail = 0; 229 230 len = totlen = UGETW(req->wLength); 231 if (len) 232 buf = xfer->ux_buf; 233 value = UGETW(req->wValue); 234 235 #define C(x,y) ((x) | ((y) << 8)) 236 switch(C(req->bRequest, req->bmRequestType)) { 237 case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): 238 switch (value>>8) { 239 case UDESC_DEVICE: 240 { 241 usb_device_descriptor_t uddesc; 242 totlen = uimin(len, USB_DEVICE_DESCRIPTOR_SIZE); 243 memset(buf, 0, totlen); 244 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 245 USB_GET_DEVICE_DESC, &uddesc, &ru_error) == -1) { 246 err = EIO; 247 goto ret; 248 } 249 memcpy(buf, &uddesc, totlen); 250 } 251 252 break; 253 case UDESC_CONFIG: 254 { 255 struct usb_full_desc ufdesc; 256 ufdesc.ufd_config_index = value & 0xff; 257 ufdesc.ufd_size = len; 258 ufdesc.ufd_data = buf; 259 memset(buf, 0, len); 260 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 261 USB_GET_FULL_DESC, &ufdesc, &ru_error) == -1) { 262 err = USBD_IOERROR; 263 goto ret; 264 } 265 totlen = ufdesc.ufd_size; 266 } 267 break; 268 269 case UDESC_STRING: 270 { 271 struct usb_device_info udi; 272 273 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 274 USB_GET_DEVICEINFO, &udi, &ru_error) == -1) { 275 printf("ugenhc: get dev info failed: %d\n", 276 ru_error); 277 err = USBD_IOERROR; 278 goto ret; 279 } 280 281 switch (value & 0xff) { 282 #define sd ((usb_string_descriptor_t *)buf) 283 case 0: /* language table */ 284 break; 285 case 1: /* vendor */ 286 totlen = usb_makestrdesc(sd, len, 287 udi.udi_vendor); 288 break; 289 case 2: /* product */ 290 totlen = usb_makestrdesc(sd, len, 291 udi.udi_product); 292 break; 293 } 294 #undef sd 295 } 296 break; 297 298 default: 299 panic("not handled"); 300 } 301 break; 302 303 case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): 304 /* ignored, ugen won't let us */ 305 break; 306 307 case C(UR_SET_CONFIG, UT_WRITE_DEVICE): 308 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 309 USB_SET_CONFIG, &value, &ru_error) == -1) { 310 printf("ugenhc: set config failed: %d\n", 311 ru_error); 312 err = USBD_IOERROR; 313 goto ret; 314 } 315 break; 316 317 case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): 318 { 319 struct usb_alt_interface uai; 320 321 totlen = 0; 322 uai.uai_interface_index = UGETW(req->wIndex); 323 uai.uai_alt_no = value; 324 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 325 USB_SET_ALTINTERFACE, &uai, &ru_error) == -1) { 326 printf("ugenhc: set alt interface failed: %d\n", 327 ru_error); 328 err = USBD_IOERROR; 329 goto ret; 330 } 331 break; 332 } 333 334 /* 335 * This request might fail unknown reasons. "EIO" doesn't 336 * give much help, and debugging the host ugen would be 337 * necessary. However, since it doesn't seem to really 338 * affect anything, just let it fail for now. 339 */ 340 case C(0x00, UT_WRITE_CLASS_INTERFACE): 341 mightfail = 1; 342 /*FALLTHROUGH*/ 343 344 /* 345 * XXX: don't wildcard these yet. I want to better figure 346 * out what to trap here. This is kinda silly, though ... 347 */ 348 349 case C(0x01, UT_WRITE_VENDOR_DEVICE): 350 case C(0x06, UT_WRITE_VENDOR_DEVICE): 351 case C(0x07, UT_READ_VENDOR_DEVICE): 352 case C(0x09, UT_READ_VENDOR_DEVICE): 353 case C(0xfe, UT_READ_CLASS_INTERFACE): 354 case C(0x01, UT_READ_CLASS_INTERFACE): 355 case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): 356 case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): 357 case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): 358 case C(UR_GET_DESCRIPTOR, UT_READ_INTERFACE): 359 case C(0xff, UT_WRITE_CLASS_INTERFACE): 360 case C(0x20, UT_WRITE_CLASS_INTERFACE): 361 case C(0x22, UT_WRITE_CLASS_INTERFACE): 362 case C(0x0a, UT_WRITE_CLASS_INTERFACE): 363 case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): 364 case C(0x00, UT_WRITE_CLASS_DEVICE): 365 case C(UR_SET_FEATURE, UT_WRITE_DEVICE): 366 case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): 367 case C(UR_SET_REPORT, UT_WRITE_CLASS_INTERFACE): 368 case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): 369 { 370 struct usb_ctl_request ucr; 371 372 memcpy(&ucr.ucr_request, req, sizeof(ucr.ucr_request)); 373 ucr.ucr_data = buf; 374 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL], 375 USB_DO_REQUEST, &ucr, &ru_error) == -1) { 376 if (!mightfail) { 377 panic("request failed: %d", ru_error); 378 } else { 379 err = ru_error; 380 } 381 } 382 } 383 break; 384 385 default: 386 panic("unhandled request"); 387 break; 388 } 389 xfer->ux_actlen = totlen; 390 err = USBD_NORMAL_COMPLETION; 391 392 ret: 393 xfer->ux_status = err; 394 mutex_enter(&sc->sc_lock); 395 usb_transfer_complete(xfer); 396 mutex_exit(&sc->sc_lock); 397 398 return USBD_IN_PROGRESS; 399 } 400 401 static usbd_status 402 rumpusb_device_ctrl_transfer(struct usbd_xfer *xfer) 403 { 404 struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer); 405 usbd_status err; 406 407 mutex_enter(&sc->sc_lock); 408 err = usb_insert_transfer(xfer); 409 mutex_exit(&sc->sc_lock); 410 if (err) 411 return err; 412 413 return rumpusb_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); 414 } 415 416 static void 417 rumpusb_device_ctrl_abort(struct usbd_xfer *xfer) 418 { 419 420 } 421 422 static void 423 rumpusb_device_ctrl_close(struct usbd_pipe *pipe) 424 { 425 426 } 427 428 static void 429 rumpusb_device_ctrl_cleartoggle(struct usbd_pipe *pipe) 430 { 431 432 } 433 434 static void 435 rumpusb_device_ctrl_done(struct usbd_xfer *xfer) 436 { 437 438 } 439 440 static const struct usbd_pipe_methods rumpusb_device_ctrl_methods = { 441 .upm_transfer = rumpusb_device_ctrl_transfer, 442 .upm_start = rumpusb_device_ctrl_start, 443 .upm_abort = rumpusb_device_ctrl_abort, 444 .upm_close = rumpusb_device_ctrl_close, 445 .upm_cleartoggle = rumpusb_device_ctrl_cleartoggle, 446 .upm_done = rumpusb_device_ctrl_done, 447 }; 448 449 static void 450 rhscintr(void *arg) 451 { 452 char buf[UGENDEV_BUFSIZE]; 453 struct ugenhc_softc *sc = arg; 454 struct usbd_xfer *xfer; 455 int fd, error; 456 457 makeugendevstr(sc->sc_devnum, 0, buf, sizeof(buf)); 458 459 for (;;) { 460 /* 461 * Detect device attach. 462 */ 463 464 for (;;) { 465 error = rumpuser_open(buf, RUMPUSER_OPEN_RDWR, &fd); 466 if (error == 0) 467 break; 468 kpause("ugwait", false, hz/4, NULL); 469 } 470 471 sc->sc_ugenfd[UGEN_EPT_CTRL] = fd; 472 sc->sc_port_status = UPS_CURRENT_CONNECT_STATUS 473 | UPS_PORT_ENABLED | UPS_PORT_POWER; 474 sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET; 475 476 xfer = sc->sc_intrxfer; 477 memset(xfer->ux_buffer, 0xff, xfer->ux_length); 478 xfer->ux_actlen = xfer->ux_length; 479 xfer->ux_status = USBD_NORMAL_COMPLETION; 480 481 mutex_enter(&sc->sc_lock); 482 usb_transfer_complete(xfer); 483 mutex_exit(&sc->sc_lock); 484 485 kpause("ugwait2", false, hz, NULL); 486 487 /* 488 * Detect device detach. 489 */ 490 491 for (;;) { 492 error = rumpuser_open(buf, RUMPUSER_OPEN_RDWR, &fd); 493 if (fd == -1) 494 break; 495 496 error = rumpuser_close(fd); 497 kpause("ugwait2", false, hz/4, NULL); 498 } 499 500 sc->sc_port_status = ~(UPS_CURRENT_CONNECT_STATUS 501 | UPS_PORT_ENABLED | UPS_PORT_POWER); 502 sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET; 503 504 error = rumpuser_close(sc->sc_ugenfd[UGEN_EPT_CTRL]); 505 sc->sc_ugenfd[UGEN_EPT_CTRL] = -1; 506 507 xfer = sc->sc_intrxfer; 508 memset(xfer->ux_buffer, 0xff, xfer->ux_length); 509 xfer->ux_actlen = xfer->ux_length; 510 xfer->ux_status = USBD_NORMAL_COMPLETION; 511 mutex_enter(&sc->sc_lock); 512 usb_transfer_complete(xfer); 513 mutex_exit(&sc->sc_lock); 514 515 kpause("ugwait3", false, hz, NULL); 516 } 517 518 kthread_exit(0); 519 } 520 521 static usbd_status 522 rumpusb_root_intr_start(struct usbd_xfer *xfer) 523 { 524 struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer); 525 int error; 526 527 mutex_enter(&sc->sc_lock); 528 sc->sc_intrxfer = xfer; 529 if (!sc->sc_rhintr) { 530 error = kthread_create(PRI_NONE, 0, NULL, 531 rhscintr, sc, &sc->sc_rhintr, "ugenrhi"); 532 if (error) 533 xfer->ux_status = USBD_IOERROR; 534 } 535 mutex_exit(&sc->sc_lock); 536 537 return USBD_IN_PROGRESS; 538 } 539 540 static usbd_status 541 rumpusb_root_intr_transfer(struct usbd_xfer *xfer) 542 { 543 struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer); 544 usbd_status err; 545 546 mutex_enter(&sc->sc_lock); 547 err = usb_insert_transfer(xfer); 548 mutex_exit(&sc->sc_lock); 549 if (err) 550 return err; 551 552 return rumpusb_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); 553 } 554 555 static void 556 rumpusb_root_intr_abort(struct usbd_xfer *xfer) 557 { 558 559 } 560 561 static void 562 rumpusb_root_intr_close(struct usbd_pipe *pipe) 563 { 564 565 } 566 567 static void 568 rumpusb_root_intr_cleartoggle(struct usbd_pipe *pipe) 569 { 570 571 } 572 573 static void 574 rumpusb_root_intr_done(struct usbd_xfer *xfer) 575 { 576 577 } 578 579 static const struct usbd_pipe_methods rumpusb_root_intr_methods = { 580 .upm_transfer = rumpusb_root_intr_transfer, 581 .upm_start = rumpusb_root_intr_start, 582 .upm_abort = rumpusb_root_intr_abort, 583 .upm_close = rumpusb_root_intr_close, 584 .upm_cleartoggle = rumpusb_root_intr_cleartoggle, 585 .upm_done = rumpusb_root_intr_done, 586 }; 587 588 static usbd_status 589 rumpusb_device_bulk_start(struct usbd_xfer *xfer) 590 { 591 struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer); 592 usb_endpoint_descriptor_t *ed = xfer->ux_pipe->up_endpoint->ue_edesc; 593 size_t n, done; 594 bool isread; 595 int len, error, endpt; 596 uint8_t *buf; 597 int xfererr = USBD_NORMAL_COMPLETION; 598 int shortval, i; 599 600 ed = xfer->ux_pipe->up_endpoint->ue_edesc; 601 endpt = ed->bEndpointAddress; 602 isread = UE_GET_DIR(endpt) == UE_DIR_IN; 603 endpt = UE_GET_ADDR(endpt); 604 KASSERT(endpt < UGEN_NEPTS); 605 606 buf = xfer->ux_buf; 607 done = 0; 608 if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) { 609 for (i = 0, len = 0; i < xfer->ux_nframes; i++) 610 len += xfer->ux_frlengths[i]; 611 } else { 612 KASSERT(xfer->ux_length); 613 len = xfer->ux_length; 614 } 615 shortval = (xfer->ux_flags & USBD_SHORT_XFER_OK) != 0; 616 617 while (RUSB(xfer)->rusb_status == 0) { 618 if (isread) { 619 struct rumpuser_iovec iov; 620 621 rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[endpt], 622 USB_SET_SHORT_XFER, &shortval, &error); 623 iov.iov_base = buf+done; 624 iov.iov_len = len-done; 625 error = rumpuser_iovread(sc->sc_ugenfd[endpt], &iov, 1, 626 RUMPUSER_IOV_NOSEEK, &n); 627 if (error) { 628 n = 0; 629 if (done == 0) { 630 if (error == ETIMEDOUT) 631 continue; 632 xfererr = USBD_IOERROR; 633 goto out; 634 } 635 } 636 done += n; 637 if (done == len) 638 break; 639 } else { 640 struct rumpuser_iovec iov; 641 642 iov.iov_base = buf; 643 iov.iov_len = len; 644 error = rumpuser_iovwrite(sc->sc_ugenfd[endpt], &iov, 1, 645 RUMPUSER_IOV_NOSEEK, &n); 646 done = n; 647 if (done == len) 648 break; 649 else if (!error) 650 panic("short write"); 651 652 xfererr = USBD_IOERROR; 653 goto out; 654 } 655 656 if (shortval) { 657 /* 658 * Holy XXX, bitman. I get >16byte interrupt 659 * transfers from ugen in 16 byte chunks. 660 * Don't know how to better fix this for now. 661 * Of course this hack will fail e.g. if someone 662 * sports other magic values or if the transfer 663 * happens to be an integral multiple of 16 664 * in size .... 665 */ 666 if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT 667 && n == 16) { 668 continue; 669 } else { 670 break; 671 } 672 } 673 } 674 675 if (RUSB(xfer)->rusb_status == 0) { 676 xfer->ux_actlen = done; 677 } else { 678 xfererr = USBD_CANCELLED; 679 RUSB(xfer)->rusb_status = 2; 680 } 681 out: 682 if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) 683 if (done != len) 684 panic("lazy bum"); 685 xfer->ux_status = xfererr; 686 mutex_enter(&sc->sc_lock); 687 usb_transfer_complete(xfer); 688 mutex_exit(&sc->sc_lock); 689 return USBD_IN_PROGRESS; 690 } 691 692 static void 693 doxfer_kth(void *arg) 694 { 695 struct usbd_pipe *pipe = arg; 696 struct ugenhc_softc *sc = UGENHC_PIPE2SC(pipe); 697 698 mutex_enter(&sc->sc_lock); 699 do { 700 struct usbd_xfer *xfer = SIMPLEQ_FIRST(&pipe->up_queue); 701 mutex_exit(&sc->sc_lock); 702 rumpusb_device_bulk_start(xfer); 703 mutex_enter(&sc->sc_lock); 704 } while (!SIMPLEQ_EMPTY(&pipe->up_queue)); 705 mutex_exit(&sc->sc_lock); 706 kthread_exit(0); 707 } 708 709 static usbd_status 710 rumpusb_device_bulk_transfer(struct usbd_xfer *xfer) 711 { 712 struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer); 713 usbd_status err; 714 715 if (!rump_threads) { 716 /* XXX: lie about supporting async transfers */ 717 if ((xfer->ux_flags & USBD_SYNCHRONOUS) == 0) { 718 printf("non-threaded rump does not support " 719 "async transfers.\n"); 720 return USBD_IN_PROGRESS; 721 } 722 723 mutex_enter(&sc->sc_lock); 724 err = usb_insert_transfer(xfer); 725 mutex_exit(&sc->sc_lock); 726 if (err) 727 return err; 728 729 return rumpusb_device_bulk_start( 730 SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); 731 } else { 732 mutex_enter(&sc->sc_lock); 733 err = usb_insert_transfer(xfer); 734 mutex_exit(&sc->sc_lock); 735 if (err) 736 return err; 737 kthread_create(PRI_NONE, 0, NULL, doxfer_kth, xfer->ux_pipe, NULL, 738 "rusbhcxf"); 739 740 return USBD_IN_PROGRESS; 741 } 742 } 743 744 /* wait for transfer to abort. yea, this is cheesy (from a spray can) */ 745 static void 746 rumpusb_device_bulk_abort(struct usbd_xfer *xfer) 747 { 748 struct rusb_xfer *rx = RUSB(xfer); 749 750 rx->rusb_status = 1; 751 while (rx->rusb_status < 2) { 752 kpause("jopo", false, hz/10, NULL); 753 } 754 } 755 756 static void 757 rumpusb_device_bulk_close(struct usbd_pipe *pipe) 758 { 759 struct ugenhc_softc *sc = UGENHC_PIPE2SC(pipe); 760 int endpt = pipe->up_endpoint->ue_edesc->bEndpointAddress; 761 struct usbd_xfer *xfer; 762 763 KASSERT(mutex_owned(&sc->sc_lock)); 764 765 endpt = UE_GET_ADDR(endpt); 766 767 while ((xfer = SIMPLEQ_FIRST(&pipe->up_queue)) != NULL) 768 rumpusb_device_bulk_abort(xfer); 769 770 rumpuser_close(sc->sc_ugenfd[endpt]); 771 sc->sc_ugenfd[endpt] = -1; 772 sc->sc_fdmodes[endpt] = -1; 773 } 774 775 static void 776 rumpusb_device_bulk_cleartoggle(struct usbd_pipe *pipe) 777 { 778 779 } 780 781 static void 782 rumpusb_device_bulk_done(struct usbd_xfer *xfer) 783 { 784 785 } 786 787 static const struct usbd_pipe_methods rumpusb_device_bulk_methods = { 788 .upm_transfer = rumpusb_device_bulk_transfer, 789 .upm_start = rumpusb_device_bulk_start, 790 .upm_abort = rumpusb_device_bulk_abort, 791 .upm_close = rumpusb_device_bulk_close, 792 .upm_cleartoggle = rumpusb_device_bulk_cleartoggle, 793 .upm_done = rumpusb_device_bulk_done, 794 }; 795 796 static usbd_status 797 ugenhc_open(struct usbd_pipe *pipe) 798 { 799 struct usbd_device *dev = pipe->up_dev; 800 struct ugenhc_softc *sc = UGENHC_PIPE2SC(pipe); 801 usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc; 802 uint8_t rhaddr = dev->ud_bus->ub_rhaddr; 803 uint8_t addr = dev->ud_addr; 804 uint8_t xfertype = ed->bmAttributes & UE_XFERTYPE; 805 char buf[UGENDEV_BUFSIZE]; 806 int endpt, oflags, error; 807 int fd, val; 808 809 if (addr == rhaddr) { 810 switch (xfertype) { 811 case UE_CONTROL: 812 pipe->up_methods = &roothub_ctrl_methods; 813 break; 814 case UE_INTERRUPT: 815 pipe->up_methods = &rumpusb_root_intr_methods; 816 break; 817 default: 818 panic("%d not supported", xfertype); 819 break; 820 } 821 } else { 822 switch (xfertype) { 823 case UE_CONTROL: 824 pipe->up_methods = &rumpusb_device_ctrl_methods; 825 break; 826 case UE_INTERRUPT: 827 case UE_BULK: 828 case UE_ISOCHRONOUS: 829 pipe->up_methods = &rumpusb_device_bulk_methods; 830 endpt = pipe->up_endpoint->ue_edesc->bEndpointAddress; 831 if (UE_GET_DIR(endpt) == UE_DIR_IN) { 832 oflags = O_RDONLY; 833 } else { 834 oflags = O_WRONLY; 835 } 836 endpt = UE_GET_ADDR(endpt); 837 838 if (oflags != O_RDONLY && xfertype == UE_ISOCHRONOUS) { 839 printf("WARNING: faking isoc write open\n"); 840 oflags = O_RDONLY; 841 } 842 843 if (sc->sc_fdmodes[endpt] == oflags 844 || sc->sc_fdmodes[endpt] == O_RDWR) 845 break; 846 847 if (sc->sc_fdmodes[endpt] != -1) { 848 /* XXX: closing from under someone? */ 849 error = rumpuser_close(sc->sc_ugenfd[endpt]); 850 oflags = O_RDWR; 851 } 852 853 makeugendevstr(sc->sc_devnum, endpt, buf, sizeof(buf)); 854 /* XXX: theoretically should convert oflags */ 855 error = rumpuser_open(buf, oflags, &fd); 856 if (error != 0) { 857 return USBD_INVAL; /* XXX: no mapping */ 858 } 859 val = 100; 860 if (rumpcomp_ugenhc_ioctl(fd, USB_SET_TIMEOUT, &val, 861 &error) == -1) 862 panic("timeout set failed"); 863 sc->sc_ugenfd[endpt] = fd; 864 sc->sc_fdmodes[endpt] = oflags; 865 866 break; 867 default: 868 panic("%d not supported", xfertype); 869 break; 870 871 } 872 } 873 return 0; 874 } 875 876 static void 877 ugenhc_softint(void *arg) 878 { 879 880 } 881 882 static void 883 ugenhc_poll(struct usbd_bus *ubus) 884 { 885 886 } 887 888 static struct usbd_xfer * 889 ugenhc_allocx(struct usbd_bus *bus, unsigned int nframes) 890 { 891 struct usbd_xfer *xfer; 892 893 xfer = kmem_zalloc(sizeof(struct usbd_xfer), KM_SLEEP); 894 xfer->ux_state = XFER_BUSY; 895 896 return xfer; 897 } 898 899 static void 900 ugenhc_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) 901 { 902 903 kmem_free(xfer, sizeof(struct usbd_xfer)); 904 } 905 906 907 static void 908 ugenhc_getlock(struct usbd_bus *bus, kmutex_t **lock) 909 { 910 struct ugenhc_softc *sc = UGENHC_BUS2SC(bus); 911 912 *lock = &sc->sc_lock; 913 } 914 915 struct ugenhc_pipe { 916 struct usbd_pipe pipe; 917 }; 918 919 static const struct usbd_bus_methods ugenhc_bus_methods = { 920 .ubm_open = ugenhc_open, 921 .ubm_softint = ugenhc_softint, 922 .ubm_dopoll = ugenhc_poll, 923 .ubm_allocx = ugenhc_allocx, 924 .ubm_freex = ugenhc_freex, 925 .ubm_getlock = ugenhc_getlock, 926 .ubm_rhctrl = ugenhc_roothub_ctrl, 927 }; 928 929 static int 930 ugenhc_probe(device_t parent, cfdata_t match, void *aux) 931 { 932 char buf[UGENDEV_BUFSIZE]; 933 934 makeugendevstr(match->cf_unit, 0, buf, sizeof(buf)); 935 if (rumpuser_getfileinfo(buf, NULL, NULL) != 0) 936 return 0; 937 938 return 1; 939 } 940 941 static void 942 ugenhc_attach(device_t parent, device_t self, void *aux) 943 { 944 struct mainbus_attach_args *maa = aux; 945 struct ugenhc_softc *sc = device_private(self); 946 947 aprint_normal("\n"); 948 949 memset(sc, 0, sizeof(*sc)); 950 memset(&sc->sc_ugenfd, -1, sizeof(sc->sc_ugenfd)); 951 memset(&sc->sc_fdmodes, -1, sizeof(sc->sc_fdmodes)); 952 953 sc->sc_bus.ub_revision = USBREV_2_0; 954 sc->sc_bus.ub_methods = &ugenhc_bus_methods; 955 sc->sc_bus.ub_hcpriv = sc; 956 sc->sc_bus.ub_pipesize = sizeof(struct ugenhc_pipe); 957 sc->sc_bus.ub_usedma = false; 958 sc->sc_devnum = maa->maa_unit; 959 960 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 961 962 config_found(self, &sc->sc_bus, usbctlprint, CFARGS_NONE); 963 } 964