| @@ -1,1338 +1,1343 @@ | | | @@ -1,1338 +1,1343 @@ |
1 | /* $NetBSD: usbdi.c,v 1.162.2.11 2015/03/05 08:34:47 skrll Exp $ */ | | 1 | /* $NetBSD: usbdi.c,v 1.162.2.12 2015/03/05 08:48:07 skrll 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.162.2.11 2015/03/05 08:34:47 skrll Exp $"); | | 34 | __KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.162.2.12 2015/03/05 08:48:07 skrll Exp $"); |
35 | | | 35 | |
36 | #ifdef _KERNEL_OPT | | 36 | #ifdef _KERNEL_OPT |
37 | #include "opt_usb.h" | | 37 | #include "opt_usb.h" |
38 | #include "opt_compat_netbsd.h" | | 38 | #include "opt_compat_netbsd.h" |
39 | #endif | | 39 | #endif |
40 | | | 40 | |
41 | #include "usb_dma.h" | | 41 | #include "usb_dma.h" |
42 | | | 42 | |
43 | #include <sys/param.h> | | 43 | #include <sys/param.h> |
44 | #include <sys/systm.h> | | 44 | #include <sys/systm.h> |
45 | #include <sys/kernel.h> | | 45 | #include <sys/kernel.h> |
46 | #include <sys/device.h> | | 46 | #include <sys/device.h> |
47 | #include <sys/kmem.h> | | 47 | #include <sys/kmem.h> |
48 | #include <sys/proc.h> | | 48 | #include <sys/proc.h> |
49 | #include <sys/bus.h> | | 49 | #include <sys/bus.h> |
50 | #include <sys/cpu.h> | | 50 | #include <sys/cpu.h> |
51 | | | 51 | |
52 | #include <dev/usb/usb.h> | | 52 | #include <dev/usb/usb.h> |
53 | #include <dev/usb/usbdi.h> | | 53 | #include <dev/usb/usbdi.h> |
54 | #include <dev/usb/usbdi_util.h> | | 54 | #include <dev/usb/usbdi_util.h> |
55 | #include <dev/usb/usbdivar.h> | | 55 | #include <dev/usb/usbdivar.h> |
56 | #include <dev/usb/usb_mem.h> | | 56 | #include <dev/usb/usb_mem.h> |
57 | #include <dev/usb/usb_quirks.h> | | 57 | #include <dev/usb/usb_quirks.h> |
58 | #include <dev/usb/usbhist.h> | | 58 | #include <dev/usb/usbhist.h> |
59 | | | 59 | |
60 | /* UTF-8 encoding stuff */ | | 60 | /* UTF-8 encoding stuff */ |
61 | #include <fs/unicode.h> | | 61 | #include <fs/unicode.h> |
62 | | | 62 | |
63 | extern int usbdebug; | | 63 | extern int usbdebug; |
64 | | | 64 | |
65 | Static usbd_status usbd_ar_pipe(usbd_pipe_handle); | | 65 | Static usbd_status usbd_ar_pipe(usbd_pipe_handle); |
66 | Static void usbd_start_next(usbd_pipe_handle); | | 66 | Static void usbd_start_next(usbd_pipe_handle); |
67 | Static usbd_status usbd_open_pipe_ival | | 67 | Static usbd_status usbd_open_pipe_ival |
68 | (usbd_interface_handle, uint8_t, uint8_t, usbd_pipe_handle *, int); | | 68 | (usbd_interface_handle, uint8_t, uint8_t, usbd_pipe_handle *, int); |
69 | | | 69 | |
70 | static inline int | | 70 | static inline int |
71 | usbd_xfer_isread(usbd_xfer_handle xfer) | | 71 | usbd_xfer_isread(usbd_xfer_handle xfer) |
72 | { | | 72 | { |
73 | if (xfer->ux_rqflags & URQ_REQUEST) | | 73 | if (xfer->ux_rqflags & URQ_REQUEST) |
74 | return xfer->ux_request.bmRequestType & UT_READ; | | 74 | return xfer->ux_request.bmRequestType & UT_READ; |
75 | else | | 75 | else |
76 | return (xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress & | | 76 | return (xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress & |
77 | UE_DIR_IN); | | 77 | UE_DIR_IN); |
78 | } | | 78 | } |
79 | | | 79 | |
80 | #if defined(USB_DEBUG) | | 80 | #if defined(USB_DEBUG) |
81 | void | | 81 | void |
82 | usbd_dump_iface(struct usbd_interface *iface) | | 82 | usbd_dump_iface(struct usbd_interface *iface) |
83 | { | | 83 | { |
84 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 84 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
85 | | | 85 | |
86 | USBHIST_LOG(usbdebug, "iface %p", iface, 0, 0, 0); | | 86 | USBHIST_LOG(usbdebug, "iface %p", iface, 0, 0, 0); |
87 | if (iface == NULL) | | 87 | if (iface == NULL) |
88 | return; | | 88 | return; |
89 | USBHIST_LOG(usbdebug, " device = %p idesc = %p index = %d", | | 89 | USBHIST_LOG(usbdebug, " device = %p idesc = %p index = %d", |
90 | iface->ui_dev, iface->ui_idesc, iface->ui_index, 0); | | 90 | iface->ui_dev, iface->ui_idesc, iface->ui_index, 0); |
91 | USBHIST_LOG(usbdebug, " altindex=%d priv=%p", | | 91 | USBHIST_LOG(usbdebug, " altindex=%d priv=%p", |
92 | iface->ui_altindex, iface->ui_priv, 0, 0); | | 92 | iface->ui_altindex, iface->ui_priv, 0, 0); |
93 | } | | 93 | } |
94 | | | 94 | |
95 | void | | 95 | void |
96 | usbd_dump_device(struct usbd_device *dev) | | 96 | usbd_dump_device(struct usbd_device *dev) |
97 | { | | 97 | { |
98 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 98 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
99 | | | 99 | |
100 | USBHIST_LOG(usbdebug, "dev = %p", dev, 0, 0, 0); | | 100 | USBHIST_LOG(usbdebug, "dev = %p", dev, 0, 0, 0); |
101 | if (dev == NULL) | | 101 | if (dev == NULL) |
102 | return; | | 102 | return; |
103 | USBHIST_LOG(usbdebug, " bus = %p default_pipe = %p", | | 103 | USBHIST_LOG(usbdebug, " bus = %p default_pipe = %p", |
104 | dev->ud_bus, dev->ud_pipe0, 0, 0); | | 104 | dev->ud_bus, dev->ud_pipe0, 0, 0); |
105 | USBHIST_LOG(usbdebug, " address = %d config = %d depth = %d ", | | 105 | USBHIST_LOG(usbdebug, " address = %d config = %d depth = %d ", |
106 | dev->ud_addr, dev->ud_config, dev->ud_depth, 0); | | 106 | dev->ud_addr, dev->ud_config, dev->ud_depth, 0); |
107 | USBHIST_LOG(usbdebug, " speed = %d self_powered = %d " | | 107 | USBHIST_LOG(usbdebug, " speed = %d self_powered = %d " |
108 | "power = %d langid = %d", | | 108 | "power = %d langid = %d", |
109 | dev->ud_speed, dev->ud_selfpowered, dev->ud_power, dev->ud_langid); | | 109 | dev->ud_speed, dev->ud_selfpowered, dev->ud_power, dev->ud_langid); |
110 | } | | 110 | } |
111 | | | 111 | |
112 | void | | 112 | void |
113 | usbd_dump_endpoint(struct usbd_endpoint *endp) | | 113 | usbd_dump_endpoint(struct usbd_endpoint *endp) |
114 | { | | 114 | { |
115 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 115 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
116 | | | 116 | |
117 | USBHIST_LOG(usbdebug, "endp = %p", endp, 0, 0, 0); | | 117 | USBHIST_LOG(usbdebug, "endp = %p", endp, 0, 0, 0); |
118 | if (endp == NULL) | | 118 | if (endp == NULL) |
119 | return; | | 119 | return; |
120 | USBHIST_LOG(usbdebug, " edesc = %p refcnt = %d", | | 120 | USBHIST_LOG(usbdebug, " edesc = %p refcnt = %d", |
121 | endp->ue_edesc, endp->ue_refcnt, 0, 0); | | 121 | endp->ue_edesc, endp->ue_refcnt, 0, 0); |
122 | if (endp->ue_edesc) | | 122 | if (endp->ue_edesc) |
123 | USBHIST_LOG(usbdebug, " bEndpointAddress=0x%02x", | | 123 | USBHIST_LOG(usbdebug, " bEndpointAddress=0x%02x", |
124 | endp->ue_edesc->bEndpointAddress, 0, 0, 0); | | 124 | endp->ue_edesc->bEndpointAddress, 0, 0, 0); |
125 | } | | 125 | } |
126 | | | 126 | |
127 | void | | 127 | void |
128 | usbd_dump_queue(usbd_pipe_handle pipe) | | 128 | usbd_dump_queue(usbd_pipe_handle pipe) |
129 | { | | 129 | { |
130 | usbd_xfer_handle xfer; | | 130 | usbd_xfer_handle xfer; |
131 | | | 131 | |
132 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 132 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
133 | | | 133 | |
134 | USBHIST_LOG(usbdebug, "pipe = %p", pipe, 0, 0, 0); | | 134 | USBHIST_LOG(usbdebug, "pipe = %p", pipe, 0, 0, 0); |
135 | SIMPLEQ_FOREACH(xfer, &pipe->up_queue, ux_next) { | | 135 | SIMPLEQ_FOREACH(xfer, &pipe->up_queue, ux_next) { |
136 | USBHIST_LOG(usbdebug, " xfer = %p", xfer, 0, 0, 0); | | 136 | USBHIST_LOG(usbdebug, " xfer = %p", xfer, 0, 0, 0); |
137 | } | | 137 | } |
138 | } | | 138 | } |
139 | | | 139 | |
140 | void | | 140 | void |
141 | usbd_dump_pipe(usbd_pipe_handle pipe) | | 141 | usbd_dump_pipe(usbd_pipe_handle pipe) |
142 | { | | 142 | { |
143 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 143 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
144 | | | 144 | |
145 | USBHIST_LOG(usbdebug, "pipe = %p", pipe, 0, 0, 0); | | 145 | USBHIST_LOG(usbdebug, "pipe = %p", pipe, 0, 0, 0); |
146 | if (pipe == NULL) | | 146 | if (pipe == NULL) |
147 | return; | | 147 | return; |
148 | usbd_dump_iface(pipe->up_iface); | | 148 | usbd_dump_iface(pipe->up_iface); |
149 | usbd_dump_device(pipe->up_dev); | | 149 | usbd_dump_device(pipe->up_dev); |
150 | usbd_dump_endpoint(pipe->up_endpoint); | | 150 | usbd_dump_endpoint(pipe->up_endpoint); |
151 | USBHIST_LOG(usbdebug, "(usbd_dump_pipe)", 0, 0, 0, 0); | | 151 | USBHIST_LOG(usbdebug, "(usbd_dump_pipe)", 0, 0, 0, 0); |
152 | USBHIST_LOG(usbdebug, " refcnt = %d running = %d aborting = %d", | | 152 | USBHIST_LOG(usbdebug, " refcnt = %d running = %d aborting = %d", |
153 | pipe->up_refcnt, pipe->up_running, pipe->up_aborting, 0); | | 153 | pipe->up_refcnt, pipe->up_running, pipe->up_aborting, 0); |
154 | USBHIST_LOG(usbdebug, " intrxfer = %p, repeat = %d, interval = %d", | | 154 | USBHIST_LOG(usbdebug, " intrxfer = %p, repeat = %d, interval = %d", |
155 | pipe->up_intrxfer, pipe->up_repeat, pipe->up_interval, 0); | | 155 | pipe->up_intrxfer, pipe->up_repeat, pipe->up_interval, 0); |
156 | } | | 156 | } |
157 | #endif | | 157 | #endif |
158 | | | 158 | |
159 | usbd_status | | 159 | usbd_status |
160 | usbd_open_pipe(usbd_interface_handle iface, uint8_t address, | | 160 | usbd_open_pipe(usbd_interface_handle iface, uint8_t address, |
161 | uint8_t flags, usbd_pipe_handle *pipe) | | 161 | uint8_t flags, usbd_pipe_handle *pipe) |
162 | { | | 162 | { |
163 | return (usbd_open_pipe_ival(iface, address, flags, pipe, | | 163 | return (usbd_open_pipe_ival(iface, address, flags, pipe, |
164 | USBD_DEFAULT_INTERVAL)); | | 164 | USBD_DEFAULT_INTERVAL)); |
165 | } | | 165 | } |
166 | | | 166 | |
167 | usbd_status | | 167 | usbd_status |
168 | usbd_open_pipe_ival(usbd_interface_handle iface, uint8_t address, | | 168 | usbd_open_pipe_ival(usbd_interface_handle iface, uint8_t address, |
169 | uint8_t flags, usbd_pipe_handle *pipe, int ival) | | 169 | uint8_t flags, usbd_pipe_handle *pipe, int ival) |
170 | { | | 170 | { |
171 | usbd_pipe_handle p; | | 171 | usbd_pipe_handle p; |
172 | struct usbd_endpoint *ep; | | 172 | struct usbd_endpoint *ep; |
173 | usbd_status err; | | 173 | usbd_status err; |
174 | int i; | | 174 | int i; |
175 | | | 175 | |
176 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 176 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
177 | | | 177 | |
178 | USBHIST_LOG(usbdebug, "iface = %p address = 0x%x flags = 0x%x", | | 178 | USBHIST_LOG(usbdebug, "iface = %p address = 0x%x flags = 0x%x", |
179 | iface, address, flags, 0); | | 179 | iface, address, flags, 0); |
180 | | | 180 | |
181 | for (i = 0; i < iface->ui_idesc->bNumEndpoints; i++) { | | 181 | for (i = 0; i < iface->ui_idesc->bNumEndpoints; i++) { |
182 | ep = &iface->ui_endpoints[i]; | | 182 | ep = &iface->ui_endpoints[i]; |
183 | if (ep->ue_edesc == NULL) | | 183 | if (ep->ue_edesc == NULL) |
184 | return USBD_IOERROR; | | 184 | return USBD_IOERROR; |
185 | if (ep->ue_edesc->bEndpointAddress == address) | | 185 | if (ep->ue_edesc->bEndpointAddress == address) |
186 | goto found; | | 186 | goto found; |
187 | } | | 187 | } |
188 | return USBD_BAD_ADDRESS; | | 188 | return USBD_BAD_ADDRESS; |
189 | found: | | 189 | found: |
190 | if ((flags & USBD_EXCLUSIVE_USE) && ep->ue_refcnt != 0) | | 190 | if ((flags & USBD_EXCLUSIVE_USE) && ep->ue_refcnt != 0) |
191 | return USBD_IN_USE; | | 191 | return USBD_IN_USE; |
192 | err = usbd_setup_pipe_flags(iface->ui_dev, iface, ep, ival, &p, flags); | | 192 | err = usbd_setup_pipe_flags(iface->ui_dev, iface, ep, ival, &p, flags); |
193 | if (err) | | 193 | if (err) |
194 | return err; | | 194 | return err; |
195 | LIST_INSERT_HEAD(&iface->ui_pipes, p, up_next); | | 195 | LIST_INSERT_HEAD(&iface->ui_pipes, p, up_next); |
196 | *pipe = p; | | 196 | *pipe = p; |
197 | return USBD_NORMAL_COMPLETION; | | 197 | return USBD_NORMAL_COMPLETION; |
198 | } | | 198 | } |
199 | | | 199 | |
200 | usbd_status | | 200 | usbd_status |
201 | usbd_open_pipe_intr(usbd_interface_handle iface, uint8_t address, | | 201 | usbd_open_pipe_intr(usbd_interface_handle iface, uint8_t address, |
202 | uint8_t flags, usbd_pipe_handle *pipe, | | 202 | uint8_t flags, usbd_pipe_handle *pipe, |
203 | usbd_private_handle priv, void *buffer, uint32_t len, | | 203 | usbd_private_handle priv, void *buffer, uint32_t len, |
204 | usbd_callback cb, int ival) | | 204 | usbd_callback cb, int ival) |
205 | { | | 205 | { |
206 | usbd_status err; | | 206 | usbd_status err; |
207 | usbd_xfer_handle xfer; | | 207 | usbd_xfer_handle xfer; |
208 | usbd_pipe_handle ipipe; | | 208 | usbd_pipe_handle ipipe; |
209 | | | 209 | |
210 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 210 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
211 | | | 211 | |
212 | USBHIST_LOG(usbdebug, "address = 0x%x flags = 0x%x len = %d", | | 212 | USBHIST_LOG(usbdebug, "address = 0x%x flags = 0x%x len = %d", |
213 | address, flags, len, 0); | | 213 | address, flags, len, 0); |
214 | | | 214 | |
215 | err = usbd_open_pipe_ival(iface, address, | | 215 | err = usbd_open_pipe_ival(iface, address, |
216 | USBD_EXCLUSIVE_USE | (flags & USBD_MPSAFE), | | 216 | USBD_EXCLUSIVE_USE | (flags & USBD_MPSAFE), |
217 | &ipipe, ival); | | 217 | &ipipe, ival); |
218 | if (err) | | 218 | if (err) |
219 | return err; | | 219 | return err; |
220 | xfer = usbd_alloc_xfer(iface->ui_dev); | | 220 | xfer = usbd_alloc_xfer(iface->ui_dev); |
221 | if (xfer == NULL) { | | 221 | if (xfer == NULL) { |
222 | err = USBD_NOMEM; | | 222 | err = USBD_NOMEM; |
223 | goto bad1; | | 223 | goto bad1; |
224 | } | | 224 | } |
225 | void *buf = usbd_alloc_buffer(xfer, len); | | 225 | void *buf = usbd_alloc_buffer(xfer, len); |
226 | if (buf == NULL) { | | 226 | if (buf == NULL) { |
227 | err = ENOMEM; | | 227 | err = ENOMEM; |
228 | goto bad2; | | 228 | goto bad2; |
229 | } | | 229 | } |
230 | | | 230 | |
231 | usbd_setup_xfer(xfer, ipipe, priv, buffer, len, flags, | | 231 | usbd_setup_xfer(xfer, ipipe, priv, buffer, len, flags, |
232 | USBD_NO_TIMEOUT, cb); | | 232 | USBD_NO_TIMEOUT, cb); |
233 | ipipe->up_intrxfer = xfer; | | 233 | ipipe->up_intrxfer = xfer; |
| | | 234 | ipipe->up_intrbuf = buf; |
234 | ipipe->up_repeat = 1; | | 235 | ipipe->up_repeat = 1; |
235 | err = usbd_transfer(xfer); | | 236 | err = usbd_transfer(xfer); |
236 | *pipe = ipipe; | | 237 | *pipe = ipipe; |
237 | if (err != USBD_IN_PROGRESS) | | 238 | if (err != USBD_IN_PROGRESS) |
238 | goto bad3; | | 239 | goto bad3; |
239 | return USBD_NORMAL_COMPLETION; | | 240 | return USBD_NORMAL_COMPLETION; |
240 | | | 241 | |
241 | bad3: | | 242 | bad3: |
242 | ipipe->up_intrxfer = NULL; | | 243 | ipipe->up_intrxfer = NULL; |
243 | ipipe->up_repeat = 0; | | 244 | ipipe->up_repeat = 0; |
244 | bad2: | | 245 | bad2: |
245 | usbd_free_xfer(xfer); | | 246 | usbd_free_xfer(xfer); |
246 | bad1: | | 247 | bad1: |
247 | usbd_close_pipe(ipipe); | | 248 | usbd_close_pipe(ipipe); |
248 | return err; | | 249 | return err; |
249 | } | | 250 | } |
250 | | | 251 | |
251 | usbd_status | | 252 | usbd_status |
252 | usbd_close_pipe(usbd_pipe_handle pipe) | | 253 | usbd_close_pipe(usbd_pipe_handle pipe) |
253 | { | | 254 | { |
254 | | | 255 | |
255 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 256 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
256 | | | 257 | |
257 | #ifdef DIAGNOSTIC | | 258 | #ifdef DIAGNOSTIC |
258 | if (pipe == NULL) { | | 259 | if (pipe == NULL) { |
259 | USBHIST_LOG(usbdebug, "pipe == NULL", 0, 0, 0, 0); | | 260 | USBHIST_LOG(usbdebug, "pipe == NULL", 0, 0, 0, 0); |
260 | return USBD_NORMAL_COMPLETION; | | 261 | return USBD_NORMAL_COMPLETION; |
261 | } | | 262 | } |
262 | #endif | | 263 | #endif |
263 | | | 264 | |
264 | usbd_lock_pipe(pipe); | | 265 | usbd_lock_pipe(pipe); |
265 | if (--pipe->up_refcnt != 0) { | | 266 | if (--pipe->up_refcnt != 0) { |
266 | usbd_unlock_pipe(pipe); | | 267 | usbd_unlock_pipe(pipe); |
267 | return USBD_NORMAL_COMPLETION; | | 268 | return USBD_NORMAL_COMPLETION; |
268 | } | | 269 | } |
269 | if (! SIMPLEQ_EMPTY(&pipe->up_queue)) { | | 270 | if (! SIMPLEQ_EMPTY(&pipe->up_queue)) { |
270 | usbd_unlock_pipe(pipe); | | 271 | usbd_unlock_pipe(pipe); |
271 | return USBD_PENDING_REQUESTS; | | 272 | return USBD_PENDING_REQUESTS; |
272 | } | | 273 | } |
273 | LIST_REMOVE(pipe, up_next); | | 274 | LIST_REMOVE(pipe, up_next); |
274 | pipe->up_endpoint->ue_refcnt--; | | 275 | pipe->up_endpoint->ue_refcnt--; |
275 | pipe->up_methods->upm_close(pipe); | | 276 | pipe->up_methods->upm_close(pipe); |
276 | usbd_unlock_pipe(pipe); | | 277 | usbd_unlock_pipe(pipe); |
277 | if (pipe->up_intrxfer != NULL) | | 278 | if (pipe->up_intrxfer != NULL) { |
278 | usbd_free_xfer(pipe->up_intrxfer); | | 279 | usbd_free_xfer(pipe->up_intrxfer); |
| | | 280 | usbd_free_buffer(pipe->up_intrbuf); |
| | | 281 | } |
279 | kmem_free(pipe, pipe->up_dev->ud_bus->ub_pipesize); | | 282 | kmem_free(pipe, pipe->up_dev->ud_bus->ub_pipesize); |
280 | return USBD_NORMAL_COMPLETION; | | 283 | return USBD_NORMAL_COMPLETION; |
281 | } | | 284 | } |
282 | | | 285 | |
283 | usbd_status | | 286 | usbd_status |
284 | usbd_transfer(usbd_xfer_handle xfer) | | 287 | usbd_transfer(usbd_xfer_handle xfer) |
285 | { | | 288 | { |
286 | usbd_pipe_handle pipe = xfer->ux_pipe; | | 289 | usbd_pipe_handle pipe = xfer->ux_pipe; |
287 | usbd_status err; | | 290 | usbd_status err; |
288 | unsigned int size, flags; | | 291 | unsigned int size, flags; |
289 | | | 292 | |
290 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 293 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
291 | | | 294 | |
292 | USBHIST_LOG(usbdebug, | | 295 | USBHIST_LOG(usbdebug, |
293 | "xfer = %p, flags = %#x, pipe = %p, running = %d", | | 296 | "xfer = %p, flags = %#x, pipe = %p, running = %d", |
294 | xfer, xfer->ux_flags, pipe, pipe->up_running); | | 297 | xfer, xfer->ux_flags, pipe, pipe->up_running); |
295 | | | 298 | |
296 | #ifdef USB_DEBUG | | 299 | #ifdef USB_DEBUG |
297 | if (usbdebug > 5) | | 300 | if (usbdebug > 5) |
298 | usbd_dump_queue(pipe); | | 301 | usbd_dump_queue(pipe); |
299 | #endif | | 302 | #endif |
300 | xfer->ux_done = 0; | | 303 | xfer->ux_done = 0; |
301 | | | 304 | |
302 | if (pipe->up_aborting) { | | 305 | if (pipe->up_aborting) { |
303 | USBHIST_LOG(usbdebug, "<- done xfer %p, aborting", xfer, 0, 0, | | 306 | USBHIST_LOG(usbdebug, "<- done xfer %p, aborting", xfer, 0, 0, |
304 | 0); | | 307 | 0); |
305 | return USBD_CANCELLED; | | 308 | return USBD_CANCELLED; |
306 | } | | 309 | } |
307 | | | 310 | |
308 | KASSERT(xfer->ux_length == 0 || xfer->ux_buf != NULL); | | 311 | KASSERT(xfer->ux_length == 0 || xfer->ux_buf != NULL); |
309 | | | 312 | |
310 | size = xfer->ux_length; | | 313 | size = xfer->ux_length; |
311 | flags = xfer->ux_flags; | | 314 | flags = xfer->ux_flags; |
312 | | | 315 | |
313 | struct usbd_bus *bus = pipe->up_dev->ud_bus; | | 316 | struct usbd_bus *bus = pipe->up_dev->ud_bus; |
314 | | | 317 | |
315 | if (bus->ub_usedma) { | | 318 | if (bus->ub_usedma) { |
316 | /* | | 319 | /* |
317 | * Copy data if not using the xfer buffer. isoc transfers | | 320 | * Copy data if not using the xfer buffer. isoc transfers |
318 | * always use DMA buffer, i.e. buffer == NULL | | 321 | * always use DMA buffer, i.e. buffer == NULL |
319 | */ | | 322 | */ |
320 | if (xfer->ux_buffer == NULL) { | | 323 | if (xfer->ux_buffer == NULL) { |
321 | xfer->ux_buffer = xfer->ux_buf; | | 324 | xfer->ux_buffer = xfer->ux_buf; |
322 | } else if (xfer->ux_buffer != xfer->ux_buf) { | | 325 | } else if (xfer->ux_buffer != xfer->ux_buf) { |
323 | memcpy(xfer->ux_buf, xfer->ux_buffer, size); | | 326 | memcpy(xfer->ux_buf, xfer->ux_buffer, size); |
324 | } | | 327 | } |
325 | } else { | | 328 | } else { |
326 | xfer->ux_buffer = xfer->ux_buf; | | 329 | xfer->ux_buffer = xfer->ux_buf; |
327 | } | | 330 | } |
328 | | | 331 | |
329 | /* xfer is not valid after the transfer method unless synchronous */ | | 332 | /* xfer is not valid after the transfer method unless synchronous */ |
330 | err = pipe->up_methods->upm_transfer(xfer); | | 333 | err = pipe->up_methods->upm_transfer(xfer); |
331 | USBHIST_LOG(usbdebug, "<- done transfer %p, err = %d", xfer, err, 0, 0); | | 334 | USBHIST_LOG(usbdebug, "<- done transfer %p, err = %d", xfer, err, 0, 0); |
332 | | | 335 | |
333 | if (!(flags & USBD_SYNCHRONOUS)) { | | 336 | if (!(flags & USBD_SYNCHRONOUS)) { |
334 | USBHIST_LOG(usbdebug, "<- done xfer %p, not sync", xfer, 0, 0, | | 337 | USBHIST_LOG(usbdebug, "<- done xfer %p, not sync", xfer, 0, 0, |
335 | 0); | | 338 | 0); |
336 | return err; | | 339 | return err; |
337 | } | | 340 | } |
338 | | | 341 | |
339 | /* Sync transfer, wait for completion. */ | | 342 | /* Sync transfer, wait for completion. */ |
340 | if (err != USBD_IN_PROGRESS) { | | 343 | if (err != USBD_IN_PROGRESS) { |
341 | USBHIST_LOG(usbdebug, "<- done xfer %p, not in progress", xfer, | | 344 | USBHIST_LOG(usbdebug, "<- done xfer %p, not in progress", xfer, |
342 | 0, 0, 0); | | 345 | 0, 0, 0); |
343 | return err; | | 346 | return err; |
344 | } | | 347 | } |
345 | usbd_lock_pipe(pipe); | | 348 | usbd_lock_pipe(pipe); |
346 | while (!xfer->ux_done) { | | 349 | while (!xfer->ux_done) { |
347 | if (pipe->up_dev->ud_bus->ub_usepolling) | | 350 | if (pipe->up_dev->ud_bus->ub_usepolling) |
348 | panic("usbd_transfer: not done"); | | 351 | panic("usbd_transfer: not done"); |
349 | USBHIST_LOG(usbdebug, "<- sleeping on xfer %p", xfer, 0, 0, 0); | | 352 | USBHIST_LOG(usbdebug, "<- sleeping on xfer %p", xfer, 0, 0, 0); |
350 | | | 353 | |
351 | err = 0; | | 354 | err = 0; |
352 | if ((flags & USBD_SYNCHRONOUS_SIG) != 0) { | | 355 | if ((flags & USBD_SYNCHRONOUS_SIG) != 0) { |
353 | err = cv_wait_sig(&xfer->ux_cv, pipe->up_dev->ud_bus->ub_lock); | | 356 | err = cv_wait_sig(&xfer->ux_cv, pipe->up_dev->ud_bus->ub_lock); |
354 | } else { | | 357 | } else { |
355 | cv_wait(&xfer->ux_cv, pipe->up_dev->ud_bus->ub_lock); | | 358 | cv_wait(&xfer->ux_cv, pipe->up_dev->ud_bus->ub_lock); |
356 | } | | 359 | } |
357 | if (err) { | | 360 | if (err) { |
358 | if (!xfer->ux_done) | | 361 | if (!xfer->ux_done) |
359 | pipe->up_methods->upm_abort(xfer); | | 362 | pipe->up_methods->upm_abort(xfer); |
360 | break; | | 363 | break; |
361 | } | | 364 | } |
362 | } | | 365 | } |
363 | usbd_unlock_pipe(pipe); | | 366 | usbd_unlock_pipe(pipe); |
364 | return xfer->ux_status; | | 367 | return xfer->ux_status; |
365 | } | | 368 | } |
366 | | | 369 | |
367 | /* Like usbd_transfer(), but waits for completion. */ | | 370 | /* Like usbd_transfer(), but waits for completion. */ |
368 | usbd_status | | 371 | usbd_status |
369 | usbd_sync_transfer(usbd_xfer_handle xfer) | | 372 | usbd_sync_transfer(usbd_xfer_handle xfer) |
370 | { | | 373 | { |
371 | xfer->ux_flags |= USBD_SYNCHRONOUS; | | 374 | xfer->ux_flags |= USBD_SYNCHRONOUS; |
372 | return usbd_transfer(xfer); | | 375 | return usbd_transfer(xfer); |
373 | } | | 376 | } |
374 | | | 377 | |
375 | /* Like usbd_transfer(), but waits for completion and listens for signals. */ | | 378 | /* Like usbd_transfer(), but waits for completion and listens for signals. */ |
376 | usbd_status | | 379 | usbd_status |
377 | usbd_sync_transfer_sig(usbd_xfer_handle xfer) | | 380 | usbd_sync_transfer_sig(usbd_xfer_handle xfer) |
378 | { | | 381 | { |
379 | xfer->ux_flags |= USBD_SYNCHRONOUS | USBD_SYNCHRONOUS_SIG; | | 382 | xfer->ux_flags |= USBD_SYNCHRONOUS | USBD_SYNCHRONOUS_SIG; |
380 | return usbd_transfer(xfer); | | 383 | return usbd_transfer(xfer); |
381 | } | | 384 | } |
382 | | | 385 | |
383 | void * | | 386 | void * |
384 | usbd_alloc_buffer(usbd_xfer_handle xfer, uint32_t size) | | 387 | usbd_alloc_buffer(usbd_xfer_handle xfer, uint32_t size) |
385 | { | | 388 | { |
386 | | | 389 | |
387 | KASSERT(xfer->ux_buf == NULL); | | 390 | KASSERT(xfer->ux_buf == NULL); |
388 | KASSERT(size != 0); | | 391 | KASSERT(size != 0); |
389 | | | 392 | |
390 | xfer->ux_bufsize = 0; | | 393 | xfer->ux_bufsize = 0; |
391 | #if NUSB_DMA > 0 | | 394 | #if NUSB_DMA > 0 |
392 | struct usbd_bus *bus = xfer->ux_dev->ud_bus; | | 395 | struct usbd_bus *bus = xfer->ux_dev->ud_bus; |
393 | | | 396 | |
394 | if (bus->ub_usedma) { | | 397 | if (bus->ub_usedma) { |
395 | usb_dma_t *dmap = &xfer->ux_dmabuf; | | 398 | usb_dma_t *dmap = &xfer->ux_dmabuf; |
396 | | | 399 | |
397 | int err = usb_allocmem_flags(bus, size, 0, dmap, bus->ub_dmaflags); | | 400 | int err = usb_allocmem_flags(bus, size, 0, dmap, bus->ub_dmaflags); |
398 | if (err) { | | 401 | if (err) { |
399 | return NULL; | | 402 | return NULL; |
400 | } | | 403 | } |
401 | xfer->ux_buf = KERNADDR(&xfer->ux_dmabuf, 0); | | 404 | xfer->ux_buf = KERNADDR(&xfer->ux_dmabuf, 0); |
402 | xfer->ux_bufsize = size; | | 405 | xfer->ux_bufsize = size; |
403 | | | 406 | |
404 | return xfer->ux_buf; | | 407 | return xfer->ux_buf; |
405 | } | | 408 | } |
406 | #endif | | 409 | #endif |
407 | KASSERT(xfer->ux_dev->ud_bus->ub_usedma == false); | | 410 | KASSERT(xfer->ux_dev->ud_bus->ub_usedma == false); |
408 | xfer->ux_buf = kmem_alloc(size, KM_SLEEP); | | 411 | xfer->ux_buf = kmem_alloc(size, KM_SLEEP); |
409 | | | 412 | |
410 | if (xfer->ux_buf != NULL) { | | 413 | if (xfer->ux_buf != NULL) { |
411 | xfer->ux_bufsize = size; | | 414 | xfer->ux_bufsize = size; |
412 | } | | 415 | } |
413 | | | 416 | |
414 | return xfer->ux_buf; | | 417 | return xfer->ux_buf; |
415 | } | | 418 | } |
416 | | | 419 | |
417 | void | | 420 | void |
418 | usbd_free_buffer(usbd_xfer_handle xfer) | | 421 | usbd_free_buffer(usbd_xfer_handle xfer) |
419 | { | | 422 | { |
420 | KASSERT(xfer->ux_buf != NULL); | | 423 | KASSERT(xfer->ux_buf != NULL); |
421 | KASSERT(xfer->ux_bufsize != 0); | | 424 | KASSERT(xfer->ux_bufsize != 0); |
422 | | | 425 | |
423 | void *buf = xfer->ux_buf; | | 426 | void *buf = xfer->ux_buf; |
424 | uint32_t size = xfer->ux_bufsize; | | 427 | uint32_t size = xfer->ux_bufsize; |
425 | | | 428 | |
426 | xfer->ux_buf = NULL; | | 429 | xfer->ux_buf = NULL; |
427 | xfer->ux_bufsize = 0; | | 430 | xfer->ux_bufsize = 0; |
428 | | | 431 | |
429 | #if NUSB_DMA > 0 | | 432 | #if NUSB_DMA > 0 |
430 | struct usbd_bus *bus = xfer->ux_dev->ud_bus; | | 433 | struct usbd_bus *bus = xfer->ux_dev->ud_bus; |
431 | | | 434 | |
432 | if (bus->ub_usedma) { | | 435 | if (bus->ub_usedma) { |
433 | usb_dma_t *dmap = &xfer->ux_dmabuf; | | 436 | usb_dma_t *dmap = &xfer->ux_dmabuf; |
434 | | | 437 | |
435 | usb_freemem(bus, dmap); | | 438 | usb_freemem(bus, dmap); |
436 | return; | | 439 | return; |
437 | } | | 440 | } |
438 | #endif | | 441 | #endif |
439 | KASSERT(xfer->ux_dev->ud_bus->ub_usedma == false); | | 442 | KASSERT(xfer->ux_dev->ud_bus->ub_usedma == false); |
440 | | | 443 | |
441 | kmem_free(buf, size); | | 444 | kmem_free(buf, size); |
442 | } | | 445 | } |
443 | | | 446 | |
444 | void * | | 447 | void * |
445 | usbd_get_buffer(usbd_xfer_handle xfer) | | 448 | usbd_get_buffer(usbd_xfer_handle xfer) |
446 | { | | 449 | { |
447 | | | 450 | |
448 | return xfer->ux_buf; | | 451 | return xfer->ux_buf; |
449 | } | | 452 | } |
450 | | | 453 | |
451 | usbd_xfer_handle | | 454 | usbd_xfer_handle |
452 | usbd_alloc_xfer(usbd_device_handle dev) | | 455 | usbd_alloc_xfer(usbd_device_handle dev) |
453 | { | | 456 | { |
454 | usbd_xfer_handle xfer; | | 457 | usbd_xfer_handle xfer; |
455 | | | 458 | |
456 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 459 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
457 | | | 460 | |
458 | ASSERT_SLEEPABLE(); | | 461 | ASSERT_SLEEPABLE(); |
459 | | | 462 | |
460 | xfer = dev->ud_bus->ub_methods->ubm_allocx(dev->ud_bus); | | 463 | xfer = dev->ud_bus->ub_methods->ubm_allocx(dev->ud_bus); |
461 | if (xfer == NULL) | | 464 | if (xfer == NULL) |
462 | return NULL; | | 465 | return NULL; |
463 | xfer->ux_dev = dev; | | 466 | xfer->ux_dev = dev; |
464 | callout_init(&xfer->ux_callout, CALLOUT_MPSAFE); | | 467 | callout_init(&xfer->ux_callout, CALLOUT_MPSAFE); |
465 | cv_init(&xfer->ux_cv, "usbxfer"); | | 468 | cv_init(&xfer->ux_cv, "usbxfer"); |
466 | cv_init(&xfer->ux_hccv, "usbhcxfer"); | | 469 | cv_init(&xfer->ux_hccv, "usbhcxfer"); |
467 | | | 470 | |
468 | USBHIST_LOG(usbdebug, "returns %p", xfer, 0, 0, 0); | | 471 | USBHIST_LOG(usbdebug, "returns %p", xfer, 0, 0, 0); |
469 | | | 472 | |
470 | return xfer; | | 473 | return xfer; |
471 | } | | 474 | } |
472 | | | 475 | |
473 | usbd_status | | 476 | usbd_status |
474 | usbd_free_xfer(usbd_xfer_handle xfer) | | 477 | usbd_free_xfer(usbd_xfer_handle xfer) |
475 | { | | 478 | { |
476 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 479 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
477 | | | 480 | |
478 | USBHIST_LOG(usbdebug, "%p", xfer, 0, 0, 0); | | 481 | USBHIST_LOG(usbdebug, "%p", xfer, 0, 0, 0); |
479 | if (xfer->ux_buf) { | | 482 | if (xfer->ux_buf) { |
480 | usbd_free_buffer(xfer); | | 483 | usbd_free_buffer(xfer); |
481 | } | | 484 | } |
482 | #if defined(DIAGNOSTIC) | | 485 | #if defined(DIAGNOSTIC) |
483 | if (callout_pending(&xfer->ux_callout)) { | | 486 | if (callout_pending(&xfer->ux_callout)) { |
484 | callout_stop(&xfer->ux_callout); | | 487 | callout_stop(&xfer->ux_callout); |
485 | printf("usbd_free_xfer: timeout_handle pending\n"); | | 488 | printf("usbd_free_xfer: timeout_handle pending\n"); |
486 | } | | 489 | } |
487 | #endif | | 490 | #endif |
488 | cv_destroy(&xfer->ux_cv); | | 491 | cv_destroy(&xfer->ux_cv); |
489 | cv_destroy(&xfer->ux_hccv); | | 492 | cv_destroy(&xfer->ux_hccv); |
490 | xfer->ux_dev->ud_bus->ub_methods->ubm_freex(xfer->ux_dev->ud_bus, xfer); | | 493 | xfer->ux_dev->ud_bus->ub_methods->ubm_freex(xfer->ux_dev->ud_bus, xfer); |
491 | return USBD_NORMAL_COMPLETION; | | 494 | return USBD_NORMAL_COMPLETION; |
492 | } | | 495 | } |
493 | | | 496 | |
494 | void | | 497 | void |
495 | usbd_setup_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, | | 498 | usbd_setup_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, |
496 | usbd_private_handle priv, void *buffer, uint32_t length, | | 499 | usbd_private_handle priv, void *buffer, uint32_t length, |
497 | uint16_t flags, uint32_t timeout, | | 500 | uint16_t flags, uint32_t timeout, |
498 | usbd_callback callback) | | 501 | usbd_callback callback) |
499 | { | | 502 | { |
500 | xfer->ux_pipe = pipe; | | 503 | xfer->ux_pipe = pipe; |
501 | xfer->ux_priv = priv; | | 504 | xfer->ux_priv = priv; |
502 | xfer->ux_buffer = buffer; | | 505 | xfer->ux_buffer = buffer; |
503 | xfer->ux_length = length; | | 506 | xfer->ux_length = length; |
504 | xfer->ux_actlen = 0; | | 507 | xfer->ux_actlen = 0; |
505 | xfer->ux_flags = flags; | | 508 | xfer->ux_flags = flags; |
506 | xfer->ux_timeout = timeout; | | 509 | xfer->ux_timeout = timeout; |
507 | xfer->ux_status = USBD_NOT_STARTED; | | 510 | xfer->ux_status = USBD_NOT_STARTED; |
508 | xfer->ux_callback = callback; | | 511 | xfer->ux_callback = callback; |
509 | xfer->ux_rqflags &= ~URQ_REQUEST; | | 512 | xfer->ux_rqflags &= ~URQ_REQUEST; |
510 | xfer->ux_nframes = 0; | | 513 | xfer->ux_nframes = 0; |
511 | } | | 514 | } |
512 | | | 515 | |
513 | void | | 516 | void |
514 | usbd_setup_default_xfer(usbd_xfer_handle xfer, usbd_device_handle dev, | | 517 | usbd_setup_default_xfer(usbd_xfer_handle xfer, usbd_device_handle dev, |
515 | usbd_private_handle priv, uint32_t timeout, | | 518 | usbd_private_handle priv, uint32_t timeout, |
516 | usb_device_request_t *req, void *buffer, | | 519 | usb_device_request_t *req, void *buffer, |
517 | uint32_t length, uint16_t flags, | | 520 | uint32_t length, uint16_t flags, |
518 | usbd_callback callback) | | 521 | usbd_callback callback) |
519 | { | | 522 | { |
520 | xfer->ux_pipe = dev->ud_pipe0; | | 523 | xfer->ux_pipe = dev->ud_pipe0; |
521 | xfer->ux_priv = priv; | | 524 | xfer->ux_priv = priv; |
522 | xfer->ux_buffer = buffer; | | 525 | xfer->ux_buffer = buffer; |
523 | xfer->ux_length = length; | | 526 | xfer->ux_length = length; |
524 | xfer->ux_actlen = 0; | | 527 | xfer->ux_actlen = 0; |
525 | xfer->ux_flags = flags; | | 528 | xfer->ux_flags = flags; |
526 | xfer->ux_timeout = timeout; | | 529 | xfer->ux_timeout = timeout; |
527 | xfer->ux_status = USBD_NOT_STARTED; | | 530 | xfer->ux_status = USBD_NOT_STARTED; |
528 | xfer->ux_callback = callback; | | 531 | xfer->ux_callback = callback; |
529 | xfer->ux_request = *req; | | 532 | xfer->ux_request = *req; |
530 | xfer->ux_rqflags |= URQ_REQUEST; | | 533 | xfer->ux_rqflags |= URQ_REQUEST; |
531 | xfer->ux_nframes = 0; | | 534 | xfer->ux_nframes = 0; |
532 | } | | 535 | } |
533 | | | 536 | |
534 | void | | 537 | void |
535 | usbd_setup_isoc_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, | | 538 | usbd_setup_isoc_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, |
536 | usbd_private_handle priv, uint16_t *frlengths, | | 539 | usbd_private_handle priv, uint16_t *frlengths, |
537 | uint32_t nframes, uint16_t flags, usbd_callback callback) | | 540 | uint32_t nframes, uint16_t flags, usbd_callback callback) |
538 | { | | 541 | { |
539 | xfer->ux_pipe = pipe; | | 542 | xfer->ux_pipe = pipe; |
540 | xfer->ux_priv = priv; | | 543 | xfer->ux_priv = priv; |
541 | xfer->ux_buffer = 0; | | 544 | xfer->ux_buffer = 0; |
542 | xfer->ux_length = 0; | | 545 | xfer->ux_length = 0; |
543 | xfer->ux_actlen = 0; | | 546 | xfer->ux_actlen = 0; |
544 | xfer->ux_flags = flags; | | 547 | xfer->ux_flags = flags; |
545 | xfer->ux_timeout = USBD_NO_TIMEOUT; | | 548 | xfer->ux_timeout = USBD_NO_TIMEOUT; |
546 | xfer->ux_status = USBD_NOT_STARTED; | | 549 | xfer->ux_status = USBD_NOT_STARTED; |
547 | xfer->ux_callback = callback; | | 550 | xfer->ux_callback = callback; |
548 | xfer->ux_rqflags &= ~URQ_REQUEST; | | 551 | xfer->ux_rqflags &= ~URQ_REQUEST; |
549 | xfer->ux_frlengths = frlengths; | | 552 | xfer->ux_frlengths = frlengths; |
550 | xfer->ux_nframes = nframes; | | 553 | xfer->ux_nframes = nframes; |
551 | } | | 554 | } |
552 | | | 555 | |
553 | void | | 556 | void |
554 | usbd_get_xfer_status(usbd_xfer_handle xfer, usbd_private_handle *priv, | | 557 | usbd_get_xfer_status(usbd_xfer_handle xfer, usbd_private_handle *priv, |
555 | void **buffer, uint32_t *count, usbd_status *status) | | 558 | void **buffer, uint32_t *count, usbd_status *status) |
556 | { | | 559 | { |
557 | if (priv != NULL) | | 560 | if (priv != NULL) |
558 | *priv = xfer->ux_priv; | | 561 | *priv = xfer->ux_priv; |
559 | if (buffer != NULL) | | 562 | if (buffer != NULL) |
560 | *buffer = xfer->ux_buffer; | | 563 | *buffer = xfer->ux_buffer; |
561 | if (count != NULL) | | 564 | if (count != NULL) |
562 | *count = xfer->ux_actlen; | | 565 | *count = xfer->ux_actlen; |
563 | if (status != NULL) | | 566 | if (status != NULL) |
564 | *status = xfer->ux_status; | | 567 | *status = xfer->ux_status; |
565 | } | | 568 | } |
566 | | | 569 | |
567 | usb_config_descriptor_t * | | 570 | usb_config_descriptor_t * |
568 | usbd_get_config_descriptor(usbd_device_handle dev) | | 571 | usbd_get_config_descriptor(usbd_device_handle dev) |
569 | { | | 572 | { |
570 | #ifdef DIAGNOSTIC | | 573 | #ifdef DIAGNOSTIC |
571 | if (dev == NULL) { | | 574 | if (dev == NULL) { |
572 | printf("usbd_get_config_descriptor: dev == NULL\n"); | | 575 | printf("usbd_get_config_descriptor: dev == NULL\n"); |
573 | return NULL; | | 576 | return NULL; |
574 | } | | 577 | } |
575 | #endif | | 578 | #endif |
576 | return dev->ud_cdesc; | | 579 | return dev->ud_cdesc; |
577 | } | | 580 | } |
578 | | | 581 | |
579 | usb_interface_descriptor_t * | | 582 | usb_interface_descriptor_t * |
580 | usbd_get_interface_descriptor(usbd_interface_handle iface) | | 583 | usbd_get_interface_descriptor(usbd_interface_handle iface) |
581 | { | | 584 | { |
582 | #ifdef DIAGNOSTIC | | 585 | #ifdef DIAGNOSTIC |
583 | if (iface == NULL) { | | 586 | if (iface == NULL) { |
584 | printf("usbd_get_interface_descriptor: dev == NULL\n"); | | 587 | printf("usbd_get_interface_descriptor: dev == NULL\n"); |
585 | return NULL; | | 588 | return NULL; |
586 | } | | 589 | } |
587 | #endif | | 590 | #endif |
588 | return iface->ui_idesc; | | 591 | return iface->ui_idesc; |
589 | } | | 592 | } |
590 | | | 593 | |
591 | usb_device_descriptor_t * | | 594 | usb_device_descriptor_t * |
592 | usbd_get_device_descriptor(usbd_device_handle dev) | | 595 | usbd_get_device_descriptor(usbd_device_handle dev) |
593 | { | | 596 | { |
594 | return &dev->ud_ddesc; | | 597 | return &dev->ud_ddesc; |
595 | } | | 598 | } |
596 | | | 599 | |
597 | usb_endpoint_descriptor_t * | | 600 | usb_endpoint_descriptor_t * |
598 | usbd_interface2endpoint_descriptor(usbd_interface_handle iface, uint8_t index) | | 601 | usbd_interface2endpoint_descriptor(usbd_interface_handle iface, uint8_t index) |
599 | { | | 602 | { |
600 | if (index >= iface->ui_idesc->bNumEndpoints) | | 603 | if (index >= iface->ui_idesc->bNumEndpoints) |
601 | return NULL; | | 604 | return NULL; |
602 | return iface->ui_endpoints[index].ue_edesc; | | 605 | return iface->ui_endpoints[index].ue_edesc; |
603 | } | | 606 | } |
604 | | | 607 | |
605 | /* Some drivers may wish to abort requests on the default pipe, * | | 608 | /* Some drivers may wish to abort requests on the default pipe, * |
606 | * but there is no mechanism for getting a handle on it. */ | | 609 | * but there is no mechanism for getting a handle on it. */ |
607 | usbd_status | | 610 | usbd_status |
608 | usbd_abort_default_pipe(struct usbd_device *device) | | 611 | usbd_abort_default_pipe(struct usbd_device *device) |
609 | { | | 612 | { |
610 | | | 613 | |
611 | return usbd_abort_pipe(device->ud_pipe0); | | 614 | return usbd_abort_pipe(device->ud_pipe0); |
612 | } | | 615 | } |
613 | | | 616 | |
614 | usbd_status | | 617 | usbd_status |
615 | usbd_abort_pipe(usbd_pipe_handle pipe) | | 618 | usbd_abort_pipe(usbd_pipe_handle pipe) |
616 | { | | 619 | { |
617 | usbd_status err; | | 620 | usbd_status err; |
618 | | | 621 | |
619 | #ifdef DIAGNOSTIC | | 622 | #ifdef DIAGNOSTIC |
620 | if (pipe == NULL) { | | 623 | if (pipe == NULL) { |
621 | printf("usbd_abort_pipe: pipe==NULL\n"); | | 624 | printf("usbd_abort_pipe: pipe==NULL\n"); |
622 | return USBD_NORMAL_COMPLETION; | | 625 | return USBD_NORMAL_COMPLETION; |
623 | } | | 626 | } |
624 | #endif | | 627 | #endif |
625 | usbd_lock_pipe(pipe); | | 628 | usbd_lock_pipe(pipe); |
626 | err = usbd_ar_pipe(pipe); | | 629 | err = usbd_ar_pipe(pipe); |
627 | usbd_unlock_pipe(pipe); | | 630 | usbd_unlock_pipe(pipe); |
628 | return err; | | 631 | return err; |
629 | } | | 632 | } |
630 | | | 633 | |
631 | usbd_status | | 634 | usbd_status |
632 | usbd_clear_endpoint_stall(usbd_pipe_handle pipe) | | 635 | usbd_clear_endpoint_stall(usbd_pipe_handle pipe) |
633 | { | | 636 | { |
634 | usbd_device_handle dev = pipe->up_dev; | | 637 | usbd_device_handle dev = pipe->up_dev; |
635 | usb_device_request_t req; | | 638 | usb_device_request_t req; |
636 | usbd_status err; | | 639 | usbd_status err; |
637 | | | 640 | |
638 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 641 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
639 | | | 642 | |
640 | /* | | 643 | /* |
641 | * Clearing en endpoint stall resets the endpoint toggle, so | | 644 | * Clearing en endpoint stall resets the endpoint toggle, so |
642 | * do the same to the HC toggle. | | 645 | * do the same to the HC toggle. |
643 | */ | | 646 | */ |
644 | pipe->up_methods->upm_cleartoggle(pipe); | | 647 | pipe->up_methods->upm_cleartoggle(pipe); |
645 | | | 648 | |
646 | req.bmRequestType = UT_WRITE_ENDPOINT; | | 649 | req.bmRequestType = UT_WRITE_ENDPOINT; |
647 | req.bRequest = UR_CLEAR_FEATURE; | | 650 | req.bRequest = UR_CLEAR_FEATURE; |
648 | USETW(req.wValue, UF_ENDPOINT_HALT); | | 651 | USETW(req.wValue, UF_ENDPOINT_HALT); |
649 | USETW(req.wIndex, pipe->up_endpoint->ue_edesc->bEndpointAddress); | | 652 | USETW(req.wIndex, pipe->up_endpoint->ue_edesc->bEndpointAddress); |
650 | USETW(req.wLength, 0); | | 653 | USETW(req.wLength, 0); |
651 | err = usbd_do_request(dev, &req, 0); | | 654 | err = usbd_do_request(dev, &req, 0); |
652 | #if 0 | | 655 | #if 0 |
653 | XXX should we do this? | | 656 | XXX should we do this? |
654 | if (!err) { | | 657 | if (!err) { |
655 | pipe->state = USBD_PIPE_ACTIVE; | | 658 | pipe->state = USBD_PIPE_ACTIVE; |
656 | /* XXX activate pipe */ | | 659 | /* XXX activate pipe */ |
657 | } | | 660 | } |
658 | #endif | | 661 | #endif |
659 | return err; | | 662 | return err; |
660 | } | | 663 | } |
661 | | | 664 | |
662 | void | | 665 | void |
663 | usbd_clear_endpoint_stall_task(void *arg) | | 666 | usbd_clear_endpoint_stall_task(void *arg) |
664 | { | | 667 | { |
665 | usbd_pipe_handle pipe = arg; | | 668 | usbd_pipe_handle pipe = arg; |
666 | usbd_device_handle dev = pipe->up_dev; | | 669 | usbd_device_handle dev = pipe->up_dev; |
667 | usb_device_request_t req; | | 670 | usb_device_request_t req; |
668 | | | 671 | |
669 | pipe->up_methods->upm_cleartoggle(pipe); | | 672 | pipe->up_methods->upm_cleartoggle(pipe); |
670 | | | 673 | |
671 | req.bmRequestType = UT_WRITE_ENDPOINT; | | 674 | req.bmRequestType = UT_WRITE_ENDPOINT; |
672 | req.bRequest = UR_CLEAR_FEATURE; | | 675 | req.bRequest = UR_CLEAR_FEATURE; |
673 | USETW(req.wValue, UF_ENDPOINT_HALT); | | 676 | USETW(req.wValue, UF_ENDPOINT_HALT); |
674 | USETW(req.wIndex, pipe->up_endpoint->ue_edesc->bEndpointAddress); | | 677 | USETW(req.wIndex, pipe->up_endpoint->ue_edesc->bEndpointAddress); |
675 | USETW(req.wLength, 0); | | 678 | USETW(req.wLength, 0); |
676 | (void)usbd_do_request(dev, &req, 0); | | 679 | (void)usbd_do_request(dev, &req, 0); |
677 | } | | 680 | } |
678 | | | 681 | |
679 | void | | 682 | void |
680 | usbd_clear_endpoint_stall_async(usbd_pipe_handle pipe) | | 683 | usbd_clear_endpoint_stall_async(usbd_pipe_handle pipe) |
681 | { | | 684 | { |
682 | | | 685 | |
683 | usb_add_task(pipe->up_dev, &pipe->up_async_task, USB_TASKQ_DRIVER); | | 686 | usb_add_task(pipe->up_dev, &pipe->up_async_task, USB_TASKQ_DRIVER); |
684 | } | | 687 | } |
685 | | | 688 | |
686 | void | | 689 | void |
687 | usbd_clear_endpoint_toggle(usbd_pipe_handle pipe) | | 690 | usbd_clear_endpoint_toggle(usbd_pipe_handle pipe) |
688 | { | | 691 | { |
689 | pipe->up_methods->upm_cleartoggle(pipe); | | 692 | pipe->up_methods->upm_cleartoggle(pipe); |
690 | } | | 693 | } |
691 | | | 694 | |
692 | usbd_status | | 695 | usbd_status |
693 | usbd_endpoint_count(usbd_interface_handle iface, uint8_t *count) | | 696 | usbd_endpoint_count(usbd_interface_handle iface, uint8_t *count) |
694 | { | | 697 | { |
695 | #ifdef DIAGNOSTIC | | 698 | #ifdef DIAGNOSTIC |
696 | if (iface == NULL || iface->ui_idesc == NULL) { | | 699 | if (iface == NULL || iface->ui_idesc == NULL) { |
697 | printf("usbd_endpoint_count: NULL pointer\n"); | | 700 | printf("usbd_endpoint_count: NULL pointer\n"); |
698 | return USBD_INVAL; | | 701 | return USBD_INVAL; |
699 | } | | 702 | } |
700 | #endif | | 703 | #endif |
701 | *count = iface->ui_idesc->bNumEndpoints; | | 704 | *count = iface->ui_idesc->bNumEndpoints; |
702 | return USBD_NORMAL_COMPLETION; | | 705 | return USBD_NORMAL_COMPLETION; |
703 | } | | 706 | } |
704 | | | 707 | |
705 | usbd_status | | 708 | usbd_status |
706 | usbd_interface_count(usbd_device_handle dev, uint8_t *count) | | 709 | usbd_interface_count(usbd_device_handle dev, uint8_t *count) |
707 | { | | 710 | { |
708 | if (dev->ud_cdesc == NULL) | | 711 | if (dev->ud_cdesc == NULL) |
709 | return USBD_NOT_CONFIGURED; | | 712 | return USBD_NOT_CONFIGURED; |
710 | *count = dev->ud_cdesc->bNumInterface; | | 713 | *count = dev->ud_cdesc->bNumInterface; |
711 | return USBD_NORMAL_COMPLETION; | | 714 | return USBD_NORMAL_COMPLETION; |
712 | } | | 715 | } |
713 | | | 716 | |
714 | void | | 717 | void |
715 | usbd_interface2device_handle(usbd_interface_handle iface, | | 718 | usbd_interface2device_handle(usbd_interface_handle iface, |
716 | usbd_device_handle *dev) | | 719 | usbd_device_handle *dev) |
717 | { | | 720 | { |
718 | *dev = iface->ui_dev; | | 721 | *dev = iface->ui_dev; |
719 | } | | 722 | } |
720 | | | 723 | |
721 | usbd_status | | 724 | usbd_status |
722 | usbd_device2interface_handle(usbd_device_handle dev, | | 725 | usbd_device2interface_handle(usbd_device_handle dev, |
723 | uint8_t ifaceno, usbd_interface_handle *iface) | | 726 | uint8_t ifaceno, usbd_interface_handle *iface) |
724 | { | | 727 | { |
725 | if (dev->ud_cdesc == NULL) | | 728 | if (dev->ud_cdesc == NULL) |
726 | return USBD_NOT_CONFIGURED; | | 729 | return USBD_NOT_CONFIGURED; |
727 | if (ifaceno >= dev->ud_cdesc->bNumInterface) | | 730 | if (ifaceno >= dev->ud_cdesc->bNumInterface) |
728 | return USBD_INVAL; | | 731 | return USBD_INVAL; |
729 | *iface = &dev->ud_ifaces[ifaceno]; | | 732 | *iface = &dev->ud_ifaces[ifaceno]; |
730 | return USBD_NORMAL_COMPLETION; | | 733 | return USBD_NORMAL_COMPLETION; |
731 | } | | 734 | } |
732 | | | 735 | |
733 | usbd_device_handle | | 736 | usbd_device_handle |
734 | usbd_pipe2device_handle(usbd_pipe_handle pipe) | | 737 | usbd_pipe2device_handle(usbd_pipe_handle pipe) |
735 | { | | 738 | { |
736 | return pipe->up_dev; | | 739 | return pipe->up_dev; |
737 | } | | 740 | } |
738 | | | 741 | |
739 | /* XXXX use altno */ | | 742 | /* XXXX use altno */ |
740 | usbd_status | | 743 | usbd_status |
741 | usbd_set_interface(usbd_interface_handle iface, int altidx) | | 744 | usbd_set_interface(usbd_interface_handle iface, int altidx) |
742 | { | | 745 | { |
743 | usb_device_request_t req; | | 746 | usb_device_request_t req; |
744 | usbd_status err; | | 747 | usbd_status err; |
745 | void *endpoints; | | 748 | void *endpoints; |
746 | | | 749 | |
747 | if (LIST_FIRST(&iface->ui_pipes) != 0) | | 750 | if (LIST_FIRST(&iface->ui_pipes) != 0) |
748 | return USBD_IN_USE; | | 751 | return USBD_IN_USE; |
749 | | | 752 | |
750 | endpoints = iface->ui_endpoints; | | 753 | endpoints = iface->ui_endpoints; |
751 | err = usbd_fill_iface_data(iface->ui_dev, iface->ui_index, altidx); | | 754 | err = usbd_fill_iface_data(iface->ui_dev, iface->ui_index, altidx); |
752 | if (err) | | 755 | if (err) |
753 | return err; | | 756 | return err; |
754 | | | 757 | |
755 | /* new setting works, we can free old endpoints */ | | 758 | /* new setting works, we can free old endpoints */ |
756 | if (endpoints != NULL) { | | 759 | if (endpoints != NULL) { |
757 | int nendpt = iface->ui_idesc->bNumEndpoints; | | 760 | int nendpt = iface->ui_idesc->bNumEndpoints; |
758 | kmem_free(endpoints, nendpt * sizeof(struct usbd_endpoint)); | | 761 | kmem_free(endpoints, nendpt * sizeof(struct usbd_endpoint)); |
759 | } | | 762 | } |
760 | | | 763 | |
761 | #ifdef DIAGNOSTIC | | 764 | #ifdef DIAGNOSTIC |
762 | if (iface->ui_idesc == NULL) { | | 765 | if (iface->ui_idesc == NULL) { |
763 | printf("usbd_set_interface: NULL pointer\n"); | | 766 | printf("usbd_set_interface: NULL pointer\n"); |
764 | return USBD_INVAL; | | 767 | return USBD_INVAL; |
765 | } | | 768 | } |
766 | #endif | | 769 | #endif |
767 | | | 770 | |
768 | req.bmRequestType = UT_WRITE_INTERFACE; | | 771 | req.bmRequestType = UT_WRITE_INTERFACE; |
769 | req.bRequest = UR_SET_INTERFACE; | | 772 | req.bRequest = UR_SET_INTERFACE; |
770 | USETW(req.wValue, iface->ui_idesc->bAlternateSetting); | | 773 | USETW(req.wValue, iface->ui_idesc->bAlternateSetting); |
771 | USETW(req.wIndex, iface->ui_idesc->bInterfaceNumber); | | 774 | USETW(req.wIndex, iface->ui_idesc->bInterfaceNumber); |
772 | USETW(req.wLength, 0); | | 775 | USETW(req.wLength, 0); |
773 | return usbd_do_request(iface->ui_dev, &req, 0); | | 776 | return usbd_do_request(iface->ui_dev, &req, 0); |
774 | } | | 777 | } |
775 | | | 778 | |
776 | int | | 779 | int |
777 | usbd_get_no_alts(usb_config_descriptor_t *cdesc, int ifaceno) | | 780 | usbd_get_no_alts(usb_config_descriptor_t *cdesc, int ifaceno) |
778 | { | | 781 | { |
779 | char *p = (char *)cdesc; | | 782 | char *p = (char *)cdesc; |
780 | char *end = p + UGETW(cdesc->wTotalLength); | | 783 | char *end = p + UGETW(cdesc->wTotalLength); |
781 | usb_interface_descriptor_t *d; | | 784 | usb_interface_descriptor_t *d; |
782 | int n; | | 785 | int n; |
783 | | | 786 | |
784 | for (n = 0; p < end; p += d->bLength) { | | 787 | for (n = 0; p < end; p += d->bLength) { |
785 | d = (usb_interface_descriptor_t *)p; | | 788 | d = (usb_interface_descriptor_t *)p; |
786 | if (p + d->bLength <= end && | | 789 | if (p + d->bLength <= end && |
787 | d->bDescriptorType == UDESC_INTERFACE && | | 790 | d->bDescriptorType == UDESC_INTERFACE && |
788 | d->bInterfaceNumber == ifaceno) | | 791 | d->bInterfaceNumber == ifaceno) |
789 | n++; | | 792 | n++; |
790 | } | | 793 | } |
791 | return n; | | 794 | return n; |
792 | } | | 795 | } |
793 | | | 796 | |
794 | int | | 797 | int |
795 | usbd_get_interface_altindex(usbd_interface_handle iface) | | 798 | usbd_get_interface_altindex(usbd_interface_handle iface) |
796 | { | | 799 | { |
797 | return iface->ui_altindex; | | 800 | return iface->ui_altindex; |
798 | } | | 801 | } |
799 | | | 802 | |
800 | usbd_status | | 803 | usbd_status |
801 | usbd_get_interface(usbd_interface_handle iface, uint8_t *aiface) | | 804 | usbd_get_interface(usbd_interface_handle iface, uint8_t *aiface) |
802 | { | | 805 | { |
803 | usb_device_request_t req; | | 806 | usb_device_request_t req; |
804 | | | 807 | |
805 | req.bmRequestType = UT_READ_INTERFACE; | | 808 | req.bmRequestType = UT_READ_INTERFACE; |
806 | req.bRequest = UR_GET_INTERFACE; | | 809 | req.bRequest = UR_GET_INTERFACE; |
807 | USETW(req.wValue, 0); | | 810 | USETW(req.wValue, 0); |
808 | USETW(req.wIndex, iface->ui_idesc->bInterfaceNumber); | | 811 | USETW(req.wIndex, iface->ui_idesc->bInterfaceNumber); |
809 | USETW(req.wLength, 1); | | 812 | USETW(req.wLength, 1); |
810 | return usbd_do_request(iface->ui_dev, &req, aiface); | | 813 | return usbd_do_request(iface->ui_dev, &req, aiface); |
811 | } | | 814 | } |
812 | | | 815 | |
813 | /*** Internal routines ***/ | | 816 | /*** Internal routines ***/ |
814 | | | 817 | |
815 | /* Dequeue all pipe operations, called at splusb(). */ | | 818 | /* Dequeue all pipe operations, called at splusb(). */ |
816 | Static usbd_status | | 819 | Static usbd_status |
817 | usbd_ar_pipe(usbd_pipe_handle pipe) | | 820 | usbd_ar_pipe(usbd_pipe_handle pipe) |
818 | { | | 821 | { |
819 | usbd_xfer_handle xfer; | | 822 | usbd_xfer_handle xfer; |
820 | | | 823 | |
821 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 824 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
822 | | | 825 | |
823 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | | 826 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); |
824 | | | 827 | |
825 | USBHIST_LOG(usbdebug, "pipe = %p", pipe, 0, 0, 0); | | 828 | USBHIST_LOG(usbdebug, "pipe = %p", pipe, 0, 0, 0); |
826 | #ifdef USB_DEBUG | | 829 | #ifdef USB_DEBUG |
827 | if (usbdebug > 5) | | 830 | if (usbdebug > 5) |
828 | usbd_dump_queue(pipe); | | 831 | usbd_dump_queue(pipe); |
829 | #endif | | 832 | #endif |
830 | pipe->up_repeat = 0; | | 833 | pipe->up_repeat = 0; |
831 | pipe->up_aborting = 1; | | 834 | pipe->up_aborting = 1; |
832 | while ((xfer = SIMPLEQ_FIRST(&pipe->up_queue)) != NULL) { | | 835 | while ((xfer = SIMPLEQ_FIRST(&pipe->up_queue)) != NULL) { |
833 | USBHIST_LOG(usbdebug, "pipe = %p xfer = %p (methods = %p)", | | 836 | USBHIST_LOG(usbdebug, "pipe = %p xfer = %p (methods = %p)", |
834 | pipe, xfer, pipe->up_methods, 0); | | 837 | pipe, xfer, pipe->up_methods, 0); |
835 | /* Make the HC abort it (and invoke the callback). */ | | 838 | /* Make the HC abort it (and invoke the callback). */ |
836 | pipe->up_methods->upm_abort(xfer); | | 839 | pipe->up_methods->upm_abort(xfer); |
837 | /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */ | | 840 | /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */ |
838 | } | | 841 | } |
839 | pipe->up_aborting = 0; | | 842 | pipe->up_aborting = 0; |
840 | return USBD_NORMAL_COMPLETION; | | 843 | return USBD_NORMAL_COMPLETION; |
841 | } | | 844 | } |
842 | | | 845 | |
843 | /* Called with USB lock held. */ | | 846 | /* Called with USB lock held. */ |
844 | void | | 847 | void |
845 | usb_transfer_complete(usbd_xfer_handle xfer) | | 848 | usb_transfer_complete(usbd_xfer_handle xfer) |
846 | { | | 849 | { |
847 | usbd_pipe_handle pipe = xfer->ux_pipe; | | 850 | usbd_pipe_handle pipe = xfer->ux_pipe; |
848 | struct usbd_bus *bus = pipe->up_dev->ud_bus; | | 851 | struct usbd_bus *bus = pipe->up_dev->ud_bus; |
849 | int sync = xfer->ux_flags & USBD_SYNCHRONOUS; | | 852 | int sync = xfer->ux_flags & USBD_SYNCHRONOUS; |
850 | int erred = xfer->ux_status == USBD_CANCELLED || | | 853 | int erred = xfer->ux_status == USBD_CANCELLED || |
851 | xfer->ux_status == USBD_TIMEOUT; | | 854 | xfer->ux_status == USBD_TIMEOUT; |
852 | int polling = bus->ub_usepolling; | | 855 | int polling = bus->ub_usepolling; |
853 | int repeat; | | 856 | int repeat; |
854 | | | 857 | |
855 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 858 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
856 | | | 859 | |
857 | USBHIST_LOG(usbdebug, "pipe = %p xfer = %p status = %d actlen = %d", | | 860 | USBHIST_LOG(usbdebug, "pipe = %p xfer = %p status = %d actlen = %d", |
858 | pipe, xfer, xfer->ux_status, xfer->ux_actlen); | | 861 | pipe, xfer, xfer->ux_status, xfer->ux_actlen); |
859 | | | 862 | |
860 | KASSERT(polling || mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | | 863 | KASSERT(polling || mutex_owned(pipe->up_dev->ud_bus->ub_lock)); |
861 | | | 864 | |
862 | #ifdef DIAGNOSTIC | | 865 | #ifdef DIAGNOSTIC |
863 | if (xfer->ux_state != XFER_ONQU) { | | 866 | if (xfer->ux_state != XFER_ONQU) { |
864 | printf("usb_transfer_complete: xfer=%p not queued 0x%08x\n", | | 867 | printf("usb_transfer_complete: xfer=%p not queued 0x%08x\n", |
865 | xfer, xfer->ux_state); | | 868 | xfer, xfer->ux_state); |
866 | } | | 869 | } |
867 | #endif | | 870 | #endif |
868 | | | 871 | |
869 | #ifdef DIAGNOSTIC | | 872 | #ifdef DIAGNOSTIC |
870 | if (pipe == NULL) { | | 873 | if (pipe == NULL) { |
871 | printf("usb_transfer_complete: pipe==0, xfer=%p\n", xfer); | | 874 | printf("usb_transfer_complete: pipe==0, xfer=%p\n", xfer); |
872 | return; | | 875 | return; |
873 | } | | 876 | } |
874 | #endif | | 877 | #endif |
875 | repeat = pipe->up_repeat; | | 878 | repeat = pipe->up_repeat; |
876 | /* XXXX */ | | 879 | /* XXXX */ |
877 | if (polling) | | 880 | if (polling) |
878 | pipe->up_running = 0; | | 881 | pipe->up_running = 0; |
879 | | | 882 | |
880 | if (xfer->ux_buffer != xfer->ux_buf) { | | 883 | if (xfer->ux_buffer != xfer->ux_buf) { |
881 | /* can only be different for DMA busses */ | | 884 | /* can only be different for DMA busses */ |
882 | KASSERT(bus->ub_usedma); | | 885 | KASSERT(bus->ub_usedma); |
883 | KDASSERTMSG(xfer->ux_actlen <= xfer->ux_length, | | 886 | KDASSERTMSG(xfer->ux_actlen <= xfer->ux_length, |
884 | "actlen %d length %d",xfer->ux_actlen, xfer->ux_length); | | 887 | "actlen %d length %d",xfer->ux_actlen, xfer->ux_length); |
885 | | | 888 | |
886 | memcpy(xfer->ux_buffer, xfer->ux_buf, xfer->ux_actlen); | | 889 | memcpy(xfer->ux_buffer, xfer->ux_buf, xfer->ux_actlen); |
887 | } | | 890 | } |
888 | | | 891 | |
889 | | | 892 | |
890 | if (!repeat) { | | 893 | if (!repeat) { |
891 | /* Remove request from queue. */ | | 894 | /* Remove request from queue. */ |
892 | | | 895 | |
893 | KASSERTMSG(!SIMPLEQ_EMPTY(&pipe->up_queue), | | 896 | KASSERTMSG(!SIMPLEQ_EMPTY(&pipe->up_queue), |
894 | "pipe %p is empty, but xfer %p wants to complete", pipe, | | 897 | "pipe %p is empty, but xfer %p wants to complete", pipe, |
895 | xfer); | | 898 | xfer); |
896 | #ifdef DIAGNOSTIC | | 899 | #ifdef DIAGNOSTIC |
897 | if (xfer != SIMPLEQ_FIRST(&pipe->up_queue)) | | 900 | if (xfer != SIMPLEQ_FIRST(&pipe->up_queue)) |
898 | printf("%s: bad dequeue %p != %p\n", __func__, | | 901 | printf("%s: bad dequeue %p != %p\n", __func__, |
899 | xfer, SIMPLEQ_FIRST(&pipe->up_queue)); | | 902 | xfer, SIMPLEQ_FIRST(&pipe->up_queue)); |
900 | xfer->ux_state = XFER_BUSY; | | 903 | xfer->ux_state = XFER_BUSY; |
901 | #endif | | 904 | #endif |
902 | SIMPLEQ_REMOVE_HEAD(&pipe->up_queue, ux_next); | | 905 | SIMPLEQ_REMOVE_HEAD(&pipe->up_queue, ux_next); |
903 | } | | 906 | } |
904 | USBHIST_LOG(usbdebug, "xfer %p: repeat %d new head = %p", | | 907 | USBHIST_LOG(usbdebug, "xfer %p: repeat %d new head = %p", |
905 | xfer, repeat, SIMPLEQ_FIRST(&pipe->up_queue), 0); | | 908 | xfer, repeat, SIMPLEQ_FIRST(&pipe->up_queue), 0); |
906 | | | 909 | |
907 | /* Count completed transfers. */ | | 910 | /* Count completed transfers. */ |
908 | ++pipe->up_dev->ud_bus->ub_stats.uds_requests | | 911 | ++pipe->up_dev->ud_bus->ub_stats.uds_requests |
909 | [pipe->up_endpoint->ue_edesc->bmAttributes & UE_XFERTYPE]; | | 912 | [pipe->up_endpoint->ue_edesc->bmAttributes & UE_XFERTYPE]; |
910 | | | 913 | |
911 | xfer->ux_done = 1; | | 914 | xfer->ux_done = 1; |
912 | if (!xfer->ux_status && xfer->ux_actlen < xfer->ux_length && | | 915 | if (!xfer->ux_status && xfer->ux_actlen < xfer->ux_length && |
913 | !(xfer->ux_flags & USBD_SHORT_XFER_OK)) { | | 916 | !(xfer->ux_flags & USBD_SHORT_XFER_OK)) { |
914 | USBHIST_LOG(usbdebug, "short transfer %d < %d", | | 917 | USBHIST_LOG(usbdebug, "short transfer %d < %d", |
915 | xfer->ux_actlen, xfer->ux_length, 0, 0); | | 918 | xfer->ux_actlen, xfer->ux_length, 0, 0); |
916 | xfer->ux_status = USBD_SHORT_XFER; | | 919 | xfer->ux_status = USBD_SHORT_XFER; |
917 | } | | 920 | } |
918 | | | 921 | |
919 | if (repeat) { | | 922 | if (repeat) { |
920 | USBHIST_LOG(usbdebug, "xfer %p doing callback %p status %x", | | 923 | USBHIST_LOG(usbdebug, "xfer %p doing callback %p status %x", |
921 | xfer, xfer->ux_callback, xfer->ux_status, 0); | | 924 | xfer, xfer->ux_callback, xfer->ux_status, 0); |
922 | if (xfer->ux_callback) { | | 925 | if (xfer->ux_callback) { |
923 | if (!polling) | | 926 | if (!polling) |
924 | mutex_exit(pipe->up_dev->ud_bus->ub_lock); | | 927 | mutex_exit(pipe->up_dev->ud_bus->ub_lock); |
925 | | | 928 | |
926 | if (!(pipe->up_flags & USBD_MPSAFE)) | | 929 | if (!(pipe->up_flags & USBD_MPSAFE)) |
927 | KERNEL_LOCK(1, curlwp); | | 930 | KERNEL_LOCK(1, curlwp); |
928 | xfer->ux_callback(xfer, xfer->ux_priv, xfer->ux_status); | | 931 | xfer->ux_callback(xfer, xfer->ux_priv, xfer->ux_status); |
929 | USBHIST_LOG(usbdebug, "xfer %p doing done %p", xfer, | | 932 | USBHIST_LOG(usbdebug, "xfer %p doing done %p", xfer, |
930 | pipe->up_methods->upm_done, 0, 0); | | 933 | pipe->up_methods->upm_done, 0, 0); |
931 | if (!(pipe->up_flags & USBD_MPSAFE)) | | 934 | if (!(pipe->up_flags & USBD_MPSAFE)) |
932 | KERNEL_UNLOCK_ONE(curlwp); | | 935 | KERNEL_UNLOCK_ONE(curlwp); |
933 | | | 936 | |
934 | if (!polling) | | 937 | if (!polling) |
935 | mutex_enter(pipe->up_dev->ud_bus->ub_lock); | | 938 | mutex_enter(pipe->up_dev->ud_bus->ub_lock); |
936 | } | | 939 | } |
937 | pipe->up_methods->upm_done(xfer); | | 940 | pipe->up_methods->upm_done(xfer); |
938 | } else { | | 941 | } else { |
939 | USBHIST_LOG(usbdebug, "xfer %p doing done %p", xfer, | | 942 | USBHIST_LOG(usbdebug, "xfer %p doing done %p", xfer, |
940 | pipe->up_methods->upm_done, 0, 0); | | 943 | pipe->up_methods->upm_done, 0, 0); |
941 | pipe->up_methods->upm_done(xfer); | | 944 | pipe->up_methods->upm_done(xfer); |
942 | USBHIST_LOG(usbdebug, "xfer %p doing callback %p status %x", | | 945 | USBHIST_LOG(usbdebug, "xfer %p doing callback %p status %x", |
943 | xfer, xfer->ux_callback, xfer->ux_status, 0); | | 946 | xfer, xfer->ux_callback, xfer->ux_status, 0); |
944 | if (xfer->ux_callback) { | | 947 | if (xfer->ux_callback) { |
945 | if (!polling) | | 948 | if (!polling) |
946 | mutex_exit(pipe->up_dev->ud_bus->ub_lock); | | 949 | mutex_exit(pipe->up_dev->ud_bus->ub_lock); |
947 | | | 950 | |
948 | if (!(pipe->up_flags & USBD_MPSAFE)) | | 951 | if (!(pipe->up_flags & USBD_MPSAFE)) |
949 | KERNEL_LOCK(1, curlwp); | | 952 | KERNEL_LOCK(1, curlwp); |
950 | xfer->ux_callback(xfer, xfer->ux_priv, xfer->ux_status); | | 953 | xfer->ux_callback(xfer, xfer->ux_priv, xfer->ux_status); |
951 | if (!(pipe->up_flags & USBD_MPSAFE)) | | 954 | if (!(pipe->up_flags & USBD_MPSAFE)) |
952 | KERNEL_UNLOCK_ONE(curlwp); | | 955 | KERNEL_UNLOCK_ONE(curlwp); |
953 | | | 956 | |
954 | if (!polling) | | 957 | if (!polling) |
955 | mutex_enter(pipe->up_dev->ud_bus->ub_lock); | | 958 | mutex_enter(pipe->up_dev->ud_bus->ub_lock); |
956 | } | | 959 | } |
957 | } | | 960 | } |
958 | | | 961 | |
959 | if (sync && !polling) { | | 962 | if (sync && !polling) { |
960 | USBHIST_LOG(usbdebug, "<- done xfer %p, wakeup", xfer, 0, 0, 0); | | 963 | USBHIST_LOG(usbdebug, "<- done xfer %p, wakeup", xfer, 0, 0, 0); |
961 | cv_broadcast(&xfer->ux_cv); | | 964 | cv_broadcast(&xfer->ux_cv); |
962 | } | | 965 | } |
963 | | | 966 | |
964 | if (!repeat) { | | 967 | if (!repeat) { |
965 | /* XXX should we stop the queue on all errors? */ | | 968 | /* XXX should we stop the queue on all errors? */ |
966 | if (erred && pipe->up_iface != NULL) /* not control pipe */ | | 969 | if (erred && pipe->up_iface != NULL) /* not control pipe */ |
967 | pipe->up_running = 0; | | 970 | pipe->up_running = 0; |
968 | else | | 971 | else |
969 | usbd_start_next(pipe); | | 972 | usbd_start_next(pipe); |
970 | } | | 973 | } |
971 | } | | 974 | } |
972 | | | 975 | |
973 | /* Called with USB lock held. */ | | 976 | /* Called with USB lock held. */ |
974 | usbd_status | | 977 | usbd_status |
975 | usb_insert_transfer(usbd_xfer_handle xfer) | | 978 | usb_insert_transfer(usbd_xfer_handle xfer) |
976 | { | | 979 | { |
977 | usbd_pipe_handle pipe = xfer->ux_pipe; | | 980 | usbd_pipe_handle pipe = xfer->ux_pipe; |
978 | usbd_status err; | | 981 | usbd_status err; |
979 | | | 982 | |
980 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 983 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
981 | | | 984 | |
982 | USBHIST_LOG(usbdebug, "pipe = %p running = %d timeout = %d", | | 985 | USBHIST_LOG(usbdebug, "pipe = %p running = %d timeout = %d", |
983 | pipe, pipe->up_running, xfer->ux_timeout, 0); | | 986 | pipe, pipe->up_running, xfer->ux_timeout, 0); |
984 | | | 987 | |
985 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | | 988 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); |
986 | | | 989 | |
987 | #ifdef DIAGNOSTIC | | 990 | #ifdef DIAGNOSTIC |
988 | if (xfer->ux_state != XFER_BUSY) { | | 991 | if (xfer->ux_state != XFER_BUSY) { |
989 | USBHIST_LOG(usbdebug, "<- done, xfer %p not busy", xfer, 0, 0, | | 992 | USBHIST_LOG(usbdebug, "<- done, xfer %p not busy", xfer, 0, 0, |
990 | 0); | | 993 | 0); |
991 | printf("usb_insert_transfer: xfer=%p not busy 0x%08x\n", | | 994 | printf("usb_insert_transfer: xfer=%p not busy 0x%08x\n", |
992 | xfer, xfer->ux_state); | | 995 | xfer, xfer->ux_state); |
993 | return USBD_INVAL; | | 996 | return USBD_INVAL; |
994 | } | | 997 | } |
995 | xfer->ux_state = XFER_ONQU; | | 998 | xfer->ux_state = XFER_ONQU; |
996 | #endif | | 999 | #endif |
997 | SIMPLEQ_INSERT_TAIL(&pipe->up_queue, xfer, ux_next); | | 1000 | SIMPLEQ_INSERT_TAIL(&pipe->up_queue, xfer, ux_next); |
998 | if (pipe->up_running) | | 1001 | if (pipe->up_running) |
999 | err = USBD_IN_PROGRESS; | | 1002 | err = USBD_IN_PROGRESS; |
1000 | else { | | 1003 | else { |
1001 | pipe->up_running = 1; | | 1004 | pipe->up_running = 1; |
1002 | err = USBD_NORMAL_COMPLETION; | | 1005 | err = USBD_NORMAL_COMPLETION; |
1003 | } | | 1006 | } |
1004 | USBHIST_LOG(usbdebug, "<- done xfer %p, err %d", xfer, err, 0, 0); | | 1007 | USBHIST_LOG(usbdebug, "<- done xfer %p, err %d", xfer, err, 0, 0); |
1005 | return err; | | 1008 | return err; |
1006 | } | | 1009 | } |
1007 | | | 1010 | |
1008 | /* Called with USB lock held. */ | | 1011 | /* Called with USB lock held. */ |
1009 | void | | 1012 | void |
1010 | usbd_start_next(usbd_pipe_handle pipe) | | 1013 | usbd_start_next(usbd_pipe_handle pipe) |
1011 | { | | 1014 | { |
1012 | usbd_xfer_handle xfer; | | 1015 | usbd_xfer_handle xfer; |
1013 | usbd_status err; | | 1016 | usbd_status err; |
1014 | | | 1017 | |
1015 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 1018 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
1016 | | | 1019 | |
1017 | #ifdef DIAGNOSTIC | | 1020 | #ifdef DIAGNOSTIC |
1018 | if (pipe == NULL) { | | 1021 | if (pipe == NULL) { |
1019 | printf("usbd_start_next: pipe == NULL\n"); | | 1022 | printf("usbd_start_next: pipe == NULL\n"); |
1020 | return; | | 1023 | return; |
1021 | } | | 1024 | } |
1022 | if (pipe->up_methods == NULL || pipe->up_methods->upm_start == NULL) { | | 1025 | if (pipe->up_methods == NULL || pipe->up_methods->upm_start == NULL) { |
1023 | printf("usbd_start_next: pipe=%p no start method\n", pipe); | | 1026 | printf("usbd_start_next: pipe=%p no start method\n", pipe); |
1024 | return; | | 1027 | return; |
1025 | } | | 1028 | } |
1026 | #endif | | 1029 | #endif |
1027 | | | 1030 | |
1028 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | | 1031 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); |
1029 | | | 1032 | |
1030 | /* Get next request in queue. */ | | 1033 | /* Get next request in queue. */ |
1031 | xfer = SIMPLEQ_FIRST(&pipe->up_queue); | | 1034 | xfer = SIMPLEQ_FIRST(&pipe->up_queue); |
1032 | USBHIST_LOG(usbdebug, "pipe = %p, xfer = %p", pipe, xfer, 0, 0); | | 1035 | USBHIST_LOG(usbdebug, "pipe = %p, xfer = %p", pipe, xfer, 0, 0); |
1033 | if (xfer == NULL) { | | 1036 | if (xfer == NULL) { |
1034 | pipe->up_running = 0; | | 1037 | pipe->up_running = 0; |
1035 | } else { | | 1038 | } else { |
1036 | mutex_exit(pipe->up_dev->ud_bus->ub_lock); | | 1039 | mutex_exit(pipe->up_dev->ud_bus->ub_lock); |
1037 | err = pipe->up_methods->upm_start(xfer); | | 1040 | err = pipe->up_methods->upm_start(xfer); |
1038 | mutex_enter(pipe->up_dev->ud_bus->ub_lock); | | 1041 | mutex_enter(pipe->up_dev->ud_bus->ub_lock); |
1039 | | | 1042 | |
1040 | if (err != USBD_IN_PROGRESS) { | | 1043 | if (err != USBD_IN_PROGRESS) { |
1041 | USBHIST_LOG(usbdebug, "error = %d", err, 0, 0, 0); | | 1044 | USBHIST_LOG(usbdebug, "error = %d", err, 0, 0, 0); |
1042 | pipe->up_running = 0; | | 1045 | pipe->up_running = 0; |
1043 | /* XXX do what? */ | | 1046 | /* XXX do what? */ |
1044 | } | | 1047 | } |
1045 | } | | 1048 | } |
1046 | | | 1049 | |
1047 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | | 1050 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); |
1048 | } | | 1051 | } |
1049 | | | 1052 | |
1050 | usbd_status | | 1053 | usbd_status |
1051 | usbd_do_request(usbd_device_handle dev, usb_device_request_t *req, void *data) | | 1054 | usbd_do_request(usbd_device_handle dev, usb_device_request_t *req, void *data) |
1052 | { | | 1055 | { |
1053 | return (usbd_do_request_flags(dev, req, data, 0, 0, | | 1056 | return (usbd_do_request_flags(dev, req, data, 0, 0, |
1054 | USBD_DEFAULT_TIMEOUT)); | | 1057 | USBD_DEFAULT_TIMEOUT)); |
1055 | } | | 1058 | } |
1056 | | | 1059 | |
1057 | usbd_status | | 1060 | usbd_status |
1058 | usbd_do_request_flags(usbd_device_handle dev, usb_device_request_t *req, | | 1061 | usbd_do_request_flags(usbd_device_handle dev, usb_device_request_t *req, |
1059 | void *data, uint16_t flags, int *actlen, uint32_t timo) | | 1062 | void *data, uint16_t flags, int *actlen, uint32_t timo) |
1060 | { | | 1063 | { |
1061 | return (usbd_do_request_flags_pipe(dev, dev->ud_pipe0, req, | | 1064 | return (usbd_do_request_flags_pipe(dev, dev->ud_pipe0, req, |
1062 | data, flags, actlen, timo)); | | 1065 | data, flags, actlen, timo)); |
1063 | } | | 1066 | } |
1064 | | | 1067 | |
1065 | usbd_status | | 1068 | usbd_status |
1066 | usbd_do_request_flags_pipe(usbd_device_handle dev, usbd_pipe_handle pipe, | | 1069 | usbd_do_request_flags_pipe(usbd_device_handle dev, usbd_pipe_handle pipe, |
1067 | usb_device_request_t *req, void *data, uint16_t flags, int *actlen, | | 1070 | usb_device_request_t *req, void *data, uint16_t flags, int *actlen, |
1068 | uint32_t timeout) | | 1071 | uint32_t timeout) |
1069 | { | | 1072 | { |
1070 | usbd_xfer_handle xfer; | | 1073 | usbd_xfer_handle xfer; |
1071 | usbd_status err; | | 1074 | usbd_status err; |
| | | 1075 | void *buf = NULL; |
1072 | | | 1076 | |
1073 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 1077 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
1074 | | | 1078 | |
1075 | ASSERT_SLEEPABLE(); | | 1079 | ASSERT_SLEEPABLE(); |
1076 | | | 1080 | |
1077 | xfer = usbd_alloc_xfer(dev); | | 1081 | xfer = usbd_alloc_xfer(dev); |
1078 | if (xfer == NULL) | | 1082 | if (xfer == NULL) |
1079 | return USBD_NOMEM; | | 1083 | return USBD_NOMEM; |
1080 | | | 1084 | |
1081 | if (UGETW(req->wLength) != 0) { | | 1085 | if (UGETW(req->wLength) != 0) { |
1082 | void *buf = usbd_alloc_buffer(xfer, UGETW(req->wLength)); | | 1086 | buf = usbd_alloc_buffer(xfer, UGETW(req->wLength)); |
1083 | if (buf == NULL) { | | 1087 | if (buf == NULL) { |
1084 | err = ENOMEM; | | 1088 | err = ENOMEM; |
1085 | goto bad; | | 1089 | goto bad; |
1086 | } | | 1090 | } |
1087 | } | | 1091 | } |
1088 | | | 1092 | |
1089 | | | | |
1090 | usbd_setup_default_xfer(xfer, dev, 0, timeout, req, | | 1093 | usbd_setup_default_xfer(xfer, dev, 0, timeout, req, |
1091 | data, UGETW(req->wLength), flags, 0); | | 1094 | data, UGETW(req->wLength), flags, 0); |
1092 | xfer->ux_pipe = pipe; | | 1095 | xfer->ux_pipe = pipe; |
1093 | err = usbd_sync_transfer(xfer); | | 1096 | err = usbd_sync_transfer(xfer); |
1094 | #if defined(USB_DEBUG) || defined(DIAGNOSTIC) | | 1097 | #if defined(USB_DEBUG) || defined(DIAGNOSTIC) |
1095 | if (xfer->ux_actlen > xfer->ux_length) { | | 1098 | if (xfer->ux_actlen > xfer->ux_length) { |
1096 | USBHIST_LOG(usbdebug, "overrun addr = %d type = 0x%02x", | | 1099 | USBHIST_LOG(usbdebug, "overrun addr = %d type = 0x%02x", |
1097 | dev->ud_addr, xfer->ux_request.bmRequestType, 0, 0); | | 1100 | dev->ud_addr, xfer->ux_request.bmRequestType, 0, 0); |
1098 | USBHIST_LOG(usbdebug, " req = 0x%02x val = %d index = %d", | | 1101 | USBHIST_LOG(usbdebug, " req = 0x%02x val = %d index = %d", |
1099 | xfer->ux_request.bRequest, UGETW(xfer->ux_request.wValue), | | 1102 | xfer->ux_request.bRequest, UGETW(xfer->ux_request.wValue), |
1100 | UGETW(xfer->ux_request.wIndex), 0); | | 1103 | UGETW(xfer->ux_request.wIndex), 0); |
1101 | USBHIST_LOG(usbdebug, " rlen = %d length = %d actlen = %d", | | 1104 | USBHIST_LOG(usbdebug, " rlen = %d length = %d actlen = %d", |
1102 | UGETW(xfer->ux_request.wLength), | | 1105 | UGETW(xfer->ux_request.wLength), |
1103 | xfer->ux_length, xfer->ux_actlen, 0); | | 1106 | xfer->ux_length, xfer->ux_actlen, 0); |
1104 | } | | 1107 | } |
1105 | #endif | | 1108 | #endif |
1106 | if (actlen != NULL) | | 1109 | if (actlen != NULL) |
1107 | *actlen = xfer->ux_actlen; | | 1110 | *actlen = xfer->ux_actlen; |
1108 | if (err == USBD_STALLED) { | | 1111 | if (err == USBD_STALLED) { |
1109 | /* | | 1112 | /* |
1110 | * The control endpoint has stalled. Control endpoints | | 1113 | * The control endpoint has stalled. Control endpoints |
1111 | * should not halt, but some may do so anyway so clear | | 1114 | * should not halt, but some may do so anyway so clear |
1112 | * any halt condition. | | 1115 | * any halt condition. |
1113 | */ | | 1116 | */ |
1114 | usb_device_request_t treq; | | 1117 | usb_device_request_t treq; |
1115 | usb_status_t status; | | 1118 | usb_status_t status; |
1116 | uint16_t s; | | 1119 | uint16_t s; |
1117 | usbd_status nerr; | | 1120 | usbd_status nerr; |
1118 | | | 1121 | |
1119 | treq.bmRequestType = UT_READ_ENDPOINT; | | 1122 | treq.bmRequestType = UT_READ_ENDPOINT; |
1120 | treq.bRequest = UR_GET_STATUS; | | 1123 | treq.bRequest = UR_GET_STATUS; |
1121 | USETW(treq.wValue, 0); | | 1124 | USETW(treq.wValue, 0); |
1122 | USETW(treq.wIndex, 0); | | 1125 | USETW(treq.wIndex, 0); |
1123 | USETW(treq.wLength, sizeof(usb_status_t)); | | 1126 | USETW(treq.wLength, sizeof(usb_status_t)); |
1124 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, | | 1127 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, |
1125 | &treq, &status,sizeof(usb_status_t), | | 1128 | &treq, &status,sizeof(usb_status_t), |
1126 | 0, 0); | | 1129 | 0, 0); |
1127 | nerr = usbd_sync_transfer(xfer); | | 1130 | nerr = usbd_sync_transfer(xfer); |
1128 | if (nerr) | | 1131 | if (nerr) |
1129 | goto bad; | | 1132 | goto bad; |
1130 | s = UGETW(status.wStatus); | | 1133 | s = UGETW(status.wStatus); |
1131 | USBHIST_LOG(usbdebug, "status = 0x%04x", s, 0, 0, 0); | | 1134 | USBHIST_LOG(usbdebug, "status = 0x%04x", s, 0, 0, 0); |
1132 | if (!(s & UES_HALT)) | | 1135 | if (!(s & UES_HALT)) |
1133 | goto bad; | | 1136 | goto bad; |
1134 | treq.bmRequestType = UT_WRITE_ENDPOINT; | | 1137 | treq.bmRequestType = UT_WRITE_ENDPOINT; |
1135 | treq.bRequest = UR_CLEAR_FEATURE; | | 1138 | treq.bRequest = UR_CLEAR_FEATURE; |
1136 | USETW(treq.wValue, UF_ENDPOINT_HALT); | | 1139 | USETW(treq.wValue, UF_ENDPOINT_HALT); |
1137 | USETW(treq.wIndex, 0); | | 1140 | USETW(treq.wIndex, 0); |
1138 | USETW(treq.wLength, 0); | | 1141 | USETW(treq.wLength, 0); |
1139 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, | | 1142 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, |
1140 | &treq, &status, 0, 0, 0); | | 1143 | &treq, &status, 0, 0, 0); |
1141 | nerr = usbd_sync_transfer(xfer); | | 1144 | nerr = usbd_sync_transfer(xfer); |
1142 | if (nerr) | | 1145 | if (nerr) |
1143 | goto bad; | | 1146 | goto bad; |
1144 | } | | 1147 | } |
1145 | | | 1148 | |
1146 | bad: | | 1149 | bad: |
1147 | if (err) { | | 1150 | if (err) { |
1148 | USBHIST_LOG(usbdebug, "returning err = %s", | | 1151 | USBHIST_LOG(usbdebug, "returning err = %s", |
1149 | usbd_errstr(err), 0, 0, 0); | | 1152 | usbd_errstr(err), 0, 0, 0); |
1150 | } | | 1153 | } |
1151 | usbd_free_xfer(xfer); | | 1154 | usbd_free_xfer(xfer); |
| | | 1155 | if (buf) |
| | | 1156 | usbd_free_buffer(buf); |
1152 | return err; | | 1157 | return err; |
1153 | } | | 1158 | } |
1154 | | | 1159 | |
1155 | const struct usbd_quirks * | | 1160 | const struct usbd_quirks * |
1156 | usbd_get_quirks(usbd_device_handle dev) | | 1161 | usbd_get_quirks(usbd_device_handle dev) |
1157 | { | | 1162 | { |
1158 | #ifdef DIAGNOSTIC | | 1163 | #ifdef DIAGNOSTIC |
1159 | if (dev == NULL) { | | 1164 | if (dev == NULL) { |
1160 | printf("usbd_get_quirks: dev == NULL\n"); | | 1165 | printf("usbd_get_quirks: dev == NULL\n"); |
1161 | return 0; | | 1166 | return 0; |
1162 | } | | 1167 | } |
1163 | #endif | | 1168 | #endif |
1164 | return dev->ud_quirks; | | 1169 | return dev->ud_quirks; |
1165 | } | | 1170 | } |
1166 | | | 1171 | |
1167 | /* XXX do periodic free() of free list */ | | 1172 | /* XXX do periodic free() of free list */ |
1168 | | | 1173 | |
1169 | /* | | 1174 | /* |
1170 | * Called from keyboard driver when in polling mode. | | 1175 | * Called from keyboard driver when in polling mode. |
1171 | */ | | 1176 | */ |
1172 | void | | 1177 | void |
1173 | usbd_dopoll(usbd_interface_handle iface) | | 1178 | usbd_dopoll(usbd_interface_handle iface) |
1174 | { | | 1179 | { |
1175 | iface->ui_dev->ud_bus->ub_methods->ubm_dopoll(iface->ui_dev->ud_bus); | | 1180 | iface->ui_dev->ud_bus->ub_methods->ubm_dopoll(iface->ui_dev->ud_bus); |
1176 | } | | 1181 | } |
1177 | | | 1182 | |
1178 | /* | | 1183 | /* |
1179 | * XXX use this more??? ub_usepolling it touched manually all over | | 1184 | * XXX use this more??? ub_usepolling it touched manually all over |
1180 | */ | | 1185 | */ |
1181 | void | | 1186 | void |
1182 | usbd_set_polling(usbd_device_handle dev, int on) | | 1187 | usbd_set_polling(usbd_device_handle dev, int on) |
1183 | { | | 1188 | { |
1184 | if (on) | | 1189 | if (on) |
1185 | dev->ud_bus->ub_usepolling++; | | 1190 | dev->ud_bus->ub_usepolling++; |
1186 | else | | 1191 | else |
1187 | dev->ud_bus->ub_usepolling--; | | 1192 | dev->ud_bus->ub_usepolling--; |
1188 | | | 1193 | |
1189 | /* Kick the host controller when switching modes */ | | 1194 | /* Kick the host controller when switching modes */ |
1190 | mutex_enter(dev->ud_bus->ub_lock); | | 1195 | mutex_enter(dev->ud_bus->ub_lock); |
1191 | dev->ud_bus->ub_methods->ubm_softint(dev->ud_bus); | | 1196 | dev->ud_bus->ub_methods->ubm_softint(dev->ud_bus); |
1192 | mutex_exit(dev->ud_bus->ub_lock); | | 1197 | mutex_exit(dev->ud_bus->ub_lock); |
1193 | } | | 1198 | } |
1194 | | | 1199 | |
1195 | | | 1200 | |
1196 | usb_endpoint_descriptor_t * | | 1201 | usb_endpoint_descriptor_t * |
1197 | usbd_get_endpoint_descriptor(usbd_interface_handle iface, uint8_t address) | | 1202 | usbd_get_endpoint_descriptor(usbd_interface_handle iface, uint8_t address) |
1198 | { | | 1203 | { |
1199 | struct usbd_endpoint *ep; | | 1204 | struct usbd_endpoint *ep; |
1200 | int i; | | 1205 | int i; |
1201 | | | 1206 | |
1202 | for (i = 0; i < iface->ui_idesc->bNumEndpoints; i++) { | | 1207 | for (i = 0; i < iface->ui_idesc->bNumEndpoints; i++) { |
1203 | ep = &iface->ui_endpoints[i]; | | 1208 | ep = &iface->ui_endpoints[i]; |
1204 | if (ep->ue_edesc->bEndpointAddress == address) | | 1209 | if (ep->ue_edesc->bEndpointAddress == address) |
1205 | return iface->ui_endpoints[i].ue_edesc; | | 1210 | return iface->ui_endpoints[i].ue_edesc; |
1206 | } | | 1211 | } |
1207 | return NULL; | | 1212 | return NULL; |
1208 | } | | 1213 | } |
1209 | | | 1214 | |
1210 | /* | | 1215 | /* |
1211 | * usbd_ratecheck() can limit the number of error messages that occurs. | | 1216 | * usbd_ratecheck() can limit the number of error messages that occurs. |
1212 | * When a device is unplugged it may take up to 0.25s for the hub driver | | 1217 | * When a device is unplugged it may take up to 0.25s for the hub driver |
1213 | * to notice it. If the driver continuosly tries to do I/O operations | | 1218 | * to notice it. If the driver continuosly tries to do I/O operations |
1214 | * this can generate a large number of messages. | | 1219 | * this can generate a large number of messages. |
1215 | */ | | 1220 | */ |
1216 | int | | 1221 | int |
1217 | usbd_ratecheck(struct timeval *last) | | 1222 | usbd_ratecheck(struct timeval *last) |
1218 | { | | 1223 | { |
1219 | static struct timeval errinterval = { 0, 250000 }; /* 0.25 s*/ | | 1224 | static struct timeval errinterval = { 0, 250000 }; /* 0.25 s*/ |
1220 | | | 1225 | |
1221 | return ratecheck(last, &errinterval); | | 1226 | return ratecheck(last, &errinterval); |
1222 | } | | 1227 | } |
1223 | | | 1228 | |
1224 | /* | | 1229 | /* |
1225 | * Search for a vendor/product pair in an array. The item size is | | 1230 | * Search for a vendor/product pair in an array. The item size is |
1226 | * given as an argument. | | 1231 | * given as an argument. |
1227 | */ | | 1232 | */ |
1228 | const struct usb_devno * | | 1233 | const struct usb_devno * |
1229 | usb_match_device(const struct usb_devno *tbl, u_int nentries, u_int sz, | | 1234 | usb_match_device(const struct usb_devno *tbl, u_int nentries, u_int sz, |
1230 | uint16_t vendor, uint16_t product) | | 1235 | uint16_t vendor, uint16_t product) |
1231 | { | | 1236 | { |
1232 | while (nentries-- > 0) { | | 1237 | while (nentries-- > 0) { |
1233 | uint16_t tproduct = tbl->ud_product; | | 1238 | uint16_t tproduct = tbl->ud_product; |
1234 | if (tbl->ud_vendor == vendor && | | 1239 | if (tbl->ud_vendor == vendor && |
1235 | (tproduct == product || tproduct == USB_PRODUCT_ANY)) | | 1240 | (tproduct == product || tproduct == USB_PRODUCT_ANY)) |
1236 | return tbl; | | 1241 | return tbl; |
1237 | tbl = (const struct usb_devno *)((const char *)tbl + sz); | | 1242 | tbl = (const struct usb_devno *)((const char *)tbl + sz); |
1238 | } | | 1243 | } |
1239 | return NULL; | | 1244 | return NULL; |
1240 | } | | 1245 | } |
1241 | | | 1246 | |
1242 | | | 1247 | |
1243 | void | | 1248 | void |
1244 | usb_desc_iter_init(usbd_device_handle dev, usbd_desc_iter_t *iter) | | 1249 | usb_desc_iter_init(usbd_device_handle dev, usbd_desc_iter_t *iter) |
1245 | { | | 1250 | { |
1246 | const usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev); | | 1251 | const usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev); |
1247 | | | 1252 | |
1248 | iter->cur = (const uByte *)cd; | | 1253 | iter->cur = (const uByte *)cd; |
1249 | iter->end = (const uByte *)cd + UGETW(cd->wTotalLength); | | 1254 | iter->end = (const uByte *)cd + UGETW(cd->wTotalLength); |
1250 | } | | 1255 | } |
1251 | | | 1256 | |
1252 | const usb_descriptor_t * | | 1257 | const usb_descriptor_t * |
1253 | usb_desc_iter_next(usbd_desc_iter_t *iter) | | 1258 | usb_desc_iter_next(usbd_desc_iter_t *iter) |
1254 | { | | 1259 | { |
1255 | const usb_descriptor_t *desc; | | 1260 | const usb_descriptor_t *desc; |
1256 | | | 1261 | |
1257 | if (iter->cur + sizeof(usb_descriptor_t) >= iter->end) { | | 1262 | if (iter->cur + sizeof(usb_descriptor_t) >= iter->end) { |
1258 | if (iter->cur != iter->end) | | 1263 | if (iter->cur != iter->end) |
1259 | printf("usb_desc_iter_next: bad descriptor\n"); | | 1264 | printf("usb_desc_iter_next: bad descriptor\n"); |
1260 | return NULL; | | 1265 | return NULL; |
1261 | } | | 1266 | } |
1262 | desc = (const usb_descriptor_t *)iter->cur; | | 1267 | desc = (const usb_descriptor_t *)iter->cur; |
1263 | if (desc->bLength == 0) { | | 1268 | if (desc->bLength == 0) { |
1264 | printf("usb_desc_iter_next: descriptor length = 0\n"); | | 1269 | printf("usb_desc_iter_next: descriptor length = 0\n"); |
1265 | return NULL; | | 1270 | return NULL; |
1266 | } | | 1271 | } |
1267 | iter->cur += desc->bLength; | | 1272 | iter->cur += desc->bLength; |
1268 | if (iter->cur > iter->end) { | | 1273 | if (iter->cur > iter->end) { |
1269 | printf("usb_desc_iter_next: descriptor length too large\n"); | | 1274 | printf("usb_desc_iter_next: descriptor length too large\n"); |
1270 | return NULL; | | 1275 | return NULL; |
1271 | } | | 1276 | } |
1272 | return desc; | | 1277 | return desc; |
1273 | } | | 1278 | } |
1274 | | | 1279 | |
1275 | usbd_status | | 1280 | usbd_status |
1276 | usbd_get_string(usbd_device_handle dev, int si, char *buf) | | 1281 | usbd_get_string(usbd_device_handle dev, int si, char *buf) |
1277 | { | | 1282 | { |
1278 | return usbd_get_string0(dev, si, buf, 1); | | 1283 | return usbd_get_string0(dev, si, buf, 1); |
1279 | } | | 1284 | } |
1280 | | | 1285 | |
1281 | usbd_status | | 1286 | usbd_status |
1282 | usbd_get_string0(usbd_device_handle dev, int si, char *buf, int unicode) | | 1287 | usbd_get_string0(usbd_device_handle dev, int si, char *buf, int unicode) |
1283 | { | | 1288 | { |
1284 | int swap = dev->ud_quirks->uq_flags & UQ_SWAP_UNICODE; | | 1289 | int swap = dev->ud_quirks->uq_flags & UQ_SWAP_UNICODE; |
1285 | usb_string_descriptor_t us; | | 1290 | usb_string_descriptor_t us; |
1286 | char *s; | | 1291 | char *s; |
1287 | int i, n; | | 1292 | int i, n; |
1288 | uint16_t c; | | 1293 | uint16_t c; |
1289 | usbd_status err; | | 1294 | usbd_status err; |
1290 | int size; | | 1295 | int size; |
1291 | | | 1296 | |
1292 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | | 1297 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
1293 | | | 1298 | |
1294 | buf[0] = '\0'; | | 1299 | buf[0] = '\0'; |
1295 | if (si == 0) | | 1300 | if (si == 0) |
1296 | return USBD_INVAL; | | 1301 | return USBD_INVAL; |
1297 | if (dev->ud_quirks->uq_flags & UQ_NO_STRINGS) | | 1302 | if (dev->ud_quirks->uq_flags & UQ_NO_STRINGS) |
1298 | return USBD_STALLED; | | 1303 | return USBD_STALLED; |
1299 | if (dev->ud_langid == USBD_NOLANG) { | | 1304 | if (dev->ud_langid == USBD_NOLANG) { |
1300 | /* Set up default language */ | | 1305 | /* Set up default language */ |
1301 | err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us, | | 1306 | err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us, |
1302 | &size); | | 1307 | &size); |
1303 | if (err || size < 4) { | | 1308 | if (err || size < 4) { |
1304 | USBHIST_LOG(usbdebug, "getting lang failed, using 0", | | 1309 | USBHIST_LOG(usbdebug, "getting lang failed, using 0", |
1305 | 0, 0, 0, 0); | | 1310 | 0, 0, 0, 0); |
1306 | dev->ud_langid = 0; /* Well, just pick something then */ | | 1311 | dev->ud_langid = 0; /* Well, just pick something then */ |
1307 | } else { | | 1312 | } else { |
1308 | /* Pick the first language as the default. */ | | 1313 | /* Pick the first language as the default. */ |
1309 | dev->ud_langid = UGETW(us.bString[0]); | | 1314 | dev->ud_langid = UGETW(us.bString[0]); |
1310 | } | | 1315 | } |
1311 | } | | 1316 | } |
1312 | err = usbd_get_string_desc(dev, si, dev->ud_langid, &us, &size); | | 1317 | err = usbd_get_string_desc(dev, si, dev->ud_langid, &us, &size); |
1313 | if (err) | | 1318 | if (err) |
1314 | return err; | | 1319 | return err; |
1315 | s = buf; | | 1320 | s = buf; |
1316 | n = size / 2 - 1; | | 1321 | n = size / 2 - 1; |
1317 | if (unicode) { | | 1322 | if (unicode) { |
1318 | for (i = 0; i < n; i++) { | | 1323 | for (i = 0; i < n; i++) { |
1319 | c = UGETW(us.bString[i]); | | 1324 | c = UGETW(us.bString[i]); |
1320 | if (swap) | | 1325 | if (swap) |
1321 | c = (c >> 8) | (c << 8); | | 1326 | c = (c >> 8) | (c << 8); |
1322 | s += wput_utf8(s, 3, c); | | 1327 | s += wput_utf8(s, 3, c); |
1323 | } | | 1328 | } |
1324 | *s++ = 0; | | 1329 | *s++ = 0; |
1325 | } | | 1330 | } |
1326 | #ifdef COMPAT_30 | | 1331 | #ifdef COMPAT_30 |
1327 | else { | | 1332 | else { |
1328 | for (i = 0; i < n; i++) { | | 1333 | for (i = 0; i < n; i++) { |
1329 | c = UGETW(us.bString[i]); | | 1334 | c = UGETW(us.bString[i]); |
1330 | if (swap) | | 1335 | if (swap) |
1331 | c = (c >> 8) | (c << 8); | | 1336 | c = (c >> 8) | (c << 8); |
1332 | *s++ = (c < 0x80) ? c : '?'; | | 1337 | *s++ = (c < 0x80) ? c : '?'; |
1333 | } | | 1338 | } |
1334 | *s++ = 0; | | 1339 | *s++ = 0; |
1335 | } | | 1340 | } |
1336 | #endif | | 1341 | #endif |
1337 | return USBD_NORMAL_COMPLETION; | | 1342 | return USBD_NORMAL_COMPLETION; |
1338 | } | | 1343 | } |