ugen.c revision 1.8 1 /* $NetBSD: ugen.c,v 1.8 1999/01/01 15:31:24 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 #define UGEN_SHORT_OK 0x04 /* short xfers are OK */
76 usbd_pipe_handle pipeh;
77 struct clist q;
78 struct selinfo rsel;
79 void *ibuf;
80 };
81
82 #define UGEN_CHUNK 128 /* chunk size for read */
83 #define UGEN_IBSIZE 1020 /* buffer size */
84 #define UGEN_BBSIZE 1024
85
86 struct ugen_softc {
87 struct device sc_dev; /* base device */
88 struct usbd_device *sc_udev;
89
90 struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];
91 #define OUT 0 /* index order is important, from UE_OUT */
92 #define IN 1 /* from UE_IN */
93
94 int sc_disconnected; /* device is gone */
95 };
96
97 int ugen_match __P((struct device *, struct cfdata *, void *));
98 void ugen_attach __P((struct device *, struct device *, void *));
99
100 int ugenopen __P((dev_t, int, int, struct proc *));
101 int ugenclose __P((dev_t, int, int, struct proc *p));
102 int ugenread __P((dev_t, struct uio *uio, int));
103 int ugenwrite __P((dev_t, struct uio *uio, int));
104 int ugenioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
105 int ugenpoll __P((dev_t, int, struct proc *));
106 void ugenintr __P((usbd_request_handle reqh, usbd_private_handle addr,
107 usbd_status status));
108 void ugen_disco __P((void *));
109
110 int ugen_set_config __P((struct ugen_softc *sc, int configno));
111 usb_config_descriptor_t *ugen_get_cdesc __P((struct ugen_softc *sc, int index,
112 int *lenp));
113 usbd_status ugen_set_interface __P((struct ugen_softc *, int, int));
114 int ugen_get_alt_index __P((struct ugen_softc *sc, int ifaceidx));
115
116 #define UGENUNIT(n) (((n) >> 4) & 0xf)
117 #define UGENENDPOINT(n) ((n) & 0xf)
118
119 USB_DECLARE_DRIVER(ugen);
120
121 USB_MATCH(ugen)
122 {
123 USB_MATCH_START(ugen, uaa);
124
125 if (uaa->usegeneric)
126 return (UMATCH_GENERIC);
127 else
128 return (UMATCH_NONE);
129 }
130
131 USB_ATTACH(ugen)
132 {
133 USB_ATTACH_START(ugen, sc, uaa);
134 char devinfo[1024];
135 usbd_status r;
136 int conf;
137
138 usbd_devinfo(uaa->device, 0, devinfo);
139 USB_ATTACH_SETUP;
140 printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
141
142 sc->sc_udev = uaa->device;
143 conf = 1; /* XXX should not hard code 1 */
144 r = ugen_set_config(sc, conf);
145 if (r != USBD_NORMAL_COMPLETION) {
146 printf("%s: setting configuration %d failed\n",
147 USBDEVNAME(sc->sc_dev), conf);
148 sc->sc_disconnected = 1;
149 USB_ATTACH_ERROR_RETURN;
150 }
151 USB_ATTACH_SUCCESS_RETURN;
152 }
153
154 int
155 ugen_set_config(sc, configno)
156 struct ugen_softc *sc;
157 int configno;
158 {
159 usbd_device_handle dev = sc->sc_udev;
160 usbd_interface_handle iface;
161 usb_endpoint_descriptor_t *ed;
162 struct ugen_endpoint *sce;
163 u_int8_t niface, nendpt;
164 int ifaceno, endptno, endpt;
165 usbd_status r;
166
167 DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
168 USBDEVNAME(sc->sc_dev), configno, sc));
169 if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {
170 /* Avoid setting the current value. */
171 r = usbd_set_config_no(dev, configno, 0);
172 if (r != USBD_NORMAL_COMPLETION)
173 return (r);
174 }
175
176 r = usbd_interface_count(dev, &niface);
177 if (r != USBD_NORMAL_COMPLETION)
178 return (r);
179 memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
180 for (ifaceno = 0; ifaceno < niface; ifaceno++) {
181 DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
182 r = usbd_device2interface_handle(dev, ifaceno, &iface);
183 if (r != USBD_NORMAL_COMPLETION)
184 return (r);
185 r = usbd_endpoint_count(iface, &nendpt);
186 if (r != USBD_NORMAL_COMPLETION)
187 return (r);
188 for (endptno = 0; endptno < nendpt; endptno++) {
189 ed = usbd_interface2endpoint_descriptor(iface,endptno);
190 endpt = ed->bEndpointAddress;
191 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)]
192 [UE_GET_IN(endpt)];
193 DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
194 "(%d,%d), sce=%p\n",
195 endptno, endpt, UE_GET_ADDR(endpt),
196 UE_GET_IN(endpt), sce));
197 sce->sc = sc;
198 sce->edesc = ed;
199 sce->iface = iface;
200 }
201 }
202 return (USBD_NORMAL_COMPLETION);
203 }
204
205 void
206 ugen_disco(p)
207 void *p;
208 {
209 struct ugen_softc *sc = p;
210 sc->sc_disconnected = 1;
211 }
212
213 int
214 ugenopen(dev, flag, mode, p)
215 dev_t dev;
216 int flag;
217 int mode;
218 struct proc *p;
219 {
220 int unit = UGENUNIT(dev);
221 int endpt = UGENENDPOINT(dev);
222 usb_endpoint_descriptor_t *edesc;
223 struct ugen_softc *sc;
224 struct ugen_endpoint *sce;
225 int dir, isize;
226 usbd_status r;
227
228 DPRINTFN(5, ("ugenopen: flag=%d, unit=%d endpt=%d\n",
229 flag, unit, endpt));
230 if (unit >= ugen_cd.cd_ndevs)
231 return (ENXIO);
232 sc = ugen_cd.cd_devs[unit];
233 if (!sc)
234 return (ENXIO);
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_NOWAIT);
270 DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",
271 endpt, isize));
272 if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)
273 return (ENOMEM);
274 r = usbd_open_pipe_intr(sce->iface,
275 edesc->bEndpointAddress,
276 USBD_SHORT_XFER_OK, &sce->pipeh, sce,
277 sce->ibuf, isize, ugenintr);
278 if (r != USBD_NORMAL_COMPLETION) {
279 free(sce->ibuf, M_USB);
280 clfree(&sce->q);
281 return (EIO);
282 }
283 usbd_set_disco(sce->pipeh, ugen_disco, sc);
284 DPRINTFN(5, ("ugenopen: interrupt open done\n"));
285 break;
286 case UE_BULK:
287 r = usbd_open_pipe(sce->iface,
288 edesc->bEndpointAddress, 0,
289 &sce->pipeh);
290 if (r != USBD_NORMAL_COMPLETION)
291 return (EIO);
292 break;
293 case UE_CONTROL:
294 case UE_ISOCHRONOUS:
295 return (EINVAL);
296 }
297 }
298 sce->state |= UGEN_OPEN;
299 return (0);
300 }
301
302 int
303 ugenclose(dev, flag, mode, p)
304 dev_t dev;
305 int flag;
306 int mode;
307 struct proc *p;
308 {
309 struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
310 int endpt = UGENENDPOINT(dev);
311 struct ugen_endpoint *sce;
312 int dir;
313
314 DPRINTFN(5, ("ugenclose\n"));
315 if (sc->sc_disconnected)
316 return (EIO);
317
318 if (endpt == USB_CONTROL_ENDPOINT) {
319 sc->sc_endpoints[endpt][OUT].state = 0;
320 return (0);
321 }
322 dir = flag & FWRITE ? OUT : IN;
323 sce = &sc->sc_endpoints[endpt][dir];
324 DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n", endpt, dir, sce));
325 sce->state = 0;
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 u_int32_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 "ugenri", 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 DPRINTFN(1, ("ugenread: transfer %d bytes\n", n));
410 r = usbd_bulk_transfer(reqh, sce->pipeh, 0, buf,
411 &n, "ugenrb");
412 if (r != USBD_NORMAL_COMPLETION) {
413 if (r == USBD_INTERRUPTED)
414 error = EINTR;
415 else
416 error = EIO;
417 break;
418 }
419 error = uiomove(buf, n, uio);
420 if (error)
421 break;
422 }
423 usbd_free_request(reqh);
424 break;
425 default:
426 return (ENXIO);
427 }
428
429 return (error);
430 }
431
432 int
433 ugenwrite(dev, uio, flag)
434 dev_t dev;
435 struct uio *uio;
436 int flag;
437 {
438 struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
439 int endpt = UGENENDPOINT(dev);
440 struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
441 size_t n;
442 int error = 0;
443 char buf[UGEN_BBSIZE];
444 usbd_request_handle reqh;
445 usbd_status r;
446
447 if (sc->sc_disconnected)
448 return (EIO);
449
450 #ifdef DIAGNOSTIC
451 if (!sce->edesc) {
452 printf("ugenwrite: no edesc\n");
453 return (EIO);
454 }
455 #endif
456
457 DPRINTF(("ugenwrite\n"));
458 switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
459 case UE_BULK:
460 reqh = usbd_alloc_request();
461 if (reqh == 0)
462 return (EIO);
463 while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
464 error = uiomove(buf, n, uio);
465 if (error)
466 break;
467 DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
468 r = usbd_bulk_transfer(reqh, sce->pipeh, 0, buf,
469 &n, "ugenwb");
470 if (r != USBD_NORMAL_COMPLETION) {
471 if (r == USBD_INTERRUPTED)
472 error = EINTR;
473 else
474 error = EIO;
475 break;
476 }
477 }
478 usbd_free_request(reqh);
479 break;
480 default:
481 return (ENXIO);
482 }
483 return (error);
484 }
485
486
487 void
488 ugenintr(reqh, addr, status)
489 usbd_request_handle reqh;
490 usbd_private_handle addr;
491 usbd_status status;
492 {
493 struct ugen_endpoint *sce = addr;
494 /*struct ugen_softc *sc = sce->sc;*/
495 usbd_private_handle priv;
496 void *buffer;
497 u_int32_t count;
498 usbd_status xstatus;
499 u_char *ibuf;
500
501 if (status == USBD_CANCELLED)
502 return;
503
504 if (status != USBD_NORMAL_COMPLETION) {
505 DPRINTF(("ugenintr: status=%d\n", status));
506 usbd_clear_endpoint_stall_async(sce->pipeh);
507 return;
508 }
509
510 (void)usbd_get_request_status(reqh, &priv, &buffer, &count, &xstatus);
511 ibuf = sce->ibuf;
512
513 DPRINTFN(5, ("ugenintr: reqh=%p status=%d count=%d\n",
514 reqh, xstatus, count));
515 DPRINTFN(5, (" data = %02x %02x %02x\n",
516 ibuf[0], ibuf[1], ibuf[2]));
517
518 (void)b_to_q(ibuf, count, &sce->q);
519
520 if (sce->state & UGEN_ASLP) {
521 sce->state &= ~UGEN_ASLP;
522 DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
523 wakeup((caddr_t)sce);
524 }
525 selwakeup(&sce->rsel);
526 }
527
528 usbd_status
529 ugen_set_interface(sc, ifaceidx, altno)
530 struct ugen_softc *sc;
531 int ifaceidx, altno;
532 {
533 usbd_interface_handle iface;
534 usb_endpoint_descriptor_t *ed;
535 usbd_status r;
536 struct ugen_endpoint *sce;
537 u_int8_t niface, nendpt, endptno, endpt;
538
539 DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));
540
541 r = usbd_interface_count(sc->sc_udev, &niface);
542 if (r != USBD_NORMAL_COMPLETION)
543 return (r);
544 if (ifaceidx < 0 || ifaceidx >= niface)
545 return (USBD_INVAL);
546
547 r = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
548 if (r != USBD_NORMAL_COMPLETION)
549 return (r);
550 r = usbd_endpoint_count(iface, &nendpt);
551 if (r != USBD_NORMAL_COMPLETION)
552 return (r);
553 for (endptno = 0; endptno < nendpt; endptno++) {
554 ed = usbd_interface2endpoint_descriptor(iface,endptno);
555 endpt = ed->bEndpointAddress;
556 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
557 sce->sc = 0;
558 sce->edesc = 0;
559 sce->iface = 0;
560 }
561
562 /* change setting */
563 r = usbd_set_interface(iface, altno);
564 if (r != USBD_NORMAL_COMPLETION)
565 return (r);
566
567 r = usbd_endpoint_count(iface, &nendpt);
568 if (r != USBD_NORMAL_COMPLETION)
569 return (r);
570 for (endptno = 0; endptno < nendpt; endptno++) {
571 ed = usbd_interface2endpoint_descriptor(iface,endptno);
572 endpt = ed->bEndpointAddress;
573 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
574 sce->sc = sc;
575 sce->edesc = ed;
576 sce->iface = iface;
577 }
578 return (0);
579 }
580
581 /* Retrieve a complete descriptor for a certain device and index. */
582 usb_config_descriptor_t *
583 ugen_get_cdesc(sc, index, lenp)
584 struct ugen_softc *sc;
585 int index;
586 int *lenp;
587 {
588 usb_config_descriptor_t *cdesc, *tdesc, cdescr;
589 int len;
590 usbd_status r;
591
592 if (index == USB_CURRENT_CONFIG_INDEX) {
593 tdesc = usbd_get_config_descriptor(sc->sc_udev);
594 len = UGETW(tdesc->wTotalLength);
595 if (lenp)
596 *lenp = len;
597 cdesc = malloc(len, M_TEMP, M_WAITOK);
598 memcpy(cdesc, tdesc, len);
599 DPRINTFN(5,("ugen_get_cdesc: current, len=%d\n", len));
600 } else {
601 r = usbd_get_config_desc(sc->sc_udev, index, &cdescr);
602 if (r != USBD_NORMAL_COMPLETION)
603 return (0);
604 len = UGETW(cdescr.wTotalLength);
605 DPRINTFN(5,("ugen_get_cdesc: index=%d, len=%d\n", index, len));
606 if (lenp)
607 *lenp = len;
608 cdesc = malloc(len, M_TEMP, M_WAITOK);
609 r = usbd_get_config_desc_full(sc->sc_udev, index, cdesc, len);
610 if (r != USBD_NORMAL_COMPLETION) {
611 free(cdesc, M_TEMP);
612 return (0);
613 }
614 }
615 return (cdesc);
616 }
617
618 int
619 ugen_get_alt_index(sc, ifaceidx)
620 struct ugen_softc *sc;
621 int ifaceidx;
622 {
623 usbd_interface_handle iface;
624 usbd_status r;
625
626 r = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
627 if (r != USBD_NORMAL_COMPLETION)
628 return (-1);
629 return (usbd_get_interface_altindex(iface));
630 }
631
632 int
633 ugenioctl(dev, cmd, addr, flag, p)
634 dev_t dev;
635 u_long cmd;
636 caddr_t addr;
637 int flag;
638 struct proc *p;
639 {
640 struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
641 int endpt = UGENENDPOINT(dev);
642 struct ugen_endpoint *sce;
643 usbd_status r;
644 usbd_interface_handle iface;
645 struct usb_config_desc *cd;
646 usb_config_descriptor_t *cdesc;
647 struct usb_interface_desc *id;
648 usb_interface_descriptor_t *idesc;
649 struct usb_endpoint_desc *ed;
650 usb_endpoint_descriptor_t *edesc;
651 struct usb_alt_interface *ai;
652 struct usb_string_desc *si;
653 u_int8_t conf, alt;
654
655 DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
656 if (sc->sc_disconnected)
657 return (EIO);
658
659 switch (cmd) {
660 case FIONBIO:
661 /* All handled in the upper FS layer. */
662 return (0);
663 case USB_SET_SHORT_XFER:
664 /* This flag only affects read */
665 sce = &sc->sc_endpoints[endpt][IN];
666 if (*(int *)addr)
667 sce->state |= UGEN_SHORT_OK;
668 else
669 sce->state &= ~UGEN_SHORT_OK;
670 return (0);
671 default:
672 break;
673 }
674
675 if (endpt != USB_CONTROL_ENDPOINT)
676 return (EINVAL);
677
678 switch (cmd) {
679 #ifdef USB_DEBUG
680 case USB_SETDEBUG:
681 ugendebug = *(int *)addr;
682 break;
683 #endif
684 case USB_GET_CONFIG:
685 r = usbd_get_config(sc->sc_udev, &conf);
686 if (r != USBD_NORMAL_COMPLETION)
687 return (EIO);
688 *(int *)addr = conf;
689 break;
690 case USB_SET_CONFIG:
691 if (!(flag & FWRITE))
692 return (EPERM);
693 r = ugen_set_config(sc, *(int *)addr);
694 if (r != USBD_NORMAL_COMPLETION)
695 return (EIO);
696 break;
697 case USB_GET_ALTINTERFACE:
698 ai = (struct usb_alt_interface *)addr;
699 r = usbd_device2interface_handle(sc->sc_udev,
700 ai->interface_index, &iface);
701 if (r != USBD_NORMAL_COMPLETION)
702 return (EINVAL);
703 idesc = usbd_get_interface_descriptor(iface);
704 if (!idesc)
705 return (EIO);
706 ai->alt_no = idesc->bAlternateSetting;
707 break;
708 case USB_SET_ALTINTERFACE:
709 if (!(flag & FWRITE))
710 return (EPERM);
711 ai = (struct usb_alt_interface *)addr;
712 r = usbd_device2interface_handle(sc->sc_udev,
713 ai->interface_index, &iface);
714 if (r != USBD_NORMAL_COMPLETION)
715 return (EINVAL);
716 r = ugen_set_interface(sc, ai->interface_index, ai->alt_no);
717 if (r != USBD_NORMAL_COMPLETION)
718 return (EINVAL);
719 break;
720 case USB_GET_NO_ALT:
721 ai = (struct usb_alt_interface *)addr;
722 cdesc = ugen_get_cdesc(sc, ai->config_index, 0);
723 if (!cdesc)
724 return (EINVAL);
725 idesc = usbd_find_idesc(cdesc, ai->interface_index, 0);
726 if (!idesc)
727 return (EINVAL);
728 ai->alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber);
729 break;
730 case USB_GET_DEVICE_DESC:
731 *(usb_device_descriptor_t *)addr =
732 *usbd_get_device_descriptor(sc->sc_udev);
733 break;
734 case USB_GET_CONFIG_DESC:
735 cd = (struct usb_config_desc *)addr;
736 cdesc = ugen_get_cdesc(sc, cd->config_index, 0);
737 if (!cdesc)
738 return (EINVAL);
739 cd->desc = *cdesc;
740 free(cdesc, M_TEMP);
741 break;
742 case USB_GET_INTERFACE_DESC:
743 id = (struct usb_interface_desc *)addr;
744 cdesc = ugen_get_cdesc(sc, id->config_index, 0);
745 if (!cdesc)
746 return (EINVAL);
747 if (id->config_index == USB_CURRENT_CONFIG_INDEX &&
748 id->alt_index == USB_CURRENT_ALT_INDEX)
749 alt = ugen_get_alt_index(sc, id->interface_index);
750 else
751 alt = id->alt_index;
752 idesc = usbd_find_idesc(cdesc, id->interface_index, alt);
753 if (!idesc) {
754 free(cdesc, M_TEMP);
755 return (EINVAL);
756 }
757 id->desc = *idesc;
758 free(cdesc, M_TEMP);
759 break;
760 case USB_GET_ENDPOINT_DESC:
761 ed = (struct usb_endpoint_desc *)addr;
762 cdesc = ugen_get_cdesc(sc, ed->config_index, 0);
763 if (!cdesc)
764 return (EINVAL);
765 if (ed->config_index == USB_CURRENT_CONFIG_INDEX &&
766 ed->alt_index == USB_CURRENT_ALT_INDEX)
767 alt = ugen_get_alt_index(sc, ed->interface_index);
768 else
769 alt = ed->alt_index;
770 edesc = usbd_find_edesc(cdesc, ed->interface_index,
771 alt, ed->endpoint_index);
772 if (!edesc) {
773 free(cdesc, M_TEMP);
774 return (EINVAL);
775 }
776 ed->desc = *edesc;
777 free(cdesc, M_TEMP);
778 break;
779 case USB_GET_FULL_DESC:
780 {
781 int len;
782 struct iovec iov;
783 struct uio uio;
784 struct usb_full_desc *fd = (struct usb_full_desc *)addr;
785 int error;
786
787 cdesc = ugen_get_cdesc(sc, fd->config_index, &len);
788 if (len > fd->size)
789 len = fd->size;
790 iov.iov_base = (caddr_t)fd->data;
791 iov.iov_len = len;
792 uio.uio_iov = &iov;
793 uio.uio_iovcnt = 1;
794 uio.uio_resid = len;
795 uio.uio_offset = 0;
796 uio.uio_segflg = UIO_USERSPACE;
797 uio.uio_rw = UIO_READ;
798 uio.uio_procp = p;
799 error = uiomove(cdesc, len, &uio);
800 free(cdesc, M_TEMP);
801 return (error);
802 }
803 case USB_GET_STRING_DESC:
804 si = (struct usb_string_desc *)addr;
805 r = usbd_get_string_desc(sc->sc_udev, si->string_index,
806 si->language_id, &si->desc);
807 if (r != USBD_NORMAL_COMPLETION)
808 return (EINVAL);
809 break;
810 case USB_DO_REQUEST:
811 {
812 struct usb_ctl_request *ur = (void *)addr;
813 int len = UGETW(ur->request.wLength);
814 struct iovec iov;
815 struct uio uio;
816 void *ptr = 0;
817 usbd_status r;
818 int error = 0;
819
820 if (!(flag & FWRITE))
821 return (EPERM);
822 /* Avoid requests that would damage the bus integrity. */
823 if ((ur->request.bmRequestType == UT_WRITE_DEVICE &&
824 ur->request.bRequest == UR_SET_ADDRESS) ||
825 (ur->request.bmRequestType == UT_WRITE_DEVICE &&
826 ur->request.bRequest == UR_SET_CONFIG) ||
827 (ur->request.bmRequestType == UT_WRITE_INTERFACE &&
828 ur->request.bRequest == UR_SET_INTERFACE))
829 return (EINVAL);
830
831 if (len < 0 || len > 32767)
832 return (EINVAL);
833 if (len != 0) {
834 iov.iov_base = (caddr_t)ur->data;
835 iov.iov_len = len;
836 uio.uio_iov = &iov;
837 uio.uio_iovcnt = 1;
838 uio.uio_resid = len;
839 uio.uio_offset = 0;
840 uio.uio_segflg = UIO_USERSPACE;
841 uio.uio_rw =
842 ur->request.bmRequestType & UT_READ ?
843 UIO_READ : UIO_WRITE;
844 uio.uio_procp = p;
845 ptr = malloc(len, M_TEMP, M_WAITOK);
846 if (uio.uio_rw == UIO_WRITE) {
847 error = uiomove(ptr, len, &uio);
848 if (error)
849 goto ret;
850 }
851 }
852 r = usbd_do_request_flags(sc->sc_udev, &ur->request,
853 ptr, ur->flags);
854 if (r) {
855 error = EIO;
856 goto ret;
857 }
858 if (len != 0) {
859 if (uio.uio_rw == UIO_READ) {
860 error = uiomove(ptr, len, &uio);
861 if (error)
862 goto ret;
863 }
864 }
865 ret:
866 if (ptr)
867 free(ptr, M_TEMP);
868 return (error);
869 }
870 case USB_GET_DEVICEINFO:
871 usbd_fill_deviceinfo(sc->sc_udev,
872 (struct usb_device_info *)addr);
873 break;
874 default:
875 return (EINVAL);
876 }
877 return (0);
878 }
879
880 int
881 ugenpoll(dev, events, p)
882 dev_t dev;
883 int events;
884 struct proc *p;
885 {
886 struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
887 /* XXX */
888 struct ugen_endpoint *sce;
889 int revents = 0;
890 int s;
891
892 if (sc->sc_disconnected)
893 return (EIO);
894
895 sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
896 if (!sce->edesc) return (0); /* XXX */
897 s = splusb();
898 switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
899 case UE_INTERRUPT:
900 if (events & (POLLIN | POLLRDNORM)) {
901 if (sce->q.c_cc > 0)
902 revents |= events & (POLLIN | POLLRDNORM);
903 else
904 selrecord(p, &sce->rsel);
905 }
906 break;
907 case UE_BULK:
908 /*
909 * We have no easy way of determining if a read will
910 * yield any data or a write will happen.
911 * Pretend they will.
912 */
913 revents |= events &
914 (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);
915 break;
916 default:
917 break;
918 }
919 splx(s);
920 return (revents);
921 }
922
923 #if defined(__FreeBSD__)
924 static int
925 ugen_detach(device_t self)
926 {
927 struct ugen_softc *sc = device_get_softc(self);
928 char *devinfo = (char *) device_get_desc(self);
929
930 if (devinfo) {
931 device_set_desc(self, NULL);
932 free(devinfo, M_USB);
933 }
934 return 0;
935 }
936 #endif
937