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