Line data Source code
1 : /* $OpenBSD: ugen.c,v 1.98 2018/05/01 18:14:46 landry Exp $ */
2 : /* $NetBSD: ugen.c,v 1.63 2002/11/26 18:49:48 christos Exp $ */
3 : /* $FreeBSD: src/sys/dev/usb/ugen.c,v 1.26 1999/11/17 22:33:41 n_hibma Exp $ */
4 :
5 : /*
6 : * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 : * All rights reserved.
8 : *
9 : * This code is derived from software contributed to The NetBSD Foundation
10 : * by Lennart Augustsson (lennart@augustsson.net) at
11 : * Carlstedt Research & Technology.
12 : *
13 : * Redistribution and use in source and binary forms, with or without
14 : * modification, are permitted provided that the following conditions
15 : * are met:
16 : * 1. Redistributions of source code must retain the above copyright
17 : * notice, this list of conditions and the following disclaimer.
18 : * 2. Redistributions in binary form must reproduce the above copyright
19 : * notice, this list of conditions and the following disclaimer in the
20 : * documentation and/or other materials provided with the distribution.
21 : *
22 : * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 : * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 : * POSSIBILITY OF SUCH DAMAGE.
33 : */
34 :
35 :
36 : #include <sys/param.h>
37 : #include <sys/systm.h>
38 : #include <sys/kernel.h>
39 : #include <sys/malloc.h>
40 : #include <sys/device.h>
41 : #include <sys/ioctl.h>
42 : #include <sys/conf.h>
43 : #include <sys/tty.h>
44 : #include <sys/fcntl.h>
45 : #include <sys/selinfo.h>
46 : #include <sys/vnode.h>
47 : #include <sys/poll.h>
48 :
49 : #include <dev/usb/usb.h>
50 : #include <dev/usb/usbdi.h>
51 : #include <dev/usb/usbdi_util.h>
52 :
53 : #ifdef UGEN_DEBUG
54 : #define DPRINTF(x) do { if (ugendebug) printf x; } while (0)
55 : #define DPRINTFN(n,x) do { if (ugendebug>(n)) printf x; } while (0)
56 : int ugendebug = 0;
57 : #else
58 : #define DPRINTF(x)
59 : #define DPRINTFN(n,x)
60 : #endif
61 :
62 : #define UGEN_CHUNK 128 /* chunk size for read */
63 : #define UGEN_IBSIZE 1020 /* buffer size */
64 : #define UGEN_BBSIZE 1024
65 :
66 : #define UGEN_NISOFRAMES 500 /* 0.5 seconds worth */
67 : #define UGEN_NISOREQS 6 /* number of outstanding xfer requests */
68 : #define UGEN_NISORFRMS 4 /* number of frames (milliseconds) per req */
69 :
70 : struct ugen_endpoint {
71 : struct ugen_softc *sc;
72 : usb_endpoint_descriptor_t *edesc;
73 : struct usbd_interface *iface;
74 : int state;
75 : #define UGEN_ASLP 0x02 /* waiting for data */
76 : #define UGEN_SHORT_OK 0x04 /* short xfers are OK */
77 : struct usbd_pipe *pipeh;
78 : struct clist q;
79 : struct selinfo rsel;
80 : u_char *ibuf; /* start of buffer (circular for isoc) */
81 : size_t ibuflen;
82 : u_char *fill; /* location for input (isoc) */
83 : u_char *limit; /* end of circular buffer (isoc) */
84 : u_char *cur; /* current read location (isoc) */
85 : u_int32_t timeout;
86 : struct isoreq {
87 : struct ugen_endpoint *sce;
88 : struct usbd_xfer *xfer;
89 : void *dmabuf;
90 : u_int16_t sizes[UGEN_NISORFRMS];
91 : } isoreqs[UGEN_NISOREQS];
92 : };
93 :
94 : struct ugen_softc {
95 : struct device sc_dev; /* base device */
96 : struct usbd_device *sc_udev;
97 :
98 : char sc_is_open[USB_MAX_ENDPOINTS];
99 : struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];
100 : #define OUT 0
101 : #define IN 1
102 :
103 : int sc_refcnt;
104 : u_char sc_secondary;
105 : };
106 :
107 : void ugenintr(struct usbd_xfer *xfer, void *addr, usbd_status status);
108 : void ugen_isoc_rintr(struct usbd_xfer *xfer, void *addr, usbd_status status);
109 : int ugen_do_read(struct ugen_softc *, int, struct uio *, int);
110 : int ugen_do_write(struct ugen_softc *, int, struct uio *, int);
111 : int ugen_do_ioctl(struct ugen_softc *, int, u_long, caddr_t, int,
112 : struct proc *);
113 : int ugen_do_close(struct ugen_softc *, int, int);
114 : int ugen_set_config(struct ugen_softc *sc, int configno);
115 : int ugen_set_interface(struct ugen_softc *, int, int);
116 : int ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx);
117 :
118 : #define UGENUNIT(n) ((minor(n) >> 4) & 0xf)
119 : #define UGENENDPOINT(n) (minor(n) & 0xf)
120 : #define UGENDEV(u, e) (makedev(0, ((u) << 4) | (e)))
121 :
122 : int ugen_match(struct device *, void *, void *);
123 : void ugen_attach(struct device *, struct device *, void *);
124 : int ugen_detach(struct device *, int);
125 :
126 : struct cfdriver ugen_cd = {
127 : NULL, "ugen", DV_DULL
128 : };
129 :
130 : const struct cfattach ugen_ca = {
131 : sizeof(struct ugen_softc), ugen_match, ugen_attach, ugen_detach
132 : };
133 :
134 : int
135 0 : ugen_match(struct device *parent, void *match, void *aux)
136 : {
137 0 : struct usb_attach_arg *uaa = aux;
138 :
139 0 : if (uaa->usegeneric) {
140 0 : return (UMATCH_GENERIC);
141 : } else
142 0 : return (UMATCH_NONE);
143 0 : }
144 :
145 : void
146 0 : ugen_attach(struct device *parent, struct device *self, void *aux)
147 : {
148 0 : struct ugen_softc *sc = (struct ugen_softc *)self;
149 0 : struct usb_attach_arg *uaa = aux;
150 : struct usbd_device *udev;
151 : usbd_status err;
152 : int conf;
153 :
154 0 : sc->sc_udev = udev = uaa->device;
155 :
156 0 : if (usbd_get_devcnt(udev) > 0)
157 0 : sc->sc_secondary = 1;
158 :
159 0 : if (!sc->sc_secondary) {
160 : /* First set configuration index 0, the default one for ugen. */
161 0 : err = usbd_set_config_index(udev, 0, 0);
162 0 : if (err) {
163 0 : printf("%s: setting configuration index 0 failed\n",
164 0 : sc->sc_dev.dv_xname);
165 0 : usbd_deactivate(sc->sc_udev);
166 0 : return;
167 : }
168 : }
169 0 : conf = usbd_get_config_descriptor(udev)->bConfigurationValue;
170 :
171 : /* Set up all the local state for this configuration. */
172 0 : err = ugen_set_config(sc, conf);
173 0 : if (err) {
174 0 : printf("%s: setting configuration %d failed\n",
175 0 : sc->sc_dev.dv_xname, conf);
176 0 : usbd_deactivate(sc->sc_udev);
177 0 : return;
178 : }
179 0 : }
180 :
181 : int
182 0 : ugen_set_config(struct ugen_softc *sc, int configno)
183 : {
184 0 : struct usbd_device *dev = sc->sc_udev;
185 : usb_config_descriptor_t *cdesc;
186 : usb_interface_descriptor_t *id;
187 0 : struct usbd_interface *iface;
188 : usb_endpoint_descriptor_t *ed;
189 : struct ugen_endpoint *sce;
190 : int ifaceno, endptno, endpt;
191 : int err, dir;
192 :
193 : DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
194 : sc->sc_dev.dv_xname, configno, sc));
195 :
196 : /*
197 : * We start at 1, not 0, because we don't care whether the
198 : * control endpoint is open or not. It is always present.
199 : */
200 0 : for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++)
201 0 : if (sc->sc_is_open[endptno]) {
202 : DPRINTFN(1,
203 : ("ugen_set_config: %s - endpoint %d is open\n",
204 : sc->sc_dev.dv_xname, endptno));
205 0 : return (USBD_IN_USE);
206 : }
207 :
208 : /* Avoid setting the current value. */
209 0 : cdesc = usbd_get_config_descriptor(dev);
210 0 : if (cdesc == NULL || cdesc->bConfigurationValue != configno) {
211 0 : if (sc->sc_secondary) {
212 0 : printf("%s: secondary, not changing config to %d\n",
213 : __func__, configno);
214 0 : return (USBD_IN_USE);
215 : } else {
216 0 : err = usbd_set_config_no(dev, configno, 1);
217 0 : if (err)
218 0 : return (err);
219 : }
220 : }
221 :
222 0 : memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
223 0 : for (ifaceno = 0; ifaceno < cdesc->bNumInterface; ifaceno++) {
224 : DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
225 0 : if (usbd_iface_claimed(sc->sc_udev, ifaceno)) {
226 : DPRINTF(("%s: iface %d not available\n", __func__,
227 : ifaceno));
228 : continue;
229 : }
230 0 : err = usbd_device2interface_handle(dev, ifaceno, &iface);
231 0 : if (err)
232 0 : return (err);
233 0 : id = usbd_get_interface_descriptor(iface);
234 0 : for (endptno = 0; endptno < id->bNumEndpoints; endptno++) {
235 0 : ed = usbd_interface2endpoint_descriptor(iface,endptno);
236 0 : endpt = ed->bEndpointAddress;
237 0 : dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
238 0 : sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
239 : DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
240 : "(%d,%d), sce=%p\n",
241 : endptno, endpt, UE_GET_ADDR(endpt),
242 : UE_GET_DIR(endpt), sce));
243 0 : sce->sc = sc;
244 0 : sce->edesc = ed;
245 0 : sce->iface = iface;
246 : }
247 : }
248 0 : return (0);
249 0 : }
250 :
251 : int
252 0 : ugenopen(dev_t dev, int flag, int mode, struct proc *p)
253 : {
254 : struct ugen_softc *sc;
255 0 : int unit = UGENUNIT(dev);
256 0 : int endpt = UGENENDPOINT(dev);
257 : usb_endpoint_descriptor_t *edesc;
258 : struct ugen_endpoint *sce;
259 : int dir, isize;
260 : usbd_status err;
261 : struct usbd_xfer *xfer;
262 : void *buf;
263 : int i, j;
264 :
265 0 : if (unit >= ugen_cd.cd_ndevs)
266 0 : return (ENXIO);
267 0 : sc = ugen_cd.cd_devs[unit];
268 0 : if (sc == NULL)
269 0 : return (ENXIO);
270 :
271 : DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n",
272 : flag, mode, unit, endpt));
273 :
274 0 : if (sc == NULL || usbd_is_dying(sc->sc_udev))
275 0 : return (ENXIO);
276 :
277 0 : if (sc->sc_is_open[endpt])
278 0 : return (EBUSY);
279 :
280 0 : if (endpt == USB_CONTROL_ENDPOINT) {
281 0 : sc->sc_is_open[USB_CONTROL_ENDPOINT] = 1;
282 0 : return (0);
283 : }
284 :
285 : /* Make sure there are pipes for all directions. */
286 0 : for (dir = OUT; dir <= IN; dir++) {
287 0 : if (flag & (dir == OUT ? FWRITE : FREAD)) {
288 0 : sce = &sc->sc_endpoints[endpt][dir];
289 0 : if (sce == 0 || sce->edesc == 0)
290 0 : return (ENXIO);
291 : }
292 : }
293 :
294 : /* Actually open the pipes. */
295 : /* XXX Should back out properly if it fails. */
296 0 : for (dir = OUT; dir <= IN; dir++) {
297 0 : if (!(flag & (dir == OUT ? FWRITE : FREAD)))
298 : continue;
299 0 : sce = &sc->sc_endpoints[endpt][dir];
300 0 : sce->state = 0;
301 0 : sce->timeout = USBD_NO_TIMEOUT;
302 : DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n",
303 : sc, endpt, dir, sce));
304 0 : edesc = sce->edesc;
305 0 : switch (edesc->bmAttributes & UE_XFERTYPE) {
306 : case UE_INTERRUPT:
307 0 : if (dir == OUT) {
308 0 : err = usbd_open_pipe(sce->iface,
309 0 : edesc->bEndpointAddress, 0, &sce->pipeh);
310 0 : if (err)
311 0 : return (EIO);
312 : break;
313 : }
314 0 : isize = UGETW(edesc->wMaxPacketSize);
315 0 : if (isize == 0) /* shouldn't happen */
316 0 : return (EINVAL);
317 0 : sce->ibuflen = isize;
318 0 : sce->ibuf = malloc(sce->ibuflen, M_USBDEV, M_WAITOK);
319 : DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",
320 : endpt, isize));
321 0 : clalloc(&sce->q, UGEN_IBSIZE, 0);
322 0 : err = usbd_open_pipe_intr(sce->iface,
323 0 : edesc->bEndpointAddress,
324 0 : USBD_SHORT_XFER_OK, &sce->pipeh, sce,
325 0 : sce->ibuf, isize, ugenintr,
326 : USBD_DEFAULT_INTERVAL);
327 0 : if (err) {
328 0 : free(sce->ibuf, M_USBDEV, sce->ibuflen);
329 0 : clfree(&sce->q);
330 0 : return (EIO);
331 : }
332 : DPRINTFN(5, ("ugenopen: interrupt open done\n"));
333 : break;
334 : case UE_BULK:
335 0 : err = usbd_open_pipe(sce->iface,
336 0 : edesc->bEndpointAddress, 0, &sce->pipeh);
337 0 : if (err)
338 0 : return (EIO);
339 : break;
340 : case UE_ISOCHRONOUS:
341 0 : if (dir == OUT)
342 0 : return (EINVAL);
343 0 : isize = UGETW(edesc->wMaxPacketSize);
344 0 : if (isize == 0) /* shouldn't happen */
345 0 : return (EINVAL);
346 0 : sce->ibuflen = isize * UGEN_NISOFRAMES;
347 0 : sce->ibuf = mallocarray(isize, UGEN_NISOFRAMES,
348 : M_USBDEV, M_WAITOK);
349 0 : sce->cur = sce->fill = sce->ibuf;
350 0 : sce->limit = sce->ibuf + isize * UGEN_NISOFRAMES;
351 : DPRINTFN(5, ("ugenopen: isoc endpt=%d, isize=%d\n",
352 : endpt, isize));
353 0 : err = usbd_open_pipe(sce->iface,
354 0 : edesc->bEndpointAddress, 0, &sce->pipeh);
355 0 : if (err) {
356 0 : free(sce->ibuf, M_USBDEV, sce->ibuflen);
357 0 : return (EIO);
358 : }
359 0 : for(i = 0; i < UGEN_NISOREQS; ++i) {
360 0 : sce->isoreqs[i].sce = sce;
361 0 : xfer = usbd_alloc_xfer(sc->sc_udev);
362 0 : if (xfer == 0)
363 : goto bad;
364 0 : sce->isoreqs[i].xfer = xfer;
365 0 : buf = usbd_alloc_buffer
366 0 : (xfer, isize * UGEN_NISORFRMS);
367 0 : if (buf == 0) {
368 0 : i++;
369 0 : goto bad;
370 : }
371 0 : sce->isoreqs[i].dmabuf = buf;
372 0 : for(j = 0; j < UGEN_NISORFRMS; ++j)
373 0 : sce->isoreqs[i].sizes[j] = isize;
374 0 : usbd_setup_isoc_xfer(xfer, sce->pipeh,
375 0 : &sce->isoreqs[i], sce->isoreqs[i].sizes,
376 : UGEN_NISORFRMS, USBD_NO_COPY |
377 : USBD_SHORT_XFER_OK, ugen_isoc_rintr);
378 0 : (void)usbd_transfer(xfer);
379 : }
380 : DPRINTFN(5, ("ugenopen: isoc open done\n"));
381 : break;
382 : bad:
383 0 : while (--i >= 0) /* implicit buffer free */
384 0 : usbd_free_xfer(sce->isoreqs[i].xfer);
385 0 : return (ENOMEM);
386 : case UE_CONTROL:
387 0 : sce->timeout = USBD_DEFAULT_TIMEOUT;
388 0 : return (EINVAL);
389 : }
390 : }
391 0 : sc->sc_is_open[endpt] = 1;
392 0 : return (0);
393 0 : }
394 :
395 : int
396 0 : ugenclose(dev_t dev, int flag, int mode, struct proc *p)
397 : {
398 0 : struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
399 0 : int endpt = UGENENDPOINT(dev);
400 : int error;
401 :
402 0 : if (sc == NULL || usbd_is_dying(sc->sc_udev))
403 0 : return (EIO);
404 :
405 : DPRINTFN(5, ("ugenclose: flag=%d, mode=%d, unit=%d, endpt=%d\n",
406 : flag, mode, UGENUNIT(dev), endpt));
407 :
408 0 : sc->sc_refcnt++;
409 0 : error = ugen_do_close(sc, endpt, flag);
410 0 : if (--sc->sc_refcnt < 0)
411 0 : usb_detach_wakeup(&sc->sc_dev);
412 :
413 0 : return (error);
414 0 : }
415 :
416 : int
417 0 : ugen_do_close(struct ugen_softc *sc, int endpt, int flag)
418 : {
419 : struct ugen_endpoint *sce;
420 : int dir, i;
421 :
422 : #ifdef DIAGNOSTIC
423 0 : if (!sc->sc_is_open[endpt]) {
424 0 : printf("ugenclose: not open\n");
425 0 : return (EINVAL);
426 : }
427 : #endif
428 :
429 0 : if (endpt == USB_CONTROL_ENDPOINT) {
430 : DPRINTFN(5, ("ugenclose: close control\n"));
431 0 : sc->sc_is_open[endpt] = 0;
432 0 : return (0);
433 : }
434 :
435 0 : for (dir = OUT; dir <= IN; dir++) {
436 0 : if (!(flag & (dir == OUT ? FWRITE : FREAD)))
437 : continue;
438 0 : sce = &sc->sc_endpoints[endpt][dir];
439 0 : if (sce == NULL || sce->pipeh == NULL)
440 : continue;
441 : DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n",
442 : endpt, dir, sce));
443 :
444 0 : usbd_close_pipe(sce->pipeh);
445 0 : sce->pipeh = NULL;
446 :
447 0 : switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
448 : case UE_INTERRUPT:
449 0 : ndflush(&sce->q, sce->q.c_cc);
450 0 : clfree(&sce->q);
451 0 : break;
452 : case UE_ISOCHRONOUS:
453 0 : for (i = 0; i < UGEN_NISOREQS; ++i)
454 0 : usbd_free_xfer(sce->isoreqs[i].xfer);
455 :
456 : default:
457 : break;
458 : }
459 :
460 0 : if (sce->ibuf != NULL) {
461 0 : free(sce->ibuf, M_USBDEV, sce->ibuflen);
462 0 : sce->ibuf = NULL;
463 0 : }
464 : }
465 0 : sc->sc_is_open[endpt] = 0;
466 :
467 0 : return (0);
468 0 : }
469 :
470 : int
471 0 : ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
472 : {
473 0 : struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
474 0 : u_int32_t tn;
475 : size_t n;
476 0 : char buf[UGEN_BBSIZE];
477 : struct usbd_xfer *xfer;
478 : usbd_status err;
479 : int s;
480 : int flags, error = 0;
481 0 : u_char buffer[UGEN_CHUNK];
482 :
483 : DPRINTFN(5, ("%s: ugenread: %d\n", sc->sc_dev.dv_xname, endpt));
484 :
485 0 : if (usbd_is_dying(sc->sc_udev))
486 0 : return (EIO);
487 :
488 0 : if (endpt == USB_CONTROL_ENDPOINT)
489 0 : return (ENODEV);
490 :
491 : #ifdef DIAGNOSTIC
492 0 : if (sce->edesc == NULL) {
493 0 : printf("ugenread: no edesc\n");
494 0 : return (EIO);
495 : }
496 0 : if (sce->pipeh == NULL) {
497 0 : printf("ugenread: no pipe\n");
498 0 : return (EIO);
499 : }
500 : #endif
501 :
502 0 : switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
503 : case UE_INTERRUPT:
504 : /* Block until activity occurred. */
505 0 : s = splusb();
506 0 : while (sce->q.c_cc == 0) {
507 0 : if (flag & IO_NDELAY) {
508 0 : splx(s);
509 0 : return (EWOULDBLOCK);
510 : }
511 0 : sce->state |= UGEN_ASLP;
512 : DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
513 0 : error = tsleep(sce, PZERO | PCATCH, "ugenri",
514 0 : (sce->timeout * hz) / 1000);
515 0 : sce->state &= ~UGEN_ASLP;
516 : DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
517 0 : if (usbd_is_dying(sc->sc_udev))
518 0 : error = EIO;
519 0 : if (error == EWOULDBLOCK) { /* timeout, return 0 */
520 : error = 0;
521 0 : break;
522 : }
523 0 : if (error)
524 : break;
525 : }
526 0 : splx(s);
527 :
528 : /* Transfer as many chunks as possible. */
529 0 : while (sce->q.c_cc > 0 && uio->uio_resid > 0 && !error) {
530 0 : n = ulmin(sce->q.c_cc, uio->uio_resid);
531 0 : if (n > sizeof(buffer))
532 : n = sizeof(buffer);
533 :
534 : /* Remove a small chunk from the input queue. */
535 0 : q_to_b(&sce->q, buffer, n);
536 : DPRINTFN(5, ("ugenread: got %zu chars\n", n));
537 :
538 : /* Copy the data to the user process. */
539 0 : error = uiomove(buffer, n, uio);
540 0 : if (error)
541 : break;
542 : }
543 : break;
544 : case UE_BULK:
545 0 : xfer = usbd_alloc_xfer(sc->sc_udev);
546 0 : if (xfer == 0)
547 0 : return (ENOMEM);
548 : flags = USBD_SYNCHRONOUS;
549 0 : if (sce->state & UGEN_SHORT_OK)
550 0 : flags |= USBD_SHORT_XFER_OK;
551 0 : if (sce->timeout == 0)
552 0 : flags |= USBD_CATCH;
553 0 : while ((n = ulmin(UGEN_BBSIZE, uio->uio_resid)) != 0) {
554 : DPRINTFN(1, ("ugenread: start transfer %zu bytes\n",n));
555 0 : usbd_setup_xfer(xfer, sce->pipeh, 0, buf, n,
556 0 : flags, sce->timeout, NULL);
557 0 : err = usbd_transfer(xfer);
558 0 : if (err) {
559 0 : usbd_clear_endpoint_stall(sce->pipeh);
560 0 : if (err == USBD_INTERRUPTED)
561 0 : error = EINTR;
562 0 : else if (err == USBD_TIMEOUT)
563 0 : error = ETIMEDOUT;
564 : else
565 : error = EIO;
566 : break;
567 : }
568 0 : usbd_get_xfer_status(xfer, NULL, NULL, &tn, NULL);
569 : DPRINTFN(1, ("ugenread: got %u bytes\n", tn));
570 0 : error = uiomove(buf, tn, uio);
571 0 : if (error || tn < n)
572 : break;
573 : }
574 0 : usbd_free_xfer(xfer);
575 0 : break;
576 : case UE_ISOCHRONOUS:
577 0 : s = splusb();
578 0 : while (sce->cur == sce->fill) {
579 0 : if (flag & IO_NDELAY) {
580 0 : splx(s);
581 0 : return (EWOULDBLOCK);
582 : }
583 0 : sce->state |= UGEN_ASLP;
584 : DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
585 0 : error = tsleep(sce, PZERO | PCATCH, "ugenri",
586 0 : (sce->timeout * hz) / 1000);
587 0 : sce->state &= ~UGEN_ASLP;
588 : DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
589 0 : if (usbd_is_dying(sc->sc_udev))
590 0 : error = EIO;
591 0 : if (error == EWOULDBLOCK) { /* timeout, return 0 */
592 : error = 0;
593 0 : break;
594 : }
595 0 : if (error)
596 : break;
597 : }
598 :
599 0 : while (sce->cur != sce->fill && uio->uio_resid > 0 && !error) {
600 0 : if(sce->fill > sce->cur)
601 0 : n = ulmin(sce->fill - sce->cur, uio->uio_resid);
602 : else
603 0 : n = ulmin(sce->limit - sce->cur, uio->uio_resid);
604 :
605 : DPRINTFN(5, ("ugenread: isoc got %zu chars\n", n));
606 :
607 : /* Copy the data to the user process. */
608 0 : error = uiomove(sce->cur, n, uio);
609 0 : if (error)
610 : break;
611 0 : sce->cur += n;
612 0 : if(sce->cur >= sce->limit)
613 0 : sce->cur = sce->ibuf;
614 : }
615 0 : splx(s);
616 0 : break;
617 :
618 :
619 : default:
620 0 : return (ENXIO);
621 : }
622 0 : return (error);
623 0 : }
624 :
625 : int
626 0 : ugenread(dev_t dev, struct uio *uio, int flag)
627 : {
628 0 : int endpt = UGENENDPOINT(dev);
629 : struct ugen_softc *sc;
630 : int error;
631 :
632 0 : sc = ugen_cd.cd_devs[UGENUNIT(dev)];
633 :
634 0 : sc->sc_refcnt++;
635 0 : error = ugen_do_read(sc, endpt, uio, flag);
636 0 : if (--sc->sc_refcnt < 0)
637 0 : usb_detach_wakeup(&sc->sc_dev);
638 0 : return (error);
639 : }
640 :
641 : int
642 0 : ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
643 : {
644 0 : struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][OUT];
645 : size_t n;
646 : int flags, error = 0;
647 0 : char buf[UGEN_BBSIZE];
648 : struct usbd_xfer *xfer;
649 : usbd_status err;
650 :
651 : DPRINTFN(5, ("%s: ugenwrite: %d\n", sc->sc_dev.dv_xname, endpt));
652 :
653 0 : if (usbd_is_dying(sc->sc_udev))
654 0 : return (EIO);
655 :
656 0 : if (endpt == USB_CONTROL_ENDPOINT)
657 0 : return (ENODEV);
658 :
659 : #ifdef DIAGNOSTIC
660 0 : if (sce->edesc == NULL) {
661 0 : printf("ugenwrite: no edesc\n");
662 0 : return (EIO);
663 : }
664 0 : if (sce->pipeh == NULL) {
665 0 : printf("ugenwrite: no pipe\n");
666 0 : return (EIO);
667 : }
668 : #endif
669 : flags = USBD_SYNCHRONOUS;
670 0 : if (sce->timeout == 0)
671 0 : flags |= USBD_CATCH;
672 :
673 0 : switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
674 : case UE_BULK:
675 0 : xfer = usbd_alloc_xfer(sc->sc_udev);
676 0 : if (xfer == 0)
677 0 : return (EIO);
678 0 : while ((n = ulmin(UGEN_BBSIZE, uio->uio_resid)) != 0) {
679 0 : error = uiomove(buf, n, uio);
680 0 : if (error)
681 : break;
682 : DPRINTFN(1, ("ugenwrite: transfer %zu bytes\n", n));
683 0 : usbd_setup_xfer(xfer, sce->pipeh, 0, buf, n,
684 0 : flags, sce->timeout, NULL);
685 0 : err = usbd_transfer(xfer);
686 0 : if (err) {
687 0 : usbd_clear_endpoint_stall(sce->pipeh);
688 0 : if (err == USBD_INTERRUPTED)
689 0 : error = EINTR;
690 0 : else if (err == USBD_TIMEOUT)
691 0 : error = ETIMEDOUT;
692 : else
693 : error = EIO;
694 : break;
695 : }
696 : }
697 0 : usbd_free_xfer(xfer);
698 0 : break;
699 : case UE_INTERRUPT:
700 0 : xfer = usbd_alloc_xfer(sc->sc_udev);
701 0 : if (xfer == 0)
702 0 : return (EIO);
703 0 : while ((n = ulmin(UGETW(sce->edesc->wMaxPacketSize),
704 0 : uio->uio_resid)) != 0) {
705 0 : error = uiomove(buf, n, uio);
706 0 : if (error)
707 : break;
708 : DPRINTFN(1, ("ugenwrite: transfer %zu bytes\n", n));
709 0 : usbd_setup_xfer(xfer, sce->pipeh, 0, buf, n,
710 0 : flags, sce->timeout, NULL);
711 0 : err = usbd_transfer(xfer);
712 0 : if (err) {
713 0 : usbd_clear_endpoint_stall(sce->pipeh);
714 0 : if (err == USBD_INTERRUPTED)
715 0 : error = EINTR;
716 0 : else if (err == USBD_TIMEOUT)
717 0 : error = ETIMEDOUT;
718 : else
719 : error = EIO;
720 : break;
721 : }
722 : }
723 0 : usbd_free_xfer(xfer);
724 0 : break;
725 : default:
726 0 : return (ENXIO);
727 : }
728 0 : return (error);
729 0 : }
730 :
731 : int
732 0 : ugenwrite(dev_t dev, struct uio *uio, int flag)
733 : {
734 0 : int endpt = UGENENDPOINT(dev);
735 : struct ugen_softc *sc;
736 : int error;
737 :
738 0 : sc = ugen_cd.cd_devs[UGENUNIT(dev)];
739 :
740 0 : sc->sc_refcnt++;
741 0 : error = ugen_do_write(sc, endpt, uio, flag);
742 0 : if (--sc->sc_refcnt < 0)
743 0 : usb_detach_wakeup(&sc->sc_dev);
744 0 : return (error);
745 : }
746 :
747 : int
748 0 : ugen_detach(struct device *self, int flags)
749 : {
750 0 : struct ugen_softc *sc = (struct ugen_softc *)self;
751 : struct ugen_endpoint *sce;
752 : int i, dir, endptno;
753 : int s, maj, mn;
754 :
755 : DPRINTF(("ugen_detach: sc=%p flags=%d\n", sc, flags));
756 :
757 : /* Abort all pipes. Causes processes waiting for transfer to wake. */
758 0 : for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
759 0 : for (dir = OUT; dir <= IN; dir++) {
760 0 : sce = &sc->sc_endpoints[i][dir];
761 0 : if (sce && sce->pipeh)
762 0 : usbd_abort_pipe(sce->pipeh);
763 : }
764 : }
765 :
766 0 : s = splusb();
767 0 : if (--sc->sc_refcnt >= 0) {
768 : /* Wake everyone */
769 0 : for (i = 0; i < USB_MAX_ENDPOINTS; i++)
770 0 : wakeup(&sc->sc_endpoints[i][IN]);
771 : /* Wait for processes to go away. */
772 0 : usb_detach_wait(&sc->sc_dev);
773 0 : }
774 0 : splx(s);
775 :
776 : /* locate the major number */
777 0 : for (maj = 0; maj < nchrdev; maj++)
778 0 : if (cdevsw[maj].d_open == ugenopen)
779 : break;
780 :
781 : /* Nuke the vnodes for any open instances (calls close). */
782 0 : mn = self->dv_unit * USB_MAX_ENDPOINTS;
783 0 : vdevgone(maj, mn, mn + USB_MAX_ENDPOINTS - 1, VCHR);
784 :
785 0 : for (endptno = 0; endptno < USB_MAX_ENDPOINTS; endptno++) {
786 0 : if (sc->sc_is_open[endptno])
787 0 : ugen_do_close(sc, endptno, FREAD|FWRITE);
788 : }
789 0 : return (0);
790 : }
791 :
792 : void
793 0 : ugenintr(struct usbd_xfer *xfer, void *addr, usbd_status status)
794 : {
795 0 : struct ugen_endpoint *sce = addr;
796 : /*struct ugen_softc *sc = sce->sc;*/
797 0 : u_int32_t count;
798 : u_char *ibuf;
799 :
800 0 : if (status == USBD_CANCELLED)
801 0 : return;
802 :
803 0 : if (status != USBD_NORMAL_COMPLETION) {
804 : DPRINTF(("ugenintr: status=%d\n", status));
805 0 : if (status == USBD_STALLED)
806 0 : usbd_clear_endpoint_stall_async(sce->pipeh);
807 0 : return;
808 : }
809 :
810 0 : usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
811 0 : ibuf = sce->ibuf;
812 :
813 : DPRINTFN(5, ("ugenintr: xfer=%p status=%d count=%d\n",
814 : xfer, status, count));
815 : DPRINTFN(5, (" data = %02x %02x %02x\n",
816 : ibuf[0], ibuf[1], ibuf[2]));
817 :
818 0 : (void)b_to_q(ibuf, count, &sce->q);
819 :
820 0 : if (sce->state & UGEN_ASLP) {
821 0 : sce->state &= ~UGEN_ASLP;
822 : DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
823 0 : wakeup(sce);
824 0 : }
825 0 : selwakeup(&sce->rsel);
826 0 : }
827 :
828 : void
829 0 : ugen_isoc_rintr(struct usbd_xfer *xfer, void *addr, usbd_status status)
830 : {
831 0 : struct isoreq *req = addr;
832 0 : struct ugen_endpoint *sce = req->sce;
833 0 : u_int32_t count, n;
834 : int i, isize;
835 :
836 : /* Return if we are aborting. */
837 0 : if (status == USBD_CANCELLED)
838 0 : return;
839 :
840 0 : usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
841 : DPRINTFN(5,("%s: xfer %ld, count=%d\n", __func__, req - sce->isoreqs,
842 : count));
843 :
844 : /* throw away oldest input if the buffer is full */
845 0 : if(sce->fill < sce->cur && sce->cur <= sce->fill + count) {
846 0 : sce->cur += count;
847 0 : if(sce->cur >= sce->limit)
848 0 : sce->cur = sce->ibuf + (sce->limit - sce->cur);
849 : DPRINTFN(5, ("%s: throwing away %d bytes\n", __func__, count));
850 : }
851 :
852 0 : isize = UGETW(sce->edesc->wMaxPacketSize);
853 0 : for (i = 0; i < UGEN_NISORFRMS; i++) {
854 0 : u_int32_t actlen = req->sizes[i];
855 0 : char const *buf = (char const *)req->dmabuf + isize * i;
856 :
857 : /* copy data to buffer */
858 0 : while (actlen > 0) {
859 0 : n = min(actlen, sce->limit - sce->fill);
860 0 : memcpy(sce->fill, buf, n);
861 :
862 0 : buf += n;
863 0 : actlen -= n;
864 0 : sce->fill += n;
865 0 : if(sce->fill == sce->limit)
866 0 : sce->fill = sce->ibuf;
867 : }
868 :
869 : /* setup size for next transfer */
870 0 : req->sizes[i] = isize;
871 : }
872 :
873 0 : usbd_setup_isoc_xfer(xfer, sce->pipeh, req, req->sizes, UGEN_NISORFRMS,
874 : USBD_NO_COPY | USBD_SHORT_XFER_OK, ugen_isoc_rintr);
875 0 : (void)usbd_transfer(xfer);
876 :
877 0 : if (sce->state & UGEN_ASLP) {
878 0 : sce->state &= ~UGEN_ASLP;
879 : DPRINTFN(5, ("ugen_isoc_rintr: waking %p\n", sce));
880 0 : wakeup(sce);
881 0 : }
882 0 : selwakeup(&sce->rsel);
883 0 : }
884 :
885 : int
886 0 : ugen_set_interface(struct ugen_softc *sc, int ifaceidx, int altno)
887 : {
888 0 : struct usbd_interface *iface;
889 : usb_config_descriptor_t *cdesc;
890 : usb_interface_descriptor_t *id;
891 : usb_endpoint_descriptor_t *ed;
892 : struct ugen_endpoint *sce;
893 : uint8_t endptno, endpt;
894 : int dir, err;
895 :
896 : DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));
897 :
898 0 : cdesc = usbd_get_config_descriptor(sc->sc_udev);
899 0 : if (ifaceidx < 0 || ifaceidx >= cdesc->bNumInterface ||
900 0 : usbd_iface_claimed(sc->sc_udev, ifaceidx))
901 0 : return (USBD_INVAL);
902 :
903 0 : err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
904 0 : if (err)
905 0 : return (err);
906 0 : id = usbd_get_interface_descriptor(iface);
907 0 : for (endptno = 0; endptno < id->bNumEndpoints; endptno++) {
908 0 : ed = usbd_interface2endpoint_descriptor(iface,endptno);
909 0 : endpt = ed->bEndpointAddress;
910 0 : dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
911 0 : sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
912 0 : sce->sc = 0;
913 0 : sce->edesc = 0;
914 0 : sce->iface = 0;
915 : }
916 :
917 : /* Try to change setting, if this fails put back the descriptors. */
918 0 : err = usbd_set_interface(iface, altno);
919 :
920 0 : id = usbd_get_interface_descriptor(iface);
921 0 : for (endptno = 0; endptno < id->bNumEndpoints; endptno++) {
922 0 : ed = usbd_interface2endpoint_descriptor(iface,endptno);
923 0 : endpt = ed->bEndpointAddress;
924 0 : dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
925 0 : sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
926 0 : sce->sc = sc;
927 0 : sce->edesc = ed;
928 0 : sce->iface = iface;
929 : }
930 0 : return (err);
931 0 : }
932 :
933 : int
934 0 : ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx)
935 : {
936 0 : struct usbd_interface *iface;
937 : usbd_status err;
938 :
939 0 : err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
940 0 : if (err)
941 0 : return (-1);
942 0 : return (usbd_get_interface_altindex(iface));
943 0 : }
944 :
945 : int
946 0 : ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, caddr_t addr,
947 : int flag, struct proc *p)
948 : {
949 : struct ugen_endpoint *sce;
950 : int err;
951 0 : struct usbd_interface *iface;
952 : struct usb_config_desc *cd;
953 : usb_config_descriptor_t *cdesc;
954 : struct usb_interface_desc *id;
955 : usb_interface_descriptor_t *idesc;
956 : struct usb_endpoint_desc *ed;
957 : usb_endpoint_descriptor_t *edesc;
958 : struct usb_alt_interface *ai;
959 0 : u_int8_t conf, alt;
960 :
961 : DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
962 0 : if (usbd_is_dying(sc->sc_udev))
963 0 : return (EIO);
964 :
965 0 : switch (cmd) {
966 : case FIONBIO:
967 : /* All handled in the upper FS layer. */
968 0 : return (0);
969 : case USB_SET_SHORT_XFER:
970 0 : if (endpt == USB_CONTROL_ENDPOINT)
971 0 : return (EINVAL);
972 : /* This flag only affects read */
973 0 : sce = &sc->sc_endpoints[endpt][IN];
974 0 : if (sce == NULL || sce->pipeh == NULL)
975 0 : return (EINVAL);
976 0 : if (*(int *)addr)
977 0 : sce->state |= UGEN_SHORT_OK;
978 : else
979 0 : sce->state &= ~UGEN_SHORT_OK;
980 0 : return (0);
981 : case USB_SET_TIMEOUT:
982 0 : sce = &sc->sc_endpoints[endpt][IN];
983 0 : if (sce == NULL)
984 0 : return (EINVAL);
985 0 : sce->timeout = *(int *)addr;
986 0 : sce = &sc->sc_endpoints[endpt][OUT];
987 0 : if (sce == NULL)
988 0 : return (EINVAL);
989 0 : sce->timeout = *(int *)addr;
990 0 : return (0);
991 : default:
992 : break;
993 : }
994 :
995 0 : if (endpt != USB_CONTROL_ENDPOINT)
996 0 : return (EINVAL);
997 :
998 0 : switch (cmd) {
999 : #ifdef UGEN_DEBUG
1000 : case USB_SETDEBUG:
1001 : ugendebug = *(int *)addr;
1002 : break;
1003 : #endif
1004 : case USB_GET_CONFIG:
1005 0 : err = usbd_get_config(sc->sc_udev, &conf);
1006 0 : if (err)
1007 0 : return (EIO);
1008 0 : *(int *)addr = conf;
1009 0 : break;
1010 : case USB_SET_CONFIG:
1011 0 : if (!(flag & FWRITE))
1012 0 : return (EPERM);
1013 0 : err = ugen_set_config(sc, *(int *)addr);
1014 0 : switch (err) {
1015 : case USBD_NORMAL_COMPLETION:
1016 : break;
1017 : case USBD_IN_USE:
1018 0 : return (EBUSY);
1019 : default:
1020 0 : return (EIO);
1021 : }
1022 : break;
1023 : case USB_GET_ALTINTERFACE:
1024 0 : ai = (struct usb_alt_interface *)addr;
1025 0 : err = usbd_device2interface_handle(sc->sc_udev,
1026 0 : ai->uai_interface_index, &iface);
1027 0 : if (err)
1028 0 : return (EINVAL);
1029 0 : idesc = usbd_get_interface_descriptor(iface);
1030 0 : if (idesc == NULL)
1031 0 : return (EIO);
1032 0 : ai->uai_alt_no = idesc->bAlternateSetting;
1033 0 : break;
1034 : case USB_SET_ALTINTERFACE:
1035 0 : if (!(flag & FWRITE))
1036 0 : return (EPERM);
1037 0 : ai = (struct usb_alt_interface *)addr;
1038 0 : err = usbd_device2interface_handle(sc->sc_udev,
1039 0 : ai->uai_interface_index, &iface);
1040 0 : if (err)
1041 0 : return (EINVAL);
1042 0 : err = ugen_set_interface(sc, ai->uai_interface_index,
1043 0 : ai->uai_alt_no);
1044 0 : if (err)
1045 0 : return (EINVAL);
1046 : break;
1047 : case USB_GET_NO_ALT:
1048 0 : ai = (struct usb_alt_interface *)addr;
1049 0 : cdesc = usbd_get_cdesc(sc->sc_udev, ai->uai_config_index, 0);
1050 0 : if (cdesc == NULL)
1051 0 : return (EINVAL);
1052 0 : idesc = usbd_find_idesc(cdesc, ai->uai_interface_index, 0);
1053 0 : if (idesc == NULL) {
1054 0 : free(cdesc, M_TEMP, 0);
1055 0 : return (EINVAL);
1056 : }
1057 0 : ai->uai_alt_no = usbd_get_no_alts(cdesc,
1058 0 : idesc->bInterfaceNumber);
1059 0 : free(cdesc, M_TEMP, 0);
1060 0 : break;
1061 : case USB_GET_DEVICE_DESC:
1062 0 : *(usb_device_descriptor_t *)addr =
1063 0 : *usbd_get_device_descriptor(sc->sc_udev);
1064 0 : break;
1065 : case USB_GET_CONFIG_DESC:
1066 0 : cd = (struct usb_config_desc *)addr;
1067 0 : cdesc = usbd_get_cdesc(sc->sc_udev, cd->ucd_config_index, 0);
1068 0 : if (cdesc == NULL)
1069 0 : return (EINVAL);
1070 0 : cd->ucd_desc = *cdesc;
1071 0 : free(cdesc, M_TEMP, 0);
1072 0 : break;
1073 : case USB_GET_INTERFACE_DESC:
1074 0 : id = (struct usb_interface_desc *)addr;
1075 0 : cdesc = usbd_get_cdesc(sc->sc_udev, id->uid_config_index, 0);
1076 0 : if (cdesc == NULL)
1077 0 : return (EINVAL);
1078 0 : if (id->uid_config_index == USB_CURRENT_CONFIG_INDEX &&
1079 0 : id->uid_alt_index == USB_CURRENT_ALT_INDEX)
1080 0 : alt = ugen_get_alt_index(sc, id->uid_interface_index);
1081 : else
1082 0 : alt = id->uid_alt_index;
1083 0 : idesc = usbd_find_idesc(cdesc, id->uid_interface_index, alt);
1084 0 : if (idesc == NULL) {
1085 0 : free(cdesc, M_TEMP, 0);
1086 0 : return (EINVAL);
1087 : }
1088 0 : id->uid_desc = *idesc;
1089 0 : free(cdesc, M_TEMP, 0);
1090 0 : break;
1091 : case USB_GET_ENDPOINT_DESC:
1092 0 : ed = (struct usb_endpoint_desc *)addr;
1093 0 : cdesc = usbd_get_cdesc(sc->sc_udev, ed->ued_config_index, 0);
1094 0 : if (cdesc == NULL)
1095 0 : return (EINVAL);
1096 0 : if (ed->ued_config_index == USB_CURRENT_CONFIG_INDEX &&
1097 0 : ed->ued_alt_index == USB_CURRENT_ALT_INDEX)
1098 0 : alt = ugen_get_alt_index(sc, ed->ued_interface_index);
1099 : else
1100 0 : alt = ed->ued_alt_index;
1101 0 : edesc = usbd_find_edesc(cdesc, ed->ued_interface_index,
1102 0 : alt, ed->ued_endpoint_index);
1103 0 : if (edesc == NULL) {
1104 0 : free(cdesc, M_TEMP, 0);
1105 0 : return (EINVAL);
1106 : }
1107 0 : ed->ued_desc = *edesc;
1108 0 : free(cdesc, M_TEMP, 0);
1109 0 : break;
1110 : case USB_GET_FULL_DESC:
1111 : {
1112 0 : u_int len;
1113 0 : struct iovec iov;
1114 0 : struct uio uio;
1115 0 : struct usb_full_desc *fd = (struct usb_full_desc *)addr;
1116 : int error;
1117 :
1118 0 : cdesc = usbd_get_cdesc(sc->sc_udev, fd->ufd_config_index, &len);
1119 0 : if (cdesc == NULL)
1120 0 : return (EINVAL);
1121 0 : if (len > fd->ufd_size)
1122 0 : len = fd->ufd_size;
1123 0 : iov.iov_base = (caddr_t)fd->ufd_data;
1124 0 : iov.iov_len = len;
1125 0 : uio.uio_iov = &iov;
1126 0 : uio.uio_iovcnt = 1;
1127 0 : uio.uio_resid = len;
1128 0 : uio.uio_offset = 0;
1129 0 : uio.uio_segflg = UIO_USERSPACE;
1130 0 : uio.uio_rw = UIO_READ;
1131 0 : uio.uio_procp = p;
1132 0 : error = uiomove((void *)cdesc, len, &uio);
1133 0 : free(cdesc, M_TEMP, 0);
1134 0 : return (error);
1135 0 : }
1136 : case USB_DO_REQUEST:
1137 : {
1138 0 : struct usb_ctl_request *ur = (void *)addr;
1139 0 : size_t len = UGETW(ur->ucr_request.wLength), mlen;
1140 0 : struct iovec iov;
1141 0 : struct uio uio;
1142 : void *ptr = NULL;
1143 : int error = 0;
1144 :
1145 0 : if (!(flag & FWRITE))
1146 0 : return (EPERM);
1147 : /* Avoid requests that would damage the bus integrity. */
1148 0 : if ((ur->ucr_request.bmRequestType == UT_WRITE_DEVICE &&
1149 0 : ur->ucr_request.bRequest == UR_SET_ADDRESS) ||
1150 0 : (ur->ucr_request.bmRequestType == UT_WRITE_DEVICE &&
1151 0 : ur->ucr_request.bRequest == UR_SET_CONFIG) ||
1152 0 : (ur->ucr_request.bmRequestType == UT_WRITE_INTERFACE &&
1153 0 : ur->ucr_request.bRequest == UR_SET_INTERFACE))
1154 0 : return (EINVAL);
1155 :
1156 0 : if (len > 32767)
1157 0 : return (EINVAL);
1158 0 : if (len != 0) {
1159 0 : iov.iov_base = (caddr_t)ur->ucr_data;
1160 0 : iov.iov_len = len;
1161 0 : uio.uio_iov = &iov;
1162 0 : uio.uio_iovcnt = 1;
1163 0 : uio.uio_resid = len;
1164 0 : uio.uio_offset = 0;
1165 0 : uio.uio_segflg = UIO_USERSPACE;
1166 0 : uio.uio_rw =
1167 0 : ur->ucr_request.bmRequestType & UT_READ ?
1168 : UIO_READ : UIO_WRITE;
1169 0 : uio.uio_procp = p;
1170 0 : if ((ptr = malloc(len, M_TEMP, M_NOWAIT)) == NULL) {
1171 : error = ENOMEM;
1172 0 : goto ret;
1173 : }
1174 0 : if (uio.uio_rw == UIO_WRITE) {
1175 0 : error = uiomove(ptr, len, &uio);
1176 0 : if (error)
1177 : goto ret;
1178 : }
1179 : }
1180 0 : sce = &sc->sc_endpoints[endpt][IN];
1181 0 : err = usbd_do_request_flags(sc->sc_udev, &ur->ucr_request,
1182 0 : ptr, ur->ucr_flags, &ur->ucr_actlen, sce->timeout);
1183 0 : if (err) {
1184 : error = EIO;
1185 0 : goto ret;
1186 : }
1187 : /* Only if USBD_SHORT_XFER_OK is set. */
1188 : mlen = len;
1189 0 : if (mlen > ur->ucr_actlen)
1190 0 : mlen = ur->ucr_actlen;
1191 0 : if (mlen != 0) {
1192 0 : if (uio.uio_rw == UIO_READ) {
1193 0 : error = uiomove(ptr, mlen, &uio);
1194 0 : if (error)
1195 : goto ret;
1196 : }
1197 : }
1198 : ret:
1199 0 : if (ptr)
1200 0 : free(ptr, M_TEMP, len);
1201 0 : return (error);
1202 0 : }
1203 : case USB_GET_DEVICEINFO:
1204 0 : usbd_fill_deviceinfo(sc->sc_udev,
1205 0 : (struct usb_device_info *)addr);
1206 0 : break;
1207 : default:
1208 0 : return (EINVAL);
1209 : }
1210 0 : return (0);
1211 0 : }
1212 :
1213 : int
1214 0 : ugenioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
1215 : {
1216 0 : int endpt = UGENENDPOINT(dev);
1217 : struct ugen_softc *sc;
1218 : int error;
1219 :
1220 0 : sc = ugen_cd.cd_devs[UGENUNIT(dev)];
1221 :
1222 0 : sc->sc_refcnt++;
1223 0 : error = ugen_do_ioctl(sc, endpt, cmd, addr, flag, p);
1224 0 : if (--sc->sc_refcnt < 0)
1225 0 : usb_detach_wakeup(&sc->sc_dev);
1226 0 : return (error);
1227 : }
1228 :
1229 : int
1230 0 : ugenpoll(dev_t dev, int events, struct proc *p)
1231 : {
1232 : struct ugen_softc *sc;
1233 : struct ugen_endpoint *sce;
1234 : int revents = 0;
1235 : int s;
1236 :
1237 0 : sc = ugen_cd.cd_devs[UGENUNIT(dev)];
1238 :
1239 0 : if (usbd_is_dying(sc->sc_udev))
1240 0 : return (POLLERR);
1241 :
1242 : /* XXX always IN */
1243 0 : sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
1244 0 : if (sce == NULL)
1245 0 : return (POLLERR);
1246 : #ifdef DIAGNOSTIC
1247 0 : if (!sce->edesc) {
1248 0 : printf("ugenpoll: no edesc\n");
1249 0 : return (POLLERR);
1250 : }
1251 0 : if (!sce->pipeh) {
1252 0 : printf("ugenpoll: no pipe\n");
1253 0 : return (POLLERR);
1254 : }
1255 : #endif
1256 0 : s = splusb();
1257 0 : switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
1258 : case UE_INTERRUPT:
1259 0 : if (events & (POLLIN | POLLRDNORM)) {
1260 0 : if (sce->q.c_cc > 0)
1261 0 : revents |= events & (POLLIN | POLLRDNORM);
1262 : else
1263 0 : selrecord(p, &sce->rsel);
1264 : }
1265 : break;
1266 : case UE_ISOCHRONOUS:
1267 0 : if (events & (POLLIN | POLLRDNORM)) {
1268 0 : if (sce->cur != sce->fill)
1269 0 : revents |= events & (POLLIN | POLLRDNORM);
1270 : else
1271 0 : selrecord(p, &sce->rsel);
1272 : }
1273 : break;
1274 : case UE_BULK:
1275 : /*
1276 : * We have no easy way of determining if a read will
1277 : * yield any data or a write will happen.
1278 : * Pretend they will.
1279 : */
1280 0 : revents |= events &
1281 : (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);
1282 0 : break;
1283 : default:
1284 : break;
1285 : }
1286 0 : splx(s);
1287 0 : return (revents);
1288 0 : }
1289 :
1290 : void filt_ugenrdetach(struct knote *);
1291 : int filt_ugenread_intr(struct knote *, long);
1292 : int filt_ugenread_isoc(struct knote *, long);
1293 : int ugenkqfilter(dev_t, struct knote *);
1294 :
1295 : void
1296 0 : filt_ugenrdetach(struct knote *kn)
1297 : {
1298 0 : struct ugen_endpoint *sce = (void *)kn->kn_hook;
1299 : int s;
1300 :
1301 0 : s = splusb();
1302 0 : SLIST_REMOVE(&sce->rsel.si_note, kn, knote, kn_selnext);
1303 0 : splx(s);
1304 0 : }
1305 :
1306 : int
1307 0 : filt_ugenread_intr(struct knote *kn, long hint)
1308 : {
1309 0 : struct ugen_endpoint *sce = (void *)kn->kn_hook;
1310 :
1311 0 : kn->kn_data = sce->q.c_cc;
1312 0 : return (kn->kn_data > 0);
1313 : }
1314 :
1315 : int
1316 0 : filt_ugenread_isoc(struct knote *kn, long hint)
1317 : {
1318 0 : struct ugen_endpoint *sce = (void *)kn->kn_hook;
1319 :
1320 0 : if (sce->cur == sce->fill)
1321 0 : return (0);
1322 :
1323 0 : if (sce->cur < sce->fill)
1324 0 : kn->kn_data = sce->fill - sce->cur;
1325 : else
1326 0 : kn->kn_data = (sce->limit - sce->cur) +
1327 0 : (sce->fill - sce->ibuf);
1328 :
1329 0 : return (1);
1330 0 : }
1331 :
1332 : struct filterops ugenread_intr_filtops =
1333 : { 1, NULL, filt_ugenrdetach, filt_ugenread_intr };
1334 :
1335 : struct filterops ugenread_isoc_filtops =
1336 : { 1, NULL, filt_ugenrdetach, filt_ugenread_isoc };
1337 :
1338 : struct filterops ugen_seltrue_filtops =
1339 : { 1, NULL, filt_ugenrdetach, filt_seltrue };
1340 :
1341 : int
1342 0 : ugenkqfilter(dev_t dev, struct knote *kn)
1343 : {
1344 : struct ugen_softc *sc;
1345 : struct ugen_endpoint *sce;
1346 : struct klist *klist;
1347 : int s;
1348 :
1349 0 : sc = ugen_cd.cd_devs[UGENUNIT(dev)];
1350 :
1351 0 : if (usbd_is_dying(sc->sc_udev))
1352 0 : return (ENXIO);
1353 :
1354 : /* XXX always IN */
1355 0 : sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
1356 0 : if (sce == NULL)
1357 0 : return (EINVAL);
1358 :
1359 0 : switch (kn->kn_filter) {
1360 : case EVFILT_READ:
1361 0 : klist = &sce->rsel.si_note;
1362 0 : switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
1363 : case UE_INTERRUPT:
1364 0 : kn->kn_fop = &ugenread_intr_filtops;
1365 0 : break;
1366 : case UE_ISOCHRONOUS:
1367 0 : kn->kn_fop = &ugenread_isoc_filtops;
1368 0 : break;
1369 : case UE_BULK:
1370 : /*
1371 : * We have no easy way of determining if a read will
1372 : * yield any data or a write will happen.
1373 : * So, emulate "seltrue".
1374 : */
1375 0 : kn->kn_fop = &ugen_seltrue_filtops;
1376 0 : break;
1377 : default:
1378 0 : return (EINVAL);
1379 : }
1380 : break;
1381 :
1382 : case EVFILT_WRITE:
1383 0 : klist = &sce->rsel.si_note;
1384 0 : switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
1385 : case UE_INTERRUPT:
1386 : case UE_ISOCHRONOUS:
1387 : /* XXX poll doesn't support this */
1388 0 : return (EINVAL);
1389 :
1390 : case UE_BULK:
1391 : /*
1392 : * We have no easy way of determining if a read will
1393 : * yield any data or a write will happen.
1394 : * So, emulate "seltrue".
1395 : */
1396 0 : kn->kn_fop = &ugen_seltrue_filtops;
1397 : break;
1398 : default:
1399 0 : return (EINVAL);
1400 : }
1401 0 : break;
1402 :
1403 : default:
1404 0 : return (EINVAL);
1405 : }
1406 :
1407 0 : kn->kn_hook = (void *)sce;
1408 :
1409 0 : s = splusb();
1410 0 : SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1411 0 : splx(s);
1412 :
1413 0 : return (0);
1414 0 : }
|