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