xref: /netbsd-src/sys/rump/dev/lib/libugenhc/ugenhc.c (revision 4e6df137e8e14049b5a701d249962c480449c141)
1 /*	$NetBSD: ugenhc.c,v 1.8 2010/02/23 14:05:04 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.8 2010/02/23 14:05:04 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(UR_SET_FEATURE, UT_WRITE_DEVICE):
510 	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
511 	case C(UR_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
512 	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
513 		{
514 		struct usb_ctl_request ucr;
515 
516 		memcpy(&ucr.ucr_request, req, sizeof(ucr.ucr_request));
517 		ucr.ucr_data = buf;
518 		if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
519 		    USB_DO_REQUEST, &ucr, &ru_error) == -1) {
520 			if (!mightfail) {
521 				panic("request failed: %d", ru_error);
522 			} else {
523 				err = ru_error;
524 			}
525 		}
526 		}
527 		break;
528 
529 	default:
530 		panic("unhandled request");
531 		break;
532 	}
533 	xfer->actlen = totlen;
534 	err = USBD_NORMAL_COMPLETION;
535 
536  ret:
537 	xfer->status = err;
538 	usb_transfer_complete(xfer);
539 	return (USBD_IN_PROGRESS);
540 }
541 
542 static usbd_status
543 rumpusb_device_ctrl_transfer(usbd_xfer_handle xfer)
544 {
545 	usbd_status err;
546 
547 	err = usb_insert_transfer(xfer);
548 	if (err)
549 		return (err);
550 
551 	return (rumpusb_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
552 }
553 
554 static void
555 rumpusb_device_ctrl_abort(usbd_xfer_handle xfer)
556 {
557 
558 }
559 
560 static void
561 rumpusb_device_ctrl_close(usbd_pipe_handle pipe)
562 {
563 
564 }
565 
566 static void
567 rumpusb_device_ctrl_cleartoggle(usbd_pipe_handle pipe)
568 {
569 
570 }
571 
572 static void
573 rumpusb_device_ctrl_done(usbd_xfer_handle xfer)
574 {
575 
576 }
577 
578 static const struct usbd_pipe_methods rumpusb_device_ctrl_methods = {
579 	.transfer =	rumpusb_device_ctrl_transfer,
580 	.start =	rumpusb_device_ctrl_start,
581 	.abort =	rumpusb_device_ctrl_abort,
582 	.close =	rumpusb_device_ctrl_close,
583 	.cleartoggle =	rumpusb_device_ctrl_cleartoggle,
584 	.done =		rumpusb_device_ctrl_done,
585 };
586 
587 static void
588 rhscintr(void *arg)
589 {
590 	char buf[UGENDEV_BUFSIZE];
591 	struct ugenhc_softc *sc = arg;
592 	usbd_xfer_handle xfer;
593 	int fd, error;
594 
595 	makeugendevstr(sc->sc_devnum, 0, buf);
596 
597 	for (;;) {
598 		/*
599 		 * Detect device attach.
600 		 */
601 
602 		for (;;) {
603 			fd = rumpuser_open(buf, O_RDWR, &error);
604 			if (fd != -1)
605 				break;
606 			kpause("ugwait", false, hz/4, NULL);
607 		}
608 
609 		sc->sc_ugenfd[UGEN_EPT_CTRL] = fd;
610 		sc->sc_port_status = UPS_CURRENT_CONNECT_STATUS
611 		    | UPS_PORT_ENABLED | UPS_PORT_POWER;
612 		sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET;
613 
614 		xfer = sc->sc_intrxfer;
615 		memset(xfer->buffer, 0xff, xfer->length);
616 		xfer->actlen = xfer->length;
617 		xfer->status = USBD_NORMAL_COMPLETION;
618 
619 		usb_transfer_complete(xfer);
620 
621 		kpause("ugwait2", false, hz, NULL);
622 
623 		/*
624 		 * Detect device detach.
625 		 */
626 
627 		for (;;) {
628 			fd = rumpuser_open(buf, O_RDWR, &error);
629 			if (fd == -1)
630 				break;
631 
632 			rumpuser_close(fd, &error);
633 			kpause("ugwait2", false, hz/4, NULL);
634 		}
635 
636 		sc->sc_port_status = ~(UPS_CURRENT_CONNECT_STATUS
637 		    | UPS_PORT_ENABLED | UPS_PORT_POWER);
638 		sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET;
639 
640 		rumpuser_close(sc->sc_ugenfd[UGEN_EPT_CTRL], &error);
641 		sc->sc_ugenfd[UGEN_EPT_CTRL] = -1;
642 
643 		xfer = sc->sc_intrxfer;
644 		memset(xfer->buffer, 0xff, xfer->length);
645 		xfer->actlen = xfer->length;
646 		xfer->status = USBD_NORMAL_COMPLETION;
647 		usb_transfer_complete(xfer);
648 
649 		kpause("ugwait3", false, hz, NULL);
650 	}
651 
652 	kthread_exit(0);
653 }
654 
655 static usbd_status
656 rumpusb_root_intr_start(usbd_xfer_handle xfer)
657 {
658 	struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private;
659 	int error;
660 
661 	sc->sc_intrxfer = xfer;
662 	if (!sc->sc_rhintr) {
663 		error = kthread_create(PRI_NONE, 0, NULL,
664 		    rhscintr, sc, &sc->sc_rhintr, "ugenrhi");
665 		if (error)
666 			xfer->status = error;
667 	}
668 
669 	return (USBD_IN_PROGRESS);
670 }
671 
672 static usbd_status
673 rumpusb_root_intr_transfer(usbd_xfer_handle xfer)
674 {
675 	usbd_status err;
676 
677 	err = usb_insert_transfer(xfer);
678 	if (err)
679 		return (err);
680 
681 	return (rumpusb_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
682 }
683 
684 static void
685 rumpusb_root_intr_abort(usbd_xfer_handle xfer)
686 {
687 
688 }
689 
690 static void
691 rumpusb_root_intr_close(usbd_pipe_handle pipe)
692 {
693 
694 }
695 
696 static void
697 rumpusb_root_intr_cleartoggle(usbd_pipe_handle pipe)
698 {
699 
700 }
701 
702 static void
703 rumpusb_root_intr_done(usbd_xfer_handle xfer)
704 {
705 
706 }
707 
708 static const struct usbd_pipe_methods rumpusb_root_intr_methods = {
709 	.transfer =	rumpusb_root_intr_transfer,
710 	.start =	rumpusb_root_intr_start,
711 	.abort =	rumpusb_root_intr_abort,
712 	.close =	rumpusb_root_intr_close,
713 	.cleartoggle =	rumpusb_root_intr_cleartoggle,
714 	.done =		rumpusb_root_intr_done,
715 };
716 
717 static usbd_status
718 rumpusb_device_bulk_start(usbd_xfer_handle xfer)
719 {
720 	struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private;
721 	ssize_t n;
722 	ssize_t done;
723 	bool isread;
724 	int len, error, endpt;
725 	uint8_t *buf;
726 	int xfererr = USBD_NORMAL_COMPLETION;
727 	int val;
728 
729 	endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
730 	isread = UE_GET_DIR(endpt) == UE_DIR_IN;
731 	endpt = UE_GET_ADDR(endpt);
732 	KASSERT(endpt < UGEN_NEPTS);
733 
734 	KASSERT(xfer->length);
735 	len = xfer->length;
736 	buf = KERNADDR(&xfer->dmabuf, 0);
737 	done = 0;
738 
739 	while (RUSB(xfer)->rusb_status == 0) {
740 		if (isread) {
741 			if (xfer->flags & USBD_SHORT_XFER_OK)
742 				val = 1;
743 			else
744 				val = 0;
745 			rumpuser_ioctl(sc->sc_ugenfd[endpt],
746 			    USB_SET_SHORT_XFER, &val, &error);
747 			n = rumpuser_read(sc->sc_ugenfd[endpt],
748 			    buf+done, len-done, &error);
749 			if (n == -1) {
750 				if (error == ETIMEDOUT)
751 					continue;
752 				n = 0;
753 				xfererr = USBD_IOERROR;
754 				goto out;
755 			}
756 			done += n;
757 			if (done == len)
758 				break;
759 		} else {
760 			n = rumpuser_write(sc->sc_ugenfd[endpt],
761 			    buf, len, &error);
762 			done = n;
763 			if (done == len)
764 				break;
765 			else if (n != -1)
766 				panic("short write");
767 
768 			xfererr = USBD_IOERROR;
769 			goto out;
770 		}
771 
772 		if (xfer->flags & USBD_SHORT_XFER_OK)
773 			break;
774 	}
775 
776 	if (RUSB(xfer)->rusb_status == 0) {
777 		xfer->actlen = done;
778 	} else {
779 		xfererr = USBD_CANCELLED;
780 		RUSB(xfer)->rusb_status = 2;
781 	}
782  out:
783 	xfer->status = xfererr;
784 	usb_transfer_complete(xfer);
785 	return (USBD_IN_PROGRESS);
786 }
787 
788 static void
789 doxfer_kth(void *arg)
790 {
791 	usbd_xfer_handle xfer = arg;
792 
793 	do {
794 		rumpusb_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
795 	} while (!SIMPLEQ_EMPTY(&xfer->pipe->queue));
796 	kthread_exit(0);
797 }
798 
799 static usbd_status
800 rumpusb_device_bulk_transfer(usbd_xfer_handle xfer)
801 {
802 	usbd_status err;
803 
804 	if (!rump_threads) {
805 		/* XXX: lie about supporting async transfers */
806 		if ((xfer->flags & USBD_SYNCHRONOUS) == 0) {
807 			printf("non-threaded rump does not support "
808 			    "async transfers.\n");
809 			return USBD_IN_PROGRESS;
810 		}
811 
812 		err = usb_insert_transfer(xfer);
813 		if (err)
814 			return err;
815 
816 		return rumpusb_device_bulk_start(
817 		    SIMPLEQ_FIRST(&xfer->pipe->queue));
818 	} else {
819 		/* biglocked */
820 		err = usb_insert_transfer(xfer);
821 		if (err)
822 			return err;
823 		kthread_create(PRI_NONE, 0, NULL, doxfer_kth, xfer, NULL,
824 		    "rusbhcxf");
825 
826 		return USBD_IN_PROGRESS;
827 	}
828 }
829 
830 /* wait for transfer to abort.  yea, this is cheesy (from a spray can) */
831 static void
832 rumpusb_device_bulk_abort(usbd_xfer_handle xfer)
833 {
834 	struct rusb_xfer *rx = RUSB(xfer);
835 
836 	rx->rusb_status = 1;
837 	while (rx->rusb_status < 2) {
838 		kpause("jopo", false, hz/10, NULL);
839 	}
840 }
841 
842 static void
843 rumpusb_device_bulk_close(usbd_pipe_handle pipe)
844 {
845 	struct ugenhc_softc *sc = pipe->device->bus->hci_private;
846 	int endpt = pipe->endpoint->edesc->bEndpointAddress;
847 	usbd_xfer_handle xfer;
848 	int error;
849 
850 	endpt = UE_GET_ADDR(endpt);
851 
852 	while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL)
853 		rumpusb_device_bulk_abort(xfer);
854 
855 	rumpuser_close(sc->sc_ugenfd[endpt], &error);
856 	sc->sc_ugenfd[endpt] = -1;
857 	sc->sc_fdmodes[endpt] = -1;
858 }
859 
860 static void
861 rumpusb_device_bulk_cleartoggle(usbd_pipe_handle pipe)
862 {
863 
864 }
865 
866 static void
867 rumpusb_device_bulk_done(usbd_xfer_handle xfer)
868 {
869 
870 }
871 
872 static const struct usbd_pipe_methods rumpusb_device_bulk_methods = {
873 	.transfer =	rumpusb_device_bulk_transfer,
874 	.start =	rumpusb_device_bulk_start,
875 	.abort =	rumpusb_device_bulk_abort,
876 	.close =	rumpusb_device_bulk_close,
877 	.cleartoggle =	rumpusb_device_bulk_cleartoggle,
878 	.done =		rumpusb_device_bulk_done,
879 };
880 
881 static const struct usbd_pipe_methods rumpusb_device_intr_methods = {
882 	.transfer =	rumpusb_root_intr_transfer,
883 	.start =	rumpusb_root_intr_start,
884 	.abort =	rumpusb_root_intr_abort,
885 	.close =	rumpusb_root_intr_close,
886 	.cleartoggle =	rumpusb_root_intr_cleartoggle,
887 	.done =		rumpusb_root_intr_done,
888 };
889 
890 static usbd_status
891 ugenhc_open(struct usbd_pipe *pipe)
892 {
893 	usbd_device_handle dev = pipe->device;
894 	struct ugenhc_softc *sc = dev->bus->hci_private;
895 	usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
896 	u_int8_t addr = dev->address;
897 	u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
898 	char buf[UGENDEV_BUFSIZE];
899 	int endpt, oflags, error;
900 	int fd, val;
901 
902 	if (addr == sc->sc_addr) {
903 		switch (xfertype) {
904 		case UE_CONTROL:
905 			pipe->methods = &rumpusb_root_ctrl_methods;
906 			break;
907 		case UE_INTERRUPT:
908 			pipe->methods = &rumpusb_root_intr_methods;
909 			break;
910 		default:
911 			panic("%d not supported", xfertype);
912 			break;
913 		}
914 	} else {
915 		switch (xfertype) {
916 		case UE_CONTROL:
917 			pipe->methods = &rumpusb_device_ctrl_methods;
918 			break;
919 		case UE_INTERRUPT:
920 		case UE_BULK:
921 			pipe->methods = &rumpusb_device_bulk_methods;
922 			endpt = pipe->endpoint->edesc->bEndpointAddress;
923 			if (UE_GET_DIR(endpt) == UE_DIR_IN) {
924 				oflags = O_RDONLY;
925 			} else {
926 				oflags = O_WRONLY;
927 			}
928 			endpt = UE_GET_ADDR(endpt);
929 
930 			if (sc->sc_fdmodes[endpt] == oflags
931 			    || sc->sc_fdmodes[endpt] == O_RDWR)
932 				break;
933 
934 			if (sc->sc_fdmodes[endpt] != -1) {
935 				/* XXX: closing from under someone? */
936 				rumpuser_close(sc->sc_ugenfd[endpt], &error);
937 				oflags = O_RDWR;
938 			}
939 
940 			makeugendevstr(sc->sc_devnum, endpt, buf);
941 			fd = rumpuser_open(buf, oflags, &error);
942 			if (fd == -1)
943 				return USBD_INVAL; /* XXX: no mapping */
944 			val = 100;
945 			if (rumpuser_ioctl(fd, USB_SET_TIMEOUT, &val,
946 			    &error) == -1)
947 				panic("timeout set failed");
948 			sc->sc_ugenfd[endpt] = fd;
949 			sc->sc_fdmodes[endpt] = oflags;
950 			break;
951 		default:
952 			panic("%d not supported", xfertype);
953 			break;
954 
955 		}
956 	}
957 	return 0;
958 }
959 
960 static void
961 ugenhc_softint(void *arg)
962 {
963 
964 }
965 
966 static void
967 ugenhc_poll(struct usbd_bus *ubus)
968 {
969 
970 }
971 
972 static usbd_status
973 ugenhc_allocm(struct usbd_bus *bus, usb_dma_t *dma, uint32_t size)
974 {
975 	struct ugenhc_softc *sc = bus->hci_private;
976 
977 	return usb_allocmem(&sc->sc_bus, size, 0, dma);
978 }
979 
980 static void
981 ugenhc_freem(struct usbd_bus *bus, usb_dma_t *dma)
982 {
983 	struct ugenhc_softc *sc = bus->hci_private;
984 
985 	usb_freemem(&sc->sc_bus, dma);
986 }
987 
988 static struct usbd_xfer *
989 ugenhc_allocx(struct usbd_bus *bus)
990 {
991 	usbd_xfer_handle xfer;
992 
993 	xfer = kmem_zalloc(sizeof(struct usbd_xfer), KM_SLEEP);
994 	xfer->busy_free = XFER_BUSY;
995 
996 	return xfer;
997 }
998 
999 static void
1000 ugenhc_freex(struct usbd_bus *bus, struct usbd_xfer *xfer)
1001 {
1002 
1003 	kmem_free(xfer, sizeof(struct usbd_xfer));
1004 }
1005 
1006 struct ugenhc_pipe {
1007 	struct usbd_pipe pipe;
1008 };
1009 
1010 static const struct usbd_bus_methods ugenhc_bus_methods = {
1011 	.open_pipe =	ugenhc_open,
1012 	.soft_intr =	ugenhc_softint,
1013 	.do_poll =	ugenhc_poll,
1014 	.allocm = 	ugenhc_allocm,
1015 	.freem = 	ugenhc_freem,
1016 	.allocx = 	ugenhc_allocx,
1017 	.freex =	ugenhc_freex,
1018 };
1019 
1020 static int
1021 ugenhc_probe(struct device *parent, struct cfdata *match, void *aux)
1022 {
1023 	char buf[UGENDEV_BUFSIZE];
1024 	int error;
1025 
1026 	makeugendevstr(match->cf_unit, 0, buf);
1027 	if (rumpuser_getfileinfo(buf, NULL, NULL, &error) == -1)
1028 		return 0;
1029 
1030 	return 1;
1031 }
1032 
1033 static void
1034 ugenhc_attach(struct device *parent, struct device *self, void *aux)
1035 {
1036 	struct mainbus_attach_args *maa = aux;
1037 	struct ugenhc_softc *sc = device_private(self);
1038 
1039 	aprint_normal("\n");
1040 
1041 	memset(sc, 0, sizeof(*sc));
1042 	memset(&sc->sc_ugenfd, -1, sizeof(sc->sc_ugenfd));
1043 	memset(&sc->sc_fdmodes, -1, sizeof(sc->sc_fdmodes));
1044 
1045 	sc->sc_bus.usbrev = USBREV_2_0;
1046 	sc->sc_bus.methods = &ugenhc_bus_methods;
1047 	sc->sc_bus.hci_private = sc;
1048 	sc->sc_bus.pipe_size = sizeof(struct ugenhc_pipe);
1049 	sc->sc_devnum = maa->maa_unit;
1050 
1051 	config_found(self, &sc->sc_bus, usbctlprint);
1052 }
1053