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