HAMMER 43C/Many: Performance cleanup
[dragonfly.git] / sys / dev / usbmisc / ugen / ugen.c
CommitLineData
1550dfd9
MD
1/*
2 * $NetBSD: ugen.c,v 1.27 1999/10/28 12:08:38 augustss Exp $
3 * $NetBSD: ugen.c,v 1.59 2002/07/11 21:14:28 augustss Exp $
4 * $FreeBSD: src/sys/dev/usb/ugen.c,v 1.81 2003/11/09 09:17:22 tanimura Exp $
287c99c5 5 * $DragonFly: src/sys/dev/usbmisc/ugen/ugen.c,v 1.33 2007/11/06 07:37:01 hasso Exp $
1550dfd9
MD
6 */
7
8/*
9 * Also already merged from NetBSD:
10 * $NetBSD: ugen.c,v 1.61 2002/09/23 05:51:20 simonb Exp $
11 * $NetBSD: ugen.c,v 1.64 2003/06/28 14:21:46 darrenr Exp $
12 * $NetBSD: ugen.c,v 1.65 2003/06/29 22:30:56 fvdl Exp $
13 */
984263bc
MD
14
15/*
16 * Copyright (c) 1998 The NetBSD Foundation, Inc.
17 * All rights reserved.
18 *
19 * This code is derived from software contributed to The NetBSD Foundation
20 * by Lennart Augustsson (lennart@augustsson.net) at
21 * Carlstedt Research & Technology.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 * must display the following acknowledgement:
33 * This product includes software developed by the NetBSD
34 * Foundation, Inc. and its contributors.
35 * 4. Neither the name of The NetBSD Foundation nor the names of its
36 * contributors may be used to endorse or promote products derived
37 * from this software without specific prior written permission.
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
40 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
41 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
43 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
44 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
45 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
46 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49 * POSSIBILITY OF SUCH DAMAGE.
50 */
51
52
53#include <sys/param.h>
54#include <sys/systm.h>
55#include <sys/kernel.h>
56#include <sys/malloc.h>
984263bc
MD
57#include <sys/module.h>
58#include <sys/bus.h>
59#include <sys/ioccom.h>
60#include <sys/conf.h>
61#include <sys/fcntl.h>
62#include <sys/filio.h>
984263bc
MD
63#include <sys/tty.h>
64#include <sys/file.h>
65#include <sys/select.h>
984263bc
MD
66#include <sys/vnode.h>
67#include <sys/poll.h>
68#include <sys/sysctl.h>
4e01b467 69#include <sys/thread2.h>
984263bc 70
1f2de5d4
MD
71#include <bus/usb/usb.h>
72#include <bus/usb/usbdi.h>
73#include <bus/usb/usbdi_util.h>
984263bc 74
467306a6
MD
75#include "ugenbuf.h"
76
77SYSCTL_NODE(_hw_usb, OID_AUTO, ugen, CTLFLAG_RW, 0, "USB ugen");
78
984263bc 79#ifdef USB_DEBUG
fc1ef497
HT
80#define DPRINTF(x) if (ugendebug) kprintf x
81#define DPRINTFN(n,x) if (ugendebug>(n)) kprintf x
984263bc 82int ugendebug = 0;
984263bc
MD
83SYSCTL_INT(_hw_usb_ugen, OID_AUTO, debug, CTLFLAG_RW,
84 &ugendebug, 0, "ugen debug level");
85#else
86#define DPRINTF(x)
87#define DPRINTFN(n,x)
88#endif
89
467306a6
MD
90static int ugen_bufsize = 16384;
91SYSCTL_INT(_hw_usb_ugen, OID_AUTO, bufsize, CTLFLAG_RW,
92 &ugen_bufsize, 0, "ugen temporary buffer size");
93
984263bc
MD
94#define UGEN_CHUNK 128 /* chunk size for read */
95#define UGEN_IBSIZE 1020 /* buffer size */
984263bc
MD
96
97#define UGEN_NISOFRAMES 500 /* 0.5 seconds worth */
98#define UGEN_NISOREQS 6 /* number of outstanding xfer requests */
99#define UGEN_NISORFRMS 4 /* number of frames (miliseconds) per req */
100
101struct ugen_endpoint {
102 struct ugen_softc *sc;
b13267a5 103 cdev_t dev;
984263bc
MD
104 usb_endpoint_descriptor_t *edesc;
105 usbd_interface_handle iface;
106 int state;
107#define UGEN_ASLP 0x02 /* waiting for data */
108#define UGEN_SHORT_OK 0x04 /* short xfers are OK */
109 usbd_pipe_handle pipeh;
110 struct clist q;
111 struct selinfo rsel;
112 u_char *ibuf; /* start of buffer (circular for isoc) */
113 u_char *fill; /* location for input (isoc) */
114 u_char *limit; /* end of circular buffer (isoc) */
115 u_char *cur; /* current read location (isoc) */
116 u_int32_t timeout;
117 struct isoreq {
118 struct ugen_endpoint *sce;
119 usbd_xfer_handle xfer;
120 void *dmabuf;
121 u_int16_t sizes[UGEN_NISORFRMS];
122 } isoreqs[UGEN_NISOREQS];
123};
124
125struct ugen_softc {
6ed427ca 126 device_t sc_dev; /* base device */
984263bc
MD
127 usbd_device_handle sc_udev;
128
129 char sc_is_open[USB_MAX_ENDPOINTS];
130 struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];
131#define OUT 0
132#define IN 1
133
134 int sc_refcnt;
135 u_char sc_dying;
136};
137
984263bc
MD
138d_open_t ugenopen;
139d_close_t ugenclose;
140d_read_t ugenread;
141d_write_t ugenwrite;
142d_ioctl_t ugenioctl;
143d_poll_t ugenpoll;
144
145#define UGEN_CDEV_MAJOR 114
146
6ed427ca 147static struct dev_ops ugen_ops = {
fef8985e
MD
148 { "ugen", UGEN_CDEV_MAJOR, 0 },
149 .d_open = ugenopen,
150 .d_close = ugenclose,
151 .d_read = ugenread,
152 .d_write = ugenwrite,
153 .d_ioctl = ugenioctl,
154 .d_poll = ugenpoll,
984263bc 155};
984263bc 156
6ed427ca 157static void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr,
1550dfd9 158 usbd_status status);
6ed427ca 159static void ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr,
984263bc 160 usbd_status status);
6ed427ca
HT
161static int ugen_do_read(struct ugen_softc *, int, struct uio *, int);
162static int ugen_do_write(struct ugen_softc *, int, struct uio *, int);
163static int ugen_do_ioctl(struct ugen_softc *, int, u_long,
fef8985e 164 caddr_t, int);
6ed427ca
HT
165static void ugen_make_devnodes(struct ugen_softc *sc);
166static void ugen_destroy_devnodes(struct ugen_softc *sc);
167static int ugen_set_config(struct ugen_softc *sc, int configno);
168static usb_config_descriptor_t *ugen_get_cdesc(struct ugen_softc *sc,
1550dfd9 169 int index, int *lenp);
6ed427ca
HT
170static usbd_status ugen_set_interface(struct ugen_softc *, int, int);
171static int ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx);
984263bc 172
e4c9c0c8 173#define UGENUNIT(n) ((lminor(n) >> 4) & 0xff)
984263bc 174#define UGENENDPOINT(n) (minor(n) & 0xf)
e4c9c0c8
MD
175#define UGENMINOR(u, e) (((u & 0xf) << 4) | ((u & 0xf0) << 12) | (e))
176#define UGENUNITMASK 0xffff00f0
984263bc 177
61b69189
HT
178static device_probe_t ugen_match;
179static device_attach_t ugen_attach;
180static device_detach_t ugen_detach;
181
182static devclass_t ugen_devclass;
183
184static kobj_method_t ugen_methods[] = {
185 DEVMETHOD(device_probe, ugen_match),
186 DEVMETHOD(device_attach, ugen_attach),
187 DEVMETHOD(device_detach, ugen_detach),
188 {0,0}
189};
190
191static driver_t ugen_driver = {
192 "ugen",
193 ugen_methods,
194 sizeof(struct ugen_softc)
195};
196
197MODULE_DEPEND(ugen, usb, 1, 1, 1);
984263bc 198
e785a5d9
HT
199static int
200ugen_match(device_t self)
984263bc 201{
e785a5d9 202 struct usb_attach_arg *uaa = device_get_ivars(self);
984263bc 203
1550dfd9
MD
204#if 0
205 if (uaa->matchlvl)
206 return (uaa->matchlvl);
207#endif
984263bc
MD
208 if (uaa->usegeneric)
209 return (UMATCH_GENERIC);
210 else
211 return (UMATCH_NONE);
212}
213
e785a5d9
HT
214static int
215ugen_attach(device_t self)
984263bc 216{
e785a5d9
HT
217 struct ugen_softc *sc = device_get_softc(self);
218 struct usb_attach_arg *uaa = device_get_ivars(self);
984263bc 219 usbd_device_handle udev;
984263bc
MD
220 usbd_status err;
221 int conf;
1550dfd9 222
e785a5d9 223 sc->sc_dev = self;
984263bc
MD
224 sc->sc_udev = udev = uaa->device;
225
226 memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
227
228 /* First set configuration index 0, the default one for ugen. */
229 err = usbd_set_config_index(udev, 0, 0);
230 if (err) {
e3869ec7 231 kprintf("%s: setting configuration index 0 failed\n",
6ed427ca 232 device_get_nameunit(sc->sc_dev));
984263bc 233 sc->sc_dying = 1;
e785a5d9 234 return ENXIO;
984263bc
MD
235 }
236 conf = usbd_get_config_descriptor(udev)->bConfigurationValue;
237
238 /* Set up all the local state for this configuration. */
239 err = ugen_set_config(sc, conf);
240 if (err) {
e3869ec7 241 kprintf("%s: setting configuration %d failed\n",
6ed427ca 242 device_get_nameunit(sc->sc_dev), conf);
984263bc 243 sc->sc_dying = 1;
e785a5d9 244 return ENXIO;
984263bc
MD
245 }
246
1550dfd9 247 /* the main device, ctrl endpoint */
fef8985e 248 dev_ops_add(&ugen_ops,
6ed427ca
HT
249 UGENUNITMASK, UGENMINOR(device_get_unit(sc->sc_dev), 0));
250 make_dev(&ugen_ops, UGENMINOR(device_get_unit(sc->sc_dev), 0),
251 UID_ROOT, GID_OPERATOR, 0644, "%s", device_get_nameunit(sc->sc_dev));
1550dfd9 252
e785a5d9 253 return 0;
984263bc
MD
254}
255
6ed427ca 256static void
1550dfd9
MD
257ugen_make_devnodes(struct ugen_softc *sc)
258{
259 int endptno;
b13267a5 260 cdev_t dev;
1550dfd9
MD
261
262 for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) {
263 if (sc->sc_endpoints[endptno][IN].sc != NULL ||
264 sc->sc_endpoints[endptno][OUT].sc != NULL ) {
265 /* endpt can be 0x81 and 0x01, representing
266 * endpoint address 0x01 and IN/OUT directions.
267 * We map both endpts to the same device,
268 * IN is reading from it, OUT is writing to it.
269 *
270 * In the if clause above we check whether one
271 * of the structs is populated.
272 */
fef8985e 273 dev = make_dev(&ugen_ops,
6ed427ca 274 UGENMINOR(device_get_unit(sc->sc_dev), endptno),
1550dfd9
MD
275 UID_ROOT, GID_OPERATOR, 0644,
276 "%s.%d",
6ed427ca 277 device_get_nameunit(sc->sc_dev), endptno);
e4c9c0c8 278 if (sc->sc_endpoints[endptno][IN].sc != NULL) {
e4c9c0c8
MD
279 reference_dev(dev);
280 if (sc->sc_endpoints[endptno][IN].dev)
281 release_dev(sc->sc_endpoints[endptno][IN].dev);
1550dfd9 282 sc->sc_endpoints[endptno][IN].dev = dev;
e4c9c0c8
MD
283 }
284 if (sc->sc_endpoints[endptno][OUT].sc != NULL) {
e4c9c0c8
MD
285 reference_dev(dev);
286 if (sc->sc_endpoints[endptno][OUT].dev)
287 release_dev(sc->sc_endpoints[endptno][OUT].dev);
1550dfd9 288 sc->sc_endpoints[endptno][OUT].dev = dev;
e4c9c0c8 289 }
1550dfd9
MD
290 }
291 }
292}
293
6ed427ca 294static void
1550dfd9
MD
295ugen_destroy_devnodes(struct ugen_softc *sc)
296{
297 int endptno;
b13267a5 298 cdev_t dev;
1550dfd9
MD
299
300 /* destroy all devices for the other (existing) endpoints as well */
301 for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) {
302 if (sc->sc_endpoints[endptno][IN].sc != NULL ||
303 sc->sc_endpoints[endptno][OUT].sc != NULL ) {
304 /* endpt can be 0x81 and 0x01, representing
305 * endpoint address 0x01 and IN/OUT directions.
306 * We map both endpoint addresses to the same device,
307 * IN is reading from it, OUT is writing to it.
308 *
309 * In the if clause above we check whether one
310 * of the structs is populated.
311 */
e4c9c0c8
MD
312 dev = sc->sc_endpoints[endptno][IN].dev;
313 if (dev != NULL) {
e4c9c0c8
MD
314 destroy_dev(dev);
315 sc->sc_endpoints[endptno][IN].dev = NULL;
316 }
317 dev = sc->sc_endpoints[endptno][OUT].dev;
318 if (dev != NULL) {
e4c9c0c8
MD
319 destroy_dev(dev);
320 sc->sc_endpoints[endptno][OUT].dev = NULL;
321 }
1550dfd9
MD
322 }
323 }
324}
1550dfd9 325
6ed427ca 326static int
984263bc
MD
327ugen_set_config(struct ugen_softc *sc, int configno)
328{
329 usbd_device_handle dev = sc->sc_udev;
330 usbd_interface_handle iface;
331 usb_endpoint_descriptor_t *ed;
332 struct ugen_endpoint *sce;
333 u_int8_t niface, nendpt;
334 int ifaceno, endptno, endpt;
335 usbd_status err;
336 int dir;
337
338 DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
6ed427ca 339 device_get_nameunit(sc->sc_dev), configno, sc));
984263bc 340
1550dfd9 341 ugen_destroy_devnodes(sc);
1550dfd9 342
984263bc
MD
343 /* We start at 1, not 0, because we don't care whether the
344 * control endpoint is open or not. It is always present.
345 */
e4c9c0c8 346 for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) {
984263bc
MD
347 if (sc->sc_is_open[endptno]) {
348 DPRINTFN(1,
349 ("ugen_set_config: %s - endpoint %d is open\n",
6ed427ca 350 device_get_nameunit(sc->sc_dev), endptno));
984263bc
MD
351 return (USBD_IN_USE);
352 }
e4c9c0c8 353 }
984263bc 354
1550dfd9 355 /* Avoid setting the current value. */
984263bc 356 if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {
1550dfd9 357 err = usbd_set_config_no(dev, configno, 1);
984263bc
MD
358 if (err)
359 return (err);
360 }
361
362 err = usbd_interface_count(dev, &niface);
363 if (err)
364 return (err);
365 memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
366 for (ifaceno = 0; ifaceno < niface; ifaceno++) {
367 DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
368 err = usbd_device2interface_handle(dev, ifaceno, &iface);
369 if (err)
370 return (err);
371 err = usbd_endpoint_count(iface, &nendpt);
372 if (err)
373 return (err);
374 for (endptno = 0; endptno < nendpt; endptno++) {
375 ed = usbd_interface2endpoint_descriptor(iface,endptno);
1550dfd9
MD
376 endpt = ed->bEndpointAddress;
377 dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
378 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
984263bc 379 DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
1550dfd9
MD
380 "(%d,%d), sce=%p\n",
381 endptno, endpt, UE_GET_ADDR(endpt),
382 UE_GET_DIR(endpt), sce));
984263bc
MD
383 sce->sc = sc;
384 sce->edesc = ed;
385 sce->iface = iface;
386 }
387 }
388
1550dfd9 389 ugen_make_devnodes(sc);
984263bc
MD
390
391 return (USBD_NORMAL_COMPLETION);
392}
393
394int
fef8985e 395ugenopen(struct dev_open_args *ap)
984263bc 396{
b13267a5 397 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
398 struct ugen_softc *sc;
399 int unit = UGENUNIT(dev);
400 int endpt = UGENENDPOINT(dev);
401 usb_endpoint_descriptor_t *edesc;
402 struct ugen_endpoint *sce;
403 int dir, isize;
404 usbd_status err;
405 usbd_xfer_handle xfer;
406 void *buf;
407 int i, j;
408
1e089e7e
HT
409 sc = devclass_get_softc(ugen_devclass, unit);
410 if (sc == NULL)
411 return (ENXIO);
984263bc 412
1550dfd9 413 DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n",
fef8985e 414 ap->a_oflags, ap->a_devtype, unit, endpt));
984263bc
MD
415
416 if (sc == NULL || sc->sc_dying)
417 return (ENXIO);
418
419 if (sc->sc_is_open[endpt])
420 return (EBUSY);
421
422 if (endpt == USB_CONTROL_ENDPOINT) {
423 sc->sc_is_open[USB_CONTROL_ENDPOINT] = 1;
424 return (0);
425 }
426
427 /* Make sure there are pipes for all directions. */
428 for (dir = OUT; dir <= IN; dir++) {
fef8985e 429 if (ap->a_oflags & (dir == OUT ? FWRITE : FREAD)) {
984263bc
MD
430 sce = &sc->sc_endpoints[endpt][dir];
431 if (sce == 0 || sce->edesc == 0)
432 return (ENXIO);
433 }
434 }
435
436 /* Actually open the pipes. */
437 /* XXX Should back out properly if it fails. */
438 for (dir = OUT; dir <= IN; dir++) {
fef8985e 439 if (!(ap->a_oflags & (dir == OUT ? FWRITE : FREAD)))
984263bc
MD
440 continue;
441 sce = &sc->sc_endpoints[endpt][dir];
442 sce->state = 0;
443 sce->timeout = USBD_NO_TIMEOUT;
1550dfd9 444 DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n",
984263bc
MD
445 sc, endpt, dir, sce));
446 edesc = sce->edesc;
447 switch (edesc->bmAttributes & UE_XFERTYPE) {
448 case UE_INTERRUPT:
1550dfd9
MD
449 if (dir == OUT) {
450 err = usbd_open_pipe(sce->iface,
451 edesc->bEndpointAddress, 0, &sce->pipeh);
452 if (err)
453 return (EIO);
454 break;
455 }
984263bc
MD
456 isize = UGETW(edesc->wMaxPacketSize);
457 if (isize == 0) /* shouldn't happen */
458 return (EINVAL);
efda3bd0 459 sce->ibuf = kmalloc(isize, M_USBDEV, M_WAITOK);
1550dfd9 460 DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",
984263bc 461 endpt, isize));
375a9af6
HT
462 if ((clist_alloc_cblocks(&sce->q, UGEN_IBSIZE,
463 UGEN_IBSIZE), 0) == -1)
984263bc 464 return (ENOMEM);
1550dfd9
MD
465 err = usbd_open_pipe_intr(sce->iface,
466 edesc->bEndpointAddress,
467 USBD_SHORT_XFER_OK, &sce->pipeh, sce,
984263bc
MD
468 sce->ibuf, isize, ugenintr,
469 USBD_DEFAULT_INTERVAL);
470 if (err) {
efda3bd0 471 kfree(sce->ibuf, M_USBDEV);
375a9af6 472 clist_free_cblocks(&sce->q);
984263bc
MD
473 return (EIO);
474 }
475 DPRINTFN(5, ("ugenopen: interrupt open done\n"));
476 break;
477 case UE_BULK:
1550dfd9 478 err = usbd_open_pipe(sce->iface,
984263bc
MD
479 edesc->bEndpointAddress, 0, &sce->pipeh);
480 if (err)
481 return (EIO);
482 break;
483 case UE_ISOCHRONOUS:
484 if (dir == OUT)
485 return (EINVAL);
486 isize = UGETW(edesc->wMaxPacketSize);
487 if (isize == 0) /* shouldn't happen */
488 return (EINVAL);
77652cad 489 sce->ibuf = kmalloc(isize * UGEN_NISOFRAMES,
984263bc
MD
490 M_USBDEV, M_WAITOK);
491 sce->cur = sce->fill = sce->ibuf;
492 sce->limit = sce->ibuf + isize * UGEN_NISOFRAMES;
1550dfd9 493 DPRINTFN(5, ("ugenopen: isoc endpt=%d, isize=%d\n",
984263bc
MD
494 endpt, isize));
495 err = usbd_open_pipe(sce->iface,
496 edesc->bEndpointAddress, 0, &sce->pipeh);
497 if (err) {
efda3bd0 498 kfree(sce->ibuf, M_USBDEV);
984263bc
MD
499 return (EIO);
500 }
501 for(i = 0; i < UGEN_NISOREQS; ++i) {
502 sce->isoreqs[i].sce = sce;
503 xfer = usbd_alloc_xfer(sc->sc_udev);
504 if (xfer == 0)
505 goto bad;
506 sce->isoreqs[i].xfer = xfer;
507 buf = usbd_alloc_buffer
508 (xfer, isize * UGEN_NISORFRMS);
509 if (buf == 0) {
510 i++;
511 goto bad;
512 }
513 sce->isoreqs[i].dmabuf = buf;
514 for(j = 0; j < UGEN_NISORFRMS; ++j)
515 sce->isoreqs[i].sizes[j] = isize;
516 usbd_setup_isoc_xfer
517 (xfer, sce->pipeh, &sce->isoreqs[i],
518 sce->isoreqs[i].sizes,
519 UGEN_NISORFRMS, USBD_NO_COPY,
520 ugen_isoc_rintr);
521 (void)usbd_transfer(xfer);
522 }
523 DPRINTFN(5, ("ugenopen: isoc open done\n"));
524 break;
525 bad:
526 while (--i >= 0) /* implicit buffer free */
527 usbd_free_xfer(sce->isoreqs[i].xfer);
528 return (ENOMEM);
529 case UE_CONTROL:
1550dfd9 530 sce->timeout = USBD_DEFAULT_TIMEOUT;
984263bc
MD
531 return (EINVAL);
532 }
533 }
534 sc->sc_is_open[endpt] = 1;
535 return (0);
536}
537
538int
fef8985e 539ugenclose(struct dev_close_args *ap)
984263bc 540{
b13267a5 541 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
542 int endpt = UGENENDPOINT(dev);
543 struct ugen_softc *sc;
544 struct ugen_endpoint *sce;
545 int dir;
546 int i;
547
1e089e7e 548 sc = devclass_get_softc(ugen_devclass, UGENUNIT(dev));
984263bc
MD
549
550 DPRINTFN(5, ("ugenclose: flag=%d, mode=%d, unit=%d, endpt=%d\n",
fef8985e 551 ap->a_fflag, ap->a_devtype, UGENUNIT(dev), endpt));
984263bc
MD
552
553#ifdef DIAGNOSTIC
554 if (!sc->sc_is_open[endpt]) {
e3869ec7 555 kprintf("ugenclose: not open\n");
984263bc
MD
556 return (EINVAL);
557 }
558#endif
559
560 if (endpt == USB_CONTROL_ENDPOINT) {
561 DPRINTFN(5, ("ugenclose: close control\n"));
562 sc->sc_is_open[endpt] = 0;
563 return (0);
564 }
565
566 for (dir = OUT; dir <= IN; dir++) {
fef8985e 567 if (!(ap->a_fflag & (dir == OUT ? FWRITE : FREAD)))
984263bc
MD
568 continue;
569 sce = &sc->sc_endpoints[endpt][dir];
570 if (sce == NULL || sce->pipeh == NULL)
571 continue;
1550dfd9 572 DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n",
984263bc
MD
573 endpt, dir, sce));
574
575 usbd_abort_pipe(sce->pipeh);
576 usbd_close_pipe(sce->pipeh);
577 sce->pipeh = NULL;
578
579 switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
580 case UE_INTERRUPT:
581 ndflush(&sce->q, sce->q.c_cc);
375a9af6 582 clist_free_cblocks(&sce->q);
984263bc
MD
583 break;
584 case UE_ISOCHRONOUS:
585 for (i = 0; i < UGEN_NISOREQS; ++i)
586 usbd_free_xfer(sce->isoreqs[i].xfer);
587 default:
588 break;
589 }
590
591 if (sce->ibuf != NULL) {
efda3bd0 592 kfree(sce->ibuf, M_USBDEV);
984263bc 593 sce->ibuf = NULL;
375a9af6 594 clist_free_cblocks(&sce->q);
984263bc
MD
595 }
596 }
597 sc->sc_is_open[endpt] = 0;
598
599 return (0);
600}
601
6ed427ca 602static int
984263bc
MD
603ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
604{
605 struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
606 u_int32_t n, tn;
467306a6 607 char *buf;
984263bc
MD
608 usbd_xfer_handle xfer;
609 usbd_status err;
984263bc 610 int error = 0;
467306a6 611 int ugen_bbsize;
984263bc
MD
612 u_char buffer[UGEN_CHUNK];
613
6ed427ca 614 DPRINTFN(5, ("%s: ugenread: %d\n", device_get_nameunit(sc->sc_dev), endpt));
984263bc
MD
615
616 if (sc->sc_dying)
617 return (EIO);
618
619 if (endpt == USB_CONTROL_ENDPOINT)
620 return (ENODEV);
621
1550dfd9
MD
622 if (sce == NULL)
623 return (EINVAL);
624
984263bc 625 if (sce->edesc == NULL) {
e3869ec7 626 kprintf("ugenread: no edesc\n");
984263bc
MD
627 return (EIO);
628 }
629 if (sce->pipeh == NULL) {
e3869ec7 630 kprintf("ugenread: no pipe\n");
984263bc
MD
631 return (EIO);
632 }
984263bc 633
467306a6
MD
634 buf = getugenbuf(ugen_bufsize, &ugen_bbsize);
635
984263bc
MD
636 switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
637 case UE_INTERRUPT:
1550dfd9 638 /* Block until activity occurred. */
4e01b467 639 crit_enter();
984263bc
MD
640 while (sce->q.c_cc == 0) {
641 if (flag & IO_NDELAY) {
4e01b467 642 crit_exit();
467306a6
MD
643 error = EWOULDBLOCK;
644 goto done;
984263bc
MD
645 }
646 sce->state |= UGEN_ASLP;
1550dfd9 647 DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
377d4740 648 error = tsleep(sce, PCATCH, "ugenri", 0);
984263bc
MD
649 DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
650 if (sc->sc_dying)
651 error = EIO;
652 if (error) {
653 sce->state &= ~UGEN_ASLP;
654 break;
655 }
656 }
4e01b467 657 crit_exit();
984263bc
MD
658
659 /* Transfer as many chunks as possible. */
660 while (sce->q.c_cc > 0 && uio->uio_resid > 0 && !error) {
661 n = min(sce->q.c_cc, uio->uio_resid);
662 if (n > sizeof(buffer))
663 n = sizeof(buffer);
664
665 /* Remove a small chunk from the input queue. */
666 q_to_b(&sce->q, buffer, n);
667 DPRINTFN(5, ("ugenread: got %d chars\n", n));
668
669 /* Copy the data to the user process. */
670 error = uiomove(buffer, n, uio);
671 if (error)
672 break;
673 }
674 break;
675 case UE_BULK:
676 xfer = usbd_alloc_xfer(sc->sc_udev);
467306a6
MD
677 if (xfer == 0) {
678 error = ENOMEM;
679 goto done;
680 }
681 while ((n = min(ugen_bbsize, uio->uio_resid)) != 0) {
984263bc
MD
682 DPRINTFN(1, ("ugenread: start transfer %d bytes\n",n));
683 tn = n;
684 err = usbd_bulk_transfer(
685 xfer, sce->pipeh,
1550dfd9
MD
686 sce->state & UGEN_SHORT_OK ?
687 USBD_SHORT_XFER_OK : 0,
984263bc
MD
688 sce->timeout, buf, &tn, "ugenrb");
689 if (err) {
690 if (err == USBD_INTERRUPTED)
691 error = EINTR;
692 else if (err == USBD_TIMEOUT)
693 error = ETIMEDOUT;
694 else
695 error = EIO;
696 break;
697 }
698 DPRINTFN(1, ("ugenread: got %d bytes\n", tn));
699 error = uiomove(buf, tn, uio);
700 if (error || tn < n)
701 break;
702 }
703 usbd_free_xfer(xfer);
704 break;
705 case UE_ISOCHRONOUS:
4e01b467 706 crit_enter();
984263bc
MD
707 while (sce->cur == sce->fill) {
708 if (flag & IO_NDELAY) {
4e01b467 709 crit_exit();
467306a6
MD
710 error = EWOULDBLOCK;
711 goto done;
984263bc
MD
712 }
713 sce->state |= UGEN_ASLP;
1550dfd9 714 DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
377d4740 715 error = tsleep(sce, PCATCH, "ugenri", 0);
984263bc
MD
716 DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
717 if (sc->sc_dying)
718 error = EIO;
719 if (error) {
720 sce->state &= ~UGEN_ASLP;
721 break;
722 }
723 }
724
725 while (sce->cur != sce->fill && uio->uio_resid > 0 && !error) {
726 if(sce->fill > sce->cur)
727 n = min(sce->fill - sce->cur, uio->uio_resid);
728 else
729 n = min(sce->limit - sce->cur, uio->uio_resid);
730
731 DPRINTFN(5, ("ugenread: isoc got %d chars\n", n));
732
733 /* Copy the data to the user process. */
734 error = uiomove(sce->cur, n, uio);
735 if (error)
736 break;
737 sce->cur += n;
738 if(sce->cur >= sce->limit)
739 sce->cur = sce->ibuf;
740 }
4e01b467 741 crit_exit();
984263bc
MD
742 break;
743
1550dfd9 744
984263bc 745 default:
467306a6
MD
746 error = ENXIO;
747 break;
984263bc 748 }
467306a6
MD
749done:
750 relugenbuf(buf, ugen_bbsize);
984263bc
MD
751 return (error);
752}
753
754int
fef8985e 755ugenread(struct dev_read_args *ap)
984263bc 756{
b13267a5 757 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
758 int endpt = UGENENDPOINT(dev);
759 struct ugen_softc *sc;
760 int error;
761
1e089e7e 762 sc = devclass_get_softc(ugen_devclass, UGENUNIT(dev));
984263bc
MD
763
764 sc->sc_refcnt++;
fef8985e 765 error = ugen_do_read(sc, endpt, ap->a_uio, ap->a_ioflag);
984263bc 766 if (--sc->sc_refcnt < 0)
2939c544 767 usb_detach_wakeup(sc->sc_dev);
984263bc
MD
768 return (error);
769}
770
6ed427ca 771static int
984263bc
MD
772ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
773{
774 struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][OUT];
775 u_int32_t n;
776 int error = 0;
467306a6
MD
777 int ugen_bbsize;
778 char *buf;
984263bc
MD
779 usbd_xfer_handle xfer;
780 usbd_status err;
781
6ed427ca 782 DPRINTFN(5, ("%s: ugenwrite: %d\n", device_get_nameunit(sc->sc_dev), endpt));
984263bc
MD
783
784 if (sc->sc_dying)
785 return (EIO);
786
787 if (endpt == USB_CONTROL_ENDPOINT)
788 return (ENODEV);
789
1550dfd9
MD
790 if (sce == NULL)
791 return (EINVAL);
792
984263bc 793 if (sce->edesc == NULL) {
e3869ec7 794 kprintf("ugenwrite: no edesc\n");
984263bc
MD
795 return (EIO);
796 }
797 if (sce->pipeh == NULL) {
e3869ec7 798 kprintf("ugenwrite: no pipe\n");
984263bc
MD
799 return (EIO);
800 }
984263bc 801
467306a6
MD
802 buf = getugenbuf(ugen_bufsize, &ugen_bbsize);
803
984263bc
MD
804 switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
805 case UE_BULK:
806 xfer = usbd_alloc_xfer(sc->sc_udev);
467306a6
MD
807 if (xfer == 0) {
808 error = EIO;
809 goto done;
810 }
811 while ((n = min(ugen_bbsize, uio->uio_resid)) != 0) {
984263bc
MD
812 error = uiomove(buf, n, uio);
813 if (error)
814 break;
1550dfd9
MD
815 DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
816 err = usbd_bulk_transfer(xfer, sce->pipeh, 0,
984263bc
MD
817 sce->timeout, buf, &n,"ugenwb");
818 if (err) {
819 if (err == USBD_INTERRUPTED)
820 error = EINTR;
1550dfd9
MD
821 else if (err == USBD_TIMEOUT)
822 error = ETIMEDOUT;
823 else
824 error = EIO;
825 break;
826 }
827 }
828 usbd_free_xfer(xfer);
829 break;
830 case UE_INTERRUPT:
831 xfer = usbd_alloc_xfer(sc->sc_udev);
467306a6
MD
832 if (xfer == 0) {
833 error = EIO;
834 goto done;
835 }
1550dfd9
MD
836 while ((n = min(UGETW(sce->edesc->wMaxPacketSize),
837 uio->uio_resid)) != 0) {
838 error = uiomove(buf, n, uio);
839 if (error)
840 break;
841 DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
842 err = usbd_intr_transfer(xfer, sce->pipeh, 0,
843 sce->timeout, buf, &n,"ugenwi");
844 if (err) {
845 if (err == USBD_INTERRUPTED)
846 error = EINTR;
847 else if (err == USBD_TIMEOUT)
848 error = ETIMEDOUT;
984263bc
MD
849 else
850 error = EIO;
851 break;
852 }
853 }
854 usbd_free_xfer(xfer);
855 break;
856 default:
467306a6
MD
857 error = ENXIO;
858 break;
984263bc 859 }
467306a6
MD
860done:
861 relugenbuf(buf, ugen_bbsize);
984263bc
MD
862 return (error);
863}
864
865int
fef8985e 866ugenwrite(struct dev_write_args *ap)
984263bc 867{
b13267a5 868 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
869 int endpt = UGENENDPOINT(dev);
870 struct ugen_softc *sc;
871 int error;
872
1e089e7e 873 sc = devclass_get_softc(ugen_devclass, UGENUNIT(dev));
984263bc
MD
874
875 sc->sc_refcnt++;
fef8985e 876 error = ugen_do_write(sc, endpt, ap->a_uio, ap->a_ioflag);
984263bc 877 if (--sc->sc_refcnt < 0)
2939c544 878 usb_detach_wakeup(sc->sc_dev);
984263bc
MD
879 return (error);
880}
881
e785a5d9
HT
882static int
883ugen_detach(device_t self)
984263bc 884{
e785a5d9 885 struct ugen_softc *sc = device_get_softc(self);
984263bc
MD
886 struct ugen_endpoint *sce;
887 int i, dir;
984263bc 888
984263bc 889 DPRINTF(("ugen_detach: sc=%p\n", sc));
984263bc
MD
890
891 sc->sc_dying = 1;
892 /* Abort all pipes. Causes processes waiting for transfer to wake. */
893 for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
894 for (dir = OUT; dir <= IN; dir++) {
895 sce = &sc->sc_endpoints[i][dir];
896 if (sce && sce->pipeh)
897 usbd_abort_pipe(sce->pipeh);
898 }
899 }
4e01b467 900 crit_enter();
984263bc
MD
901 if (--sc->sc_refcnt >= 0) {
902 /* Wake everyone */
903 for (i = 0; i < USB_MAX_ENDPOINTS; i++)
904 wakeup(&sc->sc_endpoints[i][IN]);
905 /* Wait for processes to go away. */
2939c544 906 usb_detach_wait(sc->sc_dev);
984263bc 907 }
4e01b467 908 crit_exit();
984263bc 909
984263bc 910 /* destroy the device for the control endpoint */
1550dfd9 911 ugen_destroy_devnodes(sc);
fef8985e 912 dev_ops_remove(&ugen_ops,
6ed427ca 913 UGENUNITMASK, UGENMINOR(device_get_unit(sc->sc_dev), 0));
984263bc
MD
914 return (0);
915}
916
6ed427ca 917static void
984263bc
MD
918ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
919{
920 struct ugen_endpoint *sce = addr;
921 /*struct ugen_softc *sc = sce->sc;*/
922 u_int32_t count;
923 u_char *ibuf;
924
925 if (status == USBD_CANCELLED)
926 return;
927
928 if (status != USBD_NORMAL_COMPLETION) {
929 DPRINTF(("ugenintr: status=%d\n", status));
1550dfd9
MD
930 if (status == USBD_STALLED)
931 usbd_clear_endpoint_stall_async(sce->pipeh);
984263bc
MD
932 return;
933 }
934
935 usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
936 ibuf = sce->ibuf;
937
1550dfd9 938 DPRINTFN(5, ("ugenintr: xfer=%p status=%d count=%d\n",
984263bc
MD
939 xfer, status, count));
940 DPRINTFN(5, (" data = %02x %02x %02x\n",
941 ibuf[0], ibuf[1], ibuf[2]));
942
943 (void)b_to_q(ibuf, count, &sce->q);
1550dfd9 944
984263bc
MD
945 if (sce->state & UGEN_ASLP) {
946 sce->state &= ~UGEN_ASLP;
947 DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
948 wakeup(sce);
949 }
375a9af6 950 selwakeup(&sce->rsel);
984263bc
MD
951}
952
6ed427ca 953static void
1550dfd9 954ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr,
984263bc
MD
955 usbd_status status)
956{
957 struct isoreq *req = addr;
958 struct ugen_endpoint *sce = req->sce;
959 u_int32_t count, n;
1550dfd9 960 int i, isize;
984263bc
MD
961
962 /* Return if we are aborting. */
963 if (status == USBD_CANCELLED)
964 return;
965
966 usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
1550dfd9
MD
967 DPRINTFN(5,("ugen_isoc_rintr: xfer %d, count=%d\n",
968 (int)(req - sce->isoreqs),
984263bc
MD
969 count));
970
971 /* throw away oldest input if the buffer is full */
972 if(sce->fill < sce->cur && sce->cur <= sce->fill + count) {
973 sce->cur += count;
974 if(sce->cur >= sce->limit)
975 sce->cur = sce->ibuf + (sce->limit - sce->cur);
976 DPRINTFN(5, ("ugen_isoc_rintr: throwing away %d bytes\n",
977 count));
978 }
979
1550dfd9
MD
980 isize = UGETW(sce->edesc->wMaxPacketSize);
981 for (i = 0; i < UGEN_NISORFRMS; i++) {
982 u_int32_t actlen = req->sizes[i];
983 char const *buf = (char const *)req->dmabuf + isize * i;
984
985 /* copy data to buffer */
986 while (actlen > 0) {
987 n = min(actlen, sce->limit - sce->fill);
988 memcpy(sce->fill, buf, n);
989
990 buf += n;
991 actlen -= n;
992 sce->fill += n;
993 if(sce->fill == sce->limit)
994 sce->fill = sce->ibuf;
995 }
984263bc 996
1550dfd9
MD
997 /* setup size for next transfer */
998 req->sizes[i] = isize;
984263bc
MD
999 }
1000
1001 usbd_setup_isoc_xfer(xfer, sce->pipeh, req, req->sizes, UGEN_NISORFRMS,
1002 USBD_NO_COPY, ugen_isoc_rintr);
1003 (void)usbd_transfer(xfer);
1004
1005 if (sce->state & UGEN_ASLP) {
1006 sce->state &= ~UGEN_ASLP;
1007 DPRINTFN(5, ("ugen_isoc_rintr: waking %p\n", sce));
1008 wakeup(sce);
1009 }
375a9af6 1010 selwakeup(&sce->rsel);
984263bc
MD
1011}
1012
6ed427ca 1013static usbd_status
984263bc
MD
1014ugen_set_interface(struct ugen_softc *sc, int ifaceidx, int altno)
1015{
1016 usbd_interface_handle iface;
1017 usb_endpoint_descriptor_t *ed;
1018 usbd_status err;
1019 struct ugen_endpoint *sce;
1020 u_int8_t niface, nendpt, endptno, endpt;
1021 int dir;
1022
1023 DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));
1024
1025 err = usbd_interface_count(sc->sc_udev, &niface);
1026 if (err)
1027 return (err);
1028 if (ifaceidx < 0 || ifaceidx >= niface)
1029 return (USBD_INVAL);
1550dfd9 1030
984263bc
MD
1031 err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
1032 if (err)
1033 return (err);
1034 err = usbd_endpoint_count(iface, &nendpt);
1035 if (err)
1036 return (err);
1550dfd9 1037
1550dfd9
MD
1038 /* destroy the existing devices, we remake the new ones in a moment */
1039 ugen_destroy_devnodes(sc);
1550dfd9
MD
1040
1041 /* XXX should only do this after setting new altno has succeeded */
984263bc
MD
1042 for (endptno = 0; endptno < nendpt; endptno++) {
1043 ed = usbd_interface2endpoint_descriptor(iface,endptno);
1044 endpt = ed->bEndpointAddress;
1045 dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
1046 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
1047 sce->sc = 0;
1048 sce->edesc = 0;
1049 sce->iface = 0;
1050 }
1051
1052 /* change setting */
1053 err = usbd_set_interface(iface, altno);
1054 if (err)
1055 return (err);
1056
1057 err = usbd_endpoint_count(iface, &nendpt);
1058 if (err)
1059 return (err);
1060 for (endptno = 0; endptno < nendpt; endptno++) {
1061 ed = usbd_interface2endpoint_descriptor(iface,endptno);
1062 endpt = ed->bEndpointAddress;
1063 dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
1064 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
1065 sce->sc = sc;
1066 sce->edesc = ed;
1067 sce->iface = iface;
1068 }
1550dfd9 1069
1550dfd9
MD
1070 /* make the new devices */
1071 ugen_make_devnodes(sc);
1550dfd9 1072
984263bc
MD
1073 return (0);
1074}
1075
1076/* Retrieve a complete descriptor for a certain device and index. */
6ed427ca 1077static usb_config_descriptor_t *
984263bc
MD
1078ugen_get_cdesc(struct ugen_softc *sc, int index, int *lenp)
1079{
1080 usb_config_descriptor_t *cdesc, *tdesc, cdescr;
1081 int len;
1082 usbd_status err;
1083
1084 if (index == USB_CURRENT_CONFIG_INDEX) {
1085 tdesc = usbd_get_config_descriptor(sc->sc_udev);
1086 len = UGETW(tdesc->wTotalLength);
1087 if (lenp)
1088 *lenp = len;
efda3bd0 1089 cdesc = kmalloc(len, M_TEMP, M_INTWAIT);
984263bc
MD
1090 memcpy(cdesc, tdesc, len);
1091 DPRINTFN(5,("ugen_get_cdesc: current, len=%d\n", len));
1092 } else {
1093 err = usbd_get_config_desc(sc->sc_udev, index, &cdescr);
1094 if (err)
1095 return (0);
1096 len = UGETW(cdescr.wTotalLength);
1097 DPRINTFN(5,("ugen_get_cdesc: index=%d, len=%d\n", index, len));
1098 if (lenp)
1099 *lenp = len;
efda3bd0 1100 cdesc = kmalloc(len, M_TEMP, M_INTWAIT);
984263bc
MD
1101 err = usbd_get_config_desc_full(sc->sc_udev, index, cdesc, len);
1102 if (err) {
efda3bd0 1103 kfree(cdesc, M_TEMP);
984263bc
MD
1104 return (0);
1105 }
1106 }
1107 return (cdesc);
1108}
1109
6ed427ca 1110static int
984263bc
MD
1111ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx)
1112{
1113 usbd_interface_handle iface;
1114 usbd_status err;
1115
1116 err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
1117 if (err)
1550dfd9 1118 return (-1);
984263bc
MD
1119 return (usbd_get_interface_altindex(iface));
1120}
1121
6ed427ca 1122static int
984263bc 1123ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
fef8985e 1124 caddr_t addr, int flag)
984263bc
MD
1125{
1126 struct ugen_endpoint *sce;
1127 usbd_status err;
1128 usbd_interface_handle iface;
1129 struct usb_config_desc *cd;
1130 usb_config_descriptor_t *cdesc;
1131 struct usb_interface_desc *id;
1132 usb_interface_descriptor_t *idesc;
1133 struct usb_endpoint_desc *ed;
1134 usb_endpoint_descriptor_t *edesc;
1135 struct usb_alt_interface *ai;
1136 struct usb_string_desc *si;
1137 u_int8_t conf, alt;
1138
1139 DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
1140 if (sc->sc_dying)
1141 return (EIO);
1142
1143 switch (cmd) {
984263bc
MD
1144 case USB_SET_SHORT_XFER:
1145 /* This flag only affects read */
1146 if (endpt == USB_CONTROL_ENDPOINT)
1147 return (EINVAL);
1148 sce = &sc->sc_endpoints[endpt][IN];
1149 if (sce == NULL)
1150 return (EINVAL);
1550dfd9 1151
984263bc 1152 if (sce->pipeh == NULL) {
e3869ec7 1153 kprintf("ugenioctl: USB_SET_SHORT_XFER, no pipe\n");
984263bc
MD
1154 return (EIO);
1155 }
1550dfd9 1156
984263bc
MD
1157 if (*(int *)addr)
1158 sce->state |= UGEN_SHORT_OK;
1159 else
1160 sce->state &= ~UGEN_SHORT_OK;
1161 return (0);
1162 case USB_SET_TIMEOUT:
1163 sce = &sc->sc_endpoints[endpt][IN];
1164 if (sce == NULL)
1165 return (EINVAL);
984263bc
MD
1166 sce->timeout = *(int *)addr;
1167 return (0);
1168 default:
1169 break;
1170 }
1171
1172 if (endpt != USB_CONTROL_ENDPOINT)
1173 return (EINVAL);
1174
1175 switch (cmd) {
1176#ifdef USB_DEBUG
1177 case USB_SETDEBUG:
1178 ugendebug = *(int *)addr;
1179 break;
1180#endif
1181 case USB_GET_CONFIG:
1182 err = usbd_get_config(sc->sc_udev, &conf);
1183 if (err)
1184 return (EIO);
1185 *(int *)addr = conf;
1186 break;
1187 case USB_SET_CONFIG:
1188 if (!(flag & FWRITE))
1189 return (EPERM);
1190 err = ugen_set_config(sc, *(int *)addr);
1191 switch (err) {
1192 case USBD_NORMAL_COMPLETION:
1193 break;
1194 case USBD_IN_USE:
1195 return (EBUSY);
1196 default:
1197 return (EIO);
1198 }
1199 break;
1200 case USB_GET_ALTINTERFACE:
1201 ai = (struct usb_alt_interface *)addr;
1550dfd9 1202 err = usbd_device2interface_handle(sc->sc_udev,
984263bc
MD
1203 ai->uai_interface_index, &iface);
1204 if (err)
1205 return (EINVAL);
1206 idesc = usbd_get_interface_descriptor(iface);
1207 if (idesc == NULL)
1208 return (EIO);
1209 ai->uai_alt_no = idesc->bAlternateSetting;
1210 break;
1211 case USB_SET_ALTINTERFACE:
1212 if (!(flag & FWRITE))
1213 return (EPERM);
1214 ai = (struct usb_alt_interface *)addr;
1550dfd9 1215 err = usbd_device2interface_handle(sc->sc_udev,
984263bc
MD
1216 ai->uai_interface_index, &iface);
1217 if (err)
1218 return (EINVAL);
1219 err = ugen_set_interface(sc, ai->uai_interface_index, ai->uai_alt_no);
1220 if (err)
1221 return (EINVAL);
1222 break;
1223 case USB_GET_NO_ALT:
1224 ai = (struct usb_alt_interface *)addr;
1225 cdesc = ugen_get_cdesc(sc, ai->uai_config_index, 0);
1226 if (cdesc == NULL)
1227 return (EINVAL);
1228 idesc = usbd_find_idesc(cdesc, ai->uai_interface_index, 0);
1229 if (idesc == NULL) {
efda3bd0 1230 kfree(cdesc, M_TEMP);
984263bc
MD
1231 return (EINVAL);
1232 }
1233 ai->uai_alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber);
efda3bd0 1234 kfree(cdesc, M_TEMP);
984263bc
MD
1235 break;
1236 case USB_GET_DEVICE_DESC:
1237 *(usb_device_descriptor_t *)addr =
1238 *usbd_get_device_descriptor(sc->sc_udev);
1239 break;
1240 case USB_GET_CONFIG_DESC:
1241 cd = (struct usb_config_desc *)addr;
1242 cdesc = ugen_get_cdesc(sc, cd->ucd_config_index, 0);
1243 if (cdesc == NULL)
1244 return (EINVAL);
1245 cd->ucd_desc = *cdesc;
efda3bd0 1246 kfree(cdesc, M_TEMP);
984263bc
MD
1247 break;
1248 case USB_GET_INTERFACE_DESC:
1249 id = (struct usb_interface_desc *)addr;
1250 cdesc = ugen_get_cdesc(sc, id->uid_config_index, 0);
1251 if (cdesc == NULL)
1252 return (EINVAL);
1253 if (id->uid_config_index == USB_CURRENT_CONFIG_INDEX &&
1254 id->uid_alt_index == USB_CURRENT_ALT_INDEX)
1255 alt = ugen_get_alt_index(sc, id->uid_interface_index);
1256 else
1257 alt = id->uid_alt_index;
1258 idesc = usbd_find_idesc(cdesc, id->uid_interface_index, alt);
1259 if (idesc == NULL) {
efda3bd0 1260 kfree(cdesc, M_TEMP);
984263bc
MD
1261 return (EINVAL);
1262 }
1263 id->uid_desc = *idesc;
efda3bd0 1264 kfree(cdesc, M_TEMP);
984263bc
MD
1265 break;
1266 case USB_GET_ENDPOINT_DESC:
1267 ed = (struct usb_endpoint_desc *)addr;
1268 cdesc = ugen_get_cdesc(sc, ed->ued_config_index, 0);
1269 if (cdesc == NULL)
1270 return (EINVAL);
1271 if (ed->ued_config_index == USB_CURRENT_CONFIG_INDEX &&
1272 ed->ued_alt_index == USB_CURRENT_ALT_INDEX)
1273 alt = ugen_get_alt_index(sc, ed->ued_interface_index);
1274 else
1275 alt = ed->ued_alt_index;
1550dfd9 1276 edesc = usbd_find_edesc(cdesc, ed->ued_interface_index,
984263bc
MD
1277 alt, ed->ued_endpoint_index);
1278 if (edesc == NULL) {
efda3bd0 1279 kfree(cdesc, M_TEMP);
984263bc
MD
1280 return (EINVAL);
1281 }
1282 ed->ued_desc = *edesc;
efda3bd0 1283 kfree(cdesc, M_TEMP);
984263bc
MD
1284 break;
1285 case USB_GET_FULL_DESC:
1286 {
1287 int len;
1288 struct iovec iov;
1289 struct uio uio;
1290 struct usb_full_desc *fd = (struct usb_full_desc *)addr;
1291 int error;
1292
1293 cdesc = ugen_get_cdesc(sc, fd->ufd_config_index, &len);
1294 if (len > fd->ufd_size)
1295 len = fd->ufd_size;
1296 iov.iov_base = (caddr_t)fd->ufd_data;
1297 iov.iov_len = len;
1298 uio.uio_iov = &iov;
1299 uio.uio_iovcnt = 1;
1300 uio.uio_resid = len;
1301 uio.uio_offset = 0;
1302 uio.uio_segflg = UIO_USERSPACE;
1303 uio.uio_rw = UIO_READ;
67743126 1304 uio.uio_td = curthread;
984263bc 1305 error = uiomove((void *)cdesc, len, &uio);
efda3bd0 1306 kfree(cdesc, M_TEMP);
984263bc
MD
1307 return (error);
1308 }
1309 case USB_GET_STRING_DESC:
281cf3c2
SZ
1310 {
1311 int size;
1312
984263bc 1313 si = (struct usb_string_desc *)addr;
1550dfd9 1314 err = usbd_get_string_desc(sc->sc_udev, si->usd_string_index,
281cf3c2 1315 si->usd_language_id, &si->usd_desc, &size);
984263bc
MD
1316 if (err)
1317 return (EINVAL);
1318 break;
281cf3c2 1319 }
984263bc
MD
1320 case USB_DO_REQUEST:
1321 {
1322 struct usb_ctl_request *ur = (void *)addr;
1323 int len = UGETW(ur->ucr_request.wLength);
1324 struct iovec iov;
1325 struct uio uio;
1326 void *ptr = 0;
1327 usbd_status err;
1328 int error = 0;
1329
1330 if (!(flag & FWRITE))
1331 return (EPERM);
1332 /* Avoid requests that would damage the bus integrity. */
1333 if ((ur->ucr_request.bmRequestType == UT_WRITE_DEVICE &&
1334 ur->ucr_request.bRequest == UR_SET_ADDRESS) ||
1335 (ur->ucr_request.bmRequestType == UT_WRITE_DEVICE &&
1336 ur->ucr_request.bRequest == UR_SET_CONFIG) ||
1337 (ur->ucr_request.bmRequestType == UT_WRITE_INTERFACE &&
1338 ur->ucr_request.bRequest == UR_SET_INTERFACE))
1339 return (EINVAL);
1340
1341 if (len < 0 || len > 32767)
1342 return (EINVAL);
1343 if (len != 0) {
1344 iov.iov_base = (caddr_t)ur->ucr_data;
1345 iov.iov_len = len;
1346 uio.uio_iov = &iov;
1347 uio.uio_iovcnt = 1;
1348 uio.uio_resid = len;
1349 uio.uio_offset = 0;
1350 uio.uio_segflg = UIO_USERSPACE;
1351 uio.uio_rw =
1550dfd9 1352 ur->ucr_request.bmRequestType & UT_READ ?
984263bc 1353 UIO_READ : UIO_WRITE;
fef8985e 1354 uio.uio_td = curthread;
efda3bd0 1355 ptr = kmalloc(len, M_TEMP, M_WAITOK);
984263bc
MD
1356 if (uio.uio_rw == UIO_WRITE) {
1357 error = uiomove(ptr, len, &uio);
1358 if (error)
1359 goto ret;
1360 }
1361 }
1550dfd9
MD
1362 sce = &sc->sc_endpoints[endpt][IN];
1363 err = usbd_do_request_flags(sc->sc_udev, &ur->ucr_request,
1364 ptr, ur->ucr_flags, &ur->ucr_actlen, sce->timeout);
984263bc
MD
1365 if (err) {
1366 error = EIO;
1367 goto ret;
1368 }
1369 if (len != 0) {
1370 if (uio.uio_rw == UIO_READ) {
1371 error = uiomove(ptr, len, &uio);
1372 if (error)
1373 goto ret;
1374 }
1375 }
1376 ret:
1377 if (ptr)
efda3bd0 1378 kfree(ptr, M_TEMP);
984263bc
MD
1379 return (error);
1380 }
1381 case USB_GET_DEVICEINFO:
1382 usbd_fill_deviceinfo(sc->sc_udev,
1550dfd9 1383 (struct usb_device_info *)addr, 1);
984263bc
MD
1384 break;
1385 default:
1386 return (EINVAL);
1387 }
1388 return (0);
1389}
1390
1391int
fef8985e 1392ugenioctl(struct dev_ioctl_args *ap)
984263bc 1393{
b13267a5 1394 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
1395 int endpt = UGENENDPOINT(dev);
1396 struct ugen_softc *sc;
1397 int error;
1398
1e089e7e 1399 sc = devclass_get_softc(ugen_devclass, UGENUNIT(dev));
984263bc
MD
1400
1401 sc->sc_refcnt++;
fef8985e 1402 error = ugen_do_ioctl(sc, endpt, ap->a_cmd, ap->a_data, ap->a_fflag);
984263bc 1403 if (--sc->sc_refcnt < 0)
2939c544 1404 usb_detach_wakeup(sc->sc_dev);
984263bc
MD
1405 return (error);
1406}
1407
1408int
fef8985e 1409ugenpoll(struct dev_poll_args *ap)
984263bc 1410{
b13267a5 1411 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
1412 struct ugen_softc *sc;
1413 struct ugen_endpoint *sce;
1414 int revents = 0;
984263bc 1415
1e089e7e 1416 sc = devclass_get_softc(ugen_devclass, UGENUNIT(dev));
984263bc
MD
1417
1418 if (sc->sc_dying)
1419 return (EIO);
1420
1421 /* XXX always IN */
1422 sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
1423 if (sce == NULL)
1424 return (EINVAL);
1550dfd9 1425
984263bc 1426 if (!sce->edesc) {
e3869ec7 1427 kprintf("ugenpoll: no edesc\n");
984263bc
MD
1428 return (EIO);
1429 }
1430 if (!sce->pipeh) {
e3869ec7 1431 kprintf("ugenpoll: no pipe\n");
984263bc
MD
1432 return (EIO);
1433 }
1550dfd9 1434
4e01b467 1435 crit_enter();
984263bc
MD
1436 switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
1437 case UE_INTERRUPT:
fef8985e 1438 if (ap->a_events & (POLLIN | POLLRDNORM)) {
984263bc 1439 if (sce->q.c_cc > 0)
fef8985e 1440 revents |= ap->a_events & (POLLIN | POLLRDNORM);
984263bc 1441 else
fef8985e 1442 selrecord(curthread, &sce->rsel);
984263bc
MD
1443 }
1444 break;
1445 case UE_ISOCHRONOUS:
fef8985e 1446 if (ap->a_events & (POLLIN | POLLRDNORM)) {
984263bc 1447 if (sce->cur != sce->fill)
fef8985e 1448 revents |= ap->a_events & (POLLIN | POLLRDNORM);
984263bc 1449 else
fef8985e 1450 selrecord(curthread, &sce->rsel);
984263bc
MD
1451 }
1452 break;
1453 case UE_BULK:
1550dfd9 1454 /*
984263bc
MD
1455 * We have no easy way of determining if a read will
1456 * yield any data or a write will happen.
1457 * Pretend they will.
1458 */
fef8985e 1459 revents |= ap->a_events &
984263bc
MD
1460 (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);
1461 break;
1462 default:
1463 break;
1464 }
4e01b467 1465 crit_exit();
fef8985e
MD
1466 ap->a_events = revents;
1467 return (0);
984263bc
MD
1468}
1469
984263bc 1470DRIVER_MODULE(ugen, uhub, ugen_driver, ugen_devclass, usbd_driver_load, 0);
7c070ee7 1471