| @@ -1,1200 +1,1201 @@ | | | @@ -1,1200 +1,1201 @@ |
1 | /* $NetBSD: usbdi.c,v 1.149 2013/01/22 13:18:47 jmcneill Exp $ */ | | 1 | /* $NetBSD: usbdi.c,v 1.150 2013/01/22 13:27:59 jmcneill Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1998, 2012 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1998, 2012 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | | 8 | * by Lennart Augustsson (lennart@augustsson.net) at |
9 | * Carlstedt Research & Technology and Matthew R. Green (mrg@eterna.com.au). | | 9 | * Carlstedt Research & Technology and Matthew R. Green (mrg@eterna.com.au). |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. | | 15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright | | 16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the | | 17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. | | 18 | * documentation and/or other materials provided with the distribution. |
19 | * | | 19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. | | 30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | #include <sys/cdefs.h> | | 33 | #include <sys/cdefs.h> |
34 | __KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.149 2013/01/22 13:18:47 jmcneill Exp $"); | | 34 | __KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.150 2013/01/22 13:27:59 jmcneill Exp $"); |
35 | | | 35 | |
36 | #ifdef _KERNEL_OPT | | 36 | #ifdef _KERNEL_OPT |
37 | #include "opt_compat_netbsd.h" | | 37 | #include "opt_compat_netbsd.h" |
38 | #endif | | 38 | #endif |
39 | | | 39 | |
40 | #include <sys/param.h> | | 40 | #include <sys/param.h> |
41 | #include <sys/systm.h> | | 41 | #include <sys/systm.h> |
42 | #include <sys/kernel.h> | | 42 | #include <sys/kernel.h> |
43 | #include <sys/device.h> | | 43 | #include <sys/device.h> |
44 | #include <sys/malloc.h> | | 44 | #include <sys/malloc.h> |
45 | #include <sys/proc.h> | | 45 | #include <sys/proc.h> |
46 | #include <sys/bus.h> | | 46 | #include <sys/bus.h> |
47 | #include <sys/cpu.h> | | 47 | #include <sys/cpu.h> |
48 | | | 48 | |
49 | #include <dev/usb/usb.h> | | 49 | #include <dev/usb/usb.h> |
50 | #include <dev/usb/usbdi.h> | | 50 | #include <dev/usb/usbdi.h> |
51 | #include <dev/usb/usbdi_util.h> | | 51 | #include <dev/usb/usbdi_util.h> |
52 | #include <dev/usb/usbdivar.h> | | 52 | #include <dev/usb/usbdivar.h> |
53 | #include <dev/usb/usb_mem.h> | | 53 | #include <dev/usb/usb_mem.h> |
54 | #include <dev/usb/usb_quirks.h> | | 54 | #include <dev/usb/usb_quirks.h> |
55 | | | 55 | |
56 | /* UTF-8 encoding stuff */ | | 56 | /* UTF-8 encoding stuff */ |
57 | #include <fs/unicode.h> | | 57 | #include <fs/unicode.h> |
58 | | | 58 | |
59 | #ifdef USB_DEBUG | | 59 | #ifdef USB_DEBUG |
60 | #define DPRINTF(x) if (usbdebug) printf x | | 60 | #define DPRINTF(x) if (usbdebug) printf x |
61 | #define DPRINTFN(n,x) if (usbdebug>(n)) printf x | | 61 | #define DPRINTFN(n,x) if (usbdebug>(n)) printf x |
62 | extern int usbdebug; | | 62 | extern int usbdebug; |
63 | #else | | 63 | #else |
64 | #define DPRINTF(x) | | 64 | #define DPRINTF(x) |
65 | #define DPRINTFN(n,x) | | 65 | #define DPRINTFN(n,x) |
66 | #endif | | 66 | #endif |
67 | | | 67 | |
68 | Static usbd_status usbd_ar_pipe(usbd_pipe_handle pipe); | | 68 | Static usbd_status usbd_ar_pipe(usbd_pipe_handle pipe); |
69 | Static void usbd_do_request_async_cb | | 69 | Static void usbd_do_request_async_cb |
70 | (usbd_xfer_handle, usbd_private_handle, usbd_status); | | 70 | (usbd_xfer_handle, usbd_private_handle, usbd_status); |
71 | Static void usbd_start_next(usbd_pipe_handle pipe); | | 71 | Static void usbd_start_next(usbd_pipe_handle pipe); |
72 | Static usbd_status usbd_open_pipe_ival | | 72 | Static usbd_status usbd_open_pipe_ival |
73 | (usbd_interface_handle, u_int8_t, u_int8_t, usbd_pipe_handle *, int); | | 73 | (usbd_interface_handle, u_int8_t, u_int8_t, usbd_pipe_handle *, int); |
74 | | | 74 | |
75 | static inline int | | 75 | static inline int |
76 | usbd_xfer_isread(usbd_xfer_handle xfer) | | 76 | usbd_xfer_isread(usbd_xfer_handle xfer) |
77 | { | | 77 | { |
78 | if (xfer->rqflags & URQ_REQUEST) | | 78 | if (xfer->rqflags & URQ_REQUEST) |
79 | return (xfer->request.bmRequestType & UT_READ); | | 79 | return (xfer->request.bmRequestType & UT_READ); |
80 | else | | 80 | else |
81 | return (xfer->pipe->endpoint->edesc->bEndpointAddress & | | 81 | return (xfer->pipe->endpoint->edesc->bEndpointAddress & |
82 | UE_DIR_IN); | | 82 | UE_DIR_IN); |
83 | } | | 83 | } |
84 | | | 84 | |
85 | #if defined(USB_DEBUG) || defined(EHCI_DEBUG) | | 85 | #if defined(USB_DEBUG) || defined(EHCI_DEBUG) |
86 | void | | 86 | void |
87 | usbd_dump_iface(struct usbd_interface *iface) | | 87 | usbd_dump_iface(struct usbd_interface *iface) |
88 | { | | 88 | { |
89 | printf("usbd_dump_iface: iface=%p\n", iface); | | 89 | printf("usbd_dump_iface: iface=%p\n", iface); |
90 | if (iface == NULL) | | 90 | if (iface == NULL) |
91 | return; | | 91 | return; |
92 | printf(" device=%p idesc=%p index=%d altindex=%d priv=%p\n", | | 92 | printf(" device=%p idesc=%p index=%d altindex=%d priv=%p\n", |
93 | iface->device, iface->idesc, iface->index, iface->altindex, | | 93 | iface->device, iface->idesc, iface->index, iface->altindex, |
94 | iface->priv); | | 94 | iface->priv); |
95 | } | | 95 | } |
96 | | | 96 | |
97 | void | | 97 | void |
98 | usbd_dump_device(struct usbd_device *dev) | | 98 | usbd_dump_device(struct usbd_device *dev) |
99 | { | | 99 | { |
100 | printf("usbd_dump_device: dev=%p\n", dev); | | 100 | printf("usbd_dump_device: dev=%p\n", dev); |
101 | if (dev == NULL) | | 101 | if (dev == NULL) |
102 | return; | | 102 | return; |
103 | printf(" bus=%p default_pipe=%p\n", dev->bus, dev->default_pipe); | | 103 | printf(" bus=%p default_pipe=%p\n", dev->bus, dev->default_pipe); |
104 | printf(" address=%d config=%d depth=%d speed=%d self_powered=%d " | | 104 | printf(" address=%d config=%d depth=%d speed=%d self_powered=%d " |
105 | "power=%d langid=%d\n", | | 105 | "power=%d langid=%d\n", |
106 | dev->address, dev->config, dev->depth, dev->speed, | | 106 | dev->address, dev->config, dev->depth, dev->speed, |
107 | dev->self_powered, dev->power, dev->langid); | | 107 | dev->self_powered, dev->power, dev->langid); |
108 | } | | 108 | } |
109 | | | 109 | |
110 | void | | 110 | void |
111 | usbd_dump_endpoint(struct usbd_endpoint *endp) | | 111 | usbd_dump_endpoint(struct usbd_endpoint *endp) |
112 | { | | 112 | { |
113 | printf("usbd_dump_endpoint: endp=%p\n", endp); | | 113 | printf("usbd_dump_endpoint: endp=%p\n", endp); |
114 | if (endp == NULL) | | 114 | if (endp == NULL) |
115 | return; | | 115 | return; |
116 | printf(" edesc=%p refcnt=%d\n", endp->edesc, endp->refcnt); | | 116 | printf(" edesc=%p refcnt=%d\n", endp->edesc, endp->refcnt); |
117 | if (endp->edesc) | | 117 | if (endp->edesc) |
118 | printf(" bEndpointAddress=0x%02x\n", | | 118 | printf(" bEndpointAddress=0x%02x\n", |
119 | endp->edesc->bEndpointAddress); | | 119 | endp->edesc->bEndpointAddress); |
120 | } | | 120 | } |
121 | | | 121 | |
122 | void | | 122 | void |
123 | usbd_dump_queue(usbd_pipe_handle pipe) | | 123 | usbd_dump_queue(usbd_pipe_handle pipe) |
124 | { | | 124 | { |
125 | usbd_xfer_handle xfer; | | 125 | usbd_xfer_handle xfer; |
126 | | | 126 | |
127 | printf("usbd_dump_queue: pipe=%p\n", pipe); | | 127 | printf("usbd_dump_queue: pipe=%p\n", pipe); |
128 | SIMPLEQ_FOREACH(xfer, &pipe->queue, next) { | | 128 | SIMPLEQ_FOREACH(xfer, &pipe->queue, next) { |
129 | printf(" xfer=%p\n", xfer); | | 129 | printf(" xfer=%p\n", xfer); |
130 | } | | 130 | } |
131 | } | | 131 | } |
132 | | | 132 | |
133 | void | | 133 | void |
134 | usbd_dump_pipe(usbd_pipe_handle pipe) | | 134 | usbd_dump_pipe(usbd_pipe_handle pipe) |
135 | { | | 135 | { |
136 | printf("usbd_dump_pipe: pipe=%p\n", pipe); | | 136 | printf("usbd_dump_pipe: pipe=%p\n", pipe); |
137 | if (pipe == NULL) | | 137 | if (pipe == NULL) |
138 | return; | | 138 | return; |
139 | usbd_dump_iface(pipe->iface); | | 139 | usbd_dump_iface(pipe->iface); |
140 | usbd_dump_device(pipe->device); | | 140 | usbd_dump_device(pipe->device); |
141 | usbd_dump_endpoint(pipe->endpoint); | | 141 | usbd_dump_endpoint(pipe->endpoint); |
142 | printf(" (usbd_dump_pipe:)\n refcnt=%d running=%d aborting=%d\n", | | 142 | printf(" (usbd_dump_pipe:)\n refcnt=%d running=%d aborting=%d\n", |
143 | pipe->refcnt, pipe->running, pipe->aborting); | | 143 | pipe->refcnt, pipe->running, pipe->aborting); |
144 | printf(" intrxfer=%p, repeat=%d, interval=%d\n", | | 144 | printf(" intrxfer=%p, repeat=%d, interval=%d\n", |
145 | pipe->intrxfer, pipe->repeat, pipe->interval); | | 145 | pipe->intrxfer, pipe->repeat, pipe->interval); |
146 | } | | 146 | } |
147 | #endif | | 147 | #endif |
148 | | | 148 | |
149 | usbd_status | | 149 | usbd_status |
150 | usbd_open_pipe(usbd_interface_handle iface, u_int8_t address, | | 150 | usbd_open_pipe(usbd_interface_handle iface, u_int8_t address, |
151 | u_int8_t flags, usbd_pipe_handle *pipe) | | 151 | u_int8_t flags, usbd_pipe_handle *pipe) |
152 | { | | 152 | { |
153 | return (usbd_open_pipe_ival(iface, address, flags, pipe, | | 153 | return (usbd_open_pipe_ival(iface, address, flags, pipe, |
154 | USBD_DEFAULT_INTERVAL)); | | 154 | USBD_DEFAULT_INTERVAL)); |
155 | } | | 155 | } |
156 | | | 156 | |
157 | usbd_status | | 157 | usbd_status |
158 | usbd_open_pipe_ival(usbd_interface_handle iface, u_int8_t address, | | 158 | usbd_open_pipe_ival(usbd_interface_handle iface, u_int8_t address, |
159 | u_int8_t flags, usbd_pipe_handle *pipe, int ival) | | 159 | u_int8_t flags, usbd_pipe_handle *pipe, int ival) |
160 | { | | 160 | { |
161 | usbd_pipe_handle p; | | 161 | usbd_pipe_handle p; |
162 | struct usbd_endpoint *ep; | | 162 | struct usbd_endpoint *ep; |
163 | usbd_status err; | | 163 | usbd_status err; |
164 | int i; | | 164 | int i; |
165 | | | 165 | |
166 | DPRINTFN(3,("usbd_open_pipe: iface=%p address=0x%x flags=0x%x\n", | | 166 | DPRINTFN(3,("usbd_open_pipe: iface=%p address=0x%x flags=0x%x\n", |
167 | iface, address, flags)); | | 167 | iface, address, flags)); |
168 | | | 168 | |
169 | for (i = 0; i < iface->idesc->bNumEndpoints; i++) { | | 169 | for (i = 0; i < iface->idesc->bNumEndpoints; i++) { |
170 | ep = &iface->endpoints[i]; | | 170 | ep = &iface->endpoints[i]; |
171 | if (ep->edesc == NULL) | | 171 | if (ep->edesc == NULL) |
172 | return (USBD_IOERROR); | | 172 | return (USBD_IOERROR); |
173 | if (ep->edesc->bEndpointAddress == address) | | 173 | if (ep->edesc->bEndpointAddress == address) |
174 | goto found; | | 174 | goto found; |
175 | } | | 175 | } |
176 | return (USBD_BAD_ADDRESS); | | 176 | return (USBD_BAD_ADDRESS); |
177 | found: | | 177 | found: |
178 | if ((flags & USBD_EXCLUSIVE_USE) && ep->refcnt != 0) | | 178 | if ((flags & USBD_EXCLUSIVE_USE) && ep->refcnt != 0) |
179 | return (USBD_IN_USE); | | 179 | return (USBD_IN_USE); |
180 | err = usbd_setup_pipe_flags(iface->device, iface, ep, ival, &p, flags); | | 180 | err = usbd_setup_pipe_flags(iface->device, iface, ep, ival, &p, flags); |
181 | if (err) | | 181 | if (err) |
182 | return (err); | | 182 | return (err); |
183 | LIST_INSERT_HEAD(&iface->pipes, p, next); | | 183 | LIST_INSERT_HEAD(&iface->pipes, p, next); |
184 | *pipe = p; | | 184 | *pipe = p; |
185 | return (USBD_NORMAL_COMPLETION); | | 185 | return (USBD_NORMAL_COMPLETION); |
186 | } | | 186 | } |
187 | | | 187 | |
188 | usbd_status | | 188 | usbd_status |
189 | usbd_open_pipe_intr(usbd_interface_handle iface, u_int8_t address, | | 189 | usbd_open_pipe_intr(usbd_interface_handle iface, u_int8_t address, |
190 | u_int8_t flags, usbd_pipe_handle *pipe, | | 190 | u_int8_t flags, usbd_pipe_handle *pipe, |
191 | usbd_private_handle priv, void *buffer, u_int32_t len, | | 191 | usbd_private_handle priv, void *buffer, u_int32_t len, |
192 | usbd_callback cb, int ival) | | 192 | usbd_callback cb, int ival) |
193 | { | | 193 | { |
194 | usbd_status err; | | 194 | usbd_status err; |
195 | usbd_xfer_handle xfer; | | 195 | usbd_xfer_handle xfer; |
196 | usbd_pipe_handle ipipe; | | 196 | usbd_pipe_handle ipipe; |
197 | | | 197 | |
198 | DPRINTFN(3,("usbd_open_pipe_intr: address=0x%x flags=0x%x len=%d\n", | | 198 | DPRINTFN(3,("usbd_open_pipe_intr: address=0x%x flags=0x%x len=%d\n", |
199 | address, flags, len)); | | 199 | address, flags, len)); |
200 | | | 200 | |
201 | err = usbd_open_pipe_ival(iface, address, USBD_EXCLUSIVE_USE | flags, | | 201 | err = usbd_open_pipe_ival(iface, address, |
| | | 202 | USBD_EXCLUSIVE_USE | (flags & USBD_MPSAFE), |
202 | &ipipe, ival); | | 203 | &ipipe, ival); |
203 | if (err) | | 204 | if (err) |
204 | return (err); | | 205 | return (err); |
205 | xfer = usbd_alloc_xfer(iface->device); | | 206 | xfer = usbd_alloc_xfer(iface->device); |
206 | if (xfer == NULL) { | | 207 | if (xfer == NULL) { |
207 | err = USBD_NOMEM; | | 208 | err = USBD_NOMEM; |
208 | goto bad1; | | 209 | goto bad1; |
209 | } | | 210 | } |
210 | usbd_setup_xfer(xfer, ipipe, priv, buffer, len, flags, | | 211 | usbd_setup_xfer(xfer, ipipe, priv, buffer, len, flags, |
211 | USBD_NO_TIMEOUT, cb); | | 212 | USBD_NO_TIMEOUT, cb); |
212 | ipipe->intrxfer = xfer; | | 213 | ipipe->intrxfer = xfer; |
213 | ipipe->repeat = 1; | | 214 | ipipe->repeat = 1; |
214 | err = usbd_transfer(xfer); | | 215 | err = usbd_transfer(xfer); |
215 | *pipe = ipipe; | | 216 | *pipe = ipipe; |
216 | if (err != USBD_IN_PROGRESS) | | 217 | if (err != USBD_IN_PROGRESS) |
217 | goto bad2; | | 218 | goto bad2; |
218 | return (USBD_NORMAL_COMPLETION); | | 219 | return (USBD_NORMAL_COMPLETION); |
219 | | | 220 | |
220 | bad2: | | 221 | bad2: |
221 | ipipe->intrxfer = NULL; | | 222 | ipipe->intrxfer = NULL; |
222 | ipipe->repeat = 0; | | 223 | ipipe->repeat = 0; |
223 | usbd_free_xfer(xfer); | | 224 | usbd_free_xfer(xfer); |
224 | bad1: | | 225 | bad1: |
225 | usbd_close_pipe(ipipe); | | 226 | usbd_close_pipe(ipipe); |
226 | return (err); | | 227 | return (err); |
227 | } | | 228 | } |
228 | | | 229 | |
229 | usbd_status | | 230 | usbd_status |
230 | usbd_close_pipe(usbd_pipe_handle pipe) | | 231 | usbd_close_pipe(usbd_pipe_handle pipe) |
231 | { | | 232 | { |
232 | int s; | | 233 | int s; |
233 | | | 234 | |
234 | #ifdef DIAGNOSTIC | | 235 | #ifdef DIAGNOSTIC |
235 | if (pipe == NULL) { | | 236 | if (pipe == NULL) { |
236 | printf("usbd_close_pipe: pipe==NULL\n"); | | 237 | printf("usbd_close_pipe: pipe==NULL\n"); |
237 | return (USBD_NORMAL_COMPLETION); | | 238 | return (USBD_NORMAL_COMPLETION); |
238 | } | | 239 | } |
239 | #endif | | 240 | #endif |
240 | | | 241 | |
241 | usbd_lock_pipe(pipe); | | 242 | usbd_lock_pipe(pipe); |
242 | if (--pipe->refcnt != 0) { | | 243 | if (--pipe->refcnt != 0) { |
243 | usbd_unlock_pipe(pipe); | | 244 | usbd_unlock_pipe(pipe); |
244 | return (USBD_NORMAL_COMPLETION); | | 245 | return (USBD_NORMAL_COMPLETION); |
245 | } | | 246 | } |
246 | if (! SIMPLEQ_EMPTY(&pipe->queue)) { | | 247 | if (! SIMPLEQ_EMPTY(&pipe->queue)) { |
247 | usbd_unlock_pipe(pipe); | | 248 | usbd_unlock_pipe(pipe); |
248 | return (USBD_PENDING_REQUESTS); | | 249 | return (USBD_PENDING_REQUESTS); |
249 | } | | 250 | } |
250 | LIST_REMOVE(pipe, next); | | 251 | LIST_REMOVE(pipe, next); |
251 | pipe->endpoint->refcnt--; | | 252 | pipe->endpoint->refcnt--; |
252 | pipe->methods->close(pipe); | | 253 | pipe->methods->close(pipe); |
253 | usbd_unlock_pipe(pipe); | | 254 | usbd_unlock_pipe(pipe); |
254 | if (pipe->intrxfer != NULL) | | 255 | if (pipe->intrxfer != NULL) |
255 | usbd_free_xfer(pipe->intrxfer); | | 256 | usbd_free_xfer(pipe->intrxfer); |
256 | free(pipe, M_USB); | | 257 | free(pipe, M_USB); |
257 | return (USBD_NORMAL_COMPLETION); | | 258 | return (USBD_NORMAL_COMPLETION); |
258 | } | | 259 | } |
259 | | | 260 | |
260 | usbd_status | | 261 | usbd_status |
261 | usbd_transfer(usbd_xfer_handle xfer) | | 262 | usbd_transfer(usbd_xfer_handle xfer) |
262 | { | | 263 | { |
263 | usbd_pipe_handle pipe = xfer->pipe; | | 264 | usbd_pipe_handle pipe = xfer->pipe; |
264 | usb_dma_t *dmap = &xfer->dmabuf; | | 265 | usb_dma_t *dmap = &xfer->dmabuf; |
265 | usbd_status err; | | 266 | usbd_status err; |
266 | unsigned int size, flags; | | 267 | unsigned int size, flags; |
267 | int s; | | 268 | int s; |
268 | | | 269 | |
269 | DPRINTFN(5,("usbd_transfer: xfer=%p, flags=%#x, pipe=%p, running=%d\n", | | 270 | DPRINTFN(5,("usbd_transfer: xfer=%p, flags=%#x, pipe=%p, running=%d\n", |
270 | xfer, xfer->flags, pipe, pipe->running)); | | 271 | xfer, xfer->flags, pipe, pipe->running)); |
271 | | | 272 | |
272 | #ifdef USB_DEBUG | | 273 | #ifdef USB_DEBUG |
273 | if (usbdebug > 5) | | 274 | if (usbdebug > 5) |
274 | usbd_dump_queue(pipe); | | 275 | usbd_dump_queue(pipe); |
275 | #endif | | 276 | #endif |
276 | xfer->done = 0; | | 277 | xfer->done = 0; |
277 | | | 278 | |
278 | if (pipe->aborting) | | 279 | if (pipe->aborting) |
279 | return (USBD_CANCELLED); | | 280 | return (USBD_CANCELLED); |
280 | | | 281 | |
281 | size = xfer->length; | | 282 | size = xfer->length; |
282 | /* If there is no buffer, allocate one. */ | | 283 | /* If there is no buffer, allocate one. */ |
283 | if (!(xfer->rqflags & URQ_DEV_DMABUF) && size != 0) { | | 284 | if (!(xfer->rqflags & URQ_DEV_DMABUF) && size != 0) { |
284 | struct usbd_bus *bus = pipe->device->bus; | | 285 | struct usbd_bus *bus = pipe->device->bus; |
285 | | | 286 | |
286 | #ifdef DIAGNOSTIC | | 287 | #ifdef DIAGNOSTIC |
287 | if (xfer->rqflags & URQ_AUTO_DMABUF) | | 288 | if (xfer->rqflags & URQ_AUTO_DMABUF) |
288 | printf("usbd_transfer: has old buffer!\n"); | | 289 | printf("usbd_transfer: has old buffer!\n"); |
289 | #endif | | 290 | #endif |
290 | err = bus->methods->allocm(bus, dmap, size); | | 291 | err = bus->methods->allocm(bus, dmap, size); |
291 | if (err) | | 292 | if (err) |
292 | return (err); | | 293 | return (err); |
293 | xfer->rqflags |= URQ_AUTO_DMABUF; | | 294 | xfer->rqflags |= URQ_AUTO_DMABUF; |
294 | } | | 295 | } |
295 | | | 296 | |
296 | flags = xfer->flags; | | 297 | flags = xfer->flags; |
297 | | | 298 | |
298 | /* Copy data if going out. */ | | 299 | /* Copy data if going out. */ |
299 | if (!(flags & USBD_NO_COPY) && size != 0 && !usbd_xfer_isread(xfer)) | | 300 | if (!(flags & USBD_NO_COPY) && size != 0 && !usbd_xfer_isread(xfer)) |
300 | memcpy(KERNADDR(dmap, 0), xfer->buffer, size); | | 301 | memcpy(KERNADDR(dmap, 0), xfer->buffer, size); |
301 | | | 302 | |
302 | /* xfer is not valid after the transfer method unless synchronous */ | | 303 | /* xfer is not valid after the transfer method unless synchronous */ |
303 | err = pipe->methods->transfer(xfer); | | 304 | err = pipe->methods->transfer(xfer); |
304 | | | 305 | |
305 | if (err != USBD_IN_PROGRESS && err) { | | 306 | if (err != USBD_IN_PROGRESS && err) { |
306 | /* The transfer has not been queued, so free buffer. */ | | 307 | /* The transfer has not been queued, so free buffer. */ |
307 | if (xfer->rqflags & URQ_AUTO_DMABUF) { | | 308 | if (xfer->rqflags & URQ_AUTO_DMABUF) { |
308 | struct usbd_bus *bus = pipe->device->bus; | | 309 | struct usbd_bus *bus = pipe->device->bus; |
309 | | | 310 | |
310 | bus->methods->freem(bus, &xfer->dmabuf); | | 311 | bus->methods->freem(bus, &xfer->dmabuf); |
311 | xfer->rqflags &= ~URQ_AUTO_DMABUF; | | 312 | xfer->rqflags &= ~URQ_AUTO_DMABUF; |
312 | } | | 313 | } |
313 | } | | 314 | } |
314 | | | 315 | |
315 | if (!(flags & USBD_SYNCHRONOUS)) | | 316 | if (!(flags & USBD_SYNCHRONOUS)) |
316 | return (err); | | 317 | return (err); |
317 | | | 318 | |
318 | /* Sync transfer, wait for completion. */ | | 319 | /* Sync transfer, wait for completion. */ |
319 | if (err != USBD_IN_PROGRESS) | | 320 | if (err != USBD_IN_PROGRESS) |
320 | return (err); | | 321 | return (err); |
321 | usbd_lock_pipe(pipe); | | 322 | usbd_lock_pipe(pipe); |
322 | while (!xfer->done) { | | 323 | while (!xfer->done) { |
323 | if (pipe->device->bus->use_polling) | | 324 | if (pipe->device->bus->use_polling) |
324 | panic("usbd_transfer: not done"); | | 325 | panic("usbd_transfer: not done"); |
325 | | | 326 | |
326 | err = 0; | | 327 | err = 0; |
327 | if ((flags & USBD_SYNCHRONOUS_SIG) != 0) { | | 328 | if ((flags & USBD_SYNCHRONOUS_SIG) != 0) { |
328 | if (pipe->device->bus->lock) | | 329 | if (pipe->device->bus->lock) |
329 | err = cv_wait_sig(&xfer->cv, pipe->device->bus->lock); | | 330 | err = cv_wait_sig(&xfer->cv, pipe->device->bus->lock); |
330 | else | | 331 | else |
331 | err = tsleep(xfer, PZERO|PCATCH, "usbsyn", 0); | | 332 | err = tsleep(xfer, PZERO|PCATCH, "usbsyn", 0); |
332 | } else { | | 333 | } else { |
333 | if (pipe->device->bus->lock) | | 334 | if (pipe->device->bus->lock) |
334 | cv_wait(&xfer->cv, pipe->device->bus->lock); | | 335 | cv_wait(&xfer->cv, pipe->device->bus->lock); |
335 | else | | 336 | else |
336 | err = tsleep(xfer, PRIBIO, "usbsyn", 0); | | 337 | err = tsleep(xfer, PRIBIO, "usbsyn", 0); |
337 | } | | 338 | } |
338 | if (err) | | 339 | if (err) |
339 | break; | | 340 | break; |
340 | } | | 341 | } |
341 | usbd_unlock_pipe(pipe); | | 342 | usbd_unlock_pipe(pipe); |
342 | return (xfer->status); | | 343 | return (xfer->status); |
343 | } | | 344 | } |
344 | | | 345 | |
345 | /* Like usbd_transfer(), but waits for completion. */ | | 346 | /* Like usbd_transfer(), but waits for completion. */ |
346 | usbd_status | | 347 | usbd_status |
347 | usbd_sync_transfer(usbd_xfer_handle xfer) | | 348 | usbd_sync_transfer(usbd_xfer_handle xfer) |
348 | { | | 349 | { |
349 | xfer->flags |= USBD_SYNCHRONOUS; | | 350 | xfer->flags |= USBD_SYNCHRONOUS; |
350 | return (usbd_transfer(xfer)); | | 351 | return (usbd_transfer(xfer)); |
351 | } | | 352 | } |
352 | | | 353 | |
353 | /* Like usbd_transfer(), but waits for completion and listens for signals. */ | | 354 | /* Like usbd_transfer(), but waits for completion and listens for signals. */ |
354 | usbd_status | | 355 | usbd_status |
355 | usbd_sync_transfer_sig(usbd_xfer_handle xfer) | | 356 | usbd_sync_transfer_sig(usbd_xfer_handle xfer) |
356 | { | | 357 | { |
357 | xfer->flags |= USBD_SYNCHRONOUS | USBD_SYNCHRONOUS_SIG; | | 358 | xfer->flags |= USBD_SYNCHRONOUS | USBD_SYNCHRONOUS_SIG; |
358 | return (usbd_transfer(xfer)); | | 359 | return (usbd_transfer(xfer)); |
359 | } | | 360 | } |
360 | | | 361 | |
361 | void * | | 362 | void * |
362 | usbd_alloc_buffer(usbd_xfer_handle xfer, u_int32_t size) | | 363 | usbd_alloc_buffer(usbd_xfer_handle xfer, u_int32_t size) |
363 | { | | 364 | { |
364 | struct usbd_bus *bus = xfer->device->bus; | | 365 | struct usbd_bus *bus = xfer->device->bus; |
365 | usbd_status err; | | 366 | usbd_status err; |
366 | | | 367 | |
367 | #ifdef DIAGNOSTIC | | 368 | #ifdef DIAGNOSTIC |
368 | if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF)) | | 369 | if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF)) |
369 | printf("usbd_alloc_buffer: xfer already has a buffer\n"); | | 370 | printf("usbd_alloc_buffer: xfer already has a buffer\n"); |
370 | #endif | | 371 | #endif |
371 | err = bus->methods->allocm(bus, &xfer->dmabuf, size); | | 372 | err = bus->methods->allocm(bus, &xfer->dmabuf, size); |
372 | if (err) | | 373 | if (err) |
373 | return (NULL); | | 374 | return (NULL); |
374 | xfer->rqflags |= URQ_DEV_DMABUF; | | 375 | xfer->rqflags |= URQ_DEV_DMABUF; |
375 | return (KERNADDR(&xfer->dmabuf, 0)); | | 376 | return (KERNADDR(&xfer->dmabuf, 0)); |
376 | } | | 377 | } |
377 | | | 378 | |
378 | void | | 379 | void |
379 | usbd_free_buffer(usbd_xfer_handle xfer) | | 380 | usbd_free_buffer(usbd_xfer_handle xfer) |
380 | { | | 381 | { |
381 | #ifdef DIAGNOSTIC | | 382 | #ifdef DIAGNOSTIC |
382 | if (!(xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))) { | | 383 | if (!(xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))) { |
383 | printf("usbd_free_buffer: no buffer\n"); | | 384 | printf("usbd_free_buffer: no buffer\n"); |
384 | return; | | 385 | return; |
385 | } | | 386 | } |
386 | #endif | | 387 | #endif |
387 | xfer->rqflags &= ~(URQ_DEV_DMABUF | URQ_AUTO_DMABUF); | | 388 | xfer->rqflags &= ~(URQ_DEV_DMABUF | URQ_AUTO_DMABUF); |
388 | xfer->device->bus->methods->freem(xfer->device->bus, &xfer->dmabuf); | | 389 | xfer->device->bus->methods->freem(xfer->device->bus, &xfer->dmabuf); |
389 | } | | 390 | } |
390 | | | 391 | |
391 | void * | | 392 | void * |
392 | usbd_get_buffer(usbd_xfer_handle xfer) | | 393 | usbd_get_buffer(usbd_xfer_handle xfer) |
393 | { | | 394 | { |
394 | if (!(xfer->rqflags & URQ_DEV_DMABUF)) | | 395 | if (!(xfer->rqflags & URQ_DEV_DMABUF)) |
395 | return (0); | | 396 | return (0); |
396 | return (KERNADDR(&xfer->dmabuf, 0)); | | 397 | return (KERNADDR(&xfer->dmabuf, 0)); |
397 | } | | 398 | } |
398 | | | 399 | |
399 | usbd_xfer_handle | | 400 | usbd_xfer_handle |
400 | usbd_alloc_xfer(usbd_device_handle dev) | | 401 | usbd_alloc_xfer(usbd_device_handle dev) |
401 | { | | 402 | { |
402 | usbd_xfer_handle xfer; | | 403 | usbd_xfer_handle xfer; |
403 | | | 404 | |
404 | xfer = dev->bus->methods->allocx(dev->bus); | | 405 | xfer = dev->bus->methods->allocx(dev->bus); |
405 | if (xfer == NULL) | | 406 | if (xfer == NULL) |
406 | return (NULL); | | 407 | return (NULL); |
407 | xfer->device = dev; | | 408 | xfer->device = dev; |
408 | callout_init(&xfer->timeout_handle, | | 409 | callout_init(&xfer->timeout_handle, |
409 | dev->bus->methods->get_lock ? CALLOUT_MPSAFE : 0); | | 410 | dev->bus->methods->get_lock ? CALLOUT_MPSAFE : 0); |
410 | cv_init(&xfer->cv, "usbxfer"); | | 411 | cv_init(&xfer->cv, "usbxfer"); |
411 | cv_init(&xfer->hccv, "usbhcxfer"); | | 412 | cv_init(&xfer->hccv, "usbhcxfer"); |
412 | DPRINTFN(5,("usbd_alloc_xfer() = %p\n", xfer)); | | 413 | DPRINTFN(5,("usbd_alloc_xfer() = %p\n", xfer)); |
413 | return (xfer); | | 414 | return (xfer); |
414 | } | | 415 | } |
415 | | | 416 | |
416 | usbd_status | | 417 | usbd_status |
417 | usbd_free_xfer(usbd_xfer_handle xfer) | | 418 | usbd_free_xfer(usbd_xfer_handle xfer) |
418 | { | | 419 | { |
419 | DPRINTFN(5,("usbd_free_xfer: %p\n", xfer)); | | 420 | DPRINTFN(5,("usbd_free_xfer: %p\n", xfer)); |
420 | if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF)) | | 421 | if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF)) |
421 | usbd_free_buffer(xfer); | | 422 | usbd_free_buffer(xfer); |
422 | #if defined(DIAGNOSTIC) | | 423 | #if defined(DIAGNOSTIC) |
423 | if (callout_pending(&xfer->timeout_handle)) { | | 424 | if (callout_pending(&xfer->timeout_handle)) { |
424 | callout_stop(&xfer->timeout_handle); | | 425 | callout_stop(&xfer->timeout_handle); |
425 | printf("usbd_free_xfer: timeout_handle pending\n"); | | 426 | printf("usbd_free_xfer: timeout_handle pending\n"); |
426 | } | | 427 | } |
427 | #endif | | 428 | #endif |
428 | cv_destroy(&xfer->cv); | | 429 | cv_destroy(&xfer->cv); |
429 | cv_destroy(&xfer->hccv); | | 430 | cv_destroy(&xfer->hccv); |
430 | xfer->device->bus->methods->freex(xfer->device->bus, xfer); | | 431 | xfer->device->bus->methods->freex(xfer->device->bus, xfer); |
431 | return (USBD_NORMAL_COMPLETION); | | 432 | return (USBD_NORMAL_COMPLETION); |
432 | } | | 433 | } |
433 | | | 434 | |
434 | void | | 435 | void |
435 | usbd_setup_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, | | 436 | usbd_setup_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, |
436 | usbd_private_handle priv, void *buffer, u_int32_t length, | | 437 | usbd_private_handle priv, void *buffer, u_int32_t length, |
437 | u_int16_t flags, u_int32_t timeout, | | 438 | u_int16_t flags, u_int32_t timeout, |
438 | usbd_callback callback) | | 439 | usbd_callback callback) |
439 | { | | 440 | { |
440 | xfer->pipe = pipe; | | 441 | xfer->pipe = pipe; |
441 | xfer->priv = priv; | | 442 | xfer->priv = priv; |
442 | xfer->buffer = buffer; | | 443 | xfer->buffer = buffer; |
443 | xfer->length = length; | | 444 | xfer->length = length; |
444 | xfer->actlen = 0; | | 445 | xfer->actlen = 0; |
445 | xfer->flags = flags; | | 446 | xfer->flags = flags; |
446 | xfer->timeout = timeout; | | 447 | xfer->timeout = timeout; |
447 | xfer->status = USBD_NOT_STARTED; | | 448 | xfer->status = USBD_NOT_STARTED; |
448 | xfer->callback = callback; | | 449 | xfer->callback = callback; |
449 | xfer->rqflags &= ~URQ_REQUEST; | | 450 | xfer->rqflags &= ~URQ_REQUEST; |
450 | xfer->nframes = 0; | | 451 | xfer->nframes = 0; |
451 | } | | 452 | } |
452 | | | 453 | |
453 | void | | 454 | void |
454 | usbd_setup_default_xfer(usbd_xfer_handle xfer, usbd_device_handle dev, | | 455 | usbd_setup_default_xfer(usbd_xfer_handle xfer, usbd_device_handle dev, |
455 | usbd_private_handle priv, u_int32_t timeout, | | 456 | usbd_private_handle priv, u_int32_t timeout, |
456 | usb_device_request_t *req, void *buffer, | | 457 | usb_device_request_t *req, void *buffer, |
457 | u_int32_t length, u_int16_t flags, | | 458 | u_int32_t length, u_int16_t flags, |
458 | usbd_callback callback) | | 459 | usbd_callback callback) |
459 | { | | 460 | { |
460 | xfer->pipe = dev->default_pipe; | | 461 | xfer->pipe = dev->default_pipe; |
461 | xfer->priv = priv; | | 462 | xfer->priv = priv; |
462 | xfer->buffer = buffer; | | 463 | xfer->buffer = buffer; |
463 | xfer->length = length; | | 464 | xfer->length = length; |
464 | xfer->actlen = 0; | | 465 | xfer->actlen = 0; |
465 | xfer->flags = flags; | | 466 | xfer->flags = flags; |
466 | xfer->timeout = timeout; | | 467 | xfer->timeout = timeout; |
467 | xfer->status = USBD_NOT_STARTED; | | 468 | xfer->status = USBD_NOT_STARTED; |
468 | xfer->callback = callback; | | 469 | xfer->callback = callback; |
469 | xfer->request = *req; | | 470 | xfer->request = *req; |
470 | xfer->rqflags |= URQ_REQUEST; | | 471 | xfer->rqflags |= URQ_REQUEST; |
471 | xfer->nframes = 0; | | 472 | xfer->nframes = 0; |
472 | } | | 473 | } |
473 | | | 474 | |
474 | void | | 475 | void |
475 | usbd_setup_isoc_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, | | 476 | usbd_setup_isoc_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, |
476 | usbd_private_handle priv, u_int16_t *frlengths, | | 477 | usbd_private_handle priv, u_int16_t *frlengths, |
477 | u_int32_t nframes, u_int16_t flags, usbd_callback callback) | | 478 | u_int32_t nframes, u_int16_t flags, usbd_callback callback) |
478 | { | | 479 | { |
479 | xfer->pipe = pipe; | | 480 | xfer->pipe = pipe; |
480 | xfer->priv = priv; | | 481 | xfer->priv = priv; |
481 | xfer->buffer = 0; | | 482 | xfer->buffer = 0; |
482 | xfer->length = 0; | | 483 | xfer->length = 0; |
483 | xfer->actlen = 0; | | 484 | xfer->actlen = 0; |
484 | xfer->flags = flags; | | 485 | xfer->flags = flags; |
485 | xfer->timeout = USBD_NO_TIMEOUT; | | 486 | xfer->timeout = USBD_NO_TIMEOUT; |
486 | xfer->status = USBD_NOT_STARTED; | | 487 | xfer->status = USBD_NOT_STARTED; |
487 | xfer->callback = callback; | | 488 | xfer->callback = callback; |
488 | xfer->rqflags &= ~URQ_REQUEST; | | 489 | xfer->rqflags &= ~URQ_REQUEST; |
489 | xfer->frlengths = frlengths; | | 490 | xfer->frlengths = frlengths; |
490 | xfer->nframes = nframes; | | 491 | xfer->nframes = nframes; |
491 | } | | 492 | } |
492 | | | 493 | |
493 | void | | 494 | void |
494 | usbd_get_xfer_status(usbd_xfer_handle xfer, usbd_private_handle *priv, | | 495 | usbd_get_xfer_status(usbd_xfer_handle xfer, usbd_private_handle *priv, |
495 | void **buffer, u_int32_t *count, usbd_status *status) | | 496 | void **buffer, u_int32_t *count, usbd_status *status) |
496 | { | | 497 | { |
497 | if (priv != NULL) | | 498 | if (priv != NULL) |
498 | *priv = xfer->priv; | | 499 | *priv = xfer->priv; |
499 | if (buffer != NULL) | | 500 | if (buffer != NULL) |
500 | *buffer = xfer->buffer; | | 501 | *buffer = xfer->buffer; |
501 | if (count != NULL) | | 502 | if (count != NULL) |
502 | *count = xfer->actlen; | | 503 | *count = xfer->actlen; |
503 | if (status != NULL) | | 504 | if (status != NULL) |
504 | *status = xfer->status; | | 505 | *status = xfer->status; |
505 | } | | 506 | } |
506 | | | 507 | |
507 | usb_config_descriptor_t * | | 508 | usb_config_descriptor_t * |
508 | usbd_get_config_descriptor(usbd_device_handle dev) | | 509 | usbd_get_config_descriptor(usbd_device_handle dev) |
509 | { | | 510 | { |
510 | #ifdef DIAGNOSTIC | | 511 | #ifdef DIAGNOSTIC |
511 | if (dev == NULL) { | | 512 | if (dev == NULL) { |
512 | printf("usbd_get_config_descriptor: dev == NULL\n"); | | 513 | printf("usbd_get_config_descriptor: dev == NULL\n"); |
513 | return (NULL); | | 514 | return (NULL); |
514 | } | | 515 | } |
515 | #endif | | 516 | #endif |
516 | return (dev->cdesc); | | 517 | return (dev->cdesc); |
517 | } | | 518 | } |
518 | | | 519 | |
519 | usb_interface_descriptor_t * | | 520 | usb_interface_descriptor_t * |
520 | usbd_get_interface_descriptor(usbd_interface_handle iface) | | 521 | usbd_get_interface_descriptor(usbd_interface_handle iface) |
521 | { | | 522 | { |
522 | #ifdef DIAGNOSTIC | | 523 | #ifdef DIAGNOSTIC |
523 | if (iface == NULL) { | | 524 | if (iface == NULL) { |
524 | printf("usbd_get_interface_descriptor: dev == NULL\n"); | | 525 | printf("usbd_get_interface_descriptor: dev == NULL\n"); |
525 | return (NULL); | | 526 | return (NULL); |
526 | } | | 527 | } |
527 | #endif | | 528 | #endif |
528 | return (iface->idesc); | | 529 | return (iface->idesc); |
529 | } | | 530 | } |
530 | | | 531 | |
531 | usb_device_descriptor_t * | | 532 | usb_device_descriptor_t * |
532 | usbd_get_device_descriptor(usbd_device_handle dev) | | 533 | usbd_get_device_descriptor(usbd_device_handle dev) |
533 | { | | 534 | { |
534 | return (&dev->ddesc); | | 535 | return (&dev->ddesc); |
535 | } | | 536 | } |
536 | | | 537 | |
537 | usb_endpoint_descriptor_t * | | 538 | usb_endpoint_descriptor_t * |
538 | usbd_interface2endpoint_descriptor(usbd_interface_handle iface, u_int8_t index) | | 539 | usbd_interface2endpoint_descriptor(usbd_interface_handle iface, u_int8_t index) |
539 | { | | 540 | { |
540 | if (index >= iface->idesc->bNumEndpoints) | | 541 | if (index >= iface->idesc->bNumEndpoints) |
541 | return (0); | | 542 | return (0); |
542 | return (iface->endpoints[index].edesc); | | 543 | return (iface->endpoints[index].edesc); |
543 | } | | 544 | } |
544 | | | 545 | |
545 | /* Some drivers may wish to abort requests on the default pipe, * | | 546 | /* Some drivers may wish to abort requests on the default pipe, * |
546 | * but there is no mechanism for getting a handle on it. */ | | 547 | * but there is no mechanism for getting a handle on it. */ |
547 | usbd_status | | 548 | usbd_status |
548 | usbd_abort_default_pipe(struct usbd_device *device) | | 549 | usbd_abort_default_pipe(struct usbd_device *device) |
549 | { | | 550 | { |
550 | | | 551 | |
551 | return usbd_abort_pipe(device->default_pipe); | | 552 | return usbd_abort_pipe(device->default_pipe); |
552 | } | | 553 | } |
553 | | | 554 | |
554 | usbd_status | | 555 | usbd_status |
555 | usbd_abort_pipe(usbd_pipe_handle pipe) | | 556 | usbd_abort_pipe(usbd_pipe_handle pipe) |
556 | { | | 557 | { |
557 | usbd_status err; | | 558 | usbd_status err; |
558 | int s; | | 559 | int s; |
559 | usbd_xfer_handle intrxfer = pipe->intrxfer; | | 560 | usbd_xfer_handle intrxfer = pipe->intrxfer; |
560 | | | 561 | |
561 | #ifdef DIAGNOSTIC | | 562 | #ifdef DIAGNOSTIC |
562 | if (pipe == NULL) { | | 563 | if (pipe == NULL) { |
563 | printf("usbd_abort_pipe: pipe==NULL\n"); | | 564 | printf("usbd_abort_pipe: pipe==NULL\n"); |
564 | return (USBD_NORMAL_COMPLETION); | | 565 | return (USBD_NORMAL_COMPLETION); |
565 | } | | 566 | } |
566 | #endif | | 567 | #endif |
567 | usbd_lock_pipe(pipe); | | 568 | usbd_lock_pipe(pipe); |
568 | err = usbd_ar_pipe(pipe); | | 569 | err = usbd_ar_pipe(pipe); |
569 | usbd_unlock_pipe(pipe); | | 570 | usbd_unlock_pipe(pipe); |
570 | if (pipe->intrxfer != intrxfer) | | 571 | if (pipe->intrxfer != intrxfer) |
571 | usbd_free_xfer(intrxfer); | | 572 | usbd_free_xfer(intrxfer); |
572 | return (err); | | 573 | return (err); |
573 | } | | 574 | } |
574 | | | 575 | |
575 | usbd_status | | 576 | usbd_status |
576 | usbd_clear_endpoint_stall(usbd_pipe_handle pipe) | | 577 | usbd_clear_endpoint_stall(usbd_pipe_handle pipe) |
577 | { | | 578 | { |
578 | usbd_device_handle dev = pipe->device; | | 579 | usbd_device_handle dev = pipe->device; |
579 | usb_device_request_t req; | | 580 | usb_device_request_t req; |
580 | usbd_status err; | | 581 | usbd_status err; |
581 | | | 582 | |
582 | DPRINTFN(8, ("usbd_clear_endpoint_stall\n")); | | 583 | DPRINTFN(8, ("usbd_clear_endpoint_stall\n")); |
583 | | | 584 | |
584 | /* | | 585 | /* |
585 | * Clearing en endpoint stall resets the endpoint toggle, so | | 586 | * Clearing en endpoint stall resets the endpoint toggle, so |
586 | * do the same to the HC toggle. | | 587 | * do the same to the HC toggle. |
587 | */ | | 588 | */ |
588 | pipe->methods->cleartoggle(pipe); | | 589 | pipe->methods->cleartoggle(pipe); |
589 | | | 590 | |
590 | req.bmRequestType = UT_WRITE_ENDPOINT; | | 591 | req.bmRequestType = UT_WRITE_ENDPOINT; |
591 | req.bRequest = UR_CLEAR_FEATURE; | | 592 | req.bRequest = UR_CLEAR_FEATURE; |
592 | USETW(req.wValue, UF_ENDPOINT_HALT); | | 593 | USETW(req.wValue, UF_ENDPOINT_HALT); |
593 | USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); | | 594 | USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); |
594 | USETW(req.wLength, 0); | | 595 | USETW(req.wLength, 0); |
595 | err = usbd_do_request(dev, &req, 0); | | 596 | err = usbd_do_request(dev, &req, 0); |
596 | #if 0 | | 597 | #if 0 |
597 | XXX should we do this? | | 598 | XXX should we do this? |
598 | if (!err) { | | 599 | if (!err) { |
599 | pipe->state = USBD_PIPE_ACTIVE; | | 600 | pipe->state = USBD_PIPE_ACTIVE; |
600 | /* XXX activate pipe */ | | 601 | /* XXX activate pipe */ |
601 | } | | 602 | } |
602 | #endif | | 603 | #endif |
603 | return (err); | | 604 | return (err); |
604 | } | | 605 | } |
605 | | | 606 | |
606 | void | | 607 | void |
607 | usbd_clear_endpoint_stall_async_cb(void *arg) | | 608 | usbd_clear_endpoint_stall_async_cb(void *arg) |
608 | { | | 609 | { |
609 | usbd_pipe_handle pipe = arg; | | 610 | usbd_pipe_handle pipe = arg; |
610 | usbd_device_handle dev = pipe->device; | | 611 | usbd_device_handle dev = pipe->device; |
611 | usb_device_request_t req; | | 612 | usb_device_request_t req; |
612 | | | 613 | |
613 | pipe->methods->cleartoggle(pipe); | | 614 | pipe->methods->cleartoggle(pipe); |
614 | | | 615 | |
615 | req.bmRequestType = UT_WRITE_ENDPOINT; | | 616 | req.bmRequestType = UT_WRITE_ENDPOINT; |
616 | req.bRequest = UR_CLEAR_FEATURE; | | 617 | req.bRequest = UR_CLEAR_FEATURE; |
617 | USETW(req.wValue, UF_ENDPOINT_HALT); | | 618 | USETW(req.wValue, UF_ENDPOINT_HALT); |
618 | USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); | | 619 | USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); |
619 | USETW(req.wLength, 0); | | 620 | USETW(req.wLength, 0); |
620 | (void)usbd_do_request_async(dev, &req, 0); | | 621 | (void)usbd_do_request_async(dev, &req, 0); |
621 | } | | 622 | } |
622 | | | 623 | |
623 | void | | 624 | void |
624 | usbd_clear_endpoint_stall_async(usbd_pipe_handle pipe) | | 625 | usbd_clear_endpoint_stall_async(usbd_pipe_handle pipe) |
625 | { | | 626 | { |
626 | | | 627 | |
627 | usb_add_task(pipe->device, &pipe->async_task, USB_TASKQ_DRIVER); | | 628 | usb_add_task(pipe->device, &pipe->async_task, USB_TASKQ_DRIVER); |
628 | } | | 629 | } |
629 | | | 630 | |
630 | void | | 631 | void |
631 | usbd_clear_endpoint_toggle(usbd_pipe_handle pipe) | | 632 | usbd_clear_endpoint_toggle(usbd_pipe_handle pipe) |
632 | { | | 633 | { |
633 | pipe->methods->cleartoggle(pipe); | | 634 | pipe->methods->cleartoggle(pipe); |
634 | } | | 635 | } |
635 | | | 636 | |
636 | usbd_status | | 637 | usbd_status |
637 | usbd_endpoint_count(usbd_interface_handle iface, u_int8_t *count) | | 638 | usbd_endpoint_count(usbd_interface_handle iface, u_int8_t *count) |
638 | { | | 639 | { |
639 | #ifdef DIAGNOSTIC | | 640 | #ifdef DIAGNOSTIC |
640 | if (iface == NULL || iface->idesc == NULL) { | | 641 | if (iface == NULL || iface->idesc == NULL) { |
641 | printf("usbd_endpoint_count: NULL pointer\n"); | | 642 | printf("usbd_endpoint_count: NULL pointer\n"); |
642 | return (USBD_INVAL); | | 643 | return (USBD_INVAL); |
643 | } | | 644 | } |
644 | #endif | | 645 | #endif |
645 | *count = iface->idesc->bNumEndpoints; | | 646 | *count = iface->idesc->bNumEndpoints; |
646 | return (USBD_NORMAL_COMPLETION); | | 647 | return (USBD_NORMAL_COMPLETION); |
647 | } | | 648 | } |
648 | | | 649 | |
649 | usbd_status | | 650 | usbd_status |
650 | usbd_interface_count(usbd_device_handle dev, u_int8_t *count) | | 651 | usbd_interface_count(usbd_device_handle dev, u_int8_t *count) |
651 | { | | 652 | { |
652 | if (dev->cdesc == NULL) | | 653 | if (dev->cdesc == NULL) |
653 | return (USBD_NOT_CONFIGURED); | | 654 | return (USBD_NOT_CONFIGURED); |
654 | *count = dev->cdesc->bNumInterface; | | 655 | *count = dev->cdesc->bNumInterface; |
655 | return (USBD_NORMAL_COMPLETION); | | 656 | return (USBD_NORMAL_COMPLETION); |
656 | } | | 657 | } |
657 | | | 658 | |
658 | void | | 659 | void |
659 | usbd_interface2device_handle(usbd_interface_handle iface, | | 660 | usbd_interface2device_handle(usbd_interface_handle iface, |
660 | usbd_device_handle *dev) | | 661 | usbd_device_handle *dev) |
661 | { | | 662 | { |
662 | *dev = iface->device; | | 663 | *dev = iface->device; |
663 | } | | 664 | } |
664 | | | 665 | |
665 | usbd_status | | 666 | usbd_status |
666 | usbd_device2interface_handle(usbd_device_handle dev, | | 667 | usbd_device2interface_handle(usbd_device_handle dev, |
667 | u_int8_t ifaceno, usbd_interface_handle *iface) | | 668 | u_int8_t ifaceno, usbd_interface_handle *iface) |
668 | { | | 669 | { |
669 | if (dev->cdesc == NULL) | | 670 | if (dev->cdesc == NULL) |
670 | return (USBD_NOT_CONFIGURED); | | 671 | return (USBD_NOT_CONFIGURED); |
671 | if (ifaceno >= dev->cdesc->bNumInterface) | | 672 | if (ifaceno >= dev->cdesc->bNumInterface) |
672 | return (USBD_INVAL); | | 673 | return (USBD_INVAL); |
673 | *iface = &dev->ifaces[ifaceno]; | | 674 | *iface = &dev->ifaces[ifaceno]; |
674 | return (USBD_NORMAL_COMPLETION); | | 675 | return (USBD_NORMAL_COMPLETION); |
675 | } | | 676 | } |
676 | | | 677 | |
677 | usbd_device_handle | | 678 | usbd_device_handle |
678 | usbd_pipe2device_handle(usbd_pipe_handle pipe) | | 679 | usbd_pipe2device_handle(usbd_pipe_handle pipe) |
679 | { | | 680 | { |
680 | return (pipe->device); | | 681 | return (pipe->device); |
681 | } | | 682 | } |
682 | | | 683 | |
683 | /* XXXX use altno */ | | 684 | /* XXXX use altno */ |
684 | usbd_status | | 685 | usbd_status |
685 | usbd_set_interface(usbd_interface_handle iface, int altidx) | | 686 | usbd_set_interface(usbd_interface_handle iface, int altidx) |
686 | { | | 687 | { |
687 | usb_device_request_t req; | | 688 | usb_device_request_t req; |
688 | usbd_status err; | | 689 | usbd_status err; |
689 | void *endpoints; | | 690 | void *endpoints; |
690 | | | 691 | |
691 | if (LIST_FIRST(&iface->pipes) != 0) | | 692 | if (LIST_FIRST(&iface->pipes) != 0) |
692 | return (USBD_IN_USE); | | 693 | return (USBD_IN_USE); |
693 | | | 694 | |
694 | endpoints = iface->endpoints; | | 695 | endpoints = iface->endpoints; |
695 | err = usbd_fill_iface_data(iface->device, iface->index, altidx); | | 696 | err = usbd_fill_iface_data(iface->device, iface->index, altidx); |
696 | if (err) | | 697 | if (err) |
697 | return (err); | | 698 | return (err); |
698 | | | 699 | |
699 | /* new setting works, we can free old endpoints */ | | 700 | /* new setting works, we can free old endpoints */ |
700 | if (endpoints != NULL) | | 701 | if (endpoints != NULL) |
701 | free(endpoints, M_USB); | | 702 | free(endpoints, M_USB); |
702 | | | 703 | |
703 | #ifdef DIAGNOSTIC | | 704 | #ifdef DIAGNOSTIC |
704 | if (iface->idesc == NULL) { | | 705 | if (iface->idesc == NULL) { |
705 | printf("usbd_set_interface: NULL pointer\n"); | | 706 | printf("usbd_set_interface: NULL pointer\n"); |
706 | return (USBD_INVAL); | | 707 | return (USBD_INVAL); |
707 | } | | 708 | } |
708 | #endif | | 709 | #endif |
709 | | | 710 | |
710 | req.bmRequestType = UT_WRITE_INTERFACE; | | 711 | req.bmRequestType = UT_WRITE_INTERFACE; |
711 | req.bRequest = UR_SET_INTERFACE; | | 712 | req.bRequest = UR_SET_INTERFACE; |
712 | USETW(req.wValue, iface->idesc->bAlternateSetting); | | 713 | USETW(req.wValue, iface->idesc->bAlternateSetting); |
713 | USETW(req.wIndex, iface->idesc->bInterfaceNumber); | | 714 | USETW(req.wIndex, iface->idesc->bInterfaceNumber); |
714 | USETW(req.wLength, 0); | | 715 | USETW(req.wLength, 0); |
715 | return (usbd_do_request(iface->device, &req, 0)); | | 716 | return (usbd_do_request(iface->device, &req, 0)); |
716 | } | | 717 | } |
717 | | | 718 | |
718 | int | | 719 | int |
719 | usbd_get_no_alts(usb_config_descriptor_t *cdesc, int ifaceno) | | 720 | usbd_get_no_alts(usb_config_descriptor_t *cdesc, int ifaceno) |
720 | { | | 721 | { |
721 | char *p = (char *)cdesc; | | 722 | char *p = (char *)cdesc; |
722 | char *end = p + UGETW(cdesc->wTotalLength); | | 723 | char *end = p + UGETW(cdesc->wTotalLength); |
723 | usb_interface_descriptor_t *d; | | 724 | usb_interface_descriptor_t *d; |
724 | int n; | | 725 | int n; |
725 | | | 726 | |
726 | for (n = 0; p < end; p += d->bLength) { | | 727 | for (n = 0; p < end; p += d->bLength) { |
727 | d = (usb_interface_descriptor_t *)p; | | 728 | d = (usb_interface_descriptor_t *)p; |
728 | if (p + d->bLength <= end && | | 729 | if (p + d->bLength <= end && |
729 | d->bDescriptorType == UDESC_INTERFACE && | | 730 | d->bDescriptorType == UDESC_INTERFACE && |
730 | d->bInterfaceNumber == ifaceno) | | 731 | d->bInterfaceNumber == ifaceno) |
731 | n++; | | 732 | n++; |
732 | } | | 733 | } |
733 | return (n); | | 734 | return (n); |
734 | } | | 735 | } |
735 | | | 736 | |
736 | int | | 737 | int |
737 | usbd_get_interface_altindex(usbd_interface_handle iface) | | 738 | usbd_get_interface_altindex(usbd_interface_handle iface) |
738 | { | | 739 | { |
739 | return (iface->altindex); | | 740 | return (iface->altindex); |
740 | } | | 741 | } |
741 | | | 742 | |
742 | usbd_status | | 743 | usbd_status |
743 | usbd_get_interface(usbd_interface_handle iface, u_int8_t *aiface) | | 744 | usbd_get_interface(usbd_interface_handle iface, u_int8_t *aiface) |
744 | { | | 745 | { |
745 | usb_device_request_t req; | | 746 | usb_device_request_t req; |
746 | | | 747 | |
747 | req.bmRequestType = UT_READ_INTERFACE; | | 748 | req.bmRequestType = UT_READ_INTERFACE; |
748 | req.bRequest = UR_GET_INTERFACE; | | 749 | req.bRequest = UR_GET_INTERFACE; |
749 | USETW(req.wValue, 0); | | 750 | USETW(req.wValue, 0); |
750 | USETW(req.wIndex, iface->idesc->bInterfaceNumber); | | 751 | USETW(req.wIndex, iface->idesc->bInterfaceNumber); |
751 | USETW(req.wLength, 1); | | 752 | USETW(req.wLength, 1); |
752 | return (usbd_do_request(iface->device, &req, aiface)); | | 753 | return (usbd_do_request(iface->device, &req, aiface)); |
753 | } | | 754 | } |
754 | | | 755 | |
755 | /*** Internal routines ***/ | | 756 | /*** Internal routines ***/ |
756 | | | 757 | |
757 | /* Dequeue all pipe operations, called at splusb(). */ | | 758 | /* Dequeue all pipe operations, called at splusb(). */ |
758 | Static usbd_status | | 759 | Static usbd_status |
759 | usbd_ar_pipe(usbd_pipe_handle pipe) | | 760 | usbd_ar_pipe(usbd_pipe_handle pipe) |
760 | { | | 761 | { |
761 | usbd_xfer_handle xfer; | | 762 | usbd_xfer_handle xfer; |
762 | | | 763 | |
763 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); | | 764 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); |
764 | | | 765 | |
765 | DPRINTFN(2,("usbd_ar_pipe: pipe=%p\n", pipe)); | | 766 | DPRINTFN(2,("usbd_ar_pipe: pipe=%p\n", pipe)); |
766 | #ifdef USB_DEBUG | | 767 | #ifdef USB_DEBUG |
767 | if (usbdebug > 5) | | 768 | if (usbdebug > 5) |
768 | usbd_dump_queue(pipe); | | 769 | usbd_dump_queue(pipe); |
769 | #endif | | 770 | #endif |
770 | pipe->repeat = 0; | | 771 | pipe->repeat = 0; |
771 | pipe->aborting = 1; | | 772 | pipe->aborting = 1; |
772 | while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL) { | | 773 | while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL) { |
773 | DPRINTFN(2,("usbd_ar_pipe: pipe=%p xfer=%p (methods=%p)\n", | | 774 | DPRINTFN(2,("usbd_ar_pipe: pipe=%p xfer=%p (methods=%p)\n", |
774 | pipe, xfer, pipe->methods)); | | 775 | pipe, xfer, pipe->methods)); |
775 | /* Make the HC abort it (and invoke the callback). */ | | 776 | /* Make the HC abort it (and invoke the callback). */ |
776 | pipe->methods->abort(xfer); | | 777 | pipe->methods->abort(xfer); |
777 | /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */ | | 778 | /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */ |
778 | } | | 779 | } |
779 | pipe->aborting = 0; | | 780 | pipe->aborting = 0; |
780 | return (USBD_NORMAL_COMPLETION); | | 781 | return (USBD_NORMAL_COMPLETION); |
781 | } | | 782 | } |
782 | | | 783 | |
783 | /* Called with USB lock held. */ | | 784 | /* Called with USB lock held. */ |
784 | void | | 785 | void |
785 | usb_transfer_complete(usbd_xfer_handle xfer) | | 786 | usb_transfer_complete(usbd_xfer_handle xfer) |
786 | { | | 787 | { |
787 | usbd_pipe_handle pipe = xfer->pipe; | | 788 | usbd_pipe_handle pipe = xfer->pipe; |
788 | usb_dma_t *dmap = &xfer->dmabuf; | | 789 | usb_dma_t *dmap = &xfer->dmabuf; |
789 | int sync = xfer->flags & USBD_SYNCHRONOUS; | | 790 | int sync = xfer->flags & USBD_SYNCHRONOUS; |
790 | int erred = xfer->status == USBD_CANCELLED || | | 791 | int erred = xfer->status == USBD_CANCELLED || |
791 | xfer->status == USBD_TIMEOUT; | | 792 | xfer->status == USBD_TIMEOUT; |
792 | int repeat, polling; | | 793 | int repeat, polling; |
793 | | | 794 | |
794 | DPRINTFN(5, ("usb_transfer_complete: pipe=%p xfer=%p status=%d " | | 795 | DPRINTFN(5, ("usb_transfer_complete: pipe=%p xfer=%p status=%d " |
795 | "actlen=%d\n", pipe, xfer, xfer->status, xfer->actlen)); | | 796 | "actlen=%d\n", pipe, xfer, xfer->status, xfer->actlen)); |
796 | | | 797 | |
797 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); | | 798 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); |
798 | | | 799 | |
799 | #ifdef DIAGNOSTIC | | 800 | #ifdef DIAGNOSTIC |
800 | if (xfer->busy_free != XFER_ONQU) { | | 801 | if (xfer->busy_free != XFER_ONQU) { |
801 | printf("usb_transfer_complete: xfer=%p not queued 0x%08x\n", | | 802 | printf("usb_transfer_complete: xfer=%p not queued 0x%08x\n", |
802 | xfer, xfer->busy_free); | | 803 | xfer, xfer->busy_free); |
803 | } | | 804 | } |
804 | #endif | | 805 | #endif |
805 | | | 806 | |
806 | #ifdef DIAGNOSTIC | | 807 | #ifdef DIAGNOSTIC |
807 | if (pipe == NULL) { | | 808 | if (pipe == NULL) { |
808 | printf("usb_transfer_complete: pipe==0, xfer=%p\n", xfer); | | 809 | printf("usb_transfer_complete: pipe==0, xfer=%p\n", xfer); |
809 | return; | | 810 | return; |
810 | } | | 811 | } |
811 | #endif | | 812 | #endif |
812 | repeat = pipe->repeat; | | 813 | repeat = pipe->repeat; |
813 | polling = pipe->device->bus->use_polling; | | 814 | polling = pipe->device->bus->use_polling; |
814 | /* XXXX */ | | 815 | /* XXXX */ |
815 | if (polling) | | 816 | if (polling) |
816 | pipe->running = 0; | | 817 | pipe->running = 0; |
817 | | | 818 | |
818 | if (!(xfer->flags & USBD_NO_COPY) && xfer->actlen != 0 && | | 819 | if (!(xfer->flags & USBD_NO_COPY) && xfer->actlen != 0 && |
819 | usbd_xfer_isread(xfer)) { | | 820 | usbd_xfer_isread(xfer)) { |
820 | #ifdef DIAGNOSTIC | | 821 | #ifdef DIAGNOSTIC |
821 | if (xfer->actlen > xfer->length) { | | 822 | if (xfer->actlen > xfer->length) { |
822 | printf("%s: actlen (%d) > len (%d)\n", __func__, | | 823 | printf("%s: actlen (%d) > len (%d)\n", __func__, |
823 | xfer->actlen, xfer->length); | | 824 | xfer->actlen, xfer->length); |
824 | xfer->actlen = xfer->length; | | 825 | xfer->actlen = xfer->length; |
825 | } | | 826 | } |
826 | #endif | | 827 | #endif |
827 | memcpy(xfer->buffer, KERNADDR(dmap, 0), xfer->actlen); | | 828 | memcpy(xfer->buffer, KERNADDR(dmap, 0), xfer->actlen); |
828 | } | | 829 | } |
829 | | | 830 | |
830 | /* if we allocated the buffer in usbd_transfer() we free it here. */ | | 831 | /* if we allocated the buffer in usbd_transfer() we free it here. */ |
831 | if (xfer->rqflags & URQ_AUTO_DMABUF) { | | 832 | if (xfer->rqflags & URQ_AUTO_DMABUF) { |
832 | if (!repeat) { | | 833 | if (!repeat) { |
833 | struct usbd_bus *bus = pipe->device->bus; | | 834 | struct usbd_bus *bus = pipe->device->bus; |
834 | bus->methods->freem(bus, dmap); | | 835 | bus->methods->freem(bus, dmap); |
835 | xfer->rqflags &= ~URQ_AUTO_DMABUF; | | 836 | xfer->rqflags &= ~URQ_AUTO_DMABUF; |
836 | } | | 837 | } |
837 | } | | 838 | } |
838 | | | 839 | |
839 | if (!repeat) { | | 840 | if (!repeat) { |
840 | /* Remove request from queue. */ | | 841 | /* Remove request from queue. */ |
841 | | | 842 | |
842 | KASSERTMSG(!SIMPLEQ_EMPTY(&pipe->queue), | | 843 | KASSERTMSG(!SIMPLEQ_EMPTY(&pipe->queue), |
843 | "pipe %p is empty, but xfer %p wants to complete", pipe, | | 844 | "pipe %p is empty, but xfer %p wants to complete", pipe, |
844 | xfer); | | 845 | xfer); |
845 | #ifdef DIAGNOSTIC | | 846 | #ifdef DIAGNOSTIC |
846 | if (xfer != SIMPLEQ_FIRST(&pipe->queue)) | | 847 | if (xfer != SIMPLEQ_FIRST(&pipe->queue)) |
847 | printf("%s: bad dequeue %p != %p\n", __func__, | | 848 | printf("%s: bad dequeue %p != %p\n", __func__, |
848 | xfer, SIMPLEQ_FIRST(&pipe->queue)); | | 849 | xfer, SIMPLEQ_FIRST(&pipe->queue)); |
849 | xfer->busy_free = XFER_BUSY; | | 850 | xfer->busy_free = XFER_BUSY; |
850 | #endif | | 851 | #endif |
851 | SIMPLEQ_REMOVE_HEAD(&pipe->queue, next); | | 852 | SIMPLEQ_REMOVE_HEAD(&pipe->queue, next); |
852 | } | | 853 | } |
853 | DPRINTFN(5,("usb_transfer_complete: repeat=%d new head=%p\n", | | 854 | DPRINTFN(5,("usb_transfer_complete: repeat=%d new head=%p\n", |
854 | repeat, SIMPLEQ_FIRST(&pipe->queue))); | | 855 | repeat, SIMPLEQ_FIRST(&pipe->queue))); |
855 | | | 856 | |
856 | /* Count completed transfers. */ | | 857 | /* Count completed transfers. */ |
857 | ++pipe->device->bus->stats.uds_requests | | 858 | ++pipe->device->bus->stats.uds_requests |
858 | [pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE]; | | 859 | [pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE]; |
859 | | | 860 | |
860 | xfer->done = 1; | | 861 | xfer->done = 1; |
861 | if (!xfer->status && xfer->actlen < xfer->length && | | 862 | if (!xfer->status && xfer->actlen < xfer->length && |
862 | !(xfer->flags & USBD_SHORT_XFER_OK)) { | | 863 | !(xfer->flags & USBD_SHORT_XFER_OK)) { |
863 | DPRINTFN(-1,("usb_transfer_complete: short transfer %d<%d\n", | | 864 | DPRINTFN(-1,("usb_transfer_complete: short transfer %d<%d\n", |
864 | xfer->actlen, xfer->length)); | | 865 | xfer->actlen, xfer->length)); |
865 | xfer->status = USBD_SHORT_XFER; | | 866 | xfer->status = USBD_SHORT_XFER; |
866 | } | | 867 | } |
867 | | | 868 | |
868 | if (repeat) { | | 869 | if (repeat) { |
869 | if (xfer->callback) { | | 870 | if (xfer->callback) { |
870 | if (pipe->device->bus->lock) | | 871 | if (pipe->device->bus->lock) |
871 | mutex_exit(pipe->device->bus->lock); | | 872 | mutex_exit(pipe->device->bus->lock); |
872 | | | 873 | |
873 | if (!(pipe->flags & USBD_MPSAFE)) | | 874 | if (!(pipe->flags & USBD_MPSAFE)) |
874 | KERNEL_LOCK(1, curlwp); | | 875 | KERNEL_LOCK(1, curlwp); |
875 | xfer->callback(xfer, xfer->priv, xfer->status); | | 876 | xfer->callback(xfer, xfer->priv, xfer->status); |
876 | if (!(pipe->flags & USBD_MPSAFE)) | | 877 | if (!(pipe->flags & USBD_MPSAFE)) |
877 | KERNEL_UNLOCK_ONE(curlwp); | | 878 | KERNEL_UNLOCK_ONE(curlwp); |
878 | | | 879 | |
879 | if (pipe->device->bus->lock) | | 880 | if (pipe->device->bus->lock) |
880 | mutex_enter(pipe->device->bus->lock); | | 881 | mutex_enter(pipe->device->bus->lock); |
881 | } | | 882 | } |
882 | pipe->methods->done(xfer); | | 883 | pipe->methods->done(xfer); |
883 | } else { | | 884 | } else { |
884 | pipe->methods->done(xfer); | | 885 | pipe->methods->done(xfer); |
885 | if (xfer->callback) { | | 886 | if (xfer->callback) { |
886 | if (pipe->device->bus->lock) | | 887 | if (pipe->device->bus->lock) |
887 | mutex_exit(pipe->device->bus->lock); | | 888 | mutex_exit(pipe->device->bus->lock); |
888 | | | 889 | |
889 | if (!(pipe->flags & USBD_MPSAFE)) | | 890 | if (!(pipe->flags & USBD_MPSAFE)) |
890 | KERNEL_LOCK(1, curlwp); | | 891 | KERNEL_LOCK(1, curlwp); |
891 | xfer->callback(xfer, xfer->priv, xfer->status); | | 892 | xfer->callback(xfer, xfer->priv, xfer->status); |
892 | if (!(pipe->flags & USBD_MPSAFE)) | | 893 | if (!(pipe->flags & USBD_MPSAFE)) |
893 | KERNEL_UNLOCK_ONE(curlwp); | | 894 | KERNEL_UNLOCK_ONE(curlwp); |
894 | | | 895 | |
895 | if (pipe->device->bus->lock) | | 896 | if (pipe->device->bus->lock) |
896 | mutex_enter(pipe->device->bus->lock); | | 897 | mutex_enter(pipe->device->bus->lock); |
897 | } | | 898 | } |
898 | } | | 899 | } |
899 | | | 900 | |
900 | if (sync && !polling) { | | 901 | if (sync && !polling) { |
901 | if (pipe->device->bus->lock) | | 902 | if (pipe->device->bus->lock) |
902 | cv_broadcast(&xfer->cv); | | 903 | cv_broadcast(&xfer->cv); |
903 | else | | 904 | else |
904 | wakeup(xfer); /* XXXSMP ok */ | | 905 | wakeup(xfer); /* XXXSMP ok */ |
905 | } | | 906 | } |
906 | | | 907 | |
907 | if (!repeat) { | | 908 | if (!repeat) { |
908 | /* XXX should we stop the queue on all errors? */ | | 909 | /* XXX should we stop the queue on all errors? */ |
909 | if (erred && pipe->iface != NULL) /* not control pipe */ | | 910 | if (erred && pipe->iface != NULL) /* not control pipe */ |
910 | pipe->running = 0; | | 911 | pipe->running = 0; |
911 | else | | 912 | else |
912 | usbd_start_next(pipe); | | 913 | usbd_start_next(pipe); |
913 | } | | 914 | } |
914 | } | | 915 | } |
915 | | | 916 | |
916 | /* Called with USB lock held. */ | | 917 | /* Called with USB lock held. */ |
917 | usbd_status | | 918 | usbd_status |
918 | usb_insert_transfer(usbd_xfer_handle xfer) | | 919 | usb_insert_transfer(usbd_xfer_handle xfer) |
919 | { | | 920 | { |
920 | usbd_pipe_handle pipe = xfer->pipe; | | 921 | usbd_pipe_handle pipe = xfer->pipe; |
921 | usbd_status err; | | 922 | usbd_status err; |
922 | | | 923 | |
923 | DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d timeout=%d\n", | | 924 | DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d timeout=%d\n", |
924 | pipe, pipe->running, xfer->timeout)); | | 925 | pipe, pipe->running, xfer->timeout)); |
925 | | | 926 | |
926 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); | | 927 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); |
927 | | | 928 | |
928 | #ifdef DIAGNOSTIC | | 929 | #ifdef DIAGNOSTIC |
929 | if (xfer->busy_free != XFER_BUSY) { | | 930 | if (xfer->busy_free != XFER_BUSY) { |
930 | printf("usb_insert_transfer: xfer=%p not busy 0x%08x\n", | | 931 | printf("usb_insert_transfer: xfer=%p not busy 0x%08x\n", |
931 | xfer, xfer->busy_free); | | 932 | xfer, xfer->busy_free); |
932 | return (USBD_INVAL); | | 933 | return (USBD_INVAL); |
933 | } | | 934 | } |
934 | xfer->busy_free = XFER_ONQU; | | 935 | xfer->busy_free = XFER_ONQU; |
935 | #endif | | 936 | #endif |
936 | SIMPLEQ_INSERT_TAIL(&pipe->queue, xfer, next); | | 937 | SIMPLEQ_INSERT_TAIL(&pipe->queue, xfer, next); |
937 | if (pipe->running) | | 938 | if (pipe->running) |
938 | err = USBD_IN_PROGRESS; | | 939 | err = USBD_IN_PROGRESS; |
939 | else { | | 940 | else { |
940 | pipe->running = 1; | | 941 | pipe->running = 1; |
941 | err = USBD_NORMAL_COMPLETION; | | 942 | err = USBD_NORMAL_COMPLETION; |
942 | } | | 943 | } |
943 | return (err); | | 944 | return (err); |
944 | } | | 945 | } |
945 | | | 946 | |
946 | /* Called with USB lock held. */ | | 947 | /* Called with USB lock held. */ |
947 | void | | 948 | void |
948 | usbd_start_next(usbd_pipe_handle pipe) | | 949 | usbd_start_next(usbd_pipe_handle pipe) |
949 | { | | 950 | { |
950 | usbd_xfer_handle xfer; | | 951 | usbd_xfer_handle xfer; |
951 | usbd_status err; | | 952 | usbd_status err; |
952 | | | 953 | |
953 | #ifdef DIAGNOSTIC | | 954 | #ifdef DIAGNOSTIC |
954 | if (pipe == NULL) { | | 955 | if (pipe == NULL) { |
955 | printf("usbd_start_next: pipe == NULL\n"); | | 956 | printf("usbd_start_next: pipe == NULL\n"); |
956 | return; | | 957 | return; |
957 | } | | 958 | } |
958 | if (pipe->methods == NULL || pipe->methods->start == NULL) { | | 959 | if (pipe->methods == NULL || pipe->methods->start == NULL) { |
959 | printf("usbd_start_next: pipe=%p no start method\n", pipe); | | 960 | printf("usbd_start_next: pipe=%p no start method\n", pipe); |
960 | return; | | 961 | return; |
961 | } | | 962 | } |
962 | #endif | | 963 | #endif |
963 | | | 964 | |
964 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); | | 965 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); |
965 | | | 966 | |
966 | /* Get next request in queue. */ | | 967 | /* Get next request in queue. */ |
967 | xfer = SIMPLEQ_FIRST(&pipe->queue); | | 968 | xfer = SIMPLEQ_FIRST(&pipe->queue); |
968 | DPRINTFN(5, ("usbd_start_next: pipe=%p, xfer=%p\n", pipe, xfer)); | | 969 | DPRINTFN(5, ("usbd_start_next: pipe=%p, xfer=%p\n", pipe, xfer)); |
969 | if (xfer == NULL) { | | 970 | if (xfer == NULL) { |
970 | pipe->running = 0; | | 971 | pipe->running = 0; |
971 | } else { | | 972 | } else { |
972 | if (pipe->device->bus->lock) | | 973 | if (pipe->device->bus->lock) |
973 | mutex_exit(pipe->device->bus->lock); | | 974 | mutex_exit(pipe->device->bus->lock); |
974 | err = pipe->methods->start(xfer); | | 975 | err = pipe->methods->start(xfer); |
975 | if (pipe->device->bus->lock) | | 976 | if (pipe->device->bus->lock) |
976 | mutex_enter(pipe->device->bus->lock); | | 977 | mutex_enter(pipe->device->bus->lock); |
977 | if (err != USBD_IN_PROGRESS) { | | 978 | if (err != USBD_IN_PROGRESS) { |
978 | printf("usbd_start_next: error=%d\n", err); | | 979 | printf("usbd_start_next: error=%d\n", err); |
979 | pipe->running = 0; | | 980 | pipe->running = 0; |
980 | /* XXX do what? */ | | 981 | /* XXX do what? */ |
981 | } | | 982 | } |
982 | } | | 983 | } |
983 | | | 984 | |
984 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); | | 985 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); |
985 | } | | 986 | } |
986 | | | 987 | |
987 | usbd_status | | 988 | usbd_status |
988 | usbd_do_request(usbd_device_handle dev, usb_device_request_t *req, void *data) | | 989 | usbd_do_request(usbd_device_handle dev, usb_device_request_t *req, void *data) |
989 | { | | 990 | { |
990 | return (usbd_do_request_flags(dev, req, data, 0, 0, | | 991 | return (usbd_do_request_flags(dev, req, data, 0, 0, |
991 | USBD_DEFAULT_TIMEOUT)); | | 992 | USBD_DEFAULT_TIMEOUT)); |
992 | } | | 993 | } |
993 | | | 994 | |
994 | usbd_status | | 995 | usbd_status |
995 | usbd_do_request_flags(usbd_device_handle dev, usb_device_request_t *req, | | 996 | usbd_do_request_flags(usbd_device_handle dev, usb_device_request_t *req, |
996 | void *data, u_int16_t flags, int *actlen, u_int32_t timo) | | 997 | void *data, u_int16_t flags, int *actlen, u_int32_t timo) |
997 | { | | 998 | { |
998 | return (usbd_do_request_flags_pipe(dev, dev->default_pipe, req, | | 999 | return (usbd_do_request_flags_pipe(dev, dev->default_pipe, req, |
999 | data, flags, actlen, timo)); | | 1000 | data, flags, actlen, timo)); |
1000 | } | | 1001 | } |
1001 | | | 1002 | |
1002 | usbd_status | | 1003 | usbd_status |
1003 | usbd_do_request_flags_pipe(usbd_device_handle dev, usbd_pipe_handle pipe, | | 1004 | usbd_do_request_flags_pipe(usbd_device_handle dev, usbd_pipe_handle pipe, |
1004 | usb_device_request_t *req, void *data, u_int16_t flags, int *actlen, | | 1005 | usb_device_request_t *req, void *data, u_int16_t flags, int *actlen, |
1005 | u_int32_t timeout) | | 1006 | u_int32_t timeout) |
1006 | { | | 1007 | { |
1007 | usbd_xfer_handle xfer; | | 1008 | usbd_xfer_handle xfer; |
1008 | usbd_status err; | | 1009 | usbd_status err; |
1009 | | | 1010 | |
1010 | #ifdef DIAGNOSTIC | | 1011 | #ifdef DIAGNOSTIC |
1011 | if (cpu_intr_p() || cpu_softintr_p()) { | | 1012 | if (cpu_intr_p() || cpu_softintr_p()) { |
1012 | printf("usbd_do_request: not in process context\n"); | | 1013 | printf("usbd_do_request: not in process context\n"); |
1013 | return (USBD_INVAL); | | 1014 | return (USBD_INVAL); |
1014 | } | | 1015 | } |
1015 | #endif | | 1016 | #endif |
1016 | | | 1017 | |
1017 | xfer = usbd_alloc_xfer(dev); | | 1018 | xfer = usbd_alloc_xfer(dev); |
1018 | if (xfer == NULL) | | 1019 | if (xfer == NULL) |
1019 | return (USBD_NOMEM); | | 1020 | return (USBD_NOMEM); |
1020 | usbd_setup_default_xfer(xfer, dev, 0, timeout, req, | | 1021 | usbd_setup_default_xfer(xfer, dev, 0, timeout, req, |
1021 | data, UGETW(req->wLength), flags, 0); | | 1022 | data, UGETW(req->wLength), flags, 0); |
1022 | xfer->pipe = pipe; | | 1023 | xfer->pipe = pipe; |
1023 | err = usbd_sync_transfer(xfer); | | 1024 | err = usbd_sync_transfer(xfer); |
1024 | #if defined(USB_DEBUG) || defined(DIAGNOSTIC) | | 1025 | #if defined(USB_DEBUG) || defined(DIAGNOSTIC) |
1025 | if (xfer->actlen > xfer->length) { | | 1026 | if (xfer->actlen > xfer->length) { |
1026 | DPRINTF(("%s: overrun addr=%d type=0x%02x req=0x" | | 1027 | DPRINTF(("%s: overrun addr=%d type=0x%02x req=0x" |
1027 | "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n", | | 1028 | "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n", |
1028 | __func__, dev->address, xfer->request.bmRequestType, | | 1029 | __func__, dev->address, xfer->request.bmRequestType, |
1029 | xfer->request.bRequest, UGETW(xfer->request.wValue), | | 1030 | xfer->request.bRequest, UGETW(xfer->request.wValue), |
1030 | UGETW(xfer->request.wIndex), | | 1031 | UGETW(xfer->request.wIndex), |
1031 | UGETW(xfer->request.wLength), | | 1032 | UGETW(xfer->request.wLength), |
1032 | xfer->length, xfer->actlen)); | | 1033 | xfer->length, xfer->actlen)); |
1033 | } | | 1034 | } |
1034 | #endif | | 1035 | #endif |
1035 | if (actlen != NULL) | | 1036 | if (actlen != NULL) |
1036 | *actlen = xfer->actlen; | | 1037 | *actlen = xfer->actlen; |
1037 | if (err == USBD_STALLED) { | | 1038 | if (err == USBD_STALLED) { |
1038 | /* | | 1039 | /* |
1039 | * The control endpoint has stalled. Control endpoints | | 1040 | * The control endpoint has stalled. Control endpoints |
1040 | * should not halt, but some may do so anyway so clear | | 1041 | * should not halt, but some may do so anyway so clear |
1041 | * any halt condition. | | 1042 | * any halt condition. |
1042 | */ | | 1043 | */ |
1043 | usb_device_request_t treq; | | 1044 | usb_device_request_t treq; |
1044 | usb_status_t status; | | 1045 | usb_status_t status; |
1045 | u_int16_t s; | | 1046 | u_int16_t s; |
1046 | usbd_status nerr; | | 1047 | usbd_status nerr; |
1047 | | | 1048 | |
1048 | treq.bmRequestType = UT_READ_ENDPOINT; | | 1049 | treq.bmRequestType = UT_READ_ENDPOINT; |
1049 | treq.bRequest = UR_GET_STATUS; | | 1050 | treq.bRequest = UR_GET_STATUS; |
1050 | USETW(treq.wValue, 0); | | 1051 | USETW(treq.wValue, 0); |
1051 | USETW(treq.wIndex, 0); | | 1052 | USETW(treq.wIndex, 0); |
1052 | USETW(treq.wLength, sizeof(usb_status_t)); | | 1053 | USETW(treq.wLength, sizeof(usb_status_t)); |
1053 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, | | 1054 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, |
1054 | &treq, &status,sizeof(usb_status_t), | | 1055 | &treq, &status,sizeof(usb_status_t), |
1055 | 0, 0); | | 1056 | 0, 0); |
1056 | nerr = usbd_sync_transfer(xfer); | | 1057 | nerr = usbd_sync_transfer(xfer); |
1057 | if (nerr) | | 1058 | if (nerr) |
1058 | goto bad; | | 1059 | goto bad; |
1059 | s = UGETW(status.wStatus); | | 1060 | s = UGETW(status.wStatus); |
1060 | DPRINTF(("usbd_do_request: status = 0x%04x\n", s)); | | 1061 | DPRINTF(("usbd_do_request: status = 0x%04x\n", s)); |
1061 | if (!(s & UES_HALT)) | | 1062 | if (!(s & UES_HALT)) |
1062 | goto bad; | | 1063 | goto bad; |
1063 | treq.bmRequestType = UT_WRITE_ENDPOINT; | | 1064 | treq.bmRequestType = UT_WRITE_ENDPOINT; |
1064 | treq.bRequest = UR_CLEAR_FEATURE; | | 1065 | treq.bRequest = UR_CLEAR_FEATURE; |
1065 | USETW(treq.wValue, UF_ENDPOINT_HALT); | | 1066 | USETW(treq.wValue, UF_ENDPOINT_HALT); |
1066 | USETW(treq.wIndex, 0); | | 1067 | USETW(treq.wIndex, 0); |
1067 | USETW(treq.wLength, 0); | | 1068 | USETW(treq.wLength, 0); |
1068 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, | | 1069 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, |
1069 | &treq, &status, 0, 0, 0); | | 1070 | &treq, &status, 0, 0, 0); |
1070 | nerr = usbd_sync_transfer(xfer); | | 1071 | nerr = usbd_sync_transfer(xfer); |
1071 | if (nerr) | | 1072 | if (nerr) |
1072 | goto bad; | | 1073 | goto bad; |
1073 | } | | 1074 | } |
1074 | | | 1075 | |
1075 | bad: | | 1076 | bad: |
1076 | if (err) { | | 1077 | if (err) { |
1077 | DPRINTF(("%s: returning err=%s\n", __func__, usbd_errstr(err))); | | 1078 | DPRINTF(("%s: returning err=%s\n", __func__, usbd_errstr(err))); |
1078 | } | | 1079 | } |
1079 | usbd_free_xfer(xfer); | | 1080 | usbd_free_xfer(xfer); |
1080 | return (err); | | 1081 | return (err); |
1081 | } | | 1082 | } |
1082 | | | 1083 | |
1083 | void | | 1084 | void |
1084 | usbd_do_request_async_cb(usbd_xfer_handle xfer, | | 1085 | usbd_do_request_async_cb(usbd_xfer_handle xfer, |
1085 | usbd_private_handle priv, usbd_status status) | | 1086 | usbd_private_handle priv, usbd_status status) |
1086 | { | | 1087 | { |
1087 | #if defined(USB_DEBUG) || defined(DIAGNOSTIC) | | 1088 | #if defined(USB_DEBUG) || defined(DIAGNOSTIC) |
1088 | if (xfer->actlen > xfer->length) { | | 1089 | if (xfer->actlen > xfer->length) { |
1089 | DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x" | | 1090 | DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x" |
1090 | "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n", | | 1091 | "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n", |
1091 | xfer->pipe->device->address, | | 1092 | xfer->pipe->device->address, |
1092 | xfer->request.bmRequestType, | | 1093 | xfer->request.bmRequestType, |
1093 | xfer->request.bRequest, UGETW(xfer->request.wValue), | | 1094 | xfer->request.bRequest, UGETW(xfer->request.wValue), |
1094 | UGETW(xfer->request.wIndex), | | 1095 | UGETW(xfer->request.wIndex), |
1095 | UGETW(xfer->request.wLength), | | 1096 | UGETW(xfer->request.wLength), |
1096 | xfer->length, xfer->actlen)); | | 1097 | xfer->length, xfer->actlen)); |
1097 | } | | 1098 | } |
1098 | #endif | | 1099 | #endif |
1099 | usbd_free_xfer(xfer); | | 1100 | usbd_free_xfer(xfer); |
1100 | } | | 1101 | } |
1101 | | | 1102 | |
1102 | /* | | 1103 | /* |
1103 | * Execute a request without waiting for completion. | | 1104 | * Execute a request without waiting for completion. |
1104 | * Can be used from interrupt context. | | 1105 | * Can be used from interrupt context. |
1105 | */ | | 1106 | */ |
1106 | usbd_status | | 1107 | usbd_status |
1107 | usbd_do_request_async(usbd_device_handle dev, usb_device_request_t *req, | | 1108 | usbd_do_request_async(usbd_device_handle dev, usb_device_request_t *req, |
1108 | void *data) | | 1109 | void *data) |
1109 | { | | 1110 | { |
1110 | usbd_xfer_handle xfer; | | 1111 | usbd_xfer_handle xfer; |
1111 | usbd_status err; | | 1112 | usbd_status err; |
1112 | | | 1113 | |
1113 | xfer = usbd_alloc_xfer(dev); | | 1114 | xfer = usbd_alloc_xfer(dev); |
1114 | if (xfer == NULL) | | 1115 | if (xfer == NULL) |
1115 | return (USBD_NOMEM); | | 1116 | return (USBD_NOMEM); |
1116 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, req, | | 1117 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, req, |
1117 | data, UGETW(req->wLength), 0, usbd_do_request_async_cb); | | 1118 | data, UGETW(req->wLength), 0, usbd_do_request_async_cb); |
1118 | err = usbd_transfer(xfer); | | 1119 | err = usbd_transfer(xfer); |
1119 | if (err != USBD_IN_PROGRESS) { | | 1120 | if (err != USBD_IN_PROGRESS) { |
1120 | usbd_free_xfer(xfer); | | 1121 | usbd_free_xfer(xfer); |
1121 | return (err); | | 1122 | return (err); |
1122 | } | | 1123 | } |
1123 | return (USBD_NORMAL_COMPLETION); | | 1124 | return (USBD_NORMAL_COMPLETION); |
1124 | } | | 1125 | } |
1125 | | | 1126 | |
1126 | const struct usbd_quirks * | | 1127 | const struct usbd_quirks * |
1127 | usbd_get_quirks(usbd_device_handle dev) | | 1128 | usbd_get_quirks(usbd_device_handle dev) |
1128 | { | | 1129 | { |
1129 | #ifdef DIAGNOSTIC | | 1130 | #ifdef DIAGNOSTIC |
1130 | if (dev == NULL) { | | 1131 | if (dev == NULL) { |
1131 | printf("usbd_get_quirks: dev == NULL\n"); | | 1132 | printf("usbd_get_quirks: dev == NULL\n"); |
1132 | return 0; | | 1133 | return 0; |
1133 | } | | 1134 | } |
1134 | #endif | | 1135 | #endif |
1135 | return (dev->quirks); | | 1136 | return (dev->quirks); |
1136 | } | | 1137 | } |
1137 | | | 1138 | |
1138 | /* XXX do periodic free() of free list */ | | 1139 | /* XXX do periodic free() of free list */ |
1139 | | | 1140 | |
1140 | /* | | 1141 | /* |
1141 | * Called from keyboard driver when in polling mode. | | 1142 | * Called from keyboard driver when in polling mode. |
1142 | */ | | 1143 | */ |
1143 | void | | 1144 | void |
1144 | usbd_dopoll(usbd_interface_handle iface) | | 1145 | usbd_dopoll(usbd_interface_handle iface) |
1145 | { | | 1146 | { |
1146 | iface->device->bus->methods->do_poll(iface->device->bus); | | 1147 | iface->device->bus->methods->do_poll(iface->device->bus); |
1147 | } | | 1148 | } |
1148 | | | 1149 | |
1149 | /* | | 1150 | /* |
1150 | * XXX use this more??? use_polling it touched manually all over | | 1151 | * XXX use this more??? use_polling it touched manually all over |
1151 | */ | | 1152 | */ |
1152 | void | | 1153 | void |
1153 | usbd_set_polling(usbd_device_handle dev, int on) | | 1154 | usbd_set_polling(usbd_device_handle dev, int on) |
1154 | { | | 1155 | { |
1155 | if (on) | | 1156 | if (on) |
1156 | dev->bus->use_polling++; | | 1157 | dev->bus->use_polling++; |
1157 | else | | 1158 | else |
1158 | dev->bus->use_polling--; | | 1159 | dev->bus->use_polling--; |
1159 | | | 1160 | |
1160 | /* Kick the host controller when switching modes */ | | 1161 | /* Kick the host controller when switching modes */ |
1161 | if (dev->bus->lock) | | 1162 | if (dev->bus->lock) |
1162 | mutex_enter(dev->bus->lock); | | 1163 | mutex_enter(dev->bus->lock); |
1163 | (*dev->bus->methods->soft_intr)(dev->bus); | | 1164 | (*dev->bus->methods->soft_intr)(dev->bus); |
1164 | if (dev->bus->lock) | | 1165 | if (dev->bus->lock) |
1165 | mutex_exit(dev->bus->lock); | | 1166 | mutex_exit(dev->bus->lock); |
1166 | | | 1167 | |
1167 | } | | 1168 | } |
1168 | | | 1169 | |
1169 | | | 1170 | |
1170 | usb_endpoint_descriptor_t * | | 1171 | usb_endpoint_descriptor_t * |
1171 | usbd_get_endpoint_descriptor(usbd_interface_handle iface, u_int8_t address) | | 1172 | usbd_get_endpoint_descriptor(usbd_interface_handle iface, u_int8_t address) |
1172 | { | | 1173 | { |
1173 | struct usbd_endpoint *ep; | | 1174 | struct usbd_endpoint *ep; |
1174 | int i; | | 1175 | int i; |
1175 | | | 1176 | |
1176 | for (i = 0; i < iface->idesc->bNumEndpoints; i++) { | | 1177 | for (i = 0; i < iface->idesc->bNumEndpoints; i++) { |
1177 | ep = &iface->endpoints[i]; | | 1178 | ep = &iface->endpoints[i]; |
1178 | if (ep->edesc->bEndpointAddress == address) | | 1179 | if (ep->edesc->bEndpointAddress == address) |
1179 | return (iface->endpoints[i].edesc); | | 1180 | return (iface->endpoints[i].edesc); |
1180 | } | | 1181 | } |
1181 | return (0); | | 1182 | return (0); |
1182 | } | | 1183 | } |
1183 | | | 1184 | |
1184 | /* | | 1185 | /* |
1185 | * usbd_ratecheck() can limit the number of error messages that occurs. | | 1186 | * usbd_ratecheck() can limit the number of error messages that occurs. |
1186 | * When a device is unplugged it may take up to 0.25s for the hub driver | | 1187 | * When a device is unplugged it may take up to 0.25s for the hub driver |
1187 | * to notice it. If the driver continuosly tries to do I/O operations | | 1188 | * to notice it. If the driver continuosly tries to do I/O operations |
1188 | * this can generate a large number of messages. | | 1189 | * this can generate a large number of messages. |
1189 | */ | | 1190 | */ |
1190 | int | | 1191 | int |
1191 | usbd_ratecheck(struct timeval *last) | | 1192 | usbd_ratecheck(struct timeval *last) |
1192 | { | | 1193 | { |
1193 | static struct timeval errinterval = { 0, 250000 }; /* 0.25 s*/ | | 1194 | static struct timeval errinterval = { 0, 250000 }; /* 0.25 s*/ |
1194 | | | 1195 | |
1195 | return (ratecheck(last, &errinterval)); | | 1196 | return (ratecheck(last, &errinterval)); |
1196 | } | | 1197 | } |
1197 | | | 1198 | |
1198 | /* | | 1199 | /* |
1199 | * Search for a vendor/product pair in an array. The item size is | | 1200 | * Search for a vendor/product pair in an array. The item size is |
1200 | * given as an argument. | | 1201 | * given as an argument. |