Home | History | Annotate | Line # | Download | only in libugenhc
      1 /*	$NetBSD: ugenhc.c,v 1.22.4.13 2016/03/19 11:30:35 skrll 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 (at) 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.22.4.13 2016/03/19 11:30:35 skrll 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 = min(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 = min(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 = min(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 			fd = rumpuser_open(buf, RUMPUSER_OPEN_RDWR, &error);
    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 = KERNADDR(&xfer->ux_dmabuf, 0);
    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);
    963 }
    964