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