Annotation of src/sys/rump/dev/lib/libugenhc/ugenhc.c, Revision 1.18
1.18 ! christos 1: /* $NetBSD: ugenhc.c,v 1.17 2014/03/13 01:38:11 pooka Exp $ */
1.1 pooka 2:
3: /*
1.7 pooka 4: * Copyright (c) 2009, 2010 Antti Kantee. All Rights Reserved.
1.1 pooka 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>
1.18 ! christos 64: __KERNEL_RCSID(0, "$NetBSD: ugenhc.c,v 1.17 2014/03/13 01:38:11 pooka Exp $");
1.1 pooka 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:
1.17 pooka 84: #include "ugenhc_user.h"
1.13 pooka 85:
1.1 pooka 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;
1.3 pooka 103:
104: struct lwp *sc_rhintr;
105: usbd_xfer_handle sc_intrxfer;
1.1 pooka 106: };
107:
1.12 chs 108: static int ugenhc_probe(device_t, cfdata_t, void *);
109: static void ugenhc_attach(device_t, device_t, void *);
1.1 pooka 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
1.18 ! christos 123: makeugendevstr(int devnum, int endpoint, char *buf, size_t len)
1.1 pooka 124: {
125:
126: CTASSERT(UGENDEV_BUFSIZE > sizeof(UGENDEV_BASESTR)+sizeof("0.00")+1);
1.18 ! christos 127: snprintf(buf, len, "%s%d.%02d", UGENDEV_BASESTR, devnum, endpoint);
1.1 pooka 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,
1.8 pooka 141: .idVendor = { 0x75, 0x72 },
142: .idProduct = { 0x70, 0x6d },
1.1 pooka 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;
1.10 mrg 317: /* XXX locking */
1.1 pooka 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);
1.13 pooka 392: if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
1.3 pooka 393: USB_GET_DEVICE_DESC, &uddesc, &ru_error) == -1) {
394: err = EIO;
395: goto ret;
396: }
1.1 pooka 397: memcpy(buf, &uddesc, totlen);
398: }
399:
400: break;
401: case UDESC_CONFIG:
402: {
403: struct usb_full_desc ufdesc;
1.7 pooka 404: ufdesc.ufd_config_index = value & 0xff;
1.1 pooka 405: ufdesc.ufd_size = len;
406: ufdesc.ufd_data = buf;
1.7 pooka 407: memset(buf, 0, len);
1.13 pooka 408: if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
1.7 pooka 409: USB_GET_FULL_DESC, &ufdesc, &ru_error) == -1) {
410: err = USBD_IOERROR;
411: goto ret;
412: }
413: totlen = ufdesc.ufd_size;
1.1 pooka 414: }
415: break;
416:
417: case UDESC_STRING:
418: {
419: struct usb_device_info udi;
420:
1.13 pooka 421: if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
1.1 pooka 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):
1.13 pooka 456: if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
1.7 pooka 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: }
1.1 pooka 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;
1.13 pooka 472: if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
1.1 pooka 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):
1.9 pooka 512: case C(0x00, UT_WRITE_CLASS_DEVICE):
1.2 pooka 513: case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
1.1 pooka 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;
1.13 pooka 522: if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
1.1 pooka 523: USB_DO_REQUEST, &ucr, &ru_error) == -1) {
1.2 pooka 524: if (!mightfail) {
1.1 pooka 525: panic("request failed: %d", ru_error);
1.2 pooka 526: } else {
1.1 pooka 527: err = ru_error;
1.2 pooka 528: }
1.1 pooka 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:
1.3 pooka 591: static void
592: rhscintr(void *arg)
593: {
594: char buf[UGENDEV_BUFSIZE];
595: struct ugenhc_softc *sc = arg;
1.1 pooka 596: usbd_xfer_handle xfer;
1.3 pooka 597: int fd, error;
598:
1.18 ! christos 599: makeugendevstr(sc->sc_devnum, 0, buf, sizeof(buf));
1.4 pooka 600:
1.3 pooka 601: for (;;) {
1.4 pooka 602: /*
603: * Detect device attach.
604: */
605:
606: for (;;) {
1.15 pooka 607: error = rumpuser_open(buf, RUMPUSER_OPEN_RDWR, &fd);
608: if (error != 0)
1.4 pooka 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;
1.7 pooka 616: sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET;
1.4 pooka 617:
618: xfer = sc->sc_intrxfer;
1.7 pooka 619: memset(xfer->buffer, 0xff, xfer->length);
620: xfer->actlen = xfer->length;
1.4 pooka 621: xfer->status = USBD_NORMAL_COMPLETION;
1.7 pooka 622:
1.4 pooka 623: usb_transfer_complete(xfer);
624:
1.7 pooka 625: kpause("ugwait2", false, hz, NULL);
626:
1.4 pooka 627: /*
628: * Detect device detach.
629: */
630:
631: for (;;) {
1.11 pooka 632: fd = rumpuser_open(buf, RUMPUSER_OPEN_RDWR, &error);
1.4 pooka 633: if (fd == -1)
634: break;
1.7 pooka 635:
1.15 pooka 636: error = rumpuser_close(fd);
1.4 pooka 637: kpause("ugwait2", false, hz/4, NULL);
638: }
1.1 pooka 639:
1.4 pooka 640: sc->sc_port_status = ~(UPS_CURRENT_CONNECT_STATUS
641: | UPS_PORT_ENABLED | UPS_PORT_POWER);
1.7 pooka 642: sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET;
1.5 pooka 643:
1.15 pooka 644: error = rumpuser_close(sc->sc_ugenfd[UGEN_EPT_CTRL]);
1.4 pooka 645: sc->sc_ugenfd[UGEN_EPT_CTRL] = -1;
1.1 pooka 646:
1.4 pooka 647: xfer = sc->sc_intrxfer;
1.7 pooka 648: memset(xfer->buffer, 0xff, xfer->length);
649: xfer->actlen = xfer->length;
1.4 pooka 650: xfer->status = USBD_NORMAL_COMPLETION;
651: usb_transfer_complete(xfer);
1.7 pooka 652:
653: kpause("ugwait3", false, hz, NULL);
1.4 pooka 654: }
1.1 pooka 655:
1.3 pooka 656: kthread_exit(0);
1.1 pooka 657: }
658:
659: static usbd_status
660: rumpusb_root_intr_start(usbd_xfer_handle xfer)
661: {
1.3 pooka 662: struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private;
663: int error;
1.1 pooka 664:
1.3 pooka 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: }
1.1 pooka 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;
1.9 pooka 725: usb_endpoint_descriptor_t *ed = xfer->pipe->endpoint->edesc;
1.15 pooka 726: size_t n, done;
1.1 pooka 727: bool isread;
728: int len, error, endpt;
729: uint8_t *buf;
1.6 pooka 730: int xfererr = USBD_NORMAL_COMPLETION;
1.9 pooka 731: int shortval, i;
1.1 pooka 732:
1.9 pooka 733: ed = xfer->pipe->endpoint->edesc;
734: endpt = ed->bEndpointAddress;
1.1 pooka 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;
1.9 pooka 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;
1.1 pooka 749:
750: while (RUSB(xfer)->rusb_status == 0) {
751: if (isread) {
1.14 pooka 752: struct rumpuser_iovec iov;
753:
1.13 pooka 754: rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[endpt],
1.9 pooka 755: USB_SET_SHORT_XFER, &shortval, &error);
1.14 pooka 756: iov.iov_base = buf+done;
757: iov.iov_len = len-done;
1.15 pooka 758: error = rumpuser_iovread(sc->sc_ugenfd[endpt], &iov, 1,
759: RUMPUSER_IOV_NOSEEK, &n);
760: if (error) {
1.1 pooka 761: n = 0;
1.9 pooka 762: if (done == 0) {
763: if (error == ETIMEDOUT)
764: continue;
765: xfererr = USBD_IOERROR;
766: goto out;
767: }
1.1 pooka 768: }
769: done += n;
770: if (done == len)
771: break;
772: } else {
1.14 pooka 773: struct rumpuser_iovec iov;
774:
775: iov.iov_base = buf;
776: iov.iov_len = len;
1.15 pooka 777: error = rumpuser_iovwrite(sc->sc_ugenfd[endpt], &iov, 1,
778: RUMPUSER_IOV_NOSEEK, &n);
1.1 pooka 779: done = n;
780: if (done == len)
781: break;
1.15 pooka 782: else if (!error)
1.1 pooka 783: panic("short write");
1.6 pooka 784:
785: xfererr = USBD_IOERROR;
786: goto out;
1.1 pooka 787: }
788:
1.9 pooka 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: }
1.1 pooka 806: }
807:
808: if (RUSB(xfer)->rusb_status == 0) {
809: xfer->actlen = done;
810: } else {
1.6 pooka 811: xfererr = USBD_CANCELLED;
1.1 pooka 812: RUSB(xfer)->rusb_status = 2;
813: }
814: out:
1.9 pooka 815: if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS)
816: if (done != len)
817: panic("lazy bum");
1.6 pooka 818: xfer->status = xfererr;
1.1 pooka 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 */
1.10 mrg 855: /* XXX locking */
1.1 pooka 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: {
1.7 pooka 881: struct ugenhc_softc *sc = pipe->device->bus->hci_private;
882: int endpt = pipe->endpoint->edesc->bEndpointAddress;
883: usbd_xfer_handle xfer;
1.1 pooka 884:
1.8 pooka 885: endpt = UE_GET_ADDR(endpt);
886:
1.7 pooka 887: while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL)
888: rumpusb_device_bulk_abort(xfer);
889:
1.15 pooka 890: rumpuser_close(sc->sc_ugenfd[endpt]);
1.7 pooka 891: sc->sc_ugenfd[endpt] = -1;
892: sc->sc_fdmodes[endpt] = -1;
1.1 pooka 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:
1.9 pooka 947: case UE_ISOCHRONOUS:
1.1 pooka 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:
1.9 pooka 957: if (oflags != O_RDONLY && xfertype == UE_ISOCHRONOUS) {
958: printf("WARNING: faking isoc write open\n");
959: oflags = O_RDONLY;
960: }
961:
1.1 pooka 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? */
1.15 pooka 968: error = rumpuser_close(sc->sc_ugenfd[endpt]);
1.1 pooka 969: oflags = O_RDWR;
970: }
971:
1.18 ! christos 972: makeugendevstr(sc->sc_devnum, endpt, buf, sizeof(buf));
1.11 pooka 973: /* XXX: theoretically should convert oflags */
1.15 pooka 974: error = rumpuser_open(buf, oflags, &fd);
975: if (error != 0) {
1.1 pooka 976: return USBD_INVAL; /* XXX: no mapping */
1.9 pooka 977: }
1.1 pooka 978: val = 100;
1.13 pooka 979: if (rumpcomp_ugenhc_ioctl(fd, USB_SET_TIMEOUT, &val,
1.1 pooka 980: &error) == -1)
981: panic("timeout set failed");
982: sc->sc_ugenfd[endpt] = fd;
983: sc->sc_fdmodes[endpt] = oflags;
1.9 pooka 984:
1.1 pooka 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
1.8 pooka 1016: ugenhc_freem(struct usbd_bus *bus, usb_dma_t *dma)
1.1 pooka 1017: {
1.8 pooka 1018: struct ugenhc_softc *sc = bus->hci_private;
1.1 pooka 1019:
1.8 pooka 1020: usb_freemem(&sc->sc_bus, dma);
1.1 pooka 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
1.12 chs 1056: ugenhc_probe(device_t parent, cfdata_t match, void *aux)
1.1 pooka 1057: {
1058: char buf[UGENDEV_BUFSIZE];
1059:
1.18 ! christos 1060: makeugendevstr(match->cf_unit, 0, buf, sizeof(buf));
1.15 pooka 1061: if (rumpuser_getfileinfo(buf, NULL, NULL) != 0)
1.1 pooka 1062: return 0;
1063:
1064: return 1;
1065: }
1066:
1067: static void
1.12 chs 1068: ugenhc_attach(device_t parent, device_t self, void *aux)
1.1 pooka 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: }
CVSweb <webmaster@jp.NetBSD.org>