Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / rump / dev / wip / librumpusbhc / rumpusbhc.c
blob694e9ed231656e670d9b2ced8867aa00f77300a0
1 /* $NetBSD: rumpusbhc.c,v 1.9 2009/12/15 15:50:37 pooka Exp $ */
3 /*
4 * Copyright (c) 2009 Antti Kantee. All Rights Reserved.
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.
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.
29 * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
30 * All rights reserved.
32 * This code is derived from software contributed to The NetBSD Foundation
33 * by Lennart Augustsson (lennart@augustsson.net) at
34 * Carlstedt Research & Technology.
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.
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.
59 * This rump driver attaches ugen as a kernel usb host controller.
60 * It's still somewhat under the hammer ....
63 #include <sys/cdefs.h>
64 __KERNEL_RCSID(0, "$NetBSD: rumpusbhc.c,v 1.9 2009/12/15 15:50:37 pooka Exp $");
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>
75 #include <dev/usb/usb.h>
76 #include <dev/usb/usbdi.h>
77 #include <dev/usb/usbdivar.h>
78 #include <dev/usb/usb_mem.h>
79 #include <dev/usb/usbroothub_subr.h>
81 #include <rump/rumpuser.h>
83 #include "rump_private.h"
84 #include "rump_dev_private.h"
86 #define UGEN_NEPTS 16
87 #define UGEN_EPT_CTRL 0 /* ugenx.00 is the control endpoint */
89 struct rumpusbhc_softc {
90 struct usbd_bus sc_bus;
91 int sc_devnum;
93 int sc_ugenfd[UGEN_NEPTS];
94 int sc_fdmodes[UGEN_NEPTS];
96 int sc_port_status;
97 int sc_port_change;
98 int sc_addr;
99 int sc_conf;
102 static const struct cfiattrdata usb_iattrdata = {
103 "usbus", 0, {
104 { NULL, NULL, 0 },
107 static const struct cfiattrdata *const rumpusbhc_attrs[] = {
108 &usb_iattrdata,
109 NULL,
112 static int rumpusbhc_probe(struct device *, struct cfdata *, void *);
113 static void rumpusbhc_attach(struct device *, struct device *, void *);
115 CFATTACH_DECL_NEW(rumpusbhc, sizeof(struct rumpusbhc_softc),
116 rumpusbhc_probe, rumpusbhc_attach, NULL, NULL);
117 CFDRIVER_DECL(rumpusbhc, DV_DULL, rumpusbhc_attrs);
119 struct cfparent rumpusbhcpar = {
120 "mainbus",
121 "mainbus",
122 DVUNIT_ANY
125 struct rusb_xfer {
126 struct usbd_xfer rusb_xfer;
127 int rusb_status; /* now this is a cheap trick */
129 #define RUSB(x) ((struct rusb_xfer *)x)
131 /* probe ugen0 through ugen3 */
132 struct cfdata rumpusbhc_cfdata[] = {
133 { "rumpusbhc", "rumpusbhc", 0, FSTATE_NOTFOUND, NULL, 0, &rumpusbhcpar},
134 { "rumpusbhc", "rumpusbhc", 1, FSTATE_NOTFOUND, NULL, 0, &rumpusbhcpar},
135 { "rumpusbhc", "rumpusbhc", 2, FSTATE_NOTFOUND, NULL, 0, &rumpusbhcpar},
136 { "rumpusbhc", "rumpusbhc", 3, FSTATE_NOTFOUND, NULL, 0, &rumpusbhcpar},
139 #define UGENDEV_BASESTR "/dev/ugen"
140 #define UGENDEV_BUFSIZE 32
141 static void
142 makeugendevstr(int devnum, int endpoint, char *buf)
145 CTASSERT(UGENDEV_BUFSIZE > sizeof(UGENDEV_BASESTR)+sizeof("0.00")+1);
146 sprintf(buf, "%s%d.%02d", UGENDEV_BASESTR, devnum, endpoint);
150 * Our fictional hubbie.
153 static const usb_device_descriptor_t rumphub_udd = {
154 .bLength = USB_DEVICE_DESCRIPTOR_SIZE,
155 .bDescriptorType = UDESC_DEVICE,
156 .bDeviceClass = UDCLASS_HUB,
157 .bDeviceSubClass = UDSUBCLASS_HUB,
158 .bDeviceProtocol = UDPROTO_FSHUB,
159 .bMaxPacketSize = 64,
160 .bNumConfigurations = 1,
163 static const usb_config_descriptor_t rumphub_ucd = {
164 .bLength = USB_CONFIG_DESCRIPTOR_SIZE,
165 .bDescriptorType = UDESC_CONFIG,
166 .wTotalLength = { USB_CONFIG_DESCRIPTOR_SIZE
167 + USB_INTERFACE_DESCRIPTOR_SIZE
168 + USB_ENDPOINT_DESCRIPTOR_SIZE },
169 .bNumInterface = 1,
170 .bmAttributes = UC_SELF_POWERED | UC_ATTR_MBO,
172 /* XXX: spec says UC_ATTR_MBO is reserved and set to one. required? */
174 static const usb_interface_descriptor_t rumphub_uid = {
175 .bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
176 .bDescriptorType = UDESC_INTERFACE,
177 .bInterfaceNumber = 0,
178 .bNumEndpoints = 1,
179 .bInterfaceClass = UICLASS_HUB,
180 .bInterfaceSubClass = UISUBCLASS_HUB,
181 .bInterfaceProtocol = UIPROTO_FSHUB,
184 static const usb_endpoint_descriptor_t rumphub_epd = {
185 .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
186 .bDescriptorType = UDESC_ENDPOINT,
187 .bmAttributes = UE_INTERRUPT,
188 .wMaxPacketSize = {64, 0},
191 static const usb_hub_descriptor_t rumphub_hdd = {
192 .bDescLength = USB_HUB_DESCRIPTOR_SIZE,
193 .bDescriptorType = UDESC_HUB,
194 .bNbrPorts = 1,
197 static usbd_status
198 rumpusb_root_ctrl_start(usbd_xfer_handle xfer)
200 usb_device_request_t *req = &xfer->request;
201 struct rumpusbhc_softc *sc = xfer->pipe->device->bus->hci_private;
202 int len, totlen, value, curlen, err;
203 uint8_t *buf = NULL;
205 len = totlen = UGETW(req->wLength);
206 if (len)
207 buf = KERNADDR(&xfer->dmabuf, 0);
208 value = UGETW(req->wValue);
210 #define C(x,y) ((x) | ((y) << 8))
211 switch(C(req->bRequest, req->bmRequestType)) {
213 case C(UR_GET_CONFIG, UT_READ_DEVICE):
214 if (len > 0) {
215 *buf = sc->sc_conf;
216 totlen = 1;
218 break;
220 case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
221 switch (value >> 8) {
222 case UDESC_DEVICE:
223 totlen = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
224 memcpy(buf, &rumphub_udd, totlen);
225 break;
227 case UDESC_CONFIG:
228 totlen = 0;
229 curlen = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
230 memcpy(buf, &rumphub_ucd, curlen);
231 len -= curlen;
232 buf += curlen;
233 totlen += curlen;
235 curlen = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
236 memcpy(buf, &rumphub_uid, curlen);
237 len -= curlen;
238 buf += curlen;
239 totlen += curlen;
241 curlen = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
242 memcpy(buf, &rumphub_epd, curlen);
243 len -= curlen;
244 buf += curlen;
245 totlen += curlen;
246 break;
248 case UDESC_STRING:
249 #define sd ((usb_string_descriptor_t *)buf)
250 switch (value & 0xff) {
251 case 0: /* Language table */
252 totlen = usb_makelangtbl(sd, len);
253 break;
254 case 1: /* Vendor */
255 totlen = usb_makestrdesc(sd, len, "rod nevada");
256 break;
257 case 2: /* Product */
258 totlen = usb_makestrdesc(sd, len,
259 "RUMPUSBHC root hub");
260 break;
262 #undef sd
263 break;
265 default:
266 panic("unhandled read device request");
267 break;
269 break;
271 case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
272 if (value >= USB_MAX_DEVICES) {
273 err = USBD_IOERROR;
274 goto ret;
276 sc->sc_addr = value;
277 break;
279 case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
280 if (value != 0 && value != 1) {
281 err = USBD_IOERROR;
282 goto ret;
284 sc->sc_conf = value;
285 break;
287 case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
288 switch (value) {
289 case UHF_PORT_RESET:
290 sc->sc_port_change |= UPS_C_PORT_RESET;
291 break;
292 case UHF_PORT_POWER:
293 break;
294 default:
295 panic("unhandled");
297 break;
299 case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
300 sc->sc_port_change &= ~value;
301 break;
303 case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
304 totlen = min(len, USB_HUB_DESCRIPTOR_SIZE);
305 memcpy(buf, &rumphub_hdd, totlen);
306 break;
308 case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
309 /* huh? other hc's do this */
310 memset(buf, 0, len);
311 totlen = len;
312 break;
314 case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
316 usb_port_status_t ps;
318 USETW(ps.wPortStatus, sc->sc_port_status);
319 USETW(ps.wPortChange, sc->sc_port_change);
320 totlen = min(len, sizeof(ps));
321 memcpy(buf, &ps, totlen);
322 break;
325 default:
326 panic("unhandled request");
327 break;
329 err = USBD_NORMAL_COMPLETION;
330 xfer->actlen = totlen;
332 ret:
333 xfer->status = err;
334 usb_transfer_complete(xfer);
335 return (USBD_IN_PROGRESS);
338 static usbd_status
339 rumpusb_root_ctrl_transfer(usbd_xfer_handle xfer)
341 usbd_status err;
343 err = usb_insert_transfer(xfer);
344 if (err)
345 return (err);
347 return (rumpusb_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
350 static void
351 rumpusb_root_ctrl_abort(usbd_xfer_handle xfer)
356 static void
357 rumpusb_root_ctrl_close(usbd_pipe_handle pipe)
362 static void
363 rumpusb_root_ctrl_cleartoggle(usbd_pipe_handle pipe)
368 static void
369 rumpusb_root_ctrl_done(usbd_xfer_handle xfer)
374 static const struct usbd_pipe_methods rumpusb_root_ctrl_methods = {
375 .transfer = rumpusb_root_ctrl_transfer,
376 .start = rumpusb_root_ctrl_start,
377 .abort = rumpusb_root_ctrl_abort,
378 .close = rumpusb_root_ctrl_close,
379 .cleartoggle = rumpusb_root_ctrl_cleartoggle,
380 .done = rumpusb_root_ctrl_done,
383 static usbd_status
384 rumpusb_device_ctrl_start(usbd_xfer_handle xfer)
386 usb_device_request_t *req = &xfer->request;
387 struct rumpusbhc_softc *sc = xfer->pipe->device->bus->hci_private;
388 uint8_t *buf = NULL;
389 int len, totlen;
390 int value;
391 int err = 0;
392 int ru_error;
394 len = totlen = UGETW(req->wLength);
395 if (len)
396 buf = KERNADDR(&xfer->dmabuf, 0);
397 value = UGETW(req->wValue);
399 #define C(x,y) ((x) | ((y) << 8))
400 switch(C(req->bRequest, req->bmRequestType)) {
401 case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
402 switch (value>>8) {
403 case UDESC_DEVICE:
405 usb_device_descriptor_t uddesc;
406 totlen = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
407 memset(buf, 0, totlen);
408 if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
409 USB_GET_DEVICE_DESC, &uddesc, &ru_error) == -1)
410 panic("%d", ru_error);
411 memcpy(buf, &uddesc, totlen);
414 break;
415 case UDESC_CONFIG:
417 struct usb_full_desc ufdesc;
418 ufdesc.ufd_config_index = 0;
419 ufdesc.ufd_size = len;
420 ufdesc.ufd_data = buf;
421 memset(buf, 0, totlen);
422 if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
423 USB_GET_FULL_DESC, &ufdesc, &ru_error) == -1)
424 panic("%d", ru_error);
425 totlen = len;
427 break;
429 case UDESC_STRING:
431 struct usb_device_info udi;
433 if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
434 USB_GET_DEVICEINFO, &udi, &ru_error) == -1) {
435 printf("rumpusbhc: get dev info failed: %d\n",
436 ru_error);
437 err = USBD_IOERROR;
438 goto ret;
441 switch (value & 0xff) {
442 #define sd ((usb_string_descriptor_t *)buf)
443 case 0: /* language table */
444 break;
445 case 1: /* vendor */
446 totlen = usb_makestrdesc(sd, len,
447 udi.udi_vendor);
448 break;
449 case 2: /* product */
450 totlen = usb_makestrdesc(sd, len,
451 udi.udi_product);
452 break;
454 #undef sd
456 break;
458 default:
459 panic("not handled");
461 break;
463 case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
464 /* ignored, ugen won't let us */
465 break;
467 case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
468 /* ignored, ugen won't let us .... REALLY? */
469 break;
471 case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
473 struct usb_alt_interface uai;
475 totlen = 0;
476 uai.uai_interface_index = UGETW(req->wIndex);
477 uai.uai_alt_no = value;
478 if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
479 USB_SET_ALTINTERFACE, &uai, &ru_error) == -1) {
480 printf("rumpusbhc: set alt interface failed: %d\n",
481 ru_error);
482 err = USBD_IOERROR;
483 goto ret;
485 break;
489 * XXX: don't wildcard these yet. I want to better figure
490 * out what to trap here. This is kinda silly, though ...
492 case C(0x01, UT_WRITE_VENDOR_DEVICE):
493 case C(0x06, UT_WRITE_VENDOR_DEVICE):
494 case C(0x07, UT_READ_VENDOR_DEVICE):
495 case C(0x09, UT_READ_VENDOR_DEVICE):
496 case C(0xfe, UT_READ_CLASS_INTERFACE):
497 case C(0x01, UT_READ_CLASS_INTERFACE):
498 case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
499 case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
500 case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
501 case C(0xff, UT_WRITE_CLASS_INTERFACE):
502 case C(0x20, UT_WRITE_CLASS_INTERFACE):
503 case C(0x22, UT_WRITE_CLASS_INTERFACE):
504 case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
505 case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
506 case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
508 struct usb_ctl_request ucr;
510 memcpy(&ucr.ucr_request, req, sizeof(ucr.ucr_request));
511 ucr.ucr_data = buf;
512 if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
513 USB_DO_REQUEST, &ucr, &ru_error) == -1) {
514 panic("request failed");
517 break;
519 default:
520 panic("unhandled request");
521 break;
523 xfer->actlen = totlen;
524 err = USBD_NORMAL_COMPLETION;
526 ret:
527 xfer->status = err;
528 usb_transfer_complete(xfer);
529 return (USBD_IN_PROGRESS);
532 static usbd_status
533 rumpusb_device_ctrl_transfer(usbd_xfer_handle xfer)
535 usbd_status err;
537 err = usb_insert_transfer(xfer);
538 if (err)
539 return (err);
541 return (rumpusb_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
544 static void
545 rumpusb_device_ctrl_abort(usbd_xfer_handle xfer)
550 static void
551 rumpusb_device_ctrl_close(usbd_pipe_handle pipe)
556 static void
557 rumpusb_device_ctrl_cleartoggle(usbd_pipe_handle pipe)
562 static void
563 rumpusb_device_ctrl_done(usbd_xfer_handle xfer)
568 static const struct usbd_pipe_methods rumpusb_device_ctrl_methods = {
569 .transfer = rumpusb_device_ctrl_transfer,
570 .start = rumpusb_device_ctrl_start,
571 .abort = rumpusb_device_ctrl_abort,
572 .close = rumpusb_device_ctrl_close,
573 .cleartoggle = rumpusb_device_ctrl_cleartoggle,
574 .done = rumpusb_device_ctrl_done,
577 struct intrent {
578 usbd_xfer_handle xfer;
579 LIST_ENTRY(intrent) entries;
582 static LIST_HEAD(, intrent) intrlist = LIST_HEAD_INITIALIZER(intrlist);
584 static void
585 rhscintr(void)
587 struct intrent *ie, *ie_next;
588 usbd_xfer_handle xfer;
590 for (ie = LIST_FIRST(&intrlist); ie; ie = ie_next) {
591 xfer = ie->xfer;
592 xfer->actlen = xfer->length;
593 xfer->status = USBD_NORMAL_COMPLETION;
594 usb_transfer_complete(xfer);
596 ie_next = LIST_NEXT(ie, entries);
597 LIST_REMOVE(ie, entries);
598 kmem_free(ie, sizeof(*ie));
602 static usbd_status
603 rumpusb_root_intr_start(usbd_xfer_handle xfer)
605 struct intrent *ie;
607 ie = kmem_alloc(sizeof(*ie), KM_SLEEP);
608 ie->xfer = xfer;
609 LIST_INSERT_HEAD(&intrlist, ie, entries);
611 return (USBD_IN_PROGRESS);
614 static usbd_status
615 rumpusb_root_intr_transfer(usbd_xfer_handle xfer)
617 usbd_status err;
619 err = usb_insert_transfer(xfer);
620 if (err)
621 return (err);
623 return (rumpusb_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
626 static void
627 rumpusb_root_intr_abort(usbd_xfer_handle xfer)
632 static void
633 rumpusb_root_intr_close(usbd_pipe_handle pipe)
638 static void
639 rumpusb_root_intr_cleartoggle(usbd_pipe_handle pipe)
644 static void
645 rumpusb_root_intr_done(usbd_xfer_handle xfer)
650 static const struct usbd_pipe_methods rumpusb_root_intr_methods = {
651 .transfer = rumpusb_root_intr_transfer,
652 .start = rumpusb_root_intr_start,
653 .abort = rumpusb_root_intr_abort,
654 .close = rumpusb_root_intr_close,
655 .cleartoggle = rumpusb_root_intr_cleartoggle,
656 .done = rumpusb_root_intr_done,
659 static usbd_status
660 rumpusb_device_bulk_start(usbd_xfer_handle xfer)
662 struct rumpusbhc_softc *sc = xfer->pipe->device->bus->hci_private;
663 ssize_t n;
664 ssize_t done;
665 bool isread;
666 int len, error, endpt;
667 uint8_t *buf;
668 int xfererr = 0;
669 int val;
671 endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
672 isread = UE_GET_DIR(endpt) == UE_DIR_IN;
673 endpt = UE_GET_ADDR(endpt);
674 KASSERT(endpt < UGEN_NEPTS);
676 KASSERT(xfer->length);
677 len = xfer->length;
678 buf = KERNADDR(&xfer->dmabuf, 0);
679 done = 0;
681 while (RUSB(xfer)->rusb_status == 0) {
682 if (isread) {
683 if (xfer->flags & USBD_SHORT_XFER_OK)
684 val = 1;
685 else
686 val = 0;
687 rumpuser_ioctl(sc->sc_ugenfd[endpt],
688 USB_SET_SHORT_XFER, &val, &error);
689 n = rumpuser_read(sc->sc_ugenfd[endpt],
690 buf+done, len-done, &error);
691 if (n == -1) {
692 if (error == ETIMEDOUT)
693 continue;
694 n = 0;
695 xfer->status = USBD_IOERROR;
696 goto out;
698 done += n;
699 if (done == len)
700 break;
701 } else {
702 n = rumpuser_write(sc->sc_ugenfd[endpt],
703 buf, len, &error);
704 done = n;
705 if (done == len)
706 break;
707 else
708 panic("short write");
711 if (xfer->flags & USBD_SHORT_XFER_OK)
712 break;
715 if (RUSB(xfer)->rusb_status == 0) {
716 xfer->actlen = done;
717 xfer->status = USBD_NORMAL_COMPLETION;
718 /* override */
719 if (xfererr) {
720 printf("err!\n");
721 xfer->status = xfererr;
723 } else {
724 xfer->status = USBD_CANCELLED;
725 RUSB(xfer)->rusb_status = 2;
727 out:
728 val = 0;
729 rumpuser_ioctl(sc->sc_ugenfd[endpt], USB_SET_SHORT_XFER, &val, &error);
730 usb_transfer_complete(xfer);
731 return (USBD_IN_PROGRESS);
734 static void
735 doxfer_kth(void *arg)
737 usbd_xfer_handle xfer = arg;
739 rumpusb_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
740 kthread_exit(0);
743 static usbd_status
744 rumpusb_device_bulk_transfer(usbd_xfer_handle xfer)
746 usbd_status err;
748 if (!rump_threads) {
749 /* XXX: lie about supporting async transfers */
750 if ((xfer->flags & USBD_SYNCHRONOUS) == 0) {
751 printf("non-threaded rump does not support "
752 "async transfers.\n");
753 return USBD_IN_PROGRESS;
756 err = usb_insert_transfer(xfer);
757 if (err)
758 return err;
760 return rumpusb_device_bulk_start(
761 SIMPLEQ_FIRST(&xfer->pipe->queue));
762 } else {
763 /* biglocked */
764 err = usb_insert_transfer(xfer);
765 if (err)
766 return err;
767 kthread_create(PRI_NONE, 0, NULL, doxfer_kth, xfer, NULL,
768 "rusbhcxf");
770 return USBD_IN_PROGRESS;
774 /* wait for transfer to abort. yea, this is cheesy (from a spray can) */
775 static void
776 rumpusb_device_bulk_abort(usbd_xfer_handle xfer)
778 struct rusb_xfer *rx = RUSB(xfer);
780 rx->rusb_status = 1;
781 while (rx->rusb_status < 2) {
782 kpause("jopo", false, hz/10, NULL);
786 static void
787 rumpusb_device_bulk_close(usbd_pipe_handle pipe)
792 static void
793 rumpusb_device_bulk_cleartoggle(usbd_pipe_handle pipe)
798 static void
799 rumpusb_device_bulk_done(usbd_xfer_handle xfer)
804 static const struct usbd_pipe_methods rumpusb_device_bulk_methods = {
805 .transfer = rumpusb_device_bulk_transfer,
806 .start = rumpusb_device_bulk_start,
807 .abort = rumpusb_device_bulk_abort,
808 .close = rumpusb_device_bulk_close,
809 .cleartoggle = rumpusb_device_bulk_cleartoggle,
810 .done = rumpusb_device_bulk_done,
813 static const struct usbd_pipe_methods rumpusb_device_intr_methods = {
814 .transfer = rumpusb_root_intr_transfer,
815 .start = rumpusb_root_intr_start,
816 .abort = rumpusb_root_intr_abort,
817 .close = rumpusb_root_intr_close,
818 .cleartoggle = rumpusb_root_intr_cleartoggle,
819 .done = rumpusb_root_intr_done,
822 static usbd_status
823 rumpusbhc_open(struct usbd_pipe *pipe)
825 usbd_device_handle dev = pipe->device;
826 struct rumpusbhc_softc *sc = dev->bus->hci_private;
827 usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
828 u_int8_t addr = dev->address;
829 u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
830 char buf[UGENDEV_BUFSIZE];
831 int endpt, oflags, error;
832 int fd, val;
834 sc->sc_port_status = UPS_CURRENT_CONNECT_STATUS
835 | UPS_PORT_ENABLED | UPS_PORT_POWER;
836 sc->sc_port_change = UPS_C_CONNECT_STATUS;
838 if (addr == sc->sc_addr) {
839 switch (xfertype) {
840 case UE_CONTROL:
841 pipe->methods = &rumpusb_root_ctrl_methods;
842 break;
843 case UE_INTERRUPT:
844 pipe->methods = &rumpusb_root_intr_methods;
845 break;
846 default:
847 panic("%d not supported", xfertype);
848 break;
850 } else {
851 switch (xfertype) {
852 case UE_CONTROL:
853 pipe->methods = &rumpusb_device_ctrl_methods;
854 break;
855 case UE_BULK:
856 case UE_INTERRUPT:
857 endpt = pipe->endpoint->edesc->bEndpointAddress;
858 if (UE_GET_DIR(endpt) == UE_DIR_IN) {
859 oflags = O_RDONLY;
860 } else {
861 oflags = O_WRONLY;
863 endpt = UE_GET_ADDR(endpt);
864 pipe->methods = &rumpusb_device_bulk_methods;
866 if (sc->sc_fdmodes[endpt] == oflags
867 || sc->sc_fdmodes[endpt] == O_RDWR)
868 break;
870 if (sc->sc_fdmodes[endpt] != -1) {
871 /* XXX: closing from under someone? */
872 rumpuser_close(sc->sc_ugenfd[endpt], &error);
873 oflags = O_RDWR;
876 makeugendevstr(sc->sc_devnum, endpt, buf);
877 fd = rumpuser_open(buf, oflags, &error);
878 if (fd == -1)
879 return USBD_INVAL; /* XXX: no mapping */
880 val = 100;
881 if (rumpuser_ioctl(fd, USB_SET_TIMEOUT, &val,
882 &error) == -1)
883 panic("timeout set failed");
884 sc->sc_ugenfd[endpt] = fd;
885 sc->sc_fdmodes[endpt] = oflags;
886 break;
887 default:
888 panic("%d not supported", xfertype);
889 break;
893 return 0;
896 static void
897 rumpusbhc_softint(void *arg)
902 static void
903 rumpusbhc_poll(struct usbd_bus *ubus)
908 static usbd_status
909 rumpusbhc_allocm(struct usbd_bus *bus, usb_dma_t *dma, uint32_t size)
911 struct rumpusbhc_softc *sc = bus->hci_private;
913 return usb_allocmem(&sc->sc_bus, size, 0, dma);
916 static void
917 rumpusbhc_freem(struct usbd_bus *ubus, usb_dma_t *udma)
922 static struct usbd_xfer *
923 rumpusbhc_allocx(struct usbd_bus *bus)
925 usbd_xfer_handle xfer;
927 xfer = kmem_zalloc(sizeof(struct usbd_xfer), KM_SLEEP);
928 xfer->busy_free = XFER_BUSY;
930 return xfer;
933 static void
934 rumpusbhc_freex(struct usbd_bus *bus, struct usbd_xfer *xfer)
937 kmem_free(xfer, sizeof(struct usbd_xfer));
940 struct rumpusbhc_pipe {
941 struct usbd_pipe pipe;
944 static const struct usbd_bus_methods rumpusbhc_bus_methods = {
945 .open_pipe = rumpusbhc_open,
946 .soft_intr = rumpusbhc_softint,
947 .do_poll = rumpusbhc_poll,
948 .allocm = rumpusbhc_allocm,
949 .freem = rumpusbhc_freem,
950 .allocx = rumpusbhc_allocx,
951 .freex = rumpusbhc_freex,
954 void
955 rump_dev_rumpusbhc_init()
957 int error;
959 error = config_cfdriver_attach(&rumpusbhc_cd);
960 if (error)
961 panic("rumpusbhc cfdriver attach failed: %d", error);
962 error = config_cfattach_attach("rumpusbhc", &rumpusbhc_ca);
963 if (error)
964 panic("rumpusbhc cfattach attach failed: %d", error);
965 error = config_cfdata_attach(rumpusbhc_cfdata, 0);
966 if (error)
967 panic("rumpusbhc cfdata attach failed: %d", error);
970 static int
971 rumpusbhc_probe(struct device *parent, struct cfdata *match, void *aux)
973 char buf[UGENDEV_BUFSIZE];
974 int fd, error;
976 makeugendevstr(match->cf_unit, 0, buf);
977 fd = rumpuser_open(buf, O_RDWR, &error);
978 if (fd == -1)
979 return 0;
981 rumpuser_close(fd, &error);
982 return 1;
985 static void
986 rumpusbhc_attach(struct device *parent, struct device *self, void *aux)
988 struct mainbus_attach_args *maa = aux;
989 struct rumpusbhc_softc *sc = device_private(self);
990 char buf[UGENDEV_BUFSIZE];
991 int error;
993 aprint_normal("\n");
995 memset(sc, 0, sizeof(*sc));
996 memset(&sc->sc_ugenfd, -1, sizeof(sc->sc_ugenfd));
997 memset(&sc->sc_fdmodes, -1, sizeof(sc->sc_fdmodes));
999 sc->sc_bus.usbrev = USBREV_2_0;
1000 sc->sc_bus.methods = &rumpusbhc_bus_methods;
1001 sc->sc_bus.hci_private = sc;
1002 sc->sc_bus.pipe_size = sizeof(struct rumpusbhc_pipe);
1003 sc->sc_devnum = maa->maa_unit;
1005 makeugendevstr(sc->sc_devnum, 0, buf);
1006 sc->sc_ugenfd[UGEN_EPT_CTRL] = rumpuser_open(buf, O_RDWR, &error);
1007 if (error)
1008 panic("rumpusbhc_attach: failed to open ctrl ept %s\n", buf);
1010 config_found(self, &sc->sc_bus, usbctlprint);
1012 /* whoah, like extreme XXX, bro */
1013 rhscintr();
1014 if (!rump_threads)
1015 config_pending_decr();