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