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