Annotation of src/sys/dev/usb/vhci.c, Revision 1.16
1.16 ! maxv 1: /* $NetBSD: vhci.c,v 1.15 2020/03/31 16:28:28 maxv Exp $ */
1.1 maxv 2:
3: /*
1.10 maxv 4: * Copyright (c) 2019-2020 The NetBSD Foundation, Inc.
1.1 maxv 5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Maxime Villard.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: #include <sys/cdefs.h>
1.16 ! maxv 33: __KERNEL_RCSID(0, "$NetBSD: vhci.c,v 1.15 2020/03/31 16:28:28 maxv Exp $");
1.1 maxv 34:
35: #ifdef _KERNEL_OPT
36: #include "opt_usb.h"
37: #endif
38:
39: #include <sys/param.h>
40:
41: #include <sys/bus.h>
42: #include <sys/cpu.h>
43: #include <sys/conf.h>
44: #include <sys/device.h>
45: #include <sys/kernel.h>
46: #include <sys/kmem.h>
47: #include <sys/mutex.h>
48: #include <sys/proc.h>
49: #include <sys/queue.h>
50: #include <sys/systm.h>
51: #include <sys/mman.h>
52: #include <sys/file.h>
53: #include <sys/filedesc.h>
54:
55: #include <machine/endian.h>
56:
57: #include "ioconf.h"
58:
59: #include <dev/usb/usb.h>
60: #include <dev/usb/usbdi.h>
61: #include <dev/usb/usbdivar.h>
62:
63: #include <dev/usb/usbroothub.h>
1.15 maxv 64: #include <dev/usb/vhci.h>
1.1 maxv 65:
66: #ifdef VHCI_DEBUG
67: #define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
68: #else
69: #define DPRINTF(fmt, ...) __nothing
70: #endif
71:
72: static usbd_status vhci_open(struct usbd_pipe *);
73: static void vhci_softintr(void *);
74:
75: static struct usbd_xfer *vhci_allocx(struct usbd_bus *, unsigned int);
76: static void vhci_freex(struct usbd_bus *, struct usbd_xfer *);
77: static void vhci_get_lock(struct usbd_bus *, kmutex_t **);
78: static int vhci_roothub_ctrl(struct usbd_bus *, usb_device_request_t *,
79: void *, int);
80:
81: static const struct usbd_bus_methods vhci_bus_methods = {
82: .ubm_open = vhci_open,
83: .ubm_softint = vhci_softintr,
84: .ubm_dopoll = NULL,
85: .ubm_allocx = vhci_allocx,
86: .ubm_freex = vhci_freex,
87: .ubm_getlock = vhci_get_lock,
88: .ubm_rhctrl = vhci_roothub_ctrl,
89: };
90:
91: static usbd_status vhci_device_ctrl_transfer(struct usbd_xfer *);
92: static usbd_status vhci_device_ctrl_start(struct usbd_xfer *);
93: static void vhci_device_ctrl_abort(struct usbd_xfer *);
94: static void vhci_device_ctrl_close(struct usbd_pipe *);
95: static void vhci_device_ctrl_cleartoggle(struct usbd_pipe *);
96: static void vhci_device_ctrl_done(struct usbd_xfer *);
97:
98: static const struct usbd_pipe_methods vhci_device_ctrl_methods = {
99: .upm_init = NULL,
100: .upm_fini = NULL,
101: .upm_transfer = vhci_device_ctrl_transfer,
102: .upm_start = vhci_device_ctrl_start,
103: .upm_abort = vhci_device_ctrl_abort,
104: .upm_close = vhci_device_ctrl_close,
105: .upm_cleartoggle = vhci_device_ctrl_cleartoggle,
106: .upm_done = vhci_device_ctrl_done,
107: };
108:
109: static usbd_status vhci_root_intr_transfer(struct usbd_xfer *);
110: static usbd_status vhci_root_intr_start(struct usbd_xfer *);
111: static void vhci_root_intr_abort(struct usbd_xfer *);
112: static void vhci_root_intr_close(struct usbd_pipe *);
113: static void vhci_root_intr_cleartoggle(struct usbd_pipe *);
114: static void vhci_root_intr_done(struct usbd_xfer *);
115:
116: static const struct usbd_pipe_methods vhci_root_intr_methods = {
117: .upm_init = NULL,
118: .upm_fini = NULL,
119: .upm_transfer = vhci_root_intr_transfer,
120: .upm_start = vhci_root_intr_start,
121: .upm_abort = vhci_root_intr_abort,
122: .upm_close = vhci_root_intr_close,
123: .upm_cleartoggle = vhci_root_intr_cleartoggle,
124: .upm_done = vhci_root_intr_done,
125: };
126:
1.9 maxv 127: /*
128: * There are three structures to understand: vxfers, packets, and ports.
129: *
130: * Each xfer from the point of view of the USB stack is a vxfer from the point
131: * of view of vHCI.
132: *
133: * A vxfer has a linked list containing a maximum of two packets: a request
134: * packet and possibly a data packet. Packets basically contain data exchanged
135: * between the Host and the virtual USB device. A packet is linked to both a
136: * vxfer and a port.
137: *
138: * A port is an abstraction of an actual USB port. Each virtual USB device gets
139: * connected to a port. A port has two lists:
140: * - The Usb-To-Host list, containing packets to be fetched from the USB
141: * device and provided to the host.
142: * - The Host-To-Usb list, containing packets to be sent from the Host to the
143: * USB device.
144: * Request packets are always in the H->U direction. Data packets however can
145: * be in both the H->U and U->H directions.
146: *
147: * With read() and write() operations on /dev/vhci, userland respectively
148: * "fetches" and "sends" packets from or to the virtual USB device, which
149: * respectively means reading/inserting packets in the H->U and U->H lists on
150: * the port where the virtual USB device is connected.
151: *
152: * +------------------------------------------------+
153: * | USB Stack |
154: * +---------------------^--------------------------+
155: * |
156: * +---------------------V--------------------------+
157: * | +----------------+ +-------------+ |
158: * | | Request Packet | | Data Packet | Xfer |
159: * | +-------|--------+ +----|---^----+ |
160: * +---------|------------------|---|---------------+
161: * | | |
162: * | +--------------+ |
163: * | | |
164: * +---------|---|------------------|---------------+
165: * | +---V---V---+ +---------|-+ |
166: * | | H->U List | | U->H List | vHCI Port |
167: * | +-----|-----+ +-----^-----+ |
168: * +-----------|----------------|-------------------+
169: * | |
170: * +-----------|----------------|-------------------+
171: * | +-----V-----+ +-----|-----+ |
172: * | | read() | | write() | vHCI FD |
173: * | +-----------+ +-----------+ |
174: * +------------------------------------------------+
175: */
176:
1.13 maxv 177: struct vhci_xfer;
178:
1.1 maxv 179: typedef struct vhci_packet {
1.11 maxv 180: /* General. */
1.2 maxv 181: TAILQ_ENTRY(vhci_packet) portlist;
182: TAILQ_ENTRY(vhci_packet) xferlist;
1.9 maxv 183: struct vhci_xfer *vxfer;
1.2 maxv 184: bool utoh;
1.10 maxv 185: uint8_t addr;
1.11 maxv 186:
1.14 maxv 187: /* Type. */
188: struct {
189: bool req:1;
190: bool res:1;
191: bool dat:1;
192: } type;
193:
1.11 maxv 194: /* Exposed for FD operations. */
1.1 maxv 195: uint8_t *buf;
196: size_t size;
197: size_t cursor;
198: } vhci_packet_t;
199:
1.2 maxv 200: typedef TAILQ_HEAD(, vhci_packet) vhci_packet_list_t;
1.1 maxv 201:
1.10 maxv 202: #define VHCI_NADDRS 16 /* maximum supported by USB */
203:
1.1 maxv 204: typedef struct {
205: kmutex_t lock;
206: int status;
207: int change;
208: struct {
209: vhci_packet_list_t usb_to_host;
210: vhci_packet_list_t host_to_usb;
1.10 maxv 211: } endpoints[VHCI_NADDRS];
1.1 maxv 212: } vhci_port_t;
213:
214: typedef struct {
215: struct usbd_pipe pipe;
216: } vhci_pipe_t;
217:
218: typedef struct vhci_xfer {
219: /* General. */
220: struct usbd_xfer xfer;
221:
1.9 maxv 222: /* Port where the xfer occurs. */
1.1 maxv 223: vhci_port_t *port;
1.9 maxv 224:
225: /* Packets in the xfer. */
226: size_t npkts;
1.1 maxv 227: vhci_packet_list_t pkts;
1.9 maxv 228:
1.13 maxv 229: /* Header storage. */
230: vhci_request_t reqbuf;
1.14 maxv 231: vhci_response_t resbuf;
1.13 maxv 232:
1.9 maxv 233: /* Used for G/C. */
1.2 maxv 234: TAILQ_ENTRY(vhci_xfer) freelist;
1.1 maxv 235: } vhci_xfer_t;
236:
1.2 maxv 237: typedef TAILQ_HEAD(, vhci_xfer) vhci_xfer_list_t;
1.1 maxv 238:
239: #define VHCI_INDEX2PORT(idx) (idx)
240: #define VHCI_NPORTS 4
241:
242: typedef struct {
243: device_t sc_dev;
244:
245: struct usbd_bus sc_bus;
246: bool sc_dying;
247: kmutex_t sc_lock;
248:
249: /*
250: * Intr Root. Used to attach the devices.
251: */
252: struct usbd_xfer *sc_intrxfer;
253:
254: /*
255: * The ports. Zero is for the roothub, one and beyond for the USB
256: * devices.
257: */
258: size_t sc_nports;
259: vhci_port_t sc_port[VHCI_NPORTS];
260:
261: device_t sc_child; /* /dev/usb# device */
262: } vhci_softc_t;
263:
264: typedef struct {
265: u_int port;
1.10 maxv 266: uint8_t addr;
1.1 maxv 267: vhci_softc_t *softc;
268: } vhci_fd_t;
269:
270: extern struct cfdriver vhci_cd;
271:
272: /* -------------------------------------------------------------------------- */
273:
274: static void
1.11 maxv 275: vhci_pkt_ctrl_create(vhci_port_t *port, struct usbd_xfer *xfer, bool utoh,
1.10 maxv 276: uint8_t addr)
1.1 maxv 277: {
278: vhci_xfer_t *vxfer = (vhci_xfer_t *)xfer;
1.14 maxv 279: vhci_packet_list_t *reqlist, *reslist, *datlist = NULL;
280: vhci_packet_t *req, *res = NULL, *dat = NULL;
1.9 maxv 281: size_t npkts = 0;
1.1 maxv 282:
1.9 maxv 283: /* Request packet. */
1.10 maxv 284: reqlist = &port->endpoints[addr].host_to_usb;
1.1 maxv 285: req = kmem_zalloc(sizeof(*req), KM_SLEEP);
1.9 maxv 286: req->vxfer = vxfer;
1.2 maxv 287: req->utoh = false;
1.10 maxv 288: req->addr = addr;
1.14 maxv 289: req->type.req = true;
1.13 maxv 290: req->buf = (uint8_t *)&vxfer->reqbuf;
291: req->size = sizeof(vxfer->reqbuf);
1.1 maxv 292: req->cursor = 0;
1.9 maxv 293: npkts++;
1.1 maxv 294:
1.11 maxv 295: /* Init the request buffer. */
1.13 maxv 296: memset(&vxfer->reqbuf, 0, sizeof(vxfer->reqbuf));
297: vxfer->reqbuf.type = VHCI_REQ_CTRL;
298: memcpy(&vxfer->reqbuf.u.ctrl, &xfer->ux_request,
1.11 maxv 299: sizeof(xfer->ux_request));
300:
1.14 maxv 301: /* Response packet. */
302: if (utoh && (xfer->ux_length > 0)) {
303: reslist = &port->endpoints[addr].usb_to_host;
304: res = kmem_zalloc(sizeof(*res), KM_SLEEP);
305: res->vxfer = vxfer;
306: res->utoh = true;
307: res->addr = addr;
308: res->type.res = true;
309: res->buf = (uint8_t *)&vxfer->resbuf;
310: res->size = sizeof(vxfer->resbuf);
311: res->cursor = 0;
312: npkts++;
313: }
314:
1.1 maxv 315: /* Data packet. */
1.2 maxv 316: if (xfer->ux_length > 0) {
1.10 maxv 317: if (utoh) {
318: datlist = &port->endpoints[addr].usb_to_host;
1.2 maxv 319: } else {
1.10 maxv 320: datlist = &port->endpoints[addr].host_to_usb;
1.2 maxv 321: }
1.9 maxv 322: dat = kmem_zalloc(sizeof(*dat), KM_SLEEP);
323: dat->vxfer = vxfer;
1.10 maxv 324: dat->utoh = utoh;
325: dat->addr = addr;
1.14 maxv 326: dat->type.dat = true;
1.9 maxv 327: dat->buf = xfer->ux_buf;
328: dat->size = xfer->ux_length;
329: dat->cursor = 0;
330: npkts++;
1.1 maxv 331: }
332:
333: /* Insert in the xfer. */
334: vxfer->port = port;
1.9 maxv 335: vxfer->npkts = npkts;
1.2 maxv 336: TAILQ_INIT(&vxfer->pkts);
337: TAILQ_INSERT_TAIL(&vxfer->pkts, req, xferlist);
1.14 maxv 338: if (res != NULL)
339: TAILQ_INSERT_TAIL(&vxfer->pkts, res, xferlist);
1.9 maxv 340: if (dat != NULL)
341: TAILQ_INSERT_TAIL(&vxfer->pkts, dat, xferlist);
1.1 maxv 342:
343: /* Insert in the port. */
1.3 maxv 344: KASSERT(mutex_owned(&port->lock));
1.2 maxv 345: TAILQ_INSERT_TAIL(reqlist, req, portlist);
1.14 maxv 346: if (res != NULL)
347: TAILQ_INSERT_TAIL(reslist, res, portlist);
1.9 maxv 348: if (dat != NULL)
349: TAILQ_INSERT_TAIL(datlist, dat, portlist);
1.1 maxv 350: }
351:
352: static void
353: vhci_pkt_destroy(vhci_softc_t *sc, vhci_packet_t *pkt)
354: {
1.9 maxv 355: vhci_xfer_t *vxfer = pkt->vxfer;
1.1 maxv 356: vhci_port_t *port = vxfer->port;
1.2 maxv 357: vhci_packet_list_t *pktlist;
1.1 maxv 358:
359: KASSERT(mutex_owned(&port->lock));
360:
1.9 maxv 361: /* Remove from the port. */
1.2 maxv 362: if (pkt->utoh) {
1.10 maxv 363: pktlist = &port->endpoints[pkt->addr].usb_to_host;
1.2 maxv 364: } else {
1.10 maxv 365: pktlist = &port->endpoints[pkt->addr].host_to_usb;
1.2 maxv 366: }
367: TAILQ_REMOVE(pktlist, pkt, portlist);
368:
1.9 maxv 369: /* Remove from the xfer. */
1.2 maxv 370: TAILQ_REMOVE(&vxfer->pkts, pkt, xferlist);
1.1 maxv 371: kmem_free(pkt, sizeof(*pkt));
372:
1.9 maxv 373: /* Unref. */
374: KASSERT(vxfer->npkts > 0);
375: vxfer->npkts--;
376: if (vxfer->npkts > 0)
1.1 maxv 377: return;
1.2 maxv 378: KASSERT(TAILQ_FIRST(&vxfer->pkts) == NULL);
1.1 maxv 379: }
380:
381: /* -------------------------------------------------------------------------- */
382:
383: static usbd_status
384: vhci_open(struct usbd_pipe *pipe)
385: {
386: struct usbd_device *dev = pipe->up_dev;
387: struct usbd_bus *bus = dev->ud_bus;
388: usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc;
389: vhci_softc_t *sc = bus->ub_hcpriv;
390: uint8_t addr = dev->ud_addr;
391:
392: if (sc->sc_dying)
393: return USBD_IOERROR;
394:
395: DPRINTF("%s: called, type=%d\n", __func__,
396: UE_GET_XFERTYPE(ed->bmAttributes));
397:
398: if (addr == bus->ub_rhaddr) {
399: switch (ed->bEndpointAddress) {
400: case USB_CONTROL_ENDPOINT:
401: DPRINTF("%s: roothub_ctrl\n", __func__);
402: pipe->up_methods = &roothub_ctrl_methods;
403: break;
404: case UE_DIR_IN | USBROOTHUB_INTR_ENDPT:
405: DPRINTF("%s: root_intr\n", __func__);
406: pipe->up_methods = &vhci_root_intr_methods;
407: break;
408: default:
409: DPRINTF("%s: inval\n", __func__);
410: return USBD_INVAL;
411: }
412: } else {
413: switch (UE_GET_XFERTYPE(ed->bmAttributes)) {
414: case UE_CONTROL:
415: pipe->up_methods = &vhci_device_ctrl_methods;
416: break;
1.10 maxv 417: case UE_INTERRUPT:
1.1 maxv 418: case UE_BULK:
419: default:
420: goto bad;
421: }
422: }
423:
424: return USBD_NORMAL_COMPLETION;
425:
426: bad:
427: return USBD_NOMEM;
428: }
429:
430: static void
431: vhci_softintr(void *v)
432: {
433: DPRINTF("%s: called\n", __func__);
434: }
435:
436: static struct usbd_xfer *
437: vhci_allocx(struct usbd_bus *bus, unsigned int nframes)
438: {
439: vhci_xfer_t *vxfer;
440:
441: vxfer = kmem_zalloc(sizeof(*vxfer), KM_SLEEP);
442: #ifdef DIAGNOSTIC
443: vxfer->xfer.ux_state = XFER_BUSY;
444: #endif
445: return (struct usbd_xfer *)vxfer;
446: }
447:
448: static void
449: vhci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer)
450: {
451: vhci_xfer_t *vxfer = (vhci_xfer_t *)xfer;
452:
1.9 maxv 453: KASSERT(vxfer->npkts == 0);
1.2 maxv 454: KASSERT(TAILQ_FIRST(&vxfer->pkts) == NULL);
1.1 maxv 455:
456: #ifdef DIAGNOSTIC
457: vxfer->xfer.ux_state = XFER_FREE;
458: #endif
459: kmem_free(vxfer, sizeof(*vxfer));
460: }
461:
462: static void
463: vhci_get_lock(struct usbd_bus *bus, kmutex_t **lock)
464: {
465: vhci_softc_t *sc = bus->ub_hcpriv;
466:
467: *lock = &sc->sc_lock;
468: }
469:
470: static int
471: vhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
472: void *buf, int buflen)
473: {
474: vhci_softc_t *sc = bus->ub_hcpriv;
475: vhci_port_t *port;
476: usb_hub_descriptor_t hubd;
477: uint16_t len, value, index;
478: int totlen = 0;
479:
480: len = UGETW(req->wLength);
481: value = UGETW(req->wValue);
482: index = UGETW(req->wIndex);
483:
484: #define C(x,y) ((x) | ((y) << 8))
485: switch (C(req->bRequest, req->bmRequestType)) {
486: case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
487: switch (value) {
488: case C(0, UDESC_DEVICE): {
489: usb_device_descriptor_t devd;
490:
491: totlen = uimin(buflen, sizeof(devd));
492: memcpy(&devd, buf, totlen);
493: USETW(devd.idVendor, 0);
494: USETW(devd.idProduct, 0);
495: memcpy(buf, &devd, totlen);
496: break;
497: }
498: #define sd ((usb_string_descriptor_t *)buf)
499: case C(1, UDESC_STRING):
500: /* Vendor */
501: totlen = usb_makestrdesc(sd, len, "NetBSD");
502: break;
503: case C(2, UDESC_STRING):
504: /* Product */
505: totlen = usb_makestrdesc(sd, len, "VHCI root hub");
506: break;
507: #undef sd
508: default:
509: /* default from usbroothub */
510: return buflen;
511: }
512: break;
513:
514: case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
515: switch (value) {
516: case UHF_PORT_RESET:
517: if (index < 1 || index >= sc->sc_nports) {
518: return -1;
519: }
1.4 maxv 520: port = &sc->sc_port[VHCI_INDEX2PORT(index)];
1.1 maxv 521: port->status |= UPS_C_PORT_RESET;
522: break;
523: case UHF_PORT_POWER:
524: break;
525: default:
526: return -1;
527: }
528: break;
529:
530: /* Hub requests. */
531: case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
532: break;
533: case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
534: if (index < 1 || index >= sc->sc_nports) {
535: return -1;
536: }
1.4 maxv 537: port = &sc->sc_port[VHCI_INDEX2PORT(index)];
1.1 maxv 538: switch (value) {
539: case UHF_PORT_ENABLE:
540: port->status &= ~UPS_PORT_ENABLED;
541: break;
542: case UHF_C_PORT_ENABLE:
543: port->change |= UPS_C_PORT_ENABLED;
544: break;
545: default:
546: return -1;
547: }
548: break;
549:
550: case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
551: totlen = uimin(buflen, sizeof(hubd));
552: memcpy(&hubd, buf, totlen);
553: hubd.bNbrPorts = sc->sc_nports - 1;
554: hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE;
555: totlen = uimin(totlen, hubd.bDescLength);
556: memcpy(buf, &hubd, totlen);
557: break;
558:
559: case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
560: /* XXX The other HCs do this */
561: memset(buf, 0, len);
562: totlen = len;
563: break;
564:
565: case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): {
566: usb_port_status_t ps;
567:
568: if (index < 1 || index >= sc->sc_nports) {
569: return -1;
570: }
1.4 maxv 571: port = &sc->sc_port[VHCI_INDEX2PORT(index)];
1.1 maxv 572: USETW(ps.wPortStatus, port->status);
573: USETW(ps.wPortChange, port->change);
574: totlen = uimin(len, sizeof(ps));
575: memcpy(buf, &ps, totlen);
576: break;
577: }
578: default:
579: /* default from usbroothub */
580: return buflen;
581: }
582:
583: return totlen;
584: }
585:
586: /* -------------------------------------------------------------------------- */
587:
588: static usbd_status
589: vhci_device_ctrl_transfer(struct usbd_xfer *xfer)
590: {
591: vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
592: usbd_status err;
593:
594: DPRINTF("%s: called\n", __func__);
595:
596: /* Insert last in queue. */
597: mutex_enter(&sc->sc_lock);
598: err = usb_insert_transfer(xfer);
599: mutex_exit(&sc->sc_lock);
600: if (err)
601: return err;
602:
603: /* Pipe isn't running, start first */
604: return vhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
605: }
606:
607: static usbd_status
608: vhci_device_ctrl_start(struct usbd_xfer *xfer)
609: {
1.10 maxv 610: usb_endpoint_descriptor_t *ed = xfer->ux_pipe->up_endpoint->ue_edesc;
1.1 maxv 611: usb_device_request_t *req = &xfer->ux_request;
612: struct usbd_device *dev = xfer->ux_pipe->up_dev;
613: vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
614: vhci_port_t *port;
615: bool polling = sc->sc_bus.ub_usepolling;
616: bool isread = (req->bmRequestType & UT_READ) != 0;
1.10 maxv 617: uint8_t addr = UE_GET_ADDR(ed->bEndpointAddress);
1.3 maxv 618: int portno, ret;
1.1 maxv 619:
1.10 maxv 620: KASSERT(addr == 0);
1.1 maxv 621: KASSERT(xfer->ux_rqflags & URQ_REQUEST);
622: KASSERT(dev->ud_myhsport != NULL);
623: portno = dev->ud_myhsport->up_portno;
624:
1.8 christos 625: DPRINTF("%s: type=0x%02x, len=%d, isread=%d, portno=%d\n",
1.1 maxv 626: __func__, req->bmRequestType, UGETW(req->wLength), isread, portno);
627:
628: if (sc->sc_dying)
629: return USBD_IOERROR;
630:
631: port = &sc->sc_port[portno];
632:
633: if (!polling)
634: mutex_enter(&sc->sc_lock);
1.3 maxv 635:
636: mutex_enter(&port->lock);
637: if (port->status & UPS_PORT_ENABLED) {
638: xfer->ux_status = USBD_IN_PROGRESS;
1.11 maxv 639: vhci_pkt_ctrl_create(port, xfer, isread, addr);
1.3 maxv 640: ret = USBD_IN_PROGRESS;
641: } else {
642: ret = USBD_IOERROR;
643: }
644: mutex_exit(&port->lock);
645:
1.1 maxv 646: if (!polling)
647: mutex_exit(&sc->sc_lock);
648:
1.3 maxv 649: return ret;
1.1 maxv 650: }
651:
652: static void
653: vhci_device_ctrl_abort(struct usbd_xfer *xfer)
654: {
655: vhci_xfer_t *vxfer = (vhci_xfer_t *)xfer;
656: vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
657: vhci_port_t *port = vxfer->port;
658: vhci_packet_t *pkt;
659:
660: DPRINTF("%s: called\n", __func__);
661:
662: KASSERT(mutex_owned(&sc->sc_lock));
663:
664: callout_halt(&xfer->ux_callout, &sc->sc_lock);
665:
1.11 maxv 666: /* If anyone else beat us, we're done. */
1.1 maxv 667: KASSERT(xfer->ux_status != USBD_CANCELLED);
668: if (xfer->ux_status != USBD_IN_PROGRESS)
669: return;
670:
671: mutex_enter(&port->lock);
1.9 maxv 672: while (vxfer->npkts > 0) {
1.2 maxv 673: pkt = TAILQ_FIRST(&vxfer->pkts);
1.1 maxv 674: KASSERT(pkt != NULL);
675: vhci_pkt_destroy(sc, pkt);
676: }
1.2 maxv 677: KASSERT(TAILQ_FIRST(&vxfer->pkts) == NULL);
1.1 maxv 678: mutex_exit(&port->lock);
679:
680: xfer->ux_status = USBD_CANCELLED;
681: usb_transfer_complete(xfer);
682: KASSERT(mutex_owned(&sc->sc_lock));
683: }
684:
685: static void
686: vhci_device_ctrl_close(struct usbd_pipe *pipe)
687: {
688: DPRINTF("%s: called\n", __func__);
689: }
690:
691: static void
692: vhci_device_ctrl_cleartoggle(struct usbd_pipe *pipe)
693: {
694: DPRINTF("%s: called\n", __func__);
695: }
696:
697: static void
698: vhci_device_ctrl_done(struct usbd_xfer *xfer)
699: {
700: DPRINTF("%s: called\n", __func__);
701: }
702:
703: /* -------------------------------------------------------------------------- */
704:
705: static usbd_status
706: vhci_root_intr_transfer(struct usbd_xfer *xfer)
707: {
708: vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
709: usbd_status err;
710:
711: DPRINTF("%s: called\n", __func__);
712:
713: /* Insert last in queue. */
714: mutex_enter(&sc->sc_lock);
715: err = usb_insert_transfer(xfer);
716: mutex_exit(&sc->sc_lock);
717: if (err)
718: return err;
719:
720: /* Pipe isn't running, start first */
721: return vhci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
722: }
723:
724: static usbd_status
725: vhci_root_intr_start(struct usbd_xfer *xfer)
726: {
727: vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
728: const bool polling = sc->sc_bus.ub_usepolling;
729:
730: DPRINTF("%s: called, len=%zu\n", __func__, (size_t)xfer->ux_length);
731:
732: if (sc->sc_dying)
733: return USBD_IOERROR;
734:
735: if (!polling)
736: mutex_enter(&sc->sc_lock);
1.5 riastrad 737: KASSERT(sc->sc_intrxfer == NULL);
1.1 maxv 738: sc->sc_intrxfer = xfer;
1.6 riastrad 739: xfer->ux_status = USBD_IN_PROGRESS;
1.1 maxv 740: if (!polling)
741: mutex_exit(&sc->sc_lock);
742:
743: return USBD_IN_PROGRESS;
744: }
745:
746: static void
747: vhci_root_intr_abort(struct usbd_xfer *xfer)
748: {
749: vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
750:
751: DPRINTF("%s: called\n", __func__);
752:
753: KASSERT(mutex_owned(&sc->sc_lock));
754: KASSERT(xfer->ux_pipe->up_intrxfer == xfer);
755:
1.5 riastrad 756: /* If xfer has already completed, nothing to do here. */
757: if (sc->sc_intrxfer == NULL)
758: return;
1.1 maxv 759:
1.5 riastrad 760: /*
761: * Otherwise, sc->sc_intrxfer had better be this transfer.
762: * Cancel it.
763: */
764: KASSERT(sc->sc_intrxfer == xfer);
1.6 riastrad 765: KASSERT(xfer->ux_status == USBD_IN_PROGRESS);
1.1 maxv 766: xfer->ux_status = USBD_CANCELLED;
767: usb_transfer_complete(xfer);
768: }
769:
770: static void
771: vhci_root_intr_close(struct usbd_pipe *pipe)
772: {
1.5 riastrad 773: vhci_softc_t *sc __diagused = pipe->up_dev->ud_bus->ub_hcpriv;
1.1 maxv 774:
775: DPRINTF("%s: called\n", __func__);
776:
777: KASSERT(mutex_owned(&sc->sc_lock));
778:
1.5 riastrad 779: /*
780: * Caller must guarantee the xfer has completed first, by
781: * closing the pipe only after normal completion or an abort.
782: */
783: KASSERT(sc->sc_intrxfer == NULL);
1.1 maxv 784: }
785:
786: static void
787: vhci_root_intr_cleartoggle(struct usbd_pipe *pipe)
788: {
789: DPRINTF("%s: called\n", __func__);
790: }
791:
792: static void
793: vhci_root_intr_done(struct usbd_xfer *xfer)
794: {
1.5 riastrad 795: vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
796:
797: KASSERT(mutex_owned(&sc->sc_lock));
798:
799: /* Claim the xfer so it doesn't get completed again. */
800: KASSERT(sc->sc_intrxfer == xfer);
801: KASSERT(xfer->ux_status != USBD_IN_PROGRESS);
802: sc->sc_intrxfer = NULL;
1.1 maxv 803: }
804:
805: /* -------------------------------------------------------------------------- */
806:
807: static int
1.12 maxv 808: vhci_usb_attach(vhci_fd_t *vfd)
1.1 maxv 809: {
810: vhci_softc_t *sc = vfd->softc;
811: vhci_port_t *port;
812: struct usbd_xfer *xfer;
813: u_char *p;
814: int ret = 0;
815:
1.12 maxv 816: port = &sc->sc_port[vfd->port];
1.1 maxv 817:
818: mutex_enter(&sc->sc_lock);
819:
1.3 maxv 820: mutex_enter(&port->lock);
1.1 maxv 821: port->status = UPS_CURRENT_CONNECT_STATUS | UPS_PORT_ENABLED |
822: UPS_PORT_POWER;
823: port->change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET;
1.3 maxv 824: mutex_exit(&port->lock);
1.1 maxv 825:
826: xfer = sc->sc_intrxfer;
827:
828: if (xfer == NULL) {
829: ret = ENOBUFS;
830: goto done;
831: }
1.6 riastrad 832: KASSERT(xfer->ux_status == USBD_IN_PROGRESS);
1.1 maxv 833:
834: p = xfer->ux_buf;
835: memset(p, 0, xfer->ux_length);
1.12 maxv 836: p[0] = __BIT(vfd->port);
1.1 maxv 837: xfer->ux_actlen = xfer->ux_length;
838: xfer->ux_status = USBD_NORMAL_COMPLETION;
839:
840: usb_transfer_complete(xfer);
841:
842: done:
843: mutex_exit(&sc->sc_lock);
844: return ret;
845: }
846:
847: static void
848: vhci_port_flush(vhci_softc_t *sc, vhci_port_t *port)
849: {
850: vhci_packet_list_t *pktlist;
851: vhci_packet_t *pkt, *nxt;
852: vhci_xfer_list_t vxferlist;
853: vhci_xfer_t *vxfer;
1.10 maxv 854: uint8_t addr;
1.1 maxv 855:
856: KASSERT(mutex_owned(&sc->sc_lock));
1.3 maxv 857: KASSERT(mutex_owned(&port->lock));
1.1 maxv 858:
1.2 maxv 859: TAILQ_INIT(&vxferlist);
1.1 maxv 860:
1.10 maxv 861: for (addr = 0; addr < VHCI_NADDRS; addr++) {
862: /* Drop all the packets in the H->U direction. */
863: pktlist = &port->endpoints[addr].host_to_usb;
864: TAILQ_FOREACH_SAFE(pkt, pktlist, portlist, nxt) {
865: vxfer = pkt->vxfer;
866: KASSERT(vxfer->xfer.ux_status == USBD_IN_PROGRESS);
867: vhci_pkt_destroy(sc, pkt);
868: if (vxfer->npkts == 0)
869: TAILQ_INSERT_TAIL(&vxferlist, vxfer, freelist);
870: }
871: KASSERT(TAILQ_FIRST(pktlist) == NULL);
1.1 maxv 872:
1.10 maxv 873: /* Drop all the packets in the U->H direction. */
874: pktlist = &port->endpoints[addr].usb_to_host;
875: TAILQ_FOREACH_SAFE(pkt, pktlist, portlist, nxt) {
876: vxfer = pkt->vxfer;
877: KASSERT(vxfer->xfer.ux_status == USBD_IN_PROGRESS);
878: vhci_pkt_destroy(sc, pkt);
879: if (vxfer->npkts == 0)
880: TAILQ_INSERT_TAIL(&vxferlist, vxfer, freelist);
881: }
882: KASSERT(TAILQ_FIRST(pktlist) == NULL);
1.1 maxv 883:
1.10 maxv 884: /* Terminate all the xfers collected. */
885: while ((vxfer = TAILQ_FIRST(&vxferlist)) != NULL) {
886: struct usbd_xfer *xfer = &vxfer->xfer;
887: TAILQ_REMOVE(&vxferlist, vxfer, freelist);
1.1 maxv 888:
1.10 maxv 889: xfer->ux_status = USBD_TIMEOUT;
890: usb_transfer_complete(xfer);
891: }
1.1 maxv 892: }
893: }
894:
895: static int
1.12 maxv 896: vhci_usb_detach(vhci_fd_t *vfd)
1.1 maxv 897: {
898: vhci_softc_t *sc = vfd->softc;
899: vhci_port_t *port;
900: struct usbd_xfer *xfer;
901: u_char *p;
902:
1.12 maxv 903: port = &sc->sc_port[vfd->port];
1.1 maxv 904:
905: mutex_enter(&sc->sc_lock);
906:
907: xfer = sc->sc_intrxfer;
908: if (xfer == NULL) {
909: mutex_exit(&sc->sc_lock);
910: return ENOBUFS;
911: }
1.6 riastrad 912: KASSERT(xfer->ux_status == USBD_IN_PROGRESS);
1.1 maxv 913:
1.3 maxv 914: mutex_enter(&port->lock);
915:
1.1 maxv 916: port->status = 0;
917: port->change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET;
918:
919: p = xfer->ux_buf;
920: memset(p, 0, xfer->ux_length);
1.12 maxv 921: p[0] = __BIT(vfd->port);
1.1 maxv 922: xfer->ux_actlen = xfer->ux_length;
923: xfer->ux_status = USBD_NORMAL_COMPLETION;
924:
925: usb_transfer_complete(xfer);
926: vhci_port_flush(sc, port);
1.3 maxv 927:
928: mutex_exit(&port->lock);
1.1 maxv 929: mutex_exit(&sc->sc_lock);
930: return 0;
931: }
932:
933: static int
934: vhci_get_info(vhci_fd_t *vfd, struct vhci_ioc_get_info *args)
935: {
936: vhci_softc_t *sc = vfd->softc;
937: vhci_port_t *port;
938:
939: port = &sc->sc_port[vfd->port];
940:
941: args->nports = VHCI_NPORTS;
942: args->port = vfd->port;
943: mutex_enter(&port->lock);
944: args->status = port->status;
945: mutex_exit(&port->lock);
1.10 maxv 946: args->addr = vfd->addr;
1.1 maxv 947:
948: return 0;
949: }
950:
951: static int
952: vhci_set_port(vhci_fd_t *vfd, struct vhci_ioc_set_port *args)
953: {
954: vhci_softc_t *sc = vfd->softc;
955:
956: if (args->port == 0 || args->port >= sc->sc_nports)
957: return EINVAL;
958:
959: vfd->port = args->port;
960:
961: return 0;
962: }
963:
1.10 maxv 964: static int
965: vhci_set_addr(vhci_fd_t *vfd, struct vhci_ioc_set_addr *args)
966: {
967: if (args->addr >= VHCI_NADDRS)
968: return EINVAL;
969:
970: vfd->addr = args->addr;
971:
972: return 0;
973: }
974:
1.1 maxv 975: /* -------------------------------------------------------------------------- */
976:
977: static dev_type_open(vhci_fd_open);
978:
979: const struct cdevsw vhci_cdevsw = {
980: .d_open = vhci_fd_open,
981: .d_close = noclose,
982: .d_read = noread,
983: .d_write = nowrite,
984: .d_ioctl = noioctl,
985: .d_stop = nostop,
986: .d_tty = notty,
987: .d_poll = nopoll,
988: .d_mmap = nommap,
989: .d_kqfilter = nokqfilter,
990: .d_discard = nodiscard,
991: .d_flag = D_OTHER | D_MPSAFE
992: };
993:
994: static int vhci_fd_ioctl(file_t *, u_long, void *);
995: static int vhci_fd_close(file_t *);
996: static int vhci_fd_read(struct file *, off_t *, struct uio *, kauth_cred_t, int);
997: static int vhci_fd_write(struct file *, off_t *, struct uio *, kauth_cred_t, int);
998:
999: const struct fileops vhci_fileops = {
1000: .fo_read = vhci_fd_read,
1001: .fo_write = vhci_fd_write,
1002: .fo_ioctl = vhci_fd_ioctl,
1003: .fo_fcntl = fnullop_fcntl,
1004: .fo_poll = fnullop_poll,
1005: .fo_stat = fbadop_stat,
1006: .fo_close = vhci_fd_close,
1007: .fo_kqfilter = fnullop_kqfilter,
1008: .fo_restart = fnullop_restart,
1009: .fo_mmap = NULL,
1010: };
1011:
1012: static int
1013: vhci_fd_open(dev_t dev, int flags, int type, struct lwp *l)
1014: {
1015: vhci_fd_t *vfd;
1016: struct file *fp;
1017: int error, fd;
1018:
1019: if (minor(dev) != 0)
1020: return EXDEV;
1021: error = fd_allocfile(&fp, &fd);
1022: if (error)
1023: return error;
1024:
1025: vfd = kmem_alloc(sizeof(*vfd), KM_SLEEP);
1026: vfd->port = 1;
1.10 maxv 1027: vfd->addr = 0;
1.1 maxv 1028: vfd->softc = device_lookup_private(&vhci_cd, minor(dev));
1029:
1030: return fd_clone(fp, fd, flags, &vhci_fileops, vfd);
1031: }
1032:
1033: static int
1034: vhci_fd_close(file_t *fp)
1035: {
1036: vhci_fd_t *vfd = fp->f_data;
1.3 maxv 1037: int ret __diagused;
1.1 maxv 1038:
1039: KASSERT(vfd != NULL);
1.12 maxv 1040: ret = vhci_usb_detach(vfd);
1.3 maxv 1041: KASSERT(ret == 0);
1.1 maxv 1042:
1043: kmem_free(vfd, sizeof(*vfd));
1044: fp->f_data = NULL;
1045:
1046: return 0;
1047: }
1048:
1049: static int
1050: vhci_fd_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
1051: int flags)
1052: {
1053: vhci_fd_t *vfd = fp->f_data;
1054: vhci_softc_t *sc = vfd->softc;
1055: vhci_packet_list_t *pktlist;
1056: vhci_packet_t *pkt, *nxt;
1057: vhci_xfer_list_t vxferlist;
1058: vhci_xfer_t *vxfer;
1059: vhci_port_t *port;
1060: int error = 0;
1061: uint8_t *buf;
1062: size_t size;
1063:
1064: if (uio->uio_resid == 0)
1065: return 0;
1066: port = &sc->sc_port[vfd->port];
1.10 maxv 1067: pktlist = &port->endpoints[vfd->addr].host_to_usb;
1.1 maxv 1068:
1.2 maxv 1069: TAILQ_INIT(&vxferlist);
1.1 maxv 1070:
1071: mutex_enter(&port->lock);
1072:
1073: if (!(port->status & UPS_PORT_ENABLED)) {
1074: error = ENOBUFS;
1075: goto out;
1076: }
1077:
1.2 maxv 1078: TAILQ_FOREACH_SAFE(pkt, pktlist, portlist, nxt) {
1.9 maxv 1079: vxfer = pkt->vxfer;
1.1 maxv 1080: buf = pkt->buf + pkt->cursor;
1.14 maxv 1081:
1.2 maxv 1082: KASSERT(pkt->size >= pkt->cursor);
1.1 maxv 1083: size = uimin(uio->uio_resid, pkt->size - pkt->cursor);
1084:
1085: KASSERT(vxfer->xfer.ux_status == USBD_IN_PROGRESS);
1086:
1087: error = uiomove(buf, size, uio);
1088: if (error) {
1089: DPRINTF("%s: error = %d\n", __func__, error);
1090: goto out;
1091: }
1092:
1093: pkt->cursor += size;
1094:
1095: if (pkt->cursor == pkt->size) {
1096: vhci_pkt_destroy(sc, pkt);
1.9 maxv 1097: if (vxfer->npkts == 0) {
1.2 maxv 1098: TAILQ_INSERT_TAIL(&vxferlist, vxfer, freelist);
1.1 maxv 1099: }
1100: }
1101: if (uio->uio_resid == 0) {
1102: break;
1103: }
1104: }
1105:
1106: out:
1107: mutex_exit(&port->lock);
1108:
1.2 maxv 1109: while ((vxfer = TAILQ_FIRST(&vxferlist)) != NULL) {
1.1 maxv 1110: struct usbd_xfer *xfer = &vxfer->xfer;
1.2 maxv 1111: TAILQ_REMOVE(&vxferlist, vxfer, freelist);
1.1 maxv 1112:
1113: mutex_enter(&sc->sc_lock);
1114: xfer->ux_actlen = xfer->ux_length;
1115: xfer->ux_status = USBD_NORMAL_COMPLETION;
1116: usb_transfer_complete(xfer);
1117: mutex_exit(&sc->sc_lock);
1118: }
1119:
1120: return error;
1121: }
1122:
1123: static int
1124: vhci_fd_write(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
1125: int flags)
1126: {
1127: vhci_fd_t *vfd = fp->f_data;
1128: vhci_softc_t *sc = vfd->softc;
1129: vhci_packet_list_t *pktlist;
1130: vhci_packet_t *pkt, *nxt;
1131: vhci_xfer_list_t vxferlist;
1132: vhci_xfer_t *vxfer;
1133: vhci_port_t *port;
1134: int error = 0;
1135: uint8_t *buf;
1.14 maxv 1136: size_t pktsize, size;
1.1 maxv 1137:
1138: if (uio->uio_resid == 0)
1139: return 0;
1140: port = &sc->sc_port[vfd->port];
1.10 maxv 1141: pktlist = &port->endpoints[vfd->addr].usb_to_host;
1.1 maxv 1142:
1.2 maxv 1143: TAILQ_INIT(&vxferlist);
1.1 maxv 1144:
1145: mutex_enter(&port->lock);
1146:
1147: if (!(port->status & UPS_PORT_ENABLED)) {
1148: error = ENOBUFS;
1149: goto out;
1150: }
1151:
1.2 maxv 1152: TAILQ_FOREACH_SAFE(pkt, pktlist, portlist, nxt) {
1.9 maxv 1153: vxfer = pkt->vxfer;
1.1 maxv 1154: buf = pkt->buf + pkt->cursor;
1.14 maxv 1155:
1156: pktsize = pkt->size;
1157: if (pkt->type.dat)
1158: pktsize = ulmin(vxfer->resbuf.size, pktsize);
1159:
1160: KASSERT(pktsize >= pkt->cursor);
1161: size = uimin(uio->uio_resid, pktsize - pkt->cursor);
1.1 maxv 1162:
1163: KASSERT(vxfer->xfer.ux_status == USBD_IN_PROGRESS);
1164:
1165: error = uiomove(buf, size, uio);
1166: if (error) {
1167: DPRINTF("%s: error = %d\n", __func__, error);
1168: goto out;
1169: }
1170:
1171: pkt->cursor += size;
1172:
1.14 maxv 1173: if (pkt->cursor == pktsize) {
1.1 maxv 1174: vhci_pkt_destroy(sc, pkt);
1.9 maxv 1175: if (vxfer->npkts == 0) {
1.2 maxv 1176: TAILQ_INSERT_TAIL(&vxferlist, vxfer, freelist);
1.1 maxv 1177: }
1178: }
1179: if (uio->uio_resid == 0) {
1180: break;
1181: }
1182: }
1183:
1184: out:
1185: mutex_exit(&port->lock);
1186:
1.2 maxv 1187: while ((vxfer = TAILQ_FIRST(&vxferlist)) != NULL) {
1.1 maxv 1188: struct usbd_xfer *xfer = &vxfer->xfer;
1.2 maxv 1189: TAILQ_REMOVE(&vxferlist, vxfer, freelist);
1.1 maxv 1190:
1191: mutex_enter(&sc->sc_lock);
1.14 maxv 1192: xfer->ux_actlen = ulmin(vxfer->resbuf.size, xfer->ux_length);
1.1 maxv 1193: xfer->ux_status = USBD_NORMAL_COMPLETION;
1194: usb_transfer_complete(xfer);
1195: mutex_exit(&sc->sc_lock);
1196: }
1197:
1198: return error;
1199: }
1200:
1201: static int
1202: vhci_fd_ioctl(file_t *fp, u_long cmd, void *data)
1203: {
1204: vhci_fd_t *vfd = fp->f_data;
1205:
1206: KASSERT(vfd != NULL);
1207:
1208: switch (cmd) {
1209: case VHCI_IOC_GET_INFO:
1210: return vhci_get_info(vfd, data);
1211: case VHCI_IOC_SET_PORT:
1212: return vhci_set_port(vfd, data);
1.10 maxv 1213: case VHCI_IOC_SET_ADDR:
1214: return vhci_set_addr(vfd, data);
1.1 maxv 1215: case VHCI_IOC_USB_ATTACH:
1.12 maxv 1216: return vhci_usb_attach(vfd);
1.1 maxv 1217: case VHCI_IOC_USB_DETACH:
1.12 maxv 1218: return vhci_usb_detach(vfd);
1.1 maxv 1219: default:
1220: return EINVAL;
1221: }
1222: }
1223:
1224: /* -------------------------------------------------------------------------- */
1225:
1226: static int vhci_match(device_t, cfdata_t, void *);
1227: static void vhci_attach(device_t, device_t, void *);
1.3 maxv 1228: static int vhci_activate(device_t, enum devact);
1.1 maxv 1229:
1230: CFATTACH_DECL_NEW(vhci, sizeof(vhci_softc_t), vhci_match, vhci_attach,
1.3 maxv 1231: NULL, vhci_activate);
1.1 maxv 1232:
1233: void
1234: vhciattach(int nunits)
1235: {
1236: static struct cfdata vhci_cfdata = {
1237: .cf_name = "vhci",
1238: .cf_atname = "vhci",
1239: .cf_unit = 0,
1240: .cf_fstate = FSTATE_STAR,
1241: };
1242: int error;
1243:
1244: error = config_cfattach_attach(vhci_cd.cd_name, &vhci_ca);
1245: if (error) {
1246: aprint_error("%s: unable to register cfattach\n",
1247: vhci_cd.cd_name);
1248: (void)config_cfdriver_detach(&vhci_cd);
1249: return;
1250: }
1251:
1252: config_attach_pseudo(&vhci_cfdata);
1253: }
1254:
1255: static int
1.3 maxv 1256: vhci_activate(device_t self, enum devact act)
1257: {
1258: vhci_softc_t *sc = device_private(self);
1259:
1260: switch (act) {
1261: case DVACT_DEACTIVATE:
1262: sc->sc_dying = 1;
1263: return 0;
1264: default:
1265: return EOPNOTSUPP;
1266: }
1267: }
1268:
1269: static int
1.1 maxv 1270: vhci_match(device_t parent, cfdata_t match, void *aux)
1271: {
1272: return 1;
1273: }
1274:
1275: static void
1276: vhci_attach(device_t parent, device_t self, void *aux)
1277: {
1278: vhci_softc_t *sc = device_private(self);
1279: vhci_port_t *port;
1.10 maxv 1280: uint8_t addr;
1.1 maxv 1281: size_t i;
1282:
1283: sc->sc_dev = self;
1284: sc->sc_bus.ub_revision = USBREV_2_0;
1285: sc->sc_bus.ub_usedma = false;
1286: sc->sc_bus.ub_methods = &vhci_bus_methods;
1287: sc->sc_bus.ub_pipesize = sizeof(vhci_pipe_t);
1288: sc->sc_bus.ub_hcpriv = sc;
1289: sc->sc_dying = false;
1290: mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
1291:
1292: sc->sc_nports = VHCI_NPORTS;
1293: for (i = 0; i < sc->sc_nports; i++) {
1294: port = &sc->sc_port[i];
1295: mutex_init(&port->lock, MUTEX_DEFAULT, IPL_SOFTUSB);
1.10 maxv 1296: for (addr = 0; addr < VHCI_NADDRS; addr++) {
1297: TAILQ_INIT(&port->endpoints[addr].usb_to_host);
1298: TAILQ_INIT(&port->endpoints[addr].host_to_usb);
1299: }
1.1 maxv 1300: }
1301:
1302: sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint);
1303: }
CVSweb <webmaster@jp.NetBSD.org>