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