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