ugen.c revision 1.11 1 /* $NetBSD: ugen.c,v 1.11 1999/01/08 11:58:25 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/tty.h>
57 #include <sys/file.h>
58 #include <sys/select.h>
59 #include <sys/proc.h>
60 #include <sys/vnode.h>
61 #include <sys/poll.h>
62
63 #include <dev/usb/usb.h>
64 #include <dev/usb/usbdi.h>
65 #include <dev/usb/usbdi_util.h>
66
67 #ifdef USB_DEBUG
68 #define DPRINTF(x) if (ugendebug) printf x
69 #define DPRINTFN(n,x) if (ugendebug>(n)) printf x
70 int ugendebug = 0;
71 #else
72 #define DPRINTF(x)
73 #define DPRINTFN(n,x)
74 #endif
75
76 struct ugen_endpoint {
77 struct ugen_softc *sc;
78 usb_endpoint_descriptor_t *edesc;
79 usbd_interface_handle iface;
80 int state;
81 #define UGEN_OPEN 0x01 /* device is open */
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 struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];
99 #define OUT 0 /* index order is important, from UE_OUT */
100 #define IN 1 /* from UE_IN */
101
102 int sc_disconnected; /* device is gone */
103 };
104
105 int ugenopen __P((dev_t, int, int, struct proc *));
106 int ugenclose __P((dev_t, int, int, struct proc *p));
107 int ugenread __P((dev_t, struct uio *uio, int));
108 int ugenwrite __P((dev_t, struct uio *uio, int));
109 int ugenioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
110 int ugenpoll __P((dev_t, int, struct proc *));
111 void ugenintr __P((usbd_request_handle reqh, usbd_private_handle addr,
112 usbd_status status));
113 void ugen_disco __P((void *));
114
115 int ugen_set_config __P((struct ugen_softc *sc, int configno));
116 usb_config_descriptor_t *ugen_get_cdesc __P((struct ugen_softc *sc, int index,
117 int *lenp));
118 usbd_status ugen_set_interface __P((struct ugen_softc *, int, int));
119 int ugen_get_alt_index __P((struct ugen_softc *sc, int ifaceidx));
120
121 #define UGENUNIT(n) (((n) >> 4) & 0xf)
122 #define UGENENDPOINT(n) ((n) & 0xf)
123
124 USB_DECLARE_DRIVER(ugen);
125
126 USB_MATCH(ugen)
127 {
128 USB_MATCH_START(ugen, uaa);
129
130 if (uaa->usegeneric)
131 return (UMATCH_GENERIC);
132 else
133 return (UMATCH_NONE);
134 }
135
136 USB_ATTACH(ugen)
137 {
138 USB_ATTACH_START(ugen, sc, uaa);
139 char devinfo[1024];
140 usbd_status r;
141 int conf;
142
143 usbd_devinfo(uaa->device, 0, devinfo);
144 USB_ATTACH_SETUP;
145 printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
146
147 sc->sc_udev = uaa->device;
148 conf = 1; /* XXX should not hard code 1 */
149 r = ugen_set_config(sc, conf);
150 if (r != USBD_NORMAL_COMPLETION) {
151 printf("%s: setting configuration %d failed\n",
152 USBDEVNAME(sc->sc_dev), conf);
153 sc->sc_disconnected = 1;
154 USB_ATTACH_ERROR_RETURN;
155 }
156 USB_ATTACH_SUCCESS_RETURN;
157 }
158
159 int
160 ugen_set_config(sc, configno)
161 struct ugen_softc *sc;
162 int configno;
163 {
164 usbd_device_handle dev = sc->sc_udev;
165 usbd_interface_handle iface;
166 usb_endpoint_descriptor_t *ed;
167 struct ugen_endpoint *sce;
168 u_int8_t niface, nendpt;
169 int ifaceno, endptno, endpt;
170 usbd_status r;
171
172 DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
173 USBDEVNAME(sc->sc_dev), configno, sc));
174 if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {
175 /* Avoid setting the current value. */
176 r = usbd_set_config_no(dev, configno, 0);
177 if (r != USBD_NORMAL_COMPLETION)
178 return (r);
179 }
180
181 r = usbd_interface_count(dev, &niface);
182 if (r != USBD_NORMAL_COMPLETION)
183 return (r);
184 memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
185 for (ifaceno = 0; ifaceno < niface; ifaceno++) {
186 DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
187 r = usbd_device2interface_handle(dev, ifaceno, &iface);
188 if (r != USBD_NORMAL_COMPLETION)
189 return (r);
190 r = usbd_endpoint_count(iface, &nendpt);
191 if (r != USBD_NORMAL_COMPLETION)
192 return (r);
193 for (endptno = 0; endptno < nendpt; endptno++) {
194 ed = usbd_interface2endpoint_descriptor(iface,endptno);
195 endpt = ed->bEndpointAddress;
196 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)]
197 [UE_GET_IN(endpt)];
198 DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
199 "(%d,%d), sce=%p\n",
200 endptno, endpt, UE_GET_ADDR(endpt),
201 UE_GET_IN(endpt), sce));
202 sce->sc = sc;
203 sce->edesc = ed;
204 sce->iface = iface;
205 }
206 }
207 return (USBD_NORMAL_COMPLETION);
208 }
209
210 void
211 ugen_disco(p)
212 void *p;
213 {
214 struct ugen_softc *sc = p;
215 sc->sc_disconnected = 1;
216 }
217
218 int
219 ugenopen(dev, flag, mode, p)
220 dev_t dev;
221 int flag;
222 int mode;
223 struct proc *p;
224 {
225 int unit = UGENUNIT(dev);
226 int endpt = UGENENDPOINT(dev);
227 usb_endpoint_descriptor_t *edesc;
228 struct ugen_endpoint *sce;
229 int dir, isize;
230 usbd_status r;
231
232 USB_GET_SC_OPEN(ugen, unit, sc);
233 DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n",
234 flag, mode, unit, endpt));
235
236 if (sc->sc_disconnected)
237 return (EIO);
238
239 if (endpt == USB_CONTROL_ENDPOINT) {
240 /*if ((flag & (FWRITE|FREAD)) != (FWRITE|FREAD))
241 return (EACCES);*/
242 sce = &sc->sc_endpoints[USB_CONTROL_ENDPOINT][OUT];
243 if (sce->state & UGEN_OPEN)
244 return (EBUSY);
245 } else {
246 switch (flag & (FWRITE|FREAD)) {
247 case FWRITE:
248 dir = OUT;
249 break;
250 case FREAD:
251 dir = IN;
252 break;
253 default:
254 return (EACCES);
255 }
256 sce = &sc->sc_endpoints[endpt][dir];
257 DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n",
258 sc, endpt, dir, sce));
259 if (sce->state & UGEN_OPEN)
260 return (EBUSY);
261 edesc = sce->edesc;
262 if (!edesc)
263 return (ENXIO);
264 switch (edesc->bmAttributes & UE_XFERTYPE) {
265 case UE_INTERRUPT:
266 isize = UGETW(edesc->wMaxPacketSize);
267 if (isize == 0) /* shouldn't happen */
268 return (EINVAL);
269 sce->ibuf = malloc(isize, M_USB, M_WAITOK);
270 DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",
271 endpt, isize));
272 #if defined(__NetBSD__)
273 if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)
274 return (ENOMEM);
275 #elif defined(__FreeBSD__)
276 clist_alloc_cblocks(&sce->q, UGEN_IBSIZE, 0);
277 #endif
278 r = usbd_open_pipe_intr(sce->iface,
279 edesc->bEndpointAddress,
280 USBD_SHORT_XFER_OK, &sce->pipeh, sce,
281 sce->ibuf, isize, ugenintr);
282 if (r != USBD_NORMAL_COMPLETION) {
283 free(sce->ibuf, M_USB);
284 #if defined(__NetBSD__)
285 clfree(&sce->q);
286 #elif defined(__FreeBSD__)
287 clist_free_cblocks(&sce->q);
288 #endif
289 return (EIO);
290 }
291 usbd_set_disco(sce->pipeh, ugen_disco, sc);
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 sce->state |= UGEN_OPEN;
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\n", flag, mode));
323 if (sc->sc_disconnected)
324 return (EIO);
325
326 if (endpt == USB_CONTROL_ENDPOINT) {
327 DPRINTFN(5, ("ugenclose: close control\n"));
328 sc->sc_endpoints[endpt][OUT].state = 0;
329 return (0);
330 }
331
332 flag = FWRITE | FREAD; /* XXX bug if generic open/close */
333
334 /* The open modes have been joined, so check for both modes. */
335 for (dir = OUT; dir <= IN; dir++) {
336 if (flag & (dir == OUT ? FWRITE : FREAD)) {
337 sce = &sc->sc_endpoints[endpt][dir];
338 if (!sce || !sce->pipeh) /* XXX */
339 continue; /* XXX */
340 DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n",
341 endpt, dir, sce));
342 sce->state = 0;
343
344 usbd_abort_pipe(sce->pipeh);
345 usbd_close_pipe(sce->pipeh);
346 sce->pipeh = 0;
347
348 if (sce->ibuf) {
349 free(sce->ibuf, M_USB);
350 sce->ibuf = 0;
351 }
352 }
353 }
354
355 return (0);
356 }
357
358 int
359 ugenread(dev, uio, flag)
360 dev_t dev;
361 struct uio *uio;
362 int flag;
363 {
364 USB_GET_SC(ugen, UGENUNIT(dev), sc);
365 int endpt = UGENENDPOINT(dev);
366 struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
367 u_int32_t n, tn;
368 char buf[UGEN_BBSIZE];
369 usbd_request_handle reqh;
370 usbd_status r;
371 int s;
372 int error = 0;
373 u_char buffer[UGEN_CHUNK];
374
375 DPRINTFN(5, ("ugenread: %d:%d\n", UGENUNIT(dev), UGENENDPOINT(dev)));
376 if (sc->sc_disconnected)
377 return (EIO);
378
379 #ifdef DIAGNOSTIC
380 if (!sce->edesc) {
381 printf("ugenread: no edesc\n");
382 return (EIO);
383 }
384 if (!sce->pipeh) {
385 printf("ugenread: no pipe\n");
386 return (EIO);
387 }
388 #endif
389
390 switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
391 case UE_INTERRUPT:
392 /* Block until activity occured. */
393 s = splusb();
394 while (sce->q.c_cc == 0) {
395 if (flag & IO_NDELAY) {
396 splx(s);
397 return (EWOULDBLOCK);
398 }
399 sce->state |= UGEN_ASLP;
400 DPRINTFN(5, ("ugenread: sleep on %p\n", sc));
401 error = tsleep((caddr_t)sce, PZERO | PCATCH,
402 "ugenri", 0);
403 DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
404 if (error) {
405 sce->state &= ~UGEN_ASLP;
406 splx(s);
407 return (error);
408 }
409 }
410 splx(s);
411
412 /* Transfer as many chunks as possible. */
413 while (sce->q.c_cc > 0 && uio->uio_resid > 0) {
414 n = min(sce->q.c_cc, uio->uio_resid);
415 if (n > sizeof(buffer))
416 n = sizeof(buffer);
417
418 /* Remove a small chunk from the input queue. */
419 q_to_b(&sce->q, buffer, n);
420 DPRINTFN(5, ("ugenread: got %d chars\n", n));
421
422 /* Copy the data to the user process. */
423 error = uiomove(buffer, n, uio);
424 if (error)
425 break;
426 }
427 break;
428 case UE_BULK:
429 reqh = usbd_alloc_request();
430 if (reqh == 0)
431 return (ENOMEM);
432 while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
433 DPRINTFN(1, ("ugenread: start transfer %d bytes\n",n));
434 tn = n;
435 r = usbd_bulk_transfer(reqh, sce->pipeh, 0, buf,
436 &tn, "ugenrb");
437 if (r != USBD_NORMAL_COMPLETION) {
438 if (r == USBD_INTERRUPTED)
439 error = EINTR;
440 else
441 error = EIO;
442 break;
443 }
444 DPRINTFN(1, ("ugenread: got %d bytes\n", tn));
445 error = uiomove(buf, tn, uio);
446 if (error || tn < n)
447 break;
448 }
449 usbd_free_request(reqh);
450 break;
451 default:
452 return (ENXIO);
453 }
454
455 return (error);
456 }
457
458 int
459 ugenwrite(dev, uio, flag)
460 dev_t dev;
461 struct uio *uio;
462 int flag;
463 {
464 USB_GET_SC(ugen, UGENUNIT(dev), sc);
465 int endpt = UGENENDPOINT(dev);
466 struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][OUT];
467 size_t n;
468 int error = 0;
469 char buf[UGEN_BBSIZE];
470 usbd_request_handle reqh;
471 usbd_status r;
472
473 if (sc->sc_disconnected)
474 return (EIO);
475
476 #ifdef DIAGNOSTIC
477 if (!sce->edesc) {
478 printf("ugenwrite: no edesc\n");
479 return (EIO);
480 }
481 if (!sce->pipeh) {
482 printf("ugenwrite: no pipe\n");
483 return (EIO);
484 }
485 #endif
486
487 DPRINTF(("ugenwrite\n"));
488 switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
489 case UE_BULK:
490 reqh = usbd_alloc_request();
491 if (reqh == 0)
492 return (EIO);
493 while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
494 error = uiomove(buf, n, uio);
495 if (error)
496 break;
497 DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
498 r = usbd_bulk_transfer(reqh, sce->pipeh, 0, buf,
499 &n, "ugenwb");
500 if (r != USBD_NORMAL_COMPLETION) {
501 if (r == USBD_INTERRUPTED)
502 error = EINTR;
503 else
504 error = EIO;
505 break;
506 }
507 }
508 usbd_free_request(reqh);
509 break;
510 default:
511 return (ENXIO);
512 }
513 return (error);
514 }
515
516
517 void
518 ugenintr(reqh, addr, status)
519 usbd_request_handle reqh;
520 usbd_private_handle addr;
521 usbd_status status;
522 {
523 struct ugen_endpoint *sce = addr;
524 /*struct ugen_softc *sc = sce->sc;*/
525 usbd_private_handle priv;
526 void *buffer;
527 u_int32_t count;
528 usbd_status xstatus;
529 u_char *ibuf;
530
531 if (status == USBD_CANCELLED)
532 return;
533
534 if (status != USBD_NORMAL_COMPLETION) {
535 DPRINTF(("ugenintr: status=%d\n", status));
536 usbd_clear_endpoint_stall_async(sce->pipeh);
537 return;
538 }
539
540 (void)usbd_get_request_status(reqh, &priv, &buffer, &count, &xstatus);
541 ibuf = sce->ibuf;
542
543 DPRINTFN(5, ("ugenintr: reqh=%p status=%d count=%d\n",
544 reqh, xstatus, count));
545 DPRINTFN(5, (" data = %02x %02x %02x\n",
546 ibuf[0], ibuf[1], ibuf[2]));
547
548 (void)b_to_q(ibuf, count, &sce->q);
549
550 if (sce->state & UGEN_ASLP) {
551 sce->state &= ~UGEN_ASLP;
552 DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
553 wakeup((caddr_t)sce);
554 }
555 selwakeup(&sce->rsel);
556 }
557
558 usbd_status
559 ugen_set_interface(sc, ifaceidx, altno)
560 struct ugen_softc *sc;
561 int ifaceidx, altno;
562 {
563 usbd_interface_handle iface;
564 usb_endpoint_descriptor_t *ed;
565 usbd_status r;
566 struct ugen_endpoint *sce;
567 u_int8_t niface, nendpt, endptno, endpt;
568
569 DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));
570
571 r = usbd_interface_count(sc->sc_udev, &niface);
572 if (r != USBD_NORMAL_COMPLETION)
573 return (r);
574 if (ifaceidx < 0 || ifaceidx >= niface)
575 return (USBD_INVAL);
576
577 r = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
578 if (r != USBD_NORMAL_COMPLETION)
579 return (r);
580 r = usbd_endpoint_count(iface, &nendpt);
581 if (r != USBD_NORMAL_COMPLETION)
582 return (r);
583 for (endptno = 0; endptno < nendpt; endptno++) {
584 ed = usbd_interface2endpoint_descriptor(iface,endptno);
585 endpt = ed->bEndpointAddress;
586 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
587 sce->sc = 0;
588 sce->edesc = 0;
589 sce->iface = 0;
590 }
591
592 /* change setting */
593 r = usbd_set_interface(iface, altno);
594 if (r != USBD_NORMAL_COMPLETION)
595 return (r);
596
597 r = usbd_endpoint_count(iface, &nendpt);
598 if (r != USBD_NORMAL_COMPLETION)
599 return (r);
600 for (endptno = 0; endptno < nendpt; endptno++) {
601 ed = usbd_interface2endpoint_descriptor(iface,endptno);
602 endpt = ed->bEndpointAddress;
603 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
604 sce->sc = sc;
605 sce->edesc = ed;
606 sce->iface = iface;
607 }
608 return (0);
609 }
610
611 /* Retrieve a complete descriptor for a certain device and index. */
612 usb_config_descriptor_t *
613 ugen_get_cdesc(sc, index, lenp)
614 struct ugen_softc *sc;
615 int index;
616 int *lenp;
617 {
618 usb_config_descriptor_t *cdesc, *tdesc, cdescr;
619 int len;
620 usbd_status r;
621
622 if (index == USB_CURRENT_CONFIG_INDEX) {
623 tdesc = usbd_get_config_descriptor(sc->sc_udev);
624 len = UGETW(tdesc->wTotalLength);
625 if (lenp)
626 *lenp = len;
627 cdesc = malloc(len, M_TEMP, M_WAITOK);
628 memcpy(cdesc, tdesc, len);
629 DPRINTFN(5,("ugen_get_cdesc: current, len=%d\n", len));
630 } else {
631 r = usbd_get_config_desc(sc->sc_udev, index, &cdescr);
632 if (r != USBD_NORMAL_COMPLETION)
633 return (0);
634 len = UGETW(cdescr.wTotalLength);
635 DPRINTFN(5,("ugen_get_cdesc: index=%d, len=%d\n", index, len));
636 if (lenp)
637 *lenp = len;
638 cdesc = malloc(len, M_TEMP, M_WAITOK);
639 r = usbd_get_config_desc_full(sc->sc_udev, index, cdesc, len);
640 if (r != USBD_NORMAL_COMPLETION) {
641 free(cdesc, M_TEMP);
642 return (0);
643 }
644 }
645 return (cdesc);
646 }
647
648 int
649 ugen_get_alt_index(sc, ifaceidx)
650 struct ugen_softc *sc;
651 int ifaceidx;
652 {
653 usbd_interface_handle iface;
654 usbd_status r;
655
656 r = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
657 if (r != USBD_NORMAL_COMPLETION)
658 return (-1);
659 return (usbd_get_interface_altindex(iface));
660 }
661
662 int
663 ugenioctl(dev, cmd, addr, flag, p)
664 dev_t dev;
665 u_long cmd;
666 caddr_t addr;
667 int flag;
668 struct proc *p;
669 {
670 USB_GET_SC(ugen, UGENUNIT(dev), sc);
671 int endpt = UGENENDPOINT(dev);
672 struct ugen_endpoint *sce;
673 usbd_status r;
674 usbd_interface_handle iface;
675 struct usb_config_desc *cd;
676 usb_config_descriptor_t *cdesc;
677 struct usb_interface_desc *id;
678 usb_interface_descriptor_t *idesc;
679 struct usb_endpoint_desc *ed;
680 usb_endpoint_descriptor_t *edesc;
681 struct usb_alt_interface *ai;
682 struct usb_string_desc *si;
683 u_int8_t conf, alt;
684
685 DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
686 if (sc->sc_disconnected)
687 return (EIO);
688
689 switch (cmd) {
690 case FIONBIO:
691 /* All handled in the upper FS layer. */
692 return (0);
693 case USB_SET_SHORT_XFER:
694 /* This flag only affects read */
695 sce = &sc->sc_endpoints[endpt][IN];
696 #ifdef DIAGNOSTIC
697 if (!sce->pipeh) {
698 printf("ugenioctl: no pipe\n");
699 return (EIO);
700 }
701 #endif
702 if (*(int *)addr)
703 sce->state |= UGEN_SHORT_OK;
704 else
705 sce->state &= ~UGEN_SHORT_OK;
706 return (0);
707 default:
708 break;
709 }
710
711 if (endpt != USB_CONTROL_ENDPOINT)
712 return (EINVAL);
713
714 switch (cmd) {
715 #ifdef USB_DEBUG
716 case USB_SETDEBUG:
717 ugendebug = *(int *)addr;
718 break;
719 #endif
720 case USB_GET_CONFIG:
721 r = usbd_get_config(sc->sc_udev, &conf);
722 if (r != USBD_NORMAL_COMPLETION)
723 return (EIO);
724 *(int *)addr = conf;
725 break;
726 case USB_SET_CONFIG:
727 if (!(flag & FWRITE))
728 return (EPERM);
729 r = ugen_set_config(sc, *(int *)addr);
730 if (r != USBD_NORMAL_COMPLETION)
731 return (EIO);
732 break;
733 case USB_GET_ALTINTERFACE:
734 ai = (struct usb_alt_interface *)addr;
735 r = usbd_device2interface_handle(sc->sc_udev,
736 ai->interface_index, &iface);
737 if (r != USBD_NORMAL_COMPLETION)
738 return (EINVAL);
739 idesc = usbd_get_interface_descriptor(iface);
740 if (!idesc)
741 return (EIO);
742 ai->alt_no = idesc->bAlternateSetting;
743 break;
744 case USB_SET_ALTINTERFACE:
745 if (!(flag & FWRITE))
746 return (EPERM);
747 ai = (struct usb_alt_interface *)addr;
748 r = usbd_device2interface_handle(sc->sc_udev,
749 ai->interface_index, &iface);
750 if (r != USBD_NORMAL_COMPLETION)
751 return (EINVAL);
752 r = ugen_set_interface(sc, ai->interface_index, ai->alt_no);
753 if (r != USBD_NORMAL_COMPLETION)
754 return (EINVAL);
755 break;
756 case USB_GET_NO_ALT:
757 ai = (struct usb_alt_interface *)addr;
758 cdesc = ugen_get_cdesc(sc, ai->config_index, 0);
759 if (!cdesc)
760 return (EINVAL);
761 idesc = usbd_find_idesc(cdesc, ai->interface_index, 0);
762 if (!idesc)
763 return (EINVAL);
764 ai->alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber);
765 break;
766 case USB_GET_DEVICE_DESC:
767 *(usb_device_descriptor_t *)addr =
768 *usbd_get_device_descriptor(sc->sc_udev);
769 break;
770 case USB_GET_CONFIG_DESC:
771 cd = (struct usb_config_desc *)addr;
772 cdesc = ugen_get_cdesc(sc, cd->config_index, 0);
773 if (!cdesc)
774 return (EINVAL);
775 cd->desc = *cdesc;
776 free(cdesc, M_TEMP);
777 break;
778 case USB_GET_INTERFACE_DESC:
779 id = (struct usb_interface_desc *)addr;
780 cdesc = ugen_get_cdesc(sc, id->config_index, 0);
781 if (!cdesc)
782 return (EINVAL);
783 if (id->config_index == USB_CURRENT_CONFIG_INDEX &&
784 id->alt_index == USB_CURRENT_ALT_INDEX)
785 alt = ugen_get_alt_index(sc, id->interface_index);
786 else
787 alt = id->alt_index;
788 idesc = usbd_find_idesc(cdesc, id->interface_index, alt);
789 if (!idesc) {
790 free(cdesc, M_TEMP);
791 return (EINVAL);
792 }
793 id->desc = *idesc;
794 free(cdesc, M_TEMP);
795 break;
796 case USB_GET_ENDPOINT_DESC:
797 ed = (struct usb_endpoint_desc *)addr;
798 cdesc = ugen_get_cdesc(sc, ed->config_index, 0);
799 if (!cdesc)
800 return (EINVAL);
801 if (ed->config_index == USB_CURRENT_CONFIG_INDEX &&
802 ed->alt_index == USB_CURRENT_ALT_INDEX)
803 alt = ugen_get_alt_index(sc, ed->interface_index);
804 else
805 alt = ed->alt_index;
806 edesc = usbd_find_edesc(cdesc, ed->interface_index,
807 alt, ed->endpoint_index);
808 if (!edesc) {
809 free(cdesc, M_TEMP);
810 return (EINVAL);
811 }
812 ed->desc = *edesc;
813 free(cdesc, M_TEMP);
814 break;
815 case USB_GET_FULL_DESC:
816 {
817 int len;
818 struct iovec iov;
819 struct uio uio;
820 struct usb_full_desc *fd = (struct usb_full_desc *)addr;
821 int error;
822
823 cdesc = ugen_get_cdesc(sc, fd->config_index, &len);
824 if (len > fd->size)
825 len = fd->size;
826 iov.iov_base = (caddr_t)fd->data;
827 iov.iov_len = len;
828 uio.uio_iov = &iov;
829 uio.uio_iovcnt = 1;
830 uio.uio_resid = len;
831 uio.uio_offset = 0;
832 uio.uio_segflg = UIO_USERSPACE;
833 uio.uio_rw = UIO_READ;
834 uio.uio_procp = p;
835 error = uiomove(cdesc, len, &uio);
836 free(cdesc, M_TEMP);
837 return (error);
838 }
839 case USB_GET_STRING_DESC:
840 si = (struct usb_string_desc *)addr;
841 r = usbd_get_string_desc(sc->sc_udev, si->string_index,
842 si->language_id, &si->desc);
843 if (r != USBD_NORMAL_COMPLETION)
844 return (EINVAL);
845 break;
846 case USB_DO_REQUEST:
847 {
848 struct usb_ctl_request *ur = (void *)addr;
849 int len = UGETW(ur->request.wLength);
850 struct iovec iov;
851 struct uio uio;
852 void *ptr = 0;
853 usbd_status r;
854 int error = 0;
855
856 if (!(flag & FWRITE))
857 return (EPERM);
858 /* Avoid requests that would damage the bus integrity. */
859 if ((ur->request.bmRequestType == UT_WRITE_DEVICE &&
860 ur->request.bRequest == UR_SET_ADDRESS) ||
861 (ur->request.bmRequestType == UT_WRITE_DEVICE &&
862 ur->request.bRequest == UR_SET_CONFIG) ||
863 (ur->request.bmRequestType == UT_WRITE_INTERFACE &&
864 ur->request.bRequest == UR_SET_INTERFACE))
865 return (EINVAL);
866
867 if (len < 0 || len > 32767)
868 return (EINVAL);
869 if (len != 0) {
870 iov.iov_base = (caddr_t)ur->data;
871 iov.iov_len = len;
872 uio.uio_iov = &iov;
873 uio.uio_iovcnt = 1;
874 uio.uio_resid = len;
875 uio.uio_offset = 0;
876 uio.uio_segflg = UIO_USERSPACE;
877 uio.uio_rw =
878 ur->request.bmRequestType & UT_READ ?
879 UIO_READ : UIO_WRITE;
880 uio.uio_procp = p;
881 ptr = malloc(len, M_TEMP, M_WAITOK);
882 if (uio.uio_rw == UIO_WRITE) {
883 error = uiomove(ptr, len, &uio);
884 if (error)
885 goto ret;
886 }
887 }
888 r = usbd_do_request_flags(sc->sc_udev, &ur->request,
889 ptr, ur->flags, &ur->actlen);
890 if (r) {
891 error = EIO;
892 goto ret;
893 }
894 if (len != 0) {
895 if (uio.uio_rw == UIO_READ) {
896 error = uiomove(ptr, len, &uio);
897 if (error)
898 goto ret;
899 }
900 }
901 ret:
902 if (ptr)
903 free(ptr, M_TEMP);
904 return (error);
905 }
906 case USB_GET_DEVICEINFO:
907 usbd_fill_deviceinfo(sc->sc_udev,
908 (struct usb_device_info *)addr);
909 break;
910 default:
911 return (EINVAL);
912 }
913 return (0);
914 }
915
916 int
917 ugenpoll(dev, events, p)
918 dev_t dev;
919 int events;
920 struct proc *p;
921 {
922 USB_GET_SC(ugen, UGENUNIT(dev), sc);
923 /* XXX */
924 struct ugen_endpoint *sce;
925 int revents = 0;
926 int s;
927
928 if (sc->sc_disconnected)
929 return (EIO);
930
931 sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
932 #ifdef DIAGNOSTIC
933 if (!sce->edesc) {
934 printf("ugenwrite: no edesc\n");
935 return (EIO);
936 }
937 if (!sce->pipeh) {
938 printf("ugenpoll: no pipe\n");
939 return (EIO);
940 }
941 #endif
942 s = splusb();
943 switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
944 case UE_INTERRUPT:
945 if (events & (POLLIN | POLLRDNORM)) {
946 if (sce->q.c_cc > 0)
947 revents |= events & (POLLIN | POLLRDNORM);
948 else
949 selrecord(p, &sce->rsel);
950 }
951 break;
952 case UE_BULK:
953 /*
954 * We have no easy way of determining if a read will
955 * yield any data or a write will happen.
956 * Pretend they will.
957 */
958 revents |= events &
959 (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);
960 break;
961 default:
962 break;
963 }
964 splx(s);
965 return (revents);
966 }
967
968 #if defined(__FreeBSD__)
969 static int
970 ugen_detach(device_t self)
971 {
972 struct ugen_softc *sc = device_get_softc(self);
973 char *devinfo = (char *) device_get_desc(self);
974
975 if (devinfo) {
976 device_set_desc(self, NULL);
977 free(devinfo, M_USB);
978 }
979 return 0;
980 }
981
982 DRIVER_MODULE(ugen, usb, ugen_driver, ugen_devclass, usbd_driver_load, 0);
983 #endif
984