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