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