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