ugen.c revision 1.1 1 /* $NetBSD: ugen.c,v 1.1 1998/12/08 15:39:00 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 = 10;
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, usb_config_descriptor_t *cdesc, 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 = spltty();
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, cdesc, ifaceidx)
627 struct ugen_softc *sc;
628 usb_config_descriptor_t *cdesc;
629 int ifaceidx;
630 {
631 u_int8_t alt;
632 usbd_interface_handle iface;
633 usb_interface_descriptor_t *idesc;
634 int altidx, nalt;
635 usbd_status r;
636
637 cdesc = usbd_get_config_descriptor(sc->sc_udev);
638 r = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
639 if (r != USBD_NORMAL_COMPLETION)
640 return (-1);
641 r = usbd_get_interface(iface, &alt);
642 if (r != USBD_NORMAL_COMPLETION)
643 return (-1);
644 nalt = usbd_get_no_alt(iface);
645 for (altidx = 0; altidx < nalt; altidx++) {
646 idesc = usbd_find_idesc(cdesc, ifaceidx, altidx);
647 if (!idesc) {
648 DPRINTF(("ugen_get_alt_index: ifaceidx=%d altidx=%d failed\n", ifaceidx, altidx));
649 return (-1);
650 }
651 DPRINTF(("ugen_get_alt_index: ifaceidx=%d altidx=%d alt=%d(%d)\n", ifaceidx, altidx, idesc->bAlternateSetting, alt));
652 if (idesc->bAlternateSetting == alt)
653 return (altidx);
654 }
655 return (-1);
656 }
657
658 int
659 ugenioctl(dev, cmd, addr, flag, p)
660 dev_t dev;
661 u_long cmd;
662 caddr_t addr;
663 int flag;
664 struct proc *p;
665 {
666 struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
667 int endpt = UGENENDPOINT(dev);
668 usbd_status r;
669 usbd_interface_handle iface;
670 struct usb_config_desc *cd;
671 usb_config_descriptor_t *cdesc;
672 struct usb_interface_desc *id;
673 usb_interface_descriptor_t *idesc;
674 struct usb_endpoint_desc *ed;
675 usb_endpoint_descriptor_t *edesc;
676 struct usb_alt_interface *ai;
677 u_int8_t conf, alt;
678
679 DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
680 if (sc->sc_disconnected)
681 return (EIO);
682
683 if (endpt != USB_CONTROL_ENDPOINT)
684 return (EINVAL);
685
686 switch (cmd) {
687 case USB_GET_CONFIG:
688 r = usbd_get_config(sc->sc_udev, &conf);
689 if (r != USBD_NORMAL_COMPLETION)
690 return (EIO);
691 *(int *)addr = conf;
692 break;
693 case USB_SET_CONFIG:
694 r = usbd_set_config_no(sc->sc_udev, *(int *)addr, 0);
695 if (r != USBD_NORMAL_COMPLETION)
696 return (EIO);
697 break;
698 case USB_GET_ALTINTERFACE:
699 ai = (struct usb_alt_interface *)addr;
700 r = usbd_device2interface_handle(sc->sc_udev,
701 ai->interface_index, &iface);
702 if (r != USBD_NORMAL_COMPLETION)
703 return (EINVAL);
704 idesc = usbd_get_interface_descriptor(iface);
705 ai->alt_no = idesc->bAlternateSetting;
706 break;
707 case USB_SET_ALTINTERFACE:
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 r = usbd_device2interface_handle(sc->sc_udev,
720 ai->interface_index, &iface);
721 if (r != USBD_NORMAL_COMPLETION)
722 return (EINVAL);
723 ai->alt_no = usbd_get_no_alt(iface);
724 break;
725 case USB_GET_DEVICE_DESC:
726 *(usb_device_descriptor_t *)addr =
727 *usbd_get_device_descriptor(sc->sc_udev);
728 break;
729 case USB_GET_CONFIG_DESC:
730 cd = (struct usb_config_desc *)addr;
731 cdesc = ugen_get_cdesc(sc, cd->config_index, 0);
732 if (!cdesc)
733 return (EINVAL);
734 cd->desc = *cdesc;
735 free(cdesc, M_TEMP);
736 break;
737 case USB_GET_INTERFACE_DESC:
738 id = (struct usb_interface_desc *)addr;
739 cdesc = ugen_get_cdesc(sc, id->config_index, 0);
740 if (!cdesc)
741 return (EINVAL);
742 if (id->config_index == USB_CURRENT_CONFIG_INDEX &&
743 id->alt_index == USB_CURRENT_ALT_INDEX)
744 alt = ugen_get_alt_index(sc, cdesc, id->interface_index);
745 else
746 alt = id->alt_index;
747 idesc = usbd_find_idesc(cdesc, id->interface_index, alt);
748 if (!idesc) {
749 free(cdesc, M_TEMP);
750 return (EINVAL);
751 }
752 id->desc = *idesc;
753 free(cdesc, M_TEMP);
754 break;
755 case USB_GET_ENDPOINT_DESC:
756 ed = (struct usb_endpoint_desc *)addr;
757 cdesc = ugen_get_cdesc(sc, ed->config_index, 0);
758 if (!cdesc)
759 return (EINVAL);
760 if (ed->config_index == USB_CURRENT_CONFIG_INDEX &&
761 ed->alt_index == USB_CURRENT_ALT_INDEX)
762 alt = ugen_get_alt_index(sc, cdesc, ed->interface_index);
763 else
764 alt = ed->alt_index;
765 edesc = usbd_find_edesc(cdesc, ed->interface_index,
766 alt, ed->endpoint_index);
767 if (!edesc) {
768 free(cdesc, M_TEMP);
769 return (EINVAL);
770 }
771 ed->desc = *edesc;
772 free(cdesc, M_TEMP);
773 break;
774 case USB_GET_FULL_DESC:
775 {
776 int len;
777 struct iovec iov;
778 struct uio uio;
779 struct usb_full_desc *fd = (struct usb_full_desc *)addr;
780 int error;
781
782 cdesc = ugen_get_cdesc(sc, fd->config_index, &len);
783 if (len > fd->size)
784 len = fd->size;
785 iov.iov_base = (caddr_t)fd->data;
786 iov.iov_len = len;
787 uio.uio_iov = &iov;
788 uio.uio_iovcnt = 1;
789 uio.uio_resid = len;
790 uio.uio_offset = 0;
791 uio.uio_segflg = UIO_USERSPACE;
792 uio.uio_rw = UIO_READ;
793 uio.uio_procp = p;
794 error = uiomove(cdesc, len, &uio);
795 free(cdesc, M_TEMP);
796 return (error);
797 }
798 case USB_DO_REQUEST:
799 {
800 struct usb_ctl_request *ur = (void *)addr;
801 int len = UGETW(ur->request.wLength);
802 struct iovec iov;
803 struct uio uio;
804 void *ptr = 0;
805 usbd_status r;
806 int error = 0;
807
808 /* Avoid requests that would damage the bus integrity. */
809 if ((ur->request.bmRequestType == UT_WRITE_DEVICE &&
810 ur->request.bRequest == UR_SET_ADDRESS) ||
811 (ur->request.bmRequestType == UT_WRITE_DEVICE &&
812 ur->request.bRequest == UR_SET_CONFIG) ||
813 (ur->request.bmRequestType == UT_WRITE_INTERFACE &&
814 ur->request.bRequest == UR_SET_INTERFACE))
815 return (EINVAL);
816
817 if (len < 0 || len > 32767)
818 return (EINVAL);
819 if (len != 0) {
820 iov.iov_base = (caddr_t)ur->data;
821 iov.iov_len = len;
822 uio.uio_iov = &iov;
823 uio.uio_iovcnt = 1;
824 uio.uio_resid = len;
825 uio.uio_offset = 0;
826 uio.uio_segflg = UIO_USERSPACE;
827 uio.uio_rw =
828 ur->request.bmRequestType & UT_READ ?
829 UIO_READ : UIO_WRITE;
830 uio.uio_procp = p;
831 ptr = malloc(len, M_TEMP, M_WAITOK);
832 if (uio.uio_rw == UIO_WRITE) {
833 error = uiomove(ptr, len, &uio);
834 if (error)
835 goto ret;
836 }
837 }
838 r = usbd_do_request(sc->sc_udev, &ur->request, ptr);
839 if (r) {
840 error = EIO;
841 goto ret;
842 }
843 if (len != 0) {
844 if (uio.uio_rw == UIO_READ) {
845 error = uiomove(ptr, len, &uio);
846 if (error)
847 goto ret;
848 }
849 }
850 ret:
851 if (ptr)
852 free(ptr, M_TEMP);
853 return (error);
854 }
855 default:
856 return (EINVAL);
857 }
858 return (0);
859 }
860
861 int
862 ugenpoll(dev, events, p)
863 dev_t dev;
864 int events;
865 struct proc *p;
866 {
867 struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
868 /* XXX */
869 struct ugen_endpoint *sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
870 int revents = 0;
871 int s;
872
873 if (sc->sc_disconnected)
874 return (EIO);
875
876 s = spltty();
877 switch (0 /*XXXsce->sc_pipekind*/) {
878 case UE_INTERRUPT:
879 if (events & (POLLIN | POLLRDNORM)) {
880 if (sce->q.c_cc > 0)
881 revents |= events & (POLLIN | POLLRDNORM);
882 else
883 selrecord(p, &sce->rsel);
884 }
885 break;
886 }
887 splx(s);
888 return (revents);
889 }
890