xref: /netbsd-src/sys/rump/dev/lib/libugenhc/ugenhc.c (revision 5bbd2a12505d72a8177929a37b5cee489d0a1cfd)
1 /*	$NetBSD: ugenhc.c,v 1.10 2012/06/10 06:15:55 mrg 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.10 2012/06/10 06:15:55 mrg 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 	/* XXX locking */
316 	usb_transfer_complete(xfer);
317 	return (USBD_IN_PROGRESS);
318 }
319 
320 static usbd_status
321 rumpusb_root_ctrl_transfer(usbd_xfer_handle xfer)
322 {
323 	usbd_status err;
324 
325 	err = usb_insert_transfer(xfer);
326 	if (err)
327 		return (err);
328 
329 	return (rumpusb_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
330 }
331 
332 static void
333 rumpusb_root_ctrl_abort(usbd_xfer_handle xfer)
334 {
335 
336 }
337 
338 static void
339 rumpusb_root_ctrl_close(usbd_pipe_handle pipe)
340 {
341 
342 }
343 
344 static void
345 rumpusb_root_ctrl_cleartoggle(usbd_pipe_handle pipe)
346 {
347 
348 }
349 
350 static void
351 rumpusb_root_ctrl_done(usbd_xfer_handle xfer)
352 {
353 
354 }
355 
356 static const struct usbd_pipe_methods rumpusb_root_ctrl_methods = {
357 	.transfer =	rumpusb_root_ctrl_transfer,
358 	.start =	rumpusb_root_ctrl_start,
359 	.abort =	rumpusb_root_ctrl_abort,
360 	.close =	rumpusb_root_ctrl_close,
361 	.cleartoggle =	rumpusb_root_ctrl_cleartoggle,
362 	.done =		rumpusb_root_ctrl_done,
363 };
364 
365 static usbd_status
366 rumpusb_device_ctrl_start(usbd_xfer_handle xfer)
367 {
368 	usb_device_request_t *req = &xfer->request;
369 	struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private;
370 	uint8_t *buf = NULL;
371 	int len, totlen;
372 	int value;
373 	int err = 0;
374 	int ru_error, mightfail = 0;
375 
376 	len = totlen = UGETW(req->wLength);
377 	if (len)
378 		buf = KERNADDR(&xfer->dmabuf, 0);
379 	value = UGETW(req->wValue);
380 
381 #define C(x,y) ((x) | ((y) << 8))
382 	switch(C(req->bRequest, req->bmRequestType)) {
383 	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
384 		switch (value>>8) {
385 		case UDESC_DEVICE:
386 			{
387 			usb_device_descriptor_t uddesc;
388 			totlen = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
389 			memset(buf, 0, totlen);
390 			if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
391 			    USB_GET_DEVICE_DESC, &uddesc, &ru_error) == -1) {
392 				err = EIO;
393 				goto ret;
394 			}
395 			memcpy(buf, &uddesc, totlen);
396 			}
397 
398 			break;
399 		case UDESC_CONFIG:
400 			{
401 			struct usb_full_desc ufdesc;
402 			ufdesc.ufd_config_index = value & 0xff;
403 			ufdesc.ufd_size = len;
404 			ufdesc.ufd_data = buf;
405 			memset(buf, 0, len);
406 			if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
407 			    USB_GET_FULL_DESC, &ufdesc, &ru_error) == -1) {
408 				err = USBD_IOERROR;
409 				goto ret;
410 			}
411 			totlen = ufdesc.ufd_size;
412 			}
413 			break;
414 
415 		case UDESC_STRING:
416 			{
417 			struct usb_device_info udi;
418 
419 			if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
420 			    USB_GET_DEVICEINFO, &udi, &ru_error) == -1) {
421 				printf("ugenhc: get dev info failed: %d\n",
422 				    ru_error);
423 				err = USBD_IOERROR;
424 				goto ret;
425 			}
426 
427 			switch (value & 0xff) {
428 #define sd ((usb_string_descriptor_t *)buf)
429 			case 0: /* language table */
430 				break;
431 			case 1: /* vendor */
432 				totlen = usb_makestrdesc(sd, len,
433 				    udi.udi_vendor);
434 				break;
435 			case 2: /* product */
436 				totlen = usb_makestrdesc(sd, len,
437 				    udi.udi_product);
438 				break;
439 			}
440 #undef sd
441 			}
442 			break;
443 
444 		default:
445 			panic("not handled");
446 		}
447 		break;
448 
449 	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
450 		/* ignored, ugen won't let us */
451 		break;
452 
453 	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
454 		if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
455 		    USB_SET_CONFIG, &value, &ru_error) == -1) {
456 			printf("ugenhc: set config failed: %d\n",
457 			    ru_error);
458 			err = USBD_IOERROR;
459 			goto ret;
460 		}
461 		break;
462 
463 	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
464 		{
465 		struct usb_alt_interface uai;
466 
467 		totlen = 0;
468 		uai.uai_interface_index = UGETW(req->wIndex);
469 		uai.uai_alt_no = value;
470 		if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
471 		    USB_SET_ALTINTERFACE, &uai, &ru_error) == -1) {
472 			printf("ugenhc: set alt interface failed: %d\n",
473 			    ru_error);
474 			err = USBD_IOERROR;
475 			goto ret;
476 		}
477 		break;
478 		}
479 
480 	/*
481 	 * This request might fail unknown reasons.  "EIO" doesn't
482 	 * give much help, and debugging the host ugen would be
483 	 * necessary.  However, since it doesn't seem to really
484 	 * affect anything, just let it fail for now.
485 	 */
486 	case C(0x00, UT_WRITE_CLASS_INTERFACE):
487 		mightfail = 1;
488 		/*FALLTHROUGH*/
489 
490 	/*
491 	 * XXX: don't wildcard these yet.  I want to better figure
492 	 * out what to trap here.  This is kinda silly, though ...
493 	 */
494 
495 	case C(0x01, UT_WRITE_VENDOR_DEVICE):
496 	case C(0x06, UT_WRITE_VENDOR_DEVICE):
497 	case C(0x07, UT_READ_VENDOR_DEVICE):
498 	case C(0x09, UT_READ_VENDOR_DEVICE):
499 	case C(0xfe, UT_READ_CLASS_INTERFACE):
500 	case C(0x01, UT_READ_CLASS_INTERFACE):
501 	case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
502 	case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
503 	case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
504 	case C(UR_GET_DESCRIPTOR, UT_READ_INTERFACE):
505 	case C(0xff, UT_WRITE_CLASS_INTERFACE):
506 	case C(0x20, UT_WRITE_CLASS_INTERFACE):
507 	case C(0x22, UT_WRITE_CLASS_INTERFACE):
508 	case C(0x0a, UT_WRITE_CLASS_INTERFACE):
509 	case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
510 	case C(0x00, UT_WRITE_CLASS_DEVICE):
511 	case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
512 	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
513 	case C(UR_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
514 	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
515 		{
516 		struct usb_ctl_request ucr;
517 
518 		memcpy(&ucr.ucr_request, req, sizeof(ucr.ucr_request));
519 		ucr.ucr_data = buf;
520 		if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
521 		    USB_DO_REQUEST, &ucr, &ru_error) == -1) {
522 			if (!mightfail) {
523 				panic("request failed: %d", ru_error);
524 			} else {
525 				err = ru_error;
526 			}
527 		}
528 		}
529 		break;
530 
531 	default:
532 		panic("unhandled request");
533 		break;
534 	}
535 	xfer->actlen = totlen;
536 	err = USBD_NORMAL_COMPLETION;
537 
538  ret:
539 	xfer->status = err;
540 	usb_transfer_complete(xfer);
541 	return (USBD_IN_PROGRESS);
542 }
543 
544 static usbd_status
545 rumpusb_device_ctrl_transfer(usbd_xfer_handle xfer)
546 {
547 	usbd_status err;
548 
549 	err = usb_insert_transfer(xfer);
550 	if (err)
551 		return (err);
552 
553 	return (rumpusb_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
554 }
555 
556 static void
557 rumpusb_device_ctrl_abort(usbd_xfer_handle xfer)
558 {
559 
560 }
561 
562 static void
563 rumpusb_device_ctrl_close(usbd_pipe_handle pipe)
564 {
565 
566 }
567 
568 static void
569 rumpusb_device_ctrl_cleartoggle(usbd_pipe_handle pipe)
570 {
571 
572 }
573 
574 static void
575 rumpusb_device_ctrl_done(usbd_xfer_handle xfer)
576 {
577 
578 }
579 
580 static const struct usbd_pipe_methods rumpusb_device_ctrl_methods = {
581 	.transfer =	rumpusb_device_ctrl_transfer,
582 	.start =	rumpusb_device_ctrl_start,
583 	.abort =	rumpusb_device_ctrl_abort,
584 	.close =	rumpusb_device_ctrl_close,
585 	.cleartoggle =	rumpusb_device_ctrl_cleartoggle,
586 	.done =		rumpusb_device_ctrl_done,
587 };
588 
589 static void
590 rhscintr(void *arg)
591 {
592 	char buf[UGENDEV_BUFSIZE];
593 	struct ugenhc_softc *sc = arg;
594 	usbd_xfer_handle xfer;
595 	int fd, error;
596 
597 	makeugendevstr(sc->sc_devnum, 0, buf);
598 
599 	for (;;) {
600 		/*
601 		 * Detect device attach.
602 		 */
603 
604 		for (;;) {
605 			fd = rumpuser_open(buf, O_RDWR, &error);
606 			if (fd != -1)
607 				break;
608 			kpause("ugwait", false, hz/4, NULL);
609 		}
610 
611 		sc->sc_ugenfd[UGEN_EPT_CTRL] = fd;
612 		sc->sc_port_status = UPS_CURRENT_CONNECT_STATUS
613 		    | UPS_PORT_ENABLED | UPS_PORT_POWER;
614 		sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET;
615 
616 		xfer = sc->sc_intrxfer;
617 		memset(xfer->buffer, 0xff, xfer->length);
618 		xfer->actlen = xfer->length;
619 		xfer->status = USBD_NORMAL_COMPLETION;
620 
621 		usb_transfer_complete(xfer);
622 
623 		kpause("ugwait2", false, hz, NULL);
624 
625 		/*
626 		 * Detect device detach.
627 		 */
628 
629 		for (;;) {
630 			fd = rumpuser_open(buf, O_RDWR, &error);
631 			if (fd == -1)
632 				break;
633 
634 			rumpuser_close(fd, &error);
635 			kpause("ugwait2", false, hz/4, NULL);
636 		}
637 
638 		sc->sc_port_status = ~(UPS_CURRENT_CONNECT_STATUS
639 		    | UPS_PORT_ENABLED | UPS_PORT_POWER);
640 		sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET;
641 
642 		rumpuser_close(sc->sc_ugenfd[UGEN_EPT_CTRL], &error);
643 		sc->sc_ugenfd[UGEN_EPT_CTRL] = -1;
644 
645 		xfer = sc->sc_intrxfer;
646 		memset(xfer->buffer, 0xff, xfer->length);
647 		xfer->actlen = xfer->length;
648 		xfer->status = USBD_NORMAL_COMPLETION;
649 		usb_transfer_complete(xfer);
650 
651 		kpause("ugwait3", false, hz, NULL);
652 	}
653 
654 	kthread_exit(0);
655 }
656 
657 static usbd_status
658 rumpusb_root_intr_start(usbd_xfer_handle xfer)
659 {
660 	struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private;
661 	int error;
662 
663 	sc->sc_intrxfer = xfer;
664 	if (!sc->sc_rhintr) {
665 		error = kthread_create(PRI_NONE, 0, NULL,
666 		    rhscintr, sc, &sc->sc_rhintr, "ugenrhi");
667 		if (error)
668 			xfer->status = error;
669 	}
670 
671 	return (USBD_IN_PROGRESS);
672 }
673 
674 static usbd_status
675 rumpusb_root_intr_transfer(usbd_xfer_handle xfer)
676 {
677 	usbd_status err;
678 
679 	err = usb_insert_transfer(xfer);
680 	if (err)
681 		return (err);
682 
683 	return (rumpusb_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
684 }
685 
686 static void
687 rumpusb_root_intr_abort(usbd_xfer_handle xfer)
688 {
689 
690 }
691 
692 static void
693 rumpusb_root_intr_close(usbd_pipe_handle pipe)
694 {
695 
696 }
697 
698 static void
699 rumpusb_root_intr_cleartoggle(usbd_pipe_handle pipe)
700 {
701 
702 }
703 
704 static void
705 rumpusb_root_intr_done(usbd_xfer_handle xfer)
706 {
707 
708 }
709 
710 static const struct usbd_pipe_methods rumpusb_root_intr_methods = {
711 	.transfer =	rumpusb_root_intr_transfer,
712 	.start =	rumpusb_root_intr_start,
713 	.abort =	rumpusb_root_intr_abort,
714 	.close =	rumpusb_root_intr_close,
715 	.cleartoggle =	rumpusb_root_intr_cleartoggle,
716 	.done =		rumpusb_root_intr_done,
717 };
718 
719 static usbd_status
720 rumpusb_device_bulk_start(usbd_xfer_handle xfer)
721 {
722 	struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private;
723 	usb_endpoint_descriptor_t *ed = xfer->pipe->endpoint->edesc;
724 	ssize_t n;
725 	ssize_t done;
726 	bool isread;
727 	int len, error, endpt;
728 	uint8_t *buf;
729 	int xfererr = USBD_NORMAL_COMPLETION;
730 	int shortval, i;
731 
732 	ed = xfer->pipe->endpoint->edesc;
733 	endpt = ed->bEndpointAddress;
734 	isread = UE_GET_DIR(endpt) == UE_DIR_IN;
735 	endpt = UE_GET_ADDR(endpt);
736 	KASSERT(endpt < UGEN_NEPTS);
737 
738 	buf = KERNADDR(&xfer->dmabuf, 0);
739 	done = 0;
740 	if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) {
741 		for (i = 0, len = 0; i < xfer->nframes; i++)
742 			len += xfer->frlengths[i];
743 	} else {
744 		KASSERT(xfer->length);
745 		len = xfer->length;
746 	}
747 	shortval = (xfer->flags & USBD_SHORT_XFER_OK) != 0;
748 
749 	while (RUSB(xfer)->rusb_status == 0) {
750 		if (isread) {
751 			rumpuser_ioctl(sc->sc_ugenfd[endpt],
752 			    USB_SET_SHORT_XFER, &shortval, &error);
753 			n = rumpuser_read(sc->sc_ugenfd[endpt],
754 			    buf+done, len-done, &error);
755 			if (n == -1) {
756 				n = 0;
757 				if (done == 0) {
758 					if (error == ETIMEDOUT)
759 						continue;
760 					xfererr = USBD_IOERROR;
761 					goto out;
762 				}
763 			}
764 			done += n;
765 			if (done == len)
766 				break;
767 		} else {
768 			n = rumpuser_write(sc->sc_ugenfd[endpt],
769 			    buf, len, &error);
770 			done = n;
771 			if (done == len)
772 				break;
773 			else if (n != -1)
774 				panic("short write");
775 
776 			xfererr = USBD_IOERROR;
777 			goto out;
778 		}
779 
780 		if (shortval) {
781 			/*
782 			 * Holy XXX, bitman.  I get >16byte interrupt
783 			 * transfers from ugen in 16 byte chunks.
784 			 * Don't know how to better fix this for now.
785 			 * Of course this hack will fail e.g. if someone
786 			 * sports other magic values or if the transfer
787 			 * happens to be an integral multiple of 16
788 			 * in size ....
789 			 */
790 			if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT
791 			    && n == 16) {
792 				continue;
793 			} else {
794 				break;
795 			}
796 		}
797 	}
798 
799 	if (RUSB(xfer)->rusb_status == 0) {
800 		xfer->actlen = done;
801 	} else {
802 		xfererr = USBD_CANCELLED;
803 		RUSB(xfer)->rusb_status = 2;
804 	}
805  out:
806 	if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS)
807 		if (done != len)
808 			panic("lazy bum");
809 	xfer->status = xfererr;
810 	usb_transfer_complete(xfer);
811 	return (USBD_IN_PROGRESS);
812 }
813 
814 static void
815 doxfer_kth(void *arg)
816 {
817 	usbd_xfer_handle xfer = arg;
818 
819 	do {
820 		rumpusb_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
821 	} while (!SIMPLEQ_EMPTY(&xfer->pipe->queue));
822 	kthread_exit(0);
823 }
824 
825 static usbd_status
826 rumpusb_device_bulk_transfer(usbd_xfer_handle xfer)
827 {
828 	usbd_status err;
829 
830 	if (!rump_threads) {
831 		/* XXX: lie about supporting async transfers */
832 		if ((xfer->flags & USBD_SYNCHRONOUS) == 0) {
833 			printf("non-threaded rump does not support "
834 			    "async transfers.\n");
835 			return USBD_IN_PROGRESS;
836 		}
837 
838 		err = usb_insert_transfer(xfer);
839 		if (err)
840 			return err;
841 
842 		return rumpusb_device_bulk_start(
843 		    SIMPLEQ_FIRST(&xfer->pipe->queue));
844 	} else {
845 		/* biglocked */
846 		/* XXX locking */
847 		err = usb_insert_transfer(xfer);
848 		if (err)
849 			return err;
850 		kthread_create(PRI_NONE, 0, NULL, doxfer_kth, xfer, NULL,
851 		    "rusbhcxf");
852 
853 		return USBD_IN_PROGRESS;
854 	}
855 }
856 
857 /* wait for transfer to abort.  yea, this is cheesy (from a spray can) */
858 static void
859 rumpusb_device_bulk_abort(usbd_xfer_handle xfer)
860 {
861 	struct rusb_xfer *rx = RUSB(xfer);
862 
863 	rx->rusb_status = 1;
864 	while (rx->rusb_status < 2) {
865 		kpause("jopo", false, hz/10, NULL);
866 	}
867 }
868 
869 static void
870 rumpusb_device_bulk_close(usbd_pipe_handle pipe)
871 {
872 	struct ugenhc_softc *sc = pipe->device->bus->hci_private;
873 	int endpt = pipe->endpoint->edesc->bEndpointAddress;
874 	usbd_xfer_handle xfer;
875 	int error;
876 
877 	endpt = UE_GET_ADDR(endpt);
878 
879 	while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL)
880 		rumpusb_device_bulk_abort(xfer);
881 
882 	rumpuser_close(sc->sc_ugenfd[endpt], &error);
883 	sc->sc_ugenfd[endpt] = -1;
884 	sc->sc_fdmodes[endpt] = -1;
885 }
886 
887 static void
888 rumpusb_device_bulk_cleartoggle(usbd_pipe_handle pipe)
889 {
890 
891 }
892 
893 static void
894 rumpusb_device_bulk_done(usbd_xfer_handle xfer)
895 {
896 
897 }
898 
899 static const struct usbd_pipe_methods rumpusb_device_bulk_methods = {
900 	.transfer =	rumpusb_device_bulk_transfer,
901 	.start =	rumpusb_device_bulk_start,
902 	.abort =	rumpusb_device_bulk_abort,
903 	.close =	rumpusb_device_bulk_close,
904 	.cleartoggle =	rumpusb_device_bulk_cleartoggle,
905 	.done =		rumpusb_device_bulk_done,
906 };
907 
908 static const struct usbd_pipe_methods rumpusb_device_intr_methods = {
909 	.transfer =	rumpusb_root_intr_transfer,
910 	.start =	rumpusb_root_intr_start,
911 	.abort =	rumpusb_root_intr_abort,
912 	.close =	rumpusb_root_intr_close,
913 	.cleartoggle =	rumpusb_root_intr_cleartoggle,
914 	.done =		rumpusb_root_intr_done,
915 };
916 
917 static usbd_status
918 ugenhc_open(struct usbd_pipe *pipe)
919 {
920 	usbd_device_handle dev = pipe->device;
921 	struct ugenhc_softc *sc = dev->bus->hci_private;
922 	usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
923 	u_int8_t addr = dev->address;
924 	u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
925 	char buf[UGENDEV_BUFSIZE];
926 	int endpt, oflags, error;
927 	int fd, val;
928 
929 	if (addr == sc->sc_addr) {
930 		switch (xfertype) {
931 		case UE_CONTROL:
932 			pipe->methods = &rumpusb_root_ctrl_methods;
933 			break;
934 		case UE_INTERRUPT:
935 			pipe->methods = &rumpusb_root_intr_methods;
936 			break;
937 		default:
938 			panic("%d not supported", xfertype);
939 			break;
940 		}
941 	} else {
942 		switch (xfertype) {
943 		case UE_CONTROL:
944 			pipe->methods = &rumpusb_device_ctrl_methods;
945 			break;
946 		case UE_INTERRUPT:
947 		case UE_BULK:
948 		case UE_ISOCHRONOUS:
949 			pipe->methods = &rumpusb_device_bulk_methods;
950 			endpt = pipe->endpoint->edesc->bEndpointAddress;
951 			if (UE_GET_DIR(endpt) == UE_DIR_IN) {
952 				oflags = O_RDONLY;
953 			} else {
954 				oflags = O_WRONLY;
955 			}
956 			endpt = UE_GET_ADDR(endpt);
957 
958 			if (oflags != O_RDONLY && xfertype == UE_ISOCHRONOUS) {
959 				printf("WARNING: faking isoc write open\n");
960 				oflags = O_RDONLY;
961 			}
962 
963 			if (sc->sc_fdmodes[endpt] == oflags
964 			    || sc->sc_fdmodes[endpt] == O_RDWR)
965 				break;
966 
967 			if (sc->sc_fdmodes[endpt] != -1) {
968 				/* XXX: closing from under someone? */
969 				rumpuser_close(sc->sc_ugenfd[endpt], &error);
970 				oflags = O_RDWR;
971 			}
972 
973 			makeugendevstr(sc->sc_devnum, endpt, buf);
974 			fd = rumpuser_open(buf, oflags, &error);
975 			if (fd == -1) {
976 				return USBD_INVAL; /* XXX: no mapping */
977 			}
978 			val = 100;
979 			if (rumpuser_ioctl(fd, USB_SET_TIMEOUT, &val,
980 			    &error) == -1)
981 				panic("timeout set failed");
982 			sc->sc_ugenfd[endpt] = fd;
983 			sc->sc_fdmodes[endpt] = oflags;
984 
985 			break;
986 		default:
987 			panic("%d not supported", xfertype);
988 			break;
989 
990 		}
991 	}
992 	return 0;
993 }
994 
995 static void
996 ugenhc_softint(void *arg)
997 {
998 
999 }
1000 
1001 static void
1002 ugenhc_poll(struct usbd_bus *ubus)
1003 {
1004 
1005 }
1006 
1007 static usbd_status
1008 ugenhc_allocm(struct usbd_bus *bus, usb_dma_t *dma, uint32_t size)
1009 {
1010 	struct ugenhc_softc *sc = bus->hci_private;
1011 
1012 	return usb_allocmem(&sc->sc_bus, size, 0, dma);
1013 }
1014 
1015 static void
1016 ugenhc_freem(struct usbd_bus *bus, usb_dma_t *dma)
1017 {
1018 	struct ugenhc_softc *sc = bus->hci_private;
1019 
1020 	usb_freemem(&sc->sc_bus, dma);
1021 }
1022 
1023 static struct usbd_xfer *
1024 ugenhc_allocx(struct usbd_bus *bus)
1025 {
1026 	usbd_xfer_handle xfer;
1027 
1028 	xfer = kmem_zalloc(sizeof(struct usbd_xfer), KM_SLEEP);
1029 	xfer->busy_free = XFER_BUSY;
1030 
1031 	return xfer;
1032 }
1033 
1034 static void
1035 ugenhc_freex(struct usbd_bus *bus, struct usbd_xfer *xfer)
1036 {
1037 
1038 	kmem_free(xfer, sizeof(struct usbd_xfer));
1039 }
1040 
1041 struct ugenhc_pipe {
1042 	struct usbd_pipe pipe;
1043 };
1044 
1045 static const struct usbd_bus_methods ugenhc_bus_methods = {
1046 	.open_pipe =	ugenhc_open,
1047 	.soft_intr =	ugenhc_softint,
1048 	.do_poll =	ugenhc_poll,
1049 	.allocm = 	ugenhc_allocm,
1050 	.freem = 	ugenhc_freem,
1051 	.allocx = 	ugenhc_allocx,
1052 	.freex =	ugenhc_freex,
1053 };
1054 
1055 static int
1056 ugenhc_probe(struct device *parent, struct cfdata *match, void *aux)
1057 {
1058 	char buf[UGENDEV_BUFSIZE];
1059 	int error;
1060 
1061 	makeugendevstr(match->cf_unit, 0, buf);
1062 	if (rumpuser_getfileinfo(buf, NULL, NULL, &error) == -1)
1063 		return 0;
1064 
1065 	return 1;
1066 }
1067 
1068 static void
1069 ugenhc_attach(struct device *parent, struct device *self, void *aux)
1070 {
1071 	struct mainbus_attach_args *maa = aux;
1072 	struct ugenhc_softc *sc = device_private(self);
1073 
1074 	aprint_normal("\n");
1075 
1076 	memset(sc, 0, sizeof(*sc));
1077 	memset(&sc->sc_ugenfd, -1, sizeof(sc->sc_ugenfd));
1078 	memset(&sc->sc_fdmodes, -1, sizeof(sc->sc_fdmodes));
1079 
1080 	sc->sc_bus.usbrev = USBREV_2_0;
1081 	sc->sc_bus.methods = &ugenhc_bus_methods;
1082 	sc->sc_bus.hci_private = sc;
1083 	sc->sc_bus.pipe_size = sizeof(struct ugenhc_pipe);
1084 	sc->sc_devnum = maa->maa_unit;
1085 
1086 	config_found(self, &sc->sc_bus, usbctlprint);
1087 }
1088