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