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