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