ugen.c revision 1.30 1 /* $NetBSD: ugen.c,v 1.30 1999/11/18 23:32:27 augustss Exp $ */
2 /* $FreeBSD: src/sys/dev/usb/ugen.c,v 1.26 1999/11/17 22:33:41 n_hibma Exp $ */
3
4 /*
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Lennart Augustsson (augustss (at) carlstedt.se) at
10 * Carlstedt Research & Technology.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #if defined(__NetBSD__) || defined(__OpenBSD__)
47 #include <sys/device.h>
48 #include <sys/ioctl.h>
49 #elif defined(__FreeBSD__)
50 #include <sys/module.h>
51 #include <sys/bus.h>
52 #include <sys/ioccom.h>
53 #include <sys/conf.h>
54 #include <sys/fcntl.h>
55 #include <sys/filio.h>
56 #endif
57 #include <sys/conf.h>
58 #include <sys/tty.h>
59 #include <sys/file.h>
60 #include <sys/select.h>
61 #include <sys/proc.h>
62 #include <sys/vnode.h>
63 #include <sys/poll.h>
64
65 #include <dev/usb/usb.h>
66 #include <dev/usb/usbdi.h>
67 #include <dev/usb/usbdi_util.h>
68
69 #ifdef UGEN_DEBUG
70 #define DPRINTF(x) if (ugendebug) logprintf x
71 #define DPRINTFN(n,x) if (ugendebug>(n)) logprintf x
72 int ugendebug = 0;
73 #else
74 #define DPRINTF(x)
75 #define DPRINTFN(n,x)
76 #endif
77
78 struct ugen_endpoint {
79 struct ugen_softc *sc;
80 usb_endpoint_descriptor_t *edesc;
81 usbd_interface_handle iface;
82 int state;
83 #define UGEN_ASLP 0x02 /* waiting for data */
84 #define UGEN_SHORT_OK 0x04 /* short xfers are OK */
85 usbd_pipe_handle pipeh;
86 struct clist q;
87 struct selinfo rsel;
88 void *ibuf;
89 u_int32_t timeout;
90 };
91
92 #define UGEN_CHUNK 128 /* chunk size for read */
93 #define UGEN_IBSIZE 1020 /* buffer size */
94 #define UGEN_BBSIZE 1024
95
96 struct ugen_softc {
97 USBBASEDEVICE sc_dev; /* base device */
98 usbd_device_handle sc_udev;
99
100 char sc_is_open[USB_MAX_ENDPOINTS];
101 struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];
102 #define OUT 0
103 #define IN 1
104
105 int sc_refcnt;
106 u_char sc_dying;
107 };
108
109 #if defined(__NetBSD__) || defined(__OpenBSD__)
110 cdev_decl(ugen);
111 #elif defined(__FreeBSD__)
112 d_open_t ugenopen;
113 d_close_t ugenclose;
114 d_read_t ugenread;
115 d_write_t ugenwrite;
116 d_ioctl_t ugenioctl;
117 d_poll_t ugenpoll;
118
119 #define UGEN_CDEV_MAJOR 114
120
121 static struct cdevsw ugen_cdevsw = {
122 /* open */ ugenopen,
123 /* close */ ugenclose,
124 /* read */ ugenread,
125 /* write */ ugenwrite,
126 /* ioctl */ ugenioctl,
127 /* poll */ ugenpoll,
128 /* mmap */ nommap,
129 /* strategy */ nostrategy,
130 /* name */ "ugen",
131 /* maj */ UGEN_CDEV_MAJOR,
132 /* dump */ nodump,
133 /* psize */ nopsize,
134 /* flags */ 0,
135 /* bmaj */ -1
136 };
137 #endif
138
139 static void ugenintr __P((usbd_xfer_handle xfer, usbd_private_handle addr,
140 usbd_status status));
141
142 static int ugen_do_read __P((struct ugen_softc *, int, struct uio *, int));
143 static int ugen_do_write __P((struct ugen_softc *, int, struct uio *, int));
144 static int ugen_do_ioctl __P((struct ugen_softc *, int, u_long,
145 caddr_t, int, struct proc *));
146 static int ugen_set_config __P((struct ugen_softc *sc, int configno));
147 static usb_config_descriptor_t *ugen_get_cdesc __P((struct ugen_softc *sc,
148 int index, int *lenp));
149 static usbd_status ugen_set_interface __P((struct ugen_softc *, int, int));
150 static int ugen_get_alt_index __P((struct ugen_softc *sc, int ifaceidx));
151
152 #define UGENUNIT(n) ((minor(n) >> 4) & 0xf)
153 #define UGENENDPOINT(n) (minor(n) & 0xf)
154 #define UGENDEV(u, e) (makedev(0, ((u) << 4) | (e)))
155
156 USB_DECLARE_DRIVER(ugen);
157
158 USB_MATCH(ugen)
159 {
160 USB_MATCH_START(ugen, uaa);
161
162 if (uaa->usegeneric)
163 return (UMATCH_GENERIC);
164 else
165 return (UMATCH_NONE);
166 }
167
168 USB_ATTACH(ugen)
169 {
170 USB_ATTACH_START(ugen, sc, uaa);
171 char devinfo[1024];
172 usbd_status err;
173 int conf;
174
175 usbd_devinfo(uaa->device, 0, devinfo);
176 USB_ATTACH_SETUP;
177 printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
178
179 sc->sc_udev = uaa->device;
180 conf = 1; /* XXX should not hard code 1 */
181 err = ugen_set_config(sc, conf);
182 if (err) {
183 printf("%s: setting configuration %d failed\n",
184 USBDEVNAME(sc->sc_dev), conf);
185 sc->sc_dying = 1;
186 USB_ATTACH_ERROR_RETURN;
187 }
188
189 #ifdef __FreeBSD__
190 {
191 static int global_init_done = 0;
192 if (!global_init_done) {
193 cdevsw_add(&ugen_cdevsw);
194 global_init_done = 1;
195 }
196 }
197 #endif
198
199 USB_ATTACH_SUCCESS_RETURN;
200 }
201
202 static int
203 ugen_set_config(sc, configno)
204 struct ugen_softc *sc;
205 int configno;
206 {
207 usbd_device_handle dev = sc->sc_udev;
208 usbd_interface_handle iface;
209 usb_endpoint_descriptor_t *ed;
210 struct ugen_endpoint *sce;
211 u_int8_t niface, nendpt;
212 int ifaceno, endptno, endpt;
213 usbd_status err;
214 int dir;
215
216 DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
217 USBDEVNAME(sc->sc_dev), configno, sc));
218 if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {
219 /* Avoid setting the current value. */
220 err = usbd_set_config_no(dev, configno, 0);
221 if (err)
222 return (err);
223 }
224
225 err = usbd_interface_count(dev, &niface);
226 if (err)
227 return (err);
228 memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
229 for (ifaceno = 0; ifaceno < niface; ifaceno++) {
230 DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
231 err = usbd_device2interface_handle(dev, ifaceno, &iface);
232 if (err)
233 return (err);
234 err = usbd_endpoint_count(iface, &nendpt);
235 if (err)
236 return (err);
237 for (endptno = 0; endptno < nendpt; endptno++) {
238 ed = usbd_interface2endpoint_descriptor(iface,endptno);
239 endpt = ed->bEndpointAddress;
240 dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
241 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
242 DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
243 "(%d,%d), sce=%p\n",
244 endptno, endpt, UE_GET_ADDR(endpt),
245 UE_GET_DIR(endpt), sce));
246 sce->sc = sc;
247 sce->edesc = ed;
248 sce->iface = iface;
249 }
250 }
251 return (USBD_NORMAL_COMPLETION);
252 }
253
254 int
255 ugenopen(dev, flag, mode, p)
256 dev_t dev;
257 int flag;
258 int mode;
259 struct proc *p;
260 {
261 struct ugen_softc *sc;
262 int unit = UGENUNIT(dev);
263 int endpt = UGENENDPOINT(dev);
264 usb_endpoint_descriptor_t *edesc;
265 struct ugen_endpoint *sce;
266 int dir, isize;
267 usbd_status err;
268
269 USB_GET_SC_OPEN(ugen, unit, sc);
270
271 DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n",
272 flag, mode, unit, endpt));
273
274 if (sc == NULL || sc->sc_dying)
275 return (ENXIO);
276
277 if (sc->sc_is_open[endpt])
278 return (EBUSY);
279
280 if (endpt == USB_CONTROL_ENDPOINT) {
281 sc->sc_is_open[USB_CONTROL_ENDPOINT] = 1;
282 return (0);
283 }
284 /* Make sure there are pipes for all directions. */
285 for (dir = OUT; dir <= IN; dir++) {
286 if (flag & (dir == OUT ? FWRITE : FREAD)) {
287 sce = &sc->sc_endpoints[endpt][dir];
288 if (sce == 0 || sce->edesc == 0)
289 return (ENXIO);
290 }
291 }
292
293 /* Actually open the pipes. */
294 /* XXX Should back out properly if it fails. */
295 for (dir = OUT; dir <= IN; dir++) {
296 if (!(flag & (dir == OUT ? FWRITE : FREAD)))
297 continue;
298 sce = &sc->sc_endpoints[endpt][dir];
299 sce->state = 0;
300 sce->timeout = USBD_NO_TIMEOUT;
301 DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n",
302 sc, endpt, dir, sce));
303 edesc = sce->edesc;
304 switch (edesc->bmAttributes & UE_XFERTYPE) {
305 case UE_INTERRUPT:
306 isize = UGETW(edesc->wMaxPacketSize);
307 if (isize == 0) /* shouldn't happen */
308 return (EINVAL);
309 sce->ibuf = malloc(isize, M_USBDEV, M_WAITOK);
310 DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",
311 endpt, isize));
312 if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)
313 return (ENOMEM);
314 err = usbd_open_pipe_intr(sce->iface,
315 edesc->bEndpointAddress,
316 USBD_SHORT_XFER_OK, &sce->pipeh, sce,
317 sce->ibuf, isize, ugenintr);
318 if (err) {
319 free(sce->ibuf, M_USBDEV);
320 clfree(&sce->q);
321 return (EIO);
322 }
323 DPRINTFN(5, ("ugenopen: interrupt open done\n"));
324 break;
325 case UE_BULK:
326 err = usbd_open_pipe(sce->iface,
327 edesc->bEndpointAddress, 0, &sce->pipeh);
328 if (err)
329 return (EIO);
330 break;
331 case UE_CONTROL:
332 case UE_ISOCHRONOUS:
333 return (EINVAL);
334 }
335 }
336 sc->sc_is_open[endpt] = 1;
337 return (0);
338 }
339
340 int
341 ugenclose(dev, flag, mode, p)
342 dev_t dev;
343 int flag;
344 int mode;
345 struct proc *p;
346 {
347 int endpt = UGENENDPOINT(dev);
348 struct ugen_softc *sc;
349 struct ugen_endpoint *sce;
350 int dir;
351
352 USB_GET_SC(ugen, UGENUNIT(dev), sc);
353
354 DPRINTFN(5, ("ugenclose: flag=%d, mode=%d, unit=%d, endpt=%d\n",
355 flag, mode, UGENUNIT(dev), endpt));
356
357 #ifdef DIAGNOSTIC
358 if (!sc->sc_is_open[endpt]) {
359 printf("ugenclose: not open\n");
360 return (EINVAL);
361 }
362 #endif
363
364 if (endpt == USB_CONTROL_ENDPOINT) {
365 DPRINTFN(5, ("ugenclose: close control\n"));
366 sc->sc_is_open[endpt] = 0;
367 return (0);
368 }
369
370 for (dir = OUT; dir <= IN; dir++) {
371 if (!(flag & (dir == OUT ? FWRITE : FREAD)))
372 continue;
373 sce = &sc->sc_endpoints[endpt][dir];
374 if (sce == NULL || sce->pipeh == NULL)
375 continue;
376 DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n",
377 endpt, dir, sce));
378
379 usbd_abort_pipe(sce->pipeh);
380 usbd_close_pipe(sce->pipeh);
381 sce->pipeh = NULL;
382
383 if (sce->ibuf != NULL) {
384 free(sce->ibuf, M_USBDEV);
385 sce->ibuf = NULL;
386 clfree(&sce->q);
387
388 }
389 }
390 sc->sc_is_open[endpt] = 0;
391
392 return (0);
393 }
394
395 static int
396 ugen_do_read(sc, endpt, uio, flag)
397 struct ugen_softc *sc;
398 int endpt;
399 struct uio *uio;
400 int flag;
401 {
402 struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
403 u_int32_t n, tn;
404 char buf[UGEN_BBSIZE];
405 usbd_xfer_handle xfer;
406 usbd_status err;
407 int s;
408 int error = 0;
409 u_char buffer[UGEN_CHUNK];
410
411 #ifdef __NetBSD__
412 DPRINTFN(5, ("ugenread: %d:%d\n", sc->sc_dev.dv_unit, endpt));
413 #endif
414
415 if (sc->sc_dying)
416 return (EIO);
417
418 if (endpt == USB_CONTROL_ENDPOINT)
419 return (ENODEV);
420
421 #ifdef DIAGNOSTIC
422 if (sce->edesc == NULL) {
423 printf("ugenread: no edesc\n");
424 return (EIO);
425 }
426 if (sce->pipeh == NULL) {
427 printf("ugenread: no pipe\n");
428 return (EIO);
429 }
430 #endif
431
432 switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
433 case UE_INTERRUPT:
434 /* Block until activity occured. */
435 s = splusb();
436 while (sce->q.c_cc == 0) {
437 if (flag & IO_NDELAY) {
438 splx(s);
439 return (EWOULDBLOCK);
440 }
441 sce->state |= UGEN_ASLP;
442 DPRINTFN(5, ("ugenread: sleep on %p\n", sc));
443 error = tsleep(sce, PZERO | PCATCH, "ugenri", 0);
444 DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
445 if (sc->sc_dying)
446 error = EIO;
447 if (error) {
448 sce->state &= ~UGEN_ASLP;
449 break;
450 }
451 }
452 splx(s);
453
454 /* Transfer as many chunks as possible. */
455 while (sce->q.c_cc > 0 && uio->uio_resid > 0 && !error) {
456 n = min(sce->q.c_cc, uio->uio_resid);
457 if (n > sizeof(buffer))
458 n = sizeof(buffer);
459
460 /* Remove a small chunk from the input queue. */
461 q_to_b(&sce->q, buffer, n);
462 DPRINTFN(5, ("ugenread: got %d chars\n", n));
463
464 /* Copy the data to the user process. */
465 error = uiomove(buffer, n, uio);
466 if (error)
467 break;
468 }
469 break;
470 case UE_BULK:
471 xfer = usbd_alloc_xfer(sc->sc_udev);
472 if (xfer == 0)
473 return (ENOMEM);
474 while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
475 DPRINTFN(1, ("ugenread: start transfer %d bytes\n",n));
476 tn = n;
477 err = usbd_bulk_transfer(
478 xfer, sce->pipeh,
479 sce->state & UGEN_SHORT_OK ?
480 USBD_SHORT_XFER_OK : 0,
481 sce->timeout, buf, &tn, "ugenrb");
482 if (err) {
483 if (err == USBD_INTERRUPTED)
484 error = EINTR;
485 else if (err == USBD_TIMEOUT)
486 error = ETIMEDOUT;
487 else
488 error = EIO;
489 break;
490 }
491 DPRINTFN(1, ("ugenread: got %d bytes\n", tn));
492 error = uiomove(buf, tn, uio);
493 if (error || tn < n)
494 break;
495 }
496 usbd_free_xfer(xfer);
497 break;
498 default:
499 return (ENXIO);
500 }
501 return (error);
502 }
503
504 int
505 ugenread(dev, uio, flag)
506 dev_t dev;
507 struct uio *uio;
508 int flag;
509 {
510 int endpt = UGENENDPOINT(dev);
511 struct ugen_softc *sc;
512 int error;
513
514 USB_GET_SC(ugen, UGENUNIT(dev), sc);
515
516 sc->sc_refcnt++;
517 error = ugen_do_read(sc, endpt, uio, flag);
518 if (--sc->sc_refcnt < 0)
519 usb_detach_wakeup(USBDEV(sc->sc_dev));
520 return (error);
521 }
522
523 static int
524 ugen_do_write(sc, endpt, uio, flag)
525 struct ugen_softc *sc;
526 int endpt;
527 struct uio *uio;
528 int flag;
529 {
530 struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][OUT];
531 u_int32_t n;
532 int error = 0;
533 char buf[UGEN_BBSIZE];
534 usbd_xfer_handle xfer;
535 usbd_status err;
536
537 DPRINTFN(5, ("%s: ugenwrite: %d\n", USBDEVNAME(sc->sc_dev), endpt));
538
539 if (sc->sc_dying)
540 return (EIO);
541
542 if (endpt == USB_CONTROL_ENDPOINT)
543 return (ENODEV);
544
545 #ifdef DIAGNOSTIC
546 if (sce->edesc == NULL) {
547 printf("ugenwrite: no edesc\n");
548 return (EIO);
549 }
550 if (sce->pipeh == NULL) {
551 printf("ugenwrite: no pipe\n");
552 return (EIO);
553 }
554 #endif
555
556 switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
557 case UE_BULK:
558 xfer = usbd_alloc_xfer(sc->sc_udev);
559 if (xfer == 0)
560 return (EIO);
561 while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
562 error = uiomove(buf, n, uio);
563 if (error)
564 break;
565 DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
566 err = usbd_bulk_transfer(xfer, sce->pipeh, 0,
567 sce->timeout, buf, &n,"ugenwb");
568 if (err) {
569 if (err == USBD_INTERRUPTED)
570 error = EINTR;
571 else
572 error = EIO;
573 break;
574 }
575 }
576 usbd_free_xfer(xfer);
577 break;
578 default:
579 return (ENXIO);
580 }
581 return (error);
582 }
583
584 int
585 ugenwrite(dev, uio, flag)
586 dev_t dev;
587 struct uio *uio;
588 int flag;
589 {
590 int endpt = UGENENDPOINT(dev);
591 struct ugen_softc *sc;
592 int error;
593
594 USB_GET_SC(ugen, UGENUNIT(dev), sc);
595
596 sc->sc_refcnt++;
597 error = ugen_do_write(sc, endpt, uio, flag);
598 if (--sc->sc_refcnt < 0)
599 usb_detach_wakeup(USBDEV(sc->sc_dev));
600 return (error);
601 }
602
603 #if defined(__NetBSD__) || defined(__OpenBSD__)
604 int
605 ugen_activate(self, act)
606 device_ptr_t self;
607 enum devact act;
608 {
609 struct ugen_softc *sc = (struct ugen_softc *)self;
610
611 switch (act) {
612 case DVACT_ACTIVATE:
613 return (EOPNOTSUPP);
614 break;
615
616 case DVACT_DEACTIVATE:
617 sc->sc_dying = 1;
618 break;
619 }
620 return (0);
621 }
622 #endif
623
624 USB_DETACH(ugen)
625 {
626 USB_DETACH_START(ugen, sc);
627 struct ugen_endpoint *sce;
628 int i, dir;
629 int s;
630 #if defined(__NetBSD__) || defined(__OpenBSD__)
631 int maj, mn;
632
633 DPRINTF(("ugen_detach: sc=%p flags=%d\n", sc, flags));
634 #elif defined(__FreeBSD__)
635 DPRINTF(("ugen_detach: sc=%p\n", sc));
636 #endif
637
638 sc->sc_dying = 1;
639 /* Abort all pipes. Causes processes waiting for transfer to wake. */
640 for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
641 for (dir = OUT; dir <= IN; dir++) {
642 sce = &sc->sc_endpoints[i][dir];
643 if (sce && sce->pipeh)
644 usbd_abort_pipe(sce->pipeh);
645 }
646 }
647
648 s = splusb();
649 if (--sc->sc_refcnt >= 0) {
650 /* Wake everyone */
651 for (i = 0; i < USB_MAX_ENDPOINTS; i++)
652 wakeup(&sc->sc_endpoints[i][IN]);
653 /* Wait for processes to go away. */
654 usb_detach_wait(USBDEV(sc->sc_dev));
655 }
656 splx(s);
657
658 #if defined(__NetBSD__) || defined(__OpenBSD__)
659 /* locate the major number */
660 for (maj = 0; maj < nchrdev; maj++)
661 if (cdevsw[maj].d_open == ugenopen)
662 break;
663
664 /* Nuke the vnodes for any open instances (calls close). */
665 mn = self->dv_unit * USB_MAX_ENDPOINTS;
666 vdevgone(maj, mn, mn + USB_MAX_ENDPOINTS - 1, VCHR);
667 #elif defined(__FreeBSD__)
668 /* XXX not implemented yet */
669 #endif
670
671 return (0);
672 }
673
674 static void
675 ugenintr(xfer, addr, status)
676 usbd_xfer_handle xfer;
677 usbd_private_handle addr;
678 usbd_status status;
679 {
680 struct ugen_endpoint *sce = addr;
681 /*struct ugen_softc *sc = sce->sc;*/
682 u_int32_t count;
683 u_char *ibuf;
684
685 if (status == USBD_CANCELLED)
686 return;
687
688 if (status != USBD_NORMAL_COMPLETION) {
689 DPRINTF(("ugenintr: status=%d\n", status));
690 usbd_clear_endpoint_stall_async(sce->pipeh);
691 return;
692 }
693
694 usbd_get_xfer_status(xfer, 0, 0, &count, 0);
695 ibuf = sce->ibuf;
696
697 DPRINTFN(5, ("ugenintr: xfer=%p status=%d count=%d\n",
698 xfer, status, count));
699 DPRINTFN(5, (" data = %02x %02x %02x\n",
700 ibuf[0], ibuf[1], ibuf[2]));
701
702 (void)b_to_q(ibuf, count, &sce->q);
703
704 if (sce->state & UGEN_ASLP) {
705 sce->state &= ~UGEN_ASLP;
706 DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
707 wakeup(sce);
708 }
709 selwakeup(&sce->rsel);
710 }
711
712 static usbd_status
713 ugen_set_interface(sc, ifaceidx, altno)
714 struct ugen_softc *sc;
715 int ifaceidx, altno;
716 {
717 usbd_interface_handle iface;
718 usb_endpoint_descriptor_t *ed;
719 usbd_status err;
720 struct ugen_endpoint *sce;
721 u_int8_t niface, nendpt, endptno, endpt;
722 int dir;
723
724 DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));
725
726 err = usbd_interface_count(sc->sc_udev, &niface);
727 if (err)
728 return (err);
729 if (ifaceidx < 0 || ifaceidx >= niface)
730 return (USBD_INVAL);
731
732 err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
733 if (err)
734 return (err);
735 err = usbd_endpoint_count(iface, &nendpt);
736 if (err)
737 return (err);
738 for (endptno = 0; endptno < nendpt; endptno++) {
739 ed = usbd_interface2endpoint_descriptor(iface,endptno);
740 endpt = ed->bEndpointAddress;
741 dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
742 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
743 sce->sc = 0;
744 sce->edesc = 0;
745 sce->iface = 0;
746 }
747
748 /* change setting */
749 err = usbd_set_interface(iface, altno);
750 if (err)
751 return (err);
752
753 err = usbd_endpoint_count(iface, &nendpt);
754 if (err)
755 return (err);
756 for (endptno = 0; endptno < nendpt; endptno++) {
757 ed = usbd_interface2endpoint_descriptor(iface,endptno);
758 endpt = ed->bEndpointAddress;
759 dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
760 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
761 sce->sc = sc;
762 sce->edesc = ed;
763 sce->iface = iface;
764 }
765 return (0);
766 }
767
768 /* Retrieve a complete descriptor for a certain device and index. */
769 static usb_config_descriptor_t *
770 ugen_get_cdesc(sc, index, lenp)
771 struct ugen_softc *sc;
772 int index;
773 int *lenp;
774 {
775 usb_config_descriptor_t *cdesc, *tdesc, cdescr;
776 int len;
777 usbd_status err;
778
779 if (index == USB_CURRENT_CONFIG_INDEX) {
780 tdesc = usbd_get_config_descriptor(sc->sc_udev);
781 len = UGETW(tdesc->wTotalLength);
782 if (lenp)
783 *lenp = len;
784 cdesc = malloc(len, M_TEMP, M_WAITOK);
785 memcpy(cdesc, tdesc, len);
786 DPRINTFN(5,("ugen_get_cdesc: current, len=%d\n", len));
787 } else {
788 err = usbd_get_config_desc(sc->sc_udev, index, &cdescr);
789 if (err)
790 return (0);
791 len = UGETW(cdescr.wTotalLength);
792 DPRINTFN(5,("ugen_get_cdesc: index=%d, len=%d\n", index, len));
793 if (lenp)
794 *lenp = len;
795 cdesc = malloc(len, M_TEMP, M_WAITOK);
796 err = usbd_get_config_desc_full(sc->sc_udev, index, cdesc,len);
797 if (err) {
798 free(cdesc, M_TEMP);
799 return (0);
800 }
801 }
802 return (cdesc);
803 }
804
805 static int
806 ugen_get_alt_index(sc, ifaceidx)
807 struct ugen_softc *sc;
808 int ifaceidx;
809 {
810 usbd_interface_handle iface;
811 usbd_status err;
812
813 err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
814 if (err)
815 return (-1);
816 return (usbd_get_interface_altindex(iface));
817 }
818
819 static int
820 ugen_do_ioctl(sc, endpt, cmd, addr, flag, p)
821 struct ugen_softc *sc;
822 int endpt;
823 u_long cmd;
824 caddr_t addr;
825 int flag;
826 struct proc *p;
827 {
828 struct ugen_endpoint *sce;
829 usbd_status err;
830 usbd_interface_handle iface;
831 struct usb_config_desc *cd;
832 usb_config_descriptor_t *cdesc;
833 struct usb_interface_desc *id;
834 usb_interface_descriptor_t *idesc;
835 struct usb_endpoint_desc *ed;
836 usb_endpoint_descriptor_t *edesc;
837 struct usb_alt_interface *ai;
838 struct usb_string_desc *si;
839 u_int8_t conf, alt;
840
841 DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
842 if (sc->sc_dying)
843 return (EIO);
844
845 switch (cmd) {
846 case FIONBIO:
847 /* All handled in the upper FS layer. */
848 return (0);
849 case USB_SET_SHORT_XFER:
850 /* This flag only affects read */
851 if (endpt == USB_CONTROL_ENDPOINT)
852 return (EINVAL);
853 sce = &sc->sc_endpoints[endpt][IN];
854 if (sce == NULL)
855 return (EINVAL);
856 #ifdef DIAGNOSTIC
857 if (sce->pipeh == NULL) {
858 printf("ugenioctl: USB_SET_SHORT_XFER, no pipe\n");
859 return (EIO);
860 }
861 #endif
862 if (*(int *)addr)
863 sce->state |= UGEN_SHORT_OK;
864 else
865 sce->state &= ~UGEN_SHORT_OK;
866 return (0);
867 case USB_SET_TIMEOUT:
868 sce = &sc->sc_endpoints[endpt][IN];
869 if (sce == NULL)
870 return (EINVAL);
871 #ifdef DIAGNOSTIC
872 if (sce->pipeh == NULL) {
873 printf("ugenioctl: USB_SET_TIMEOUT, no pipe\n");
874 return (EIO);
875 }
876 #endif
877 sce->timeout = *(int *)addr;
878 return (0);
879 default:
880 break;
881 }
882
883 if (endpt != USB_CONTROL_ENDPOINT)
884 return (EINVAL);
885
886 switch (cmd) {
887 #ifdef UGEN_DEBUG
888 case USB_SETDEBUG:
889 ugendebug = *(int *)addr;
890 break;
891 #endif
892 case USB_GET_CONFIG:
893 err = usbd_get_config(sc->sc_udev, &conf);
894 if (err)
895 return (EIO);
896 *(int *)addr = conf;
897 break;
898 case USB_SET_CONFIG:
899 if (!(flag & FWRITE))
900 return (EPERM);
901 err = ugen_set_config(sc, *(int *)addr);
902 if (err)
903 return (EIO);
904 break;
905 case USB_GET_ALTINTERFACE:
906 ai = (struct usb_alt_interface *)addr;
907 err = usbd_device2interface_handle(sc->sc_udev,
908 ai->interface_index, &iface);
909 if (err)
910 return (EINVAL);
911 idesc = usbd_get_interface_descriptor(iface);
912 if (idesc == NULL)
913 return (EIO);
914 ai->alt_no = idesc->bAlternateSetting;
915 break;
916 case USB_SET_ALTINTERFACE:
917 if (!(flag & FWRITE))
918 return (EPERM);
919 ai = (struct usb_alt_interface *)addr;
920 err = usbd_device2interface_handle(sc->sc_udev,
921 ai->interface_index, &iface);
922 if (err)
923 return (EINVAL);
924 err = ugen_set_interface(sc, ai->interface_index, ai->alt_no);
925 if (err)
926 return (EINVAL);
927 break;
928 case USB_GET_NO_ALT:
929 ai = (struct usb_alt_interface *)addr;
930 cdesc = ugen_get_cdesc(sc, ai->config_index, 0);
931 if (cdesc == NULL)
932 return (EINVAL);
933 idesc = usbd_find_idesc(cdesc, ai->interface_index, 0);
934 if (idesc == NULL) {
935 free(cdesc, M_TEMP);
936 return (EINVAL);
937 }
938 ai->alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber);
939 free(cdesc, M_TEMP);
940 break;
941 case USB_GET_DEVICE_DESC:
942 *(usb_device_descriptor_t *)addr =
943 *usbd_get_device_descriptor(sc->sc_udev);
944 break;
945 case USB_GET_CONFIG_DESC:
946 cd = (struct usb_config_desc *)addr;
947 cdesc = ugen_get_cdesc(sc, cd->config_index, 0);
948 if (cdesc == NULL)
949 return (EINVAL);
950 cd->desc = *cdesc;
951 free(cdesc, M_TEMP);
952 break;
953 case USB_GET_INTERFACE_DESC:
954 id = (struct usb_interface_desc *)addr;
955 cdesc = ugen_get_cdesc(sc, id->config_index, 0);
956 if (cdesc == NULL)
957 return (EINVAL);
958 if (id->config_index == USB_CURRENT_CONFIG_INDEX &&
959 id->alt_index == USB_CURRENT_ALT_INDEX)
960 alt = ugen_get_alt_index(sc, id->interface_index);
961 else
962 alt = id->alt_index;
963 idesc = usbd_find_idesc(cdesc, id->interface_index, alt);
964 if (idesc == NULL) {
965 free(cdesc, M_TEMP);
966 return (EINVAL);
967 }
968 id->desc = *idesc;
969 free(cdesc, M_TEMP);
970 break;
971 case USB_GET_ENDPOINT_DESC:
972 ed = (struct usb_endpoint_desc *)addr;
973 cdesc = ugen_get_cdesc(sc, ed->config_index, 0);
974 if (cdesc == NULL)
975 return (EINVAL);
976 if (ed->config_index == USB_CURRENT_CONFIG_INDEX &&
977 ed->alt_index == USB_CURRENT_ALT_INDEX)
978 alt = ugen_get_alt_index(sc, ed->interface_index);
979 else
980 alt = ed->alt_index;
981 edesc = usbd_find_edesc(cdesc, ed->interface_index,
982 alt, ed->endpoint_index);
983 if (edesc == NULL) {
984 free(cdesc, M_TEMP);
985 return (EINVAL);
986 }
987 ed->desc = *edesc;
988 free(cdesc, M_TEMP);
989 break;
990 case USB_GET_FULL_DESC:
991 {
992 int len;
993 struct iovec iov;
994 struct uio uio;
995 struct usb_full_desc *fd = (struct usb_full_desc *)addr;
996 int error;
997
998 cdesc = ugen_get_cdesc(sc, fd->config_index, &len);
999 if (len > fd->size)
1000 len = fd->size;
1001 iov.iov_base = (caddr_t)fd->data;
1002 iov.iov_len = len;
1003 uio.uio_iov = &iov;
1004 uio.uio_iovcnt = 1;
1005 uio.uio_resid = len;
1006 uio.uio_offset = 0;
1007 uio.uio_segflg = UIO_USERSPACE;
1008 uio.uio_rw = UIO_READ;
1009 uio.uio_procp = p;
1010 error = uiomove((void *)cdesc, len, &uio);
1011 free(cdesc, M_TEMP);
1012 return (error);
1013 }
1014 case USB_GET_STRING_DESC:
1015 si = (struct usb_string_desc *)addr;
1016 err = usbd_get_string_desc(sc->sc_udev, si->string_index,
1017 si->language_id, &si->desc);
1018 if (err)
1019 return (EINVAL);
1020 break;
1021 case USB_DO_REQUEST:
1022 {
1023 struct usb_ctl_request *ur = (void *)addr;
1024 int len = UGETW(ur->request.wLength);
1025 struct iovec iov;
1026 struct uio uio;
1027 void *ptr = 0;
1028 usbd_status err;
1029 int error = 0;
1030
1031 if (!(flag & FWRITE))
1032 return (EPERM);
1033 /* Avoid requests that would damage the bus integrity. */
1034 if ((ur->request.bmRequestType == UT_WRITE_DEVICE &&
1035 ur->request.bRequest == UR_SET_ADDRESS) ||
1036 (ur->request.bmRequestType == UT_WRITE_DEVICE &&
1037 ur->request.bRequest == UR_SET_CONFIG) ||
1038 (ur->request.bmRequestType == UT_WRITE_INTERFACE &&
1039 ur->request.bRequest == UR_SET_INTERFACE))
1040 return (EINVAL);
1041
1042 if (len < 0 || len > 32767)
1043 return (EINVAL);
1044 if (len != 0) {
1045 iov.iov_base = (caddr_t)ur->data;
1046 iov.iov_len = len;
1047 uio.uio_iov = &iov;
1048 uio.uio_iovcnt = 1;
1049 uio.uio_resid = len;
1050 uio.uio_offset = 0;
1051 uio.uio_segflg = UIO_USERSPACE;
1052 uio.uio_rw =
1053 ur->request.bmRequestType & UT_READ ?
1054 UIO_READ : UIO_WRITE;
1055 uio.uio_procp = p;
1056 ptr = malloc(len, M_TEMP, M_WAITOK);
1057 if (uio.uio_rw == UIO_WRITE) {
1058 error = uiomove(ptr, len, &uio);
1059 if (error)
1060 goto ret;
1061 }
1062 }
1063 err = usbd_do_request_flags(sc->sc_udev, &ur->request,
1064 ptr, ur->flags, &ur->actlen);
1065 if (err) {
1066 error = EIO;
1067 goto ret;
1068 }
1069 if (len != 0) {
1070 if (uio.uio_rw == UIO_READ) {
1071 error = uiomove(ptr, len, &uio);
1072 if (error)
1073 goto ret;
1074 }
1075 }
1076 ret:
1077 if (ptr)
1078 free(ptr, M_TEMP);
1079 return (error);
1080 }
1081 case USB_GET_DEVICEINFO:
1082 usbd_fill_deviceinfo(sc->sc_udev,
1083 (struct usb_device_info *)addr);
1084 break;
1085 default:
1086 return (EINVAL);
1087 }
1088 return (0);
1089 }
1090
1091 int
1092 ugenioctl(dev, cmd, addr, flag, p)
1093 dev_t dev;
1094 u_long cmd;
1095 caddr_t addr;
1096 int flag;
1097 struct proc *p;
1098 {
1099 int endpt = UGENENDPOINT(dev);
1100 struct ugen_softc *sc;
1101 int error;
1102
1103 USB_GET_SC(ugen, UGENUNIT(dev), sc);
1104
1105 sc->sc_refcnt++;
1106 error = ugen_do_ioctl(sc, endpt, cmd, addr, flag, p);
1107 if (--sc->sc_refcnt < 0)
1108 usb_detach_wakeup(USBDEV(sc->sc_dev));
1109 return (error);
1110 }
1111
1112 int
1113 ugenpoll(dev, events, p)
1114 dev_t dev;
1115 int events;
1116 struct proc *p;
1117 {
1118 struct ugen_softc *sc;
1119 struct ugen_endpoint *sce;
1120 int revents = 0;
1121 int s;
1122
1123 USB_GET_SC(ugen, UGENUNIT(dev), sc);
1124
1125 if (sc->sc_dying)
1126 return (EIO);
1127
1128 /* XXX always IN */
1129 sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
1130 if (sce == NULL)
1131 return (EINVAL);
1132 #ifdef DIAGNOSTIC
1133 if (!sce->edesc) {
1134 printf("ugenwrite: no edesc\n");
1135 return (EIO);
1136 }
1137 if (!sce->pipeh) {
1138 printf("ugenpoll: no pipe\n");
1139 return (EIO);
1140 }
1141 #endif
1142 s = splusb();
1143 switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
1144 case UE_INTERRUPT:
1145 if (events & (POLLIN | POLLRDNORM)) {
1146 if (sce->q.c_cc > 0)
1147 revents |= events & (POLLIN | POLLRDNORM);
1148 else
1149 selrecord(p, &sce->rsel);
1150 }
1151 break;
1152 case UE_BULK:
1153 /*
1154 * We have no easy way of determining if a read will
1155 * yield any data or a write will happen.
1156 * Pretend they will.
1157 */
1158 revents |= events &
1159 (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);
1160 break;
1161 default:
1162 break;
1163 }
1164 splx(s);
1165 return (revents);
1166 }
1167
1168 #if defined(__FreeBSD__)
1169 DRIVER_MODULE(ugen, uhub, ugen_driver, ugen_devclass, usbd_driver_load, 0);
1170 #endif
1171