1 /* $NetBSD: ugenhc.c,v 1.31 2022/03/03 06:12:11 riastradh Exp $ */
2
3 /*
4 * Copyright (c) 2009, 2010 Antti Kantee. All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 /*
29 * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
30 * All rights reserved.
31 *
32 * This code is derived from software contributed to The NetBSD Foundation
33 * by Lennart Augustsson (lennart@augustsson.net) at
34 * Carlstedt Research & Technology.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
46 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
47 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
49 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55 * POSSIBILITY OF SUCH DAMAGE.
56 */
57
58 /*
59 * This rump driver attaches ugen as a kernel usb host controller.
60 * It's still somewhat under the hammer ....
61 */
62
63 #include <sys/cdefs.h>
64 __KERNEL_RCSID(0, "$NetBSD: ugenhc.c,v 1.31 2022/03/03 06:12:11 riastradh Exp $");
65
66 #include <sys/param.h>
67 #include <sys/bus.h>
68 #include <sys/conf.h>
69 #include <sys/device.h>
70 #include <sys/fcntl.h>
71 #include <sys/kmem.h>
72 #include <sys/kernel.h>
73 #include <sys/kthread.h>
74 #include <sys/mutex.h>
75
76 #include <dev/usb/usb.h>
77 #include <dev/usb/usbdi.h>
78 #include <dev/usb/usbhid.h>
79 #include <dev/usb/usbdivar.h>
80 #include <dev/usb/usb_mem.h>
81 #include <dev/usb/usbroothub.h>
82
83 #include <rump/rumpuser.h>
84
85 #include <rump-sys/kern.h>
86 #include <rump-sys/dev.h>
87
88 #include "ugenhc_user.h"
89
90 #define UGEN_NEPTS 16
91 #define UGEN_EPT_CTRL 0 /* ugenx.00 is the control endpoint */
92
93 struct ugenhc_softc {
94 struct usbd_bus sc_bus;
95 int sc_devnum;
96
97 int sc_ugenfd[UGEN_NEPTS];
98 int sc_fdmodes[UGEN_NEPTS];
99
100 int sc_port_status;
101 int sc_port_change;
102
103 struct lwp *sc_rhintr;
104 struct usbd_xfer *sc_intrxfer;
105
106 kmutex_t sc_lock;
107 };
108
109 static int ugenhc_probe(device_t, cfdata_t, void *);
110 static void ugenhc_attach(device_t, device_t, void *);
111
112 CFATTACH_DECL_NEW(ugenhc, sizeof(struct ugenhc_softc),
113 ugenhc_probe, ugenhc_attach, NULL, NULL);
114
115 struct rusb_xfer {
116 struct usbd_xfer rusb_xfer;
117 int rusb_status; /* now this is a cheap trick */
118 };
119 #define RUSB(x) ((struct rusb_xfer *)x)
120
121 #define UGENHC_BUS2SC(bus) ((bus)->ub_hcpriv)
122 #define UGENHC_PIPE2SC(pipe) UGENHC_BUS2SC((pipe)->up_dev->ud_bus)
123 #define UGENHC_XFER2SC(pipe) UGENHC_BUS2SC((xfer)->ux_bus)
124
125 #define UGENDEV_BASESTR "/dev/ugen"
126 #define UGENDEV_BUFSIZE 32
127 static void
makeugendevstr(int devnum,int endpoint,char * buf,size_t len)128 makeugendevstr(int devnum, int endpoint, char *buf, size_t len)
129 {
130
131 CTASSERT(UGENDEV_BUFSIZE > sizeof(UGENDEV_BASESTR)+sizeof("0.00")+1);
132 snprintf(buf, len, "%s%d.%02d", UGENDEV_BASESTR, devnum, endpoint);
133 }
134
135 static int
ugenhc_roothub_ctrl(struct usbd_bus * bus,usb_device_request_t * req,void * buf,int buflen)136 ugenhc_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
137 void *buf, int buflen)
138 {
139 struct ugenhc_softc *sc = UGENHC_BUS2SC(bus);
140 int totlen = 0;
141 uint16_t len, value;
142
143 len = UGETW(req->wLength);
144 value = UGETW(req->wValue);
145
146 #define C(x,y) ((x) | ((y) << 8))
147 switch (C(req->bRequest, req->bmRequestType)) {
148 case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
149 switch (value) {
150 case C(0, UDESC_DEVICE): {
151 usb_device_descriptor_t devd;
152
153 totlen = uimin(buflen, sizeof(devd));
154 memcpy(&devd, buf, totlen);
155 USETW(devd.idVendor, 0x7275);
156 USETW(devd.idProduct, 0x6d72);
157 memcpy(buf, &devd, totlen);
158 break;
159 }
160 #define sd ((usb_string_descriptor_t *)buf)
161 case C(1, UDESC_STRING):
162 /* Vendor */
163 totlen = usb_makestrdesc(sd, len, "rod nevada");
164 break;
165 case C(2, UDESC_STRING):
166 /* Product */
167 totlen = usb_makestrdesc(sd, len, "RUMPUSBHC root hub");
168 break;
169 #undef sd
170 default:
171 /* default from usbroothub */
172 return buflen;
173 }
174 break;
175
176 case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
177 switch (value) {
178 case UHF_PORT_RESET:
179 sc->sc_port_change |= UPS_C_PORT_RESET;
180 break;
181 case UHF_PORT_POWER:
182 break;
183 default:
184 return -1;
185 }
186 break;
187
188 case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
189 sc->sc_port_change &= ~value;
190 break;
191
192 case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
193 totlen = buflen;
194 break;
195
196 case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
197 /* huh? other hc's do this */
198 memset(buf, 0, len);
199 totlen = len;
200 break;
201
202 case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): {
203 usb_port_status_t ps;
204
205 USETW(ps.wPortStatus, sc->sc_port_status);
206 USETW(ps.wPortChange, sc->sc_port_change);
207 totlen = uimin(len, sizeof(ps));
208 memcpy(buf, &ps, totlen);
209 break;
210 }
211 default:
212 /* default from usbroothub */
213 return buflen;
214 }
215
216 return totlen;
217 }
218
219 static usbd_status
rumpusb_device_ctrl_start(struct usbd_xfer * xfer)220 rumpusb_device_ctrl_start(struct usbd_xfer *xfer)
221 {
222 usb_device_request_t *req = &xfer->ux_request;
223 struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer);
224 uint8_t *buf = NULL;
225 int len, totlen;
226 int value;
227 int err = 0;
228 int ru_error, mightfail = 0;
229
230 KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
231
232 len = totlen = UGETW(req->wLength);
233 if (len)
234 buf = xfer->ux_buf;
235 value = UGETW(req->wValue);
236
237 #define C(x,y) ((x) | ((y) << 8))
238 switch(C(req->bRequest, req->bmRequestType)) {
239 case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
240 switch (value>>8) {
241 case UDESC_DEVICE:
242 {
243 usb_device_descriptor_t uddesc;
244 totlen = uimin(len, USB_DEVICE_DESCRIPTOR_SIZE);
245 memset(buf, 0, totlen);
246 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
247 USB_GET_DEVICE_DESC, &uddesc, &ru_error) == -1) {
248 err = EIO;
249 goto ret;
250 }
251 memcpy(buf, &uddesc, totlen);
252 }
253
254 break;
255 case UDESC_CONFIG:
256 {
257 struct usb_full_desc ufdesc;
258 ufdesc.ufd_config_index = value & 0xff;
259 ufdesc.ufd_size = len;
260 ufdesc.ufd_data = buf;
261 memset(buf, 0, len);
262 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
263 USB_GET_FULL_DESC, &ufdesc, &ru_error) == -1) {
264 err = USBD_IOERROR;
265 goto ret;
266 }
267 totlen = ufdesc.ufd_size;
268 }
269 break;
270
271 case UDESC_STRING:
272 {
273 struct usb_device_info udi;
274
275 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
276 USB_GET_DEVICEINFO, &udi, &ru_error) == -1) {
277 printf("ugenhc: get dev info failed: %d\n",
278 ru_error);
279 err = USBD_IOERROR;
280 goto ret;
281 }
282
283 switch (value & 0xff) {
284 #define sd ((usb_string_descriptor_t *)buf)
285 case 0: /* language table */
286 break;
287 case 1: /* vendor */
288 totlen = usb_makestrdesc(sd, len,
289 udi.udi_vendor);
290 break;
291 case 2: /* product */
292 totlen = usb_makestrdesc(sd, len,
293 udi.udi_product);
294 break;
295 }
296 #undef sd
297 }
298 break;
299
300 default:
301 panic("not handled");
302 }
303 break;
304
305 case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
306 /* ignored, ugen won't let us */
307 break;
308
309 case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
310 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
311 USB_SET_CONFIG, &value, &ru_error) == -1) {
312 printf("ugenhc: set config failed: %d\n",
313 ru_error);
314 err = USBD_IOERROR;
315 goto ret;
316 }
317 break;
318
319 case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
320 {
321 struct usb_alt_interface uai;
322
323 totlen = 0;
324 uai.uai_interface_index = UGETW(req->wIndex);
325 uai.uai_alt_no = value;
326 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
327 USB_SET_ALTINTERFACE, &uai, &ru_error) == -1) {
328 printf("ugenhc: set alt interface failed: %d\n",
329 ru_error);
330 err = USBD_IOERROR;
331 goto ret;
332 }
333 break;
334 }
335
336 /*
337 * This request might fail unknown reasons. "EIO" doesn't
338 * give much help, and debugging the host ugen would be
339 * necessary. However, since it doesn't seem to really
340 * affect anything, just let it fail for now.
341 */
342 case C(0x00, UT_WRITE_CLASS_INTERFACE):
343 mightfail = 1;
344 /*FALLTHROUGH*/
345
346 /*
347 * XXX: don't wildcard these yet. I want to better figure
348 * out what to trap here. This is kinda silly, though ...
349 */
350
351 case C(0x01, UT_WRITE_VENDOR_DEVICE):
352 case C(0x06, UT_WRITE_VENDOR_DEVICE):
353 case C(0x07, UT_READ_VENDOR_DEVICE):
354 case C(0x09, UT_READ_VENDOR_DEVICE):
355 case C(0xfe, UT_READ_CLASS_INTERFACE):
356 case C(0x01, UT_READ_CLASS_INTERFACE):
357 case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
358 case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
359 case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
360 case C(UR_GET_DESCRIPTOR, UT_READ_INTERFACE):
361 case C(0xff, UT_WRITE_CLASS_INTERFACE):
362 case C(0x20, UT_WRITE_CLASS_INTERFACE):
363 case C(0x22, UT_WRITE_CLASS_INTERFACE):
364 case C(0x0a, UT_WRITE_CLASS_INTERFACE):
365 case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
366 case C(0x00, UT_WRITE_CLASS_DEVICE):
367 case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
368 case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
369 case C(UR_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
370 case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
371 {
372 struct usb_ctl_request ucr;
373
374 memcpy(&ucr.ucr_request, req, sizeof(ucr.ucr_request));
375 ucr.ucr_data = buf;
376 if (rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
377 USB_DO_REQUEST, &ucr, &ru_error) == -1) {
378 if (!mightfail) {
379 panic("request failed: %d", ru_error);
380 } else {
381 err = ru_error;
382 }
383 }
384 }
385 break;
386
387 default:
388 panic("unhandled request");
389 break;
390 }
391 xfer->ux_actlen = totlen;
392 err = USBD_NORMAL_COMPLETION;
393
394 ret:
395 xfer->ux_status = err;
396 usb_transfer_complete(xfer);
397
398 return USBD_IN_PROGRESS;
399 }
400
401 static usbd_status
rumpusb_device_ctrl_transfer(struct usbd_xfer * xfer)402 rumpusb_device_ctrl_transfer(struct usbd_xfer *xfer)
403 {
404
405 return rumpusb_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
406 }
407
408 static void
rumpusb_device_ctrl_abort(struct usbd_xfer * xfer)409 rumpusb_device_ctrl_abort(struct usbd_xfer *xfer)
410 {
411
412 }
413
414 static void
rumpusb_device_ctrl_close(struct usbd_pipe * pipe)415 rumpusb_device_ctrl_close(struct usbd_pipe *pipe)
416 {
417
418 }
419
420 static void
rumpusb_device_ctrl_cleartoggle(struct usbd_pipe * pipe)421 rumpusb_device_ctrl_cleartoggle(struct usbd_pipe *pipe)
422 {
423
424 }
425
426 static void
rumpusb_device_ctrl_done(struct usbd_xfer * xfer)427 rumpusb_device_ctrl_done(struct usbd_xfer *xfer)
428 {
429
430 }
431
432 static const struct usbd_pipe_methods rumpusb_device_ctrl_methods = {
433 .upm_transfer = rumpusb_device_ctrl_transfer,
434 .upm_start = rumpusb_device_ctrl_start,
435 .upm_abort = rumpusb_device_ctrl_abort,
436 .upm_close = rumpusb_device_ctrl_close,
437 .upm_cleartoggle = rumpusb_device_ctrl_cleartoggle,
438 .upm_done = rumpusb_device_ctrl_done,
439 };
440
441 static void
rhscintr(void * arg)442 rhscintr(void *arg)
443 {
444 char buf[UGENDEV_BUFSIZE];
445 struct ugenhc_softc *sc = arg;
446 struct usbd_xfer *xfer;
447 int fd, error;
448
449 makeugendevstr(sc->sc_devnum, 0, buf, sizeof(buf));
450
451 for (;;) {
452 /*
453 * Detect device attach.
454 */
455
456 for (;;) {
457 error = rumpuser_open(buf, RUMPUSER_OPEN_RDWR, &fd);
458 if (error == 0)
459 break;
460 kpause("ugwait", false, hz/4, NULL);
461 }
462
463 sc->sc_ugenfd[UGEN_EPT_CTRL] = fd;
464 sc->sc_port_status = UPS_CURRENT_CONNECT_STATUS
465 | UPS_PORT_ENABLED | UPS_PORT_POWER;
466 sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET;
467
468 xfer = sc->sc_intrxfer;
469 memset(xfer->ux_buffer, 0xff, xfer->ux_length);
470 xfer->ux_actlen = xfer->ux_length;
471 xfer->ux_status = USBD_NORMAL_COMPLETION;
472
473 mutex_enter(&sc->sc_lock);
474 usb_transfer_complete(xfer);
475 mutex_exit(&sc->sc_lock);
476
477 kpause("ugwait2", false, hz, NULL);
478
479 /*
480 * Detect device detach.
481 */
482
483 for (;;) {
484 error = rumpuser_open(buf, RUMPUSER_OPEN_RDWR, &fd);
485 if (fd == -1)
486 break;
487
488 error = rumpuser_close(fd);
489 kpause("ugwait2", false, hz/4, NULL);
490 }
491
492 sc->sc_port_status = ~(UPS_CURRENT_CONNECT_STATUS
493 | UPS_PORT_ENABLED | UPS_PORT_POWER);
494 sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET;
495
496 error = rumpuser_close(sc->sc_ugenfd[UGEN_EPT_CTRL]);
497 sc->sc_ugenfd[UGEN_EPT_CTRL] = -1;
498
499 xfer = sc->sc_intrxfer;
500 memset(xfer->ux_buffer, 0xff, xfer->ux_length);
501 xfer->ux_actlen = xfer->ux_length;
502 xfer->ux_status = USBD_NORMAL_COMPLETION;
503 mutex_enter(&sc->sc_lock);
504 usb_transfer_complete(xfer);
505 mutex_exit(&sc->sc_lock);
506
507 kpause("ugwait3", false, hz, NULL);
508 }
509
510 kthread_exit(0);
511 }
512
513 static usbd_status
rumpusb_root_intr_start(struct usbd_xfer * xfer)514 rumpusb_root_intr_start(struct usbd_xfer *xfer)
515 {
516 struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer);
517 int error;
518
519 KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
520
521 sc->sc_intrxfer = xfer;
522 if (!sc->sc_rhintr) {
523 error = kthread_create(PRI_NONE, 0, NULL,
524 rhscintr, sc, &sc->sc_rhintr, "ugenrhi");
525 if (error)
526 xfer->ux_status = USBD_IOERROR;
527 }
528
529 return USBD_IN_PROGRESS;
530 }
531
532 static usbd_status
rumpusb_root_intr_transfer(struct usbd_xfer * xfer)533 rumpusb_root_intr_transfer(struct usbd_xfer *xfer)
534 {
535
536 return rumpusb_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
537 }
538
539 static void
rumpusb_root_intr_abort(struct usbd_xfer * xfer)540 rumpusb_root_intr_abort(struct usbd_xfer *xfer)
541 {
542
543 }
544
545 static void
rumpusb_root_intr_close(struct usbd_pipe * pipe)546 rumpusb_root_intr_close(struct usbd_pipe *pipe)
547 {
548
549 }
550
551 static void
rumpusb_root_intr_cleartoggle(struct usbd_pipe * pipe)552 rumpusb_root_intr_cleartoggle(struct usbd_pipe *pipe)
553 {
554
555 }
556
557 static void
rumpusb_root_intr_done(struct usbd_xfer * xfer)558 rumpusb_root_intr_done(struct usbd_xfer *xfer)
559 {
560
561 }
562
563 static const struct usbd_pipe_methods rumpusb_root_intr_methods = {
564 .upm_transfer = rumpusb_root_intr_transfer,
565 .upm_start = rumpusb_root_intr_start,
566 .upm_abort = rumpusb_root_intr_abort,
567 .upm_close = rumpusb_root_intr_close,
568 .upm_cleartoggle = rumpusb_root_intr_cleartoggle,
569 .upm_done = rumpusb_root_intr_done,
570 };
571
572 static usbd_status
rumpusb_device_bulk_start(struct usbd_xfer * xfer)573 rumpusb_device_bulk_start(struct usbd_xfer *xfer)
574 {
575 struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer);
576 usb_endpoint_descriptor_t *ed = xfer->ux_pipe->up_endpoint->ue_edesc;
577 size_t n, done;
578 bool isread;
579 int len, error, endpt;
580 uint8_t *buf;
581 int xfererr = USBD_NORMAL_COMPLETION;
582 int shortval, i;
583
584 KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
585
586 ed = xfer->ux_pipe->up_endpoint->ue_edesc;
587 endpt = ed->bEndpointAddress;
588 isread = UE_GET_DIR(endpt) == UE_DIR_IN;
589 endpt = UE_GET_ADDR(endpt);
590 KASSERT(endpt < UGEN_NEPTS);
591
592 buf = xfer->ux_buf;
593 done = 0;
594 if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) {
595 for (i = 0, len = 0; i < xfer->ux_nframes; i++)
596 len += xfer->ux_frlengths[i];
597 } else {
598 KASSERT(xfer->ux_length);
599 len = xfer->ux_length;
600 }
601 shortval = (xfer->ux_flags & USBD_SHORT_XFER_OK) != 0;
602
603 while (RUSB(xfer)->rusb_status == 0) {
604 if (isread) {
605 struct rumpuser_iovec iov;
606
607 rumpcomp_ugenhc_ioctl(sc->sc_ugenfd[endpt],
608 USB_SET_SHORT_XFER, &shortval, &error);
609 iov.iov_base = buf+done;
610 iov.iov_len = len-done;
611 error = rumpuser_iovread(sc->sc_ugenfd[endpt], &iov, 1,
612 RUMPUSER_IOV_NOSEEK, &n);
613 if (error) {
614 n = 0;
615 if (done == 0) {
616 if (error == ETIMEDOUT)
617 continue;
618 xfererr = USBD_IOERROR;
619 goto out;
620 }
621 }
622 done += n;
623 if (done == len)
624 break;
625 } else {
626 struct rumpuser_iovec iov;
627
628 iov.iov_base = buf;
629 iov.iov_len = len;
630 error = rumpuser_iovwrite(sc->sc_ugenfd[endpt], &iov, 1,
631 RUMPUSER_IOV_NOSEEK, &n);
632 done = n;
633 if (done == len)
634 break;
635 else if (!error)
636 panic("short write");
637
638 xfererr = USBD_IOERROR;
639 goto out;
640 }
641
642 if (shortval) {
643 /*
644 * Holy XXX, bitman. I get >16byte interrupt
645 * transfers from ugen in 16 byte chunks.
646 * Don't know how to better fix this for now.
647 * Of course this hack will fail e.g. if someone
648 * sports other magic values or if the transfer
649 * happens to be an integral multiple of 16
650 * in size ....
651 */
652 if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT
653 && n == 16) {
654 continue;
655 } else {
656 break;
657 }
658 }
659 }
660
661 if (RUSB(xfer)->rusb_status == 0) {
662 xfer->ux_actlen = done;
663 } else {
664 xfererr = USBD_CANCELLED;
665 RUSB(xfer)->rusb_status = 2;
666 }
667 out:
668 if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS)
669 if (done != len)
670 panic("lazy bum");
671 xfer->ux_status = xfererr;
672 usb_transfer_complete(xfer);
673 return USBD_IN_PROGRESS;
674 }
675
676 static void
doxfer_kth(void * arg)677 doxfer_kth(void *arg)
678 {
679 struct usbd_pipe *pipe = arg;
680 struct ugenhc_softc *sc = UGENHC_PIPE2SC(pipe);
681
682 mutex_enter(&sc->sc_lock);
683 do {
684 struct usbd_xfer *xfer = SIMPLEQ_FIRST(&pipe->up_queue);
685 rumpusb_device_bulk_start(xfer);
686 } while (!SIMPLEQ_EMPTY(&pipe->up_queue));
687 mutex_exit(&sc->sc_lock);
688 kthread_exit(0);
689 }
690
691 static usbd_status
rumpusb_device_bulk_transfer(struct usbd_xfer * xfer)692 rumpusb_device_bulk_transfer(struct usbd_xfer *xfer)
693 {
694
695 if (!rump_threads) {
696 /* XXX: lie about supporting async transfers */
697 if ((xfer->ux_flags & USBD_SYNCHRONOUS) == 0) {
698 printf("non-threaded rump does not support "
699 "async transfers.\n");
700 return USBD_IN_PROGRESS;
701 }
702
703 return rumpusb_device_bulk_start(
704 SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
705 } else {
706 kthread_create(PRI_NONE, 0, NULL, doxfer_kth, xfer->ux_pipe, NULL,
707 "rusbhcxf");
708
709 return USBD_IN_PROGRESS;
710 }
711 }
712
713 /* wait for transfer to abort. yea, this is cheesy (from a spray can) */
714 static void
rumpusb_device_bulk_abort(struct usbd_xfer * xfer)715 rumpusb_device_bulk_abort(struct usbd_xfer *xfer)
716 {
717 struct rusb_xfer *rx = RUSB(xfer);
718
719 rx->rusb_status = 1;
720 while (rx->rusb_status < 2) {
721 kpause("jopo", false, hz/10, NULL);
722 }
723 }
724
725 static void
rumpusb_device_bulk_close(struct usbd_pipe * pipe)726 rumpusb_device_bulk_close(struct usbd_pipe *pipe)
727 {
728 struct ugenhc_softc *sc = UGENHC_PIPE2SC(pipe);
729 int endpt = pipe->up_endpoint->ue_edesc->bEndpointAddress;
730 struct usbd_xfer *xfer;
731
732 KASSERT(mutex_owned(&sc->sc_lock));
733
734 endpt = UE_GET_ADDR(endpt);
735
736 while ((xfer = SIMPLEQ_FIRST(&pipe->up_queue)) != NULL)
737 rumpusb_device_bulk_abort(xfer);
738
739 rumpuser_close(sc->sc_ugenfd[endpt]);
740 sc->sc_ugenfd[endpt] = -1;
741 sc->sc_fdmodes[endpt] = -1;
742 }
743
744 static void
rumpusb_device_bulk_cleartoggle(struct usbd_pipe * pipe)745 rumpusb_device_bulk_cleartoggle(struct usbd_pipe *pipe)
746 {
747
748 }
749
750 static void
rumpusb_device_bulk_done(struct usbd_xfer * xfer)751 rumpusb_device_bulk_done(struct usbd_xfer *xfer)
752 {
753
754 }
755
756 static const struct usbd_pipe_methods rumpusb_device_bulk_methods = {
757 .upm_transfer = rumpusb_device_bulk_transfer,
758 .upm_start = rumpusb_device_bulk_start,
759 .upm_abort = rumpusb_device_bulk_abort,
760 .upm_close = rumpusb_device_bulk_close,
761 .upm_cleartoggle = rumpusb_device_bulk_cleartoggle,
762 .upm_done = rumpusb_device_bulk_done,
763 };
764
765 static usbd_status
ugenhc_open(struct usbd_pipe * pipe)766 ugenhc_open(struct usbd_pipe *pipe)
767 {
768 struct usbd_device *dev = pipe->up_dev;
769 struct ugenhc_softc *sc = UGENHC_PIPE2SC(pipe);
770 usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc;
771 uint8_t rhaddr = dev->ud_bus->ub_rhaddr;
772 uint8_t addr = dev->ud_addr;
773 uint8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
774 char buf[UGENDEV_BUFSIZE];
775 int endpt, oflags, error;
776 int fd, val;
777
778 if (addr == rhaddr) {
779 switch (xfertype) {
780 case UE_CONTROL:
781 pipe->up_methods = &roothub_ctrl_methods;
782 break;
783 case UE_INTERRUPT:
784 pipe->up_methods = &rumpusb_root_intr_methods;
785 break;
786 default:
787 panic("%d not supported", xfertype);
788 break;
789 }
790 } else {
791 switch (xfertype) {
792 case UE_CONTROL:
793 pipe->up_methods = &rumpusb_device_ctrl_methods;
794 break;
795 case UE_INTERRUPT:
796 case UE_BULK:
797 case UE_ISOCHRONOUS:
798 pipe->up_methods = &rumpusb_device_bulk_methods;
799 endpt = pipe->up_endpoint->ue_edesc->bEndpointAddress;
800 if (UE_GET_DIR(endpt) == UE_DIR_IN) {
801 oflags = O_RDONLY;
802 } else {
803 oflags = O_WRONLY;
804 }
805 endpt = UE_GET_ADDR(endpt);
806
807 if (oflags != O_RDONLY && xfertype == UE_ISOCHRONOUS) {
808 printf("WARNING: faking isoc write open\n");
809 oflags = O_RDONLY;
810 }
811
812 if (sc->sc_fdmodes[endpt] == oflags
813 || sc->sc_fdmodes[endpt] == O_RDWR)
814 break;
815
816 if (sc->sc_fdmodes[endpt] != -1) {
817 /* XXX: closing from under someone? */
818 error = rumpuser_close(sc->sc_ugenfd[endpt]);
819 oflags = O_RDWR;
820 }
821
822 makeugendevstr(sc->sc_devnum, endpt, buf, sizeof(buf));
823 /* XXX: theoretically should convert oflags */
824 error = rumpuser_open(buf, oflags, &fd);
825 if (error != 0) {
826 return USBD_INVAL; /* XXX: no mapping */
827 }
828 val = 100;
829 if (rumpcomp_ugenhc_ioctl(fd, USB_SET_TIMEOUT, &val,
830 &error) == -1)
831 panic("timeout set failed");
832 sc->sc_ugenfd[endpt] = fd;
833 sc->sc_fdmodes[endpt] = oflags;
834
835 break;
836 default:
837 panic("%d not supported", xfertype);
838 break;
839
840 }
841 }
842 return 0;
843 }
844
845 static void
ugenhc_softint(void * arg)846 ugenhc_softint(void *arg)
847 {
848
849 }
850
851 static void
ugenhc_poll(struct usbd_bus * ubus)852 ugenhc_poll(struct usbd_bus *ubus)
853 {
854
855 }
856
857 static struct usbd_xfer *
ugenhc_allocx(struct usbd_bus * bus,unsigned int nframes)858 ugenhc_allocx(struct usbd_bus *bus, unsigned int nframes)
859 {
860 struct usbd_xfer *xfer;
861
862 xfer = kmem_zalloc(sizeof(struct usbd_xfer), KM_SLEEP);
863 xfer->ux_state = XFER_BUSY;
864
865 return xfer;
866 }
867
868 static void
ugenhc_freex(struct usbd_bus * bus,struct usbd_xfer * xfer)869 ugenhc_freex(struct usbd_bus *bus, struct usbd_xfer *xfer)
870 {
871
872 kmem_free(xfer, sizeof(struct usbd_xfer));
873 }
874
875
876 static void
ugenhc_getlock(struct usbd_bus * bus,kmutex_t ** lock)877 ugenhc_getlock(struct usbd_bus *bus, kmutex_t **lock)
878 {
879 struct ugenhc_softc *sc = UGENHC_BUS2SC(bus);
880
881 *lock = &sc->sc_lock;
882 }
883
884 struct ugenhc_pipe {
885 struct usbd_pipe pipe;
886 };
887
888 static const struct usbd_bus_methods ugenhc_bus_methods = {
889 .ubm_open = ugenhc_open,
890 .ubm_softint = ugenhc_softint,
891 .ubm_dopoll = ugenhc_poll,
892 .ubm_allocx = ugenhc_allocx,
893 .ubm_freex = ugenhc_freex,
894 .ubm_getlock = ugenhc_getlock,
895 .ubm_rhctrl = ugenhc_roothub_ctrl,
896 };
897
898 static int
ugenhc_probe(device_t parent,cfdata_t match,void * aux)899 ugenhc_probe(device_t parent, cfdata_t match, void *aux)
900 {
901 char buf[UGENDEV_BUFSIZE];
902
903 makeugendevstr(match->cf_unit, 0, buf, sizeof(buf));
904 if (rumpuser_getfileinfo(buf, NULL, NULL) != 0)
905 return 0;
906
907 return 1;
908 }
909
910 static void
ugenhc_attach(device_t parent,device_t self,void * aux)911 ugenhc_attach(device_t parent, device_t self, void *aux)
912 {
913 struct mainbus_attach_args *maa = aux;
914 struct ugenhc_softc *sc = device_private(self);
915
916 aprint_normal("\n");
917
918 memset(sc, 0, sizeof(*sc));
919 memset(&sc->sc_ugenfd, -1, sizeof(sc->sc_ugenfd));
920 memset(&sc->sc_fdmodes, -1, sizeof(sc->sc_fdmodes));
921
922 sc->sc_bus.ub_revision = USBREV_2_0;
923 sc->sc_bus.ub_methods = &ugenhc_bus_methods;
924 sc->sc_bus.ub_hcpriv = sc;
925 sc->sc_bus.ub_pipesize = sizeof(struct ugenhc_pipe);
926 sc->sc_bus.ub_usedma = false;
927 sc->sc_devnum = maa->maa_unit;
928
929 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
930
931 config_found(self, &sc->sc_bus, usbctlprint, CFARGS_NONE);
932 }
933