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