File: | dev/usb/usb.c |
Warning: | line 659, column 19 The left operand of '==' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: usb.c,v 1.129 2022/01/09 05:43:02 jsg Exp $ */ | |||
2 | /* $NetBSD: usb.c,v 1.77 2003/01/01 00:10:26 thorpej Exp $ */ | |||
3 | ||||
4 | /* | |||
5 | * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc. | |||
6 | * All rights reserved. | |||
7 | * | |||
8 | * This code is derived from software contributed to The NetBSD Foundation | |||
9 | * by Lennart Augustsson (lennart@augustsson.net) at | |||
10 | * Carlstedt Research & Technology. | |||
11 | * | |||
12 | * Redistribution and use in source and binary forms, with or without | |||
13 | * modification, are permitted provided that the following conditions | |||
14 | * are met: | |||
15 | * 1. Redistributions of source code must retain the above copyright | |||
16 | * notice, this list of conditions and the following disclaimer. | |||
17 | * 2. Redistributions in binary form must reproduce the above copyright | |||
18 | * notice, this list of conditions and the following disclaimer in the | |||
19 | * documentation and/or other materials provided with the distribution. | |||
20 | * | |||
21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |||
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |||
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |||
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
31 | * POSSIBILITY OF SUCH DAMAGE. | |||
32 | */ | |||
33 | ||||
34 | /* | |||
35 | * USB specifications and other documentation can be found at | |||
36 | * https://www.usb.org/documents | |||
37 | */ | |||
38 | ||||
39 | #include "ohci.h" | |||
40 | #include "uhci.h" | |||
41 | #include "ehci.h" | |||
42 | ||||
43 | #include <sys/param.h> | |||
44 | #include <sys/systm.h> | |||
45 | #include <sys/kernel.h> | |||
46 | #include <sys/malloc.h> | |||
47 | #include <sys/device.h> | |||
48 | #include <sys/timeout.h> | |||
49 | #include <sys/kthread.h> | |||
50 | #include <sys/conf.h> | |||
51 | #include <sys/fcntl.h> | |||
52 | #include <sys/poll.h> | |||
53 | #include <sys/selinfo.h> | |||
54 | #include <sys/signalvar.h> | |||
55 | #include <sys/time.h> | |||
56 | #include <sys/rwlock.h> | |||
57 | ||||
58 | #include <dev/usb/usb.h> | |||
59 | #include <dev/usb/usbdi.h> | |||
60 | #include <dev/usb/usbdi_util.h> | |||
61 | ||||
62 | #include <machine/bus.h> | |||
63 | ||||
64 | #include <dev/usb/usbdivar.h> | |||
65 | #include <dev/usb/usb_mem.h> | |||
66 | #include <dev/usb/usbpcap.h> | |||
67 | ||||
68 | #ifdef USB_DEBUG | |||
69 | #define DPRINTF(x) do { if (usbdebug) printf x; } while (0) | |||
70 | #define DPRINTFN(n,x) do { if (usbdebug>(n)) printf x; } while (0) | |||
71 | int usbdebug = 0; | |||
72 | #if defined(UHCI_DEBUG) && NUHCI1 > 0 | |||
73 | extern int uhcidebug; | |||
74 | #endif | |||
75 | #if defined(OHCI_DEBUG) && NOHCI1 > 0 | |||
76 | extern int ohcidebug; | |||
77 | #endif | |||
78 | #if defined(EHCI_DEBUG) && NEHCI1 > 0 | |||
79 | extern int ehcidebug; | |||
80 | #endif | |||
81 | /* | |||
82 | * 0 - do usual exploration | |||
83 | * !0 - do no exploration | |||
84 | */ | |||
85 | int usb_noexplore = 0; | |||
86 | #else | |||
87 | #define DPRINTF(x) | |||
88 | #define DPRINTFN(n,x) | |||
89 | #endif | |||
90 | ||||
91 | struct usb_softc { | |||
92 | struct device sc_dev; /* base device */ | |||
93 | struct usbd_bus *sc_bus; /* USB controller */ | |||
94 | struct usbd_port sc_port; /* dummy port for root hub */ | |||
95 | int sc_speed; | |||
96 | ||||
97 | struct usb_task sc_explore_task; | |||
98 | ||||
99 | struct timeval sc_ptime; | |||
100 | }; | |||
101 | ||||
102 | struct rwlock usbpalock; | |||
103 | ||||
104 | TAILQ_HEAD(, usb_task)struct { struct usb_task *tqh_first; struct usb_task **tqh_last ; } usb_abort_tasks; | |||
105 | TAILQ_HEAD(, usb_task)struct { struct usb_task *tqh_first; struct usb_task **tqh_last ; } usb_explore_tasks; | |||
106 | TAILQ_HEAD(, usb_task)struct { struct usb_task *tqh_first; struct usb_task **tqh_last ; } usb_generic_tasks; | |||
107 | ||||
108 | static int usb_nbuses = 0; | |||
109 | static int usb_run_tasks, usb_run_abort_tasks; | |||
110 | int explore_pending; | |||
111 | const char *usbrev_str[] = USBREV_STR{ "unknown", "pre 1.0", "1.0", "1.1", "2.0", "3.0" }; | |||
112 | ||||
113 | void usb_explore(void *); | |||
114 | void usb_create_task_threads(void *); | |||
115 | void usb_task_thread(void *); | |||
116 | struct proc *usb_task_thread_proc = NULL((void *)0); | |||
117 | void usb_abort_task_thread(void *); | |||
118 | struct proc *usb_abort_task_thread_proc = NULL((void *)0); | |||
119 | ||||
120 | void usb_fill_udc_task(void *); | |||
121 | void usb_fill_udf_task(void *); | |||
122 | ||||
123 | int usb_match(struct device *, void *, void *); | |||
124 | void usb_attach(struct device *, struct device *, void *); | |||
125 | int usb_detach(struct device *, int); | |||
126 | int usb_activate(struct device *, int); | |||
127 | ||||
128 | int usb_attach_roothub(struct usb_softc *); | |||
129 | void usb_detach_roothub(struct usb_softc *); | |||
130 | ||||
131 | struct cfdriver usb_cd = { | |||
132 | NULL((void *)0), "usb", DV_DULL | |||
133 | }; | |||
134 | ||||
135 | const struct cfattach usb_ca = { | |||
136 | sizeof(struct usb_softc), usb_match, usb_attach, usb_detach, | |||
137 | usb_activate, | |||
138 | }; | |||
139 | ||||
140 | int | |||
141 | usb_match(struct device *parent, void *match, void *aux) | |||
142 | { | |||
143 | return (1); | |||
144 | } | |||
145 | ||||
146 | void | |||
147 | usb_attach(struct device *parent, struct device *self, void *aux) | |||
148 | { | |||
149 | struct usb_softc *sc = (struct usb_softc *)self; | |||
150 | int usbrev; | |||
151 | ||||
152 | if (usb_nbuses == 0) { | |||
153 | rw_init(&usbpalock, "usbpalock")_rw_init_flags(&usbpalock, "usbpalock", 0, ((void *)0)); | |||
154 | TAILQ_INIT(&usb_abort_tasks)do { (&usb_abort_tasks)->tqh_first = ((void *)0); (& usb_abort_tasks)->tqh_last = &(&usb_abort_tasks)-> tqh_first; } while (0); | |||
155 | TAILQ_INIT(&usb_explore_tasks)do { (&usb_explore_tasks)->tqh_first = ((void *)0); (& usb_explore_tasks)->tqh_last = &(&usb_explore_tasks )->tqh_first; } while (0); | |||
156 | TAILQ_INIT(&usb_generic_tasks)do { (&usb_generic_tasks)->tqh_first = ((void *)0); (& usb_generic_tasks)->tqh_last = &(&usb_generic_tasks )->tqh_first; } while (0); | |||
157 | usb_run_tasks = usb_run_abort_tasks = 1; | |||
158 | kthread_create_deferred(usb_create_task_threads, NULL((void *)0)); | |||
159 | } | |||
160 | usb_nbuses++; | |||
161 | ||||
162 | sc->sc_bus = aux; | |||
163 | sc->sc_bus->usbctl = self; | |||
164 | sc->sc_port.power = USB_MAX_POWER500; | |||
165 | ||||
166 | usbrev = sc->sc_bus->usbrev; | |||
167 | printf(": USB revision %s", usbrev_str[usbrev]); | |||
168 | switch (usbrev) { | |||
169 | case USBREV_1_02: | |||
170 | case USBREV_1_13: | |||
171 | sc->sc_speed = USB_SPEED_FULL2; | |||
172 | break; | |||
173 | case USBREV_2_04: | |||
174 | sc->sc_speed = USB_SPEED_HIGH3; | |||
175 | break; | |||
176 | case USBREV_3_05: | |||
177 | sc->sc_speed = USB_SPEED_SUPER4; | |||
178 | break; | |||
179 | default: | |||
180 | printf(", not supported\n"); | |||
181 | sc->sc_bus->dying = 1; | |||
182 | return; | |||
183 | } | |||
184 | printf("\n"); | |||
185 | ||||
186 | #if NBPFILTER1 > 0 | |||
187 | sc->sc_bus->bpfif = bpfsattach(&sc->sc_bus->bpf, sc->sc_dev.dv_xname, | |||
188 | DLT_USBPCAP249, sizeof(struct usbpcap_pkt_hdr)); | |||
189 | #endif | |||
190 | ||||
191 | /* Make sure not to use tsleep() if we are cold booting. */ | |||
192 | if (cold) | |||
193 | sc->sc_bus->use_polling++; | |||
194 | ||||
195 | /* Don't let hub interrupts cause explore until ready. */ | |||
196 | sc->sc_bus->flags |= USB_BUS_CONFIG_PENDING0x01; | |||
197 | ||||
198 | /* explore task */ | |||
199 | usb_init_task(&sc->sc_explore_task, usb_explore, sc,((&sc->sc_explore_task)->fun = (usb_explore), (& sc->sc_explore_task)->arg = (sc), (&sc->sc_explore_task )->type = (1), (&sc->sc_explore_task)->state = 0x0 ) | |||
200 | USB_TASK_TYPE_EXPLORE)((&sc->sc_explore_task)->fun = (usb_explore), (& sc->sc_explore_task)->arg = (sc), (&sc->sc_explore_task )->type = (1), (&sc->sc_explore_task)->state = 0x0 ); | |||
201 | ||||
202 | sc->sc_bus->soft = softintr_establish(IPL_SOFTUSB0x5, | |||
203 | sc->sc_bus->methods->soft_intr, sc->sc_bus); | |||
204 | if (sc->sc_bus->soft == NULL((void *)0)) { | |||
205 | printf("%s: can't register softintr\n", sc->sc_dev.dv_xname); | |||
206 | sc->sc_bus->dying = 1; | |||
207 | return; | |||
208 | } | |||
209 | ||||
210 | if (!usb_attach_roothub(sc)) { | |||
211 | struct usbd_device *dev = sc->sc_bus->root_hub; | |||
212 | #if 1 | |||
213 | /* | |||
214 | * Turning this code off will delay attachment of USB devices | |||
215 | * until the USB task thread is running, which means that | |||
216 | * the keyboard will not work until after cold boot. | |||
217 | */ | |||
218 | if (cold && (sc->sc_dev.dv_cfdata->cf_flags & 1)) | |||
219 | dev->hub->explore(sc->sc_bus->root_hub); | |||
220 | #endif | |||
221 | } | |||
222 | ||||
223 | if (cold) | |||
224 | sc->sc_bus->use_polling--; | |||
225 | ||||
226 | if (!sc->sc_bus->dying) { | |||
227 | getmicrouptime(&sc->sc_ptime); | |||
228 | if (sc->sc_bus->usbrev == USBREV_2_04) | |||
229 | explore_pending++; | |||
230 | config_pending_incr(); | |||
231 | usb_needs_explore(sc->sc_bus->root_hub, 1); | |||
232 | } | |||
233 | } | |||
234 | ||||
235 | int | |||
236 | usb_attach_roothub(struct usb_softc *sc) | |||
237 | { | |||
238 | struct usbd_device *dev; | |||
239 | ||||
240 | if (usbd_new_device(&sc->sc_dev, sc->sc_bus, 0, sc->sc_speed, 0, | |||
241 | &sc->sc_port)) { | |||
242 | printf("%s: root hub problem\n", sc->sc_dev.dv_xname); | |||
243 | sc->sc_bus->dying = 1; | |||
244 | return (1); | |||
245 | } | |||
246 | ||||
247 | dev = sc->sc_port.device; | |||
248 | if (dev->hub == NULL((void *)0)) { | |||
249 | printf("%s: root device is not a hub\n", sc->sc_dev.dv_xname); | |||
250 | sc->sc_bus->dying = 1; | |||
251 | return (1); | |||
252 | } | |||
253 | sc->sc_bus->root_hub = dev; | |||
254 | ||||
255 | return (0); | |||
256 | } | |||
257 | ||||
258 | void | |||
259 | usb_detach_roothub(struct usb_softc *sc) | |||
260 | { | |||
261 | /* | |||
262 | * To avoid races with the usb task thread, mark the root hub | |||
263 | * as disconnecting and schedule an exploration task to detach | |||
264 | * it. | |||
265 | */ | |||
266 | sc->sc_bus->flags |= USB_BUS_DISCONNECTING0x02; | |||
267 | /* | |||
268 | * Reset the dying flag in case it has been set by the interrupt | |||
269 | * handler when unplugging an HC card otherwise the task wont be | |||
270 | * scheduled. This is safe since a dead HC should not trigger | |||
271 | * new interrupt. | |||
272 | */ | |||
273 | sc->sc_bus->dying = 0; | |||
274 | usb_needs_explore(sc->sc_bus->root_hub, 0); | |||
275 | ||||
276 | usb_wait_task(sc->sc_bus->root_hub, &sc->sc_explore_task); | |||
277 | ||||
278 | sc->sc_bus->root_hub = NULL((void *)0); | |||
279 | } | |||
280 | ||||
281 | void | |||
282 | usb_create_task_threads(void *arg) | |||
283 | { | |||
284 | if (kthread_create(usb_abort_task_thread, NULL((void *)0), | |||
285 | &usb_abort_task_thread_proc, "usbatsk")) | |||
286 | panic("unable to create usb abort task thread"); | |||
287 | ||||
288 | if (kthread_create(usb_task_thread, NULL((void *)0), | |||
289 | &usb_task_thread_proc, "usbtask")) | |||
290 | panic("unable to create usb task thread"); | |||
291 | } | |||
292 | ||||
293 | /* | |||
294 | * Add a task to be performed by the task thread. This function can be | |||
295 | * called from any context and the task will be executed in a process | |||
296 | * context ASAP. | |||
297 | */ | |||
298 | void | |||
299 | usb_add_task(struct usbd_device *dev, struct usb_task *task) | |||
300 | { | |||
301 | int s; | |||
302 | ||||
303 | /* | |||
304 | * If the thread detaching ``dev'' is sleeping, waiting | |||
305 | * for all submitted transfers to finish, we must be able | |||
306 | * to enqueue abort tasks. Otherwise timeouts can't give | |||
307 | * back submitted transfers to the stack. | |||
308 | */ | |||
309 | if (usbd_is_dying(dev) && (task->type != USB_TASK_TYPE_ABORT2)) | |||
310 | return; | |||
311 | ||||
312 | DPRINTFN(2,("%s: task=%p state=%d type=%d\n", __func__, task, | |||
313 | task->state, task->type)); | |||
314 | ||||
315 | s = splusb()splraise(0x5); | |||
316 | if (!(task->state & USB_TASK_STATE_ONQ0x1)) { | |||
317 | switch (task->type) { | |||
318 | case USB_TASK_TYPE_ABORT2: | |||
319 | TAILQ_INSERT_TAIL(&usb_abort_tasks, task, next)do { (task)->next.tqe_next = ((void *)0); (task)->next. tqe_prev = (&usb_abort_tasks)->tqh_last; *(&usb_abort_tasks )->tqh_last = (task); (&usb_abort_tasks)->tqh_last = &(task)->next.tqe_next; } while (0); | |||
320 | break; | |||
321 | case USB_TASK_TYPE_EXPLORE1: | |||
322 | TAILQ_INSERT_TAIL(&usb_explore_tasks, task, next)do { (task)->next.tqe_next = ((void *)0); (task)->next. tqe_prev = (&usb_explore_tasks)->tqh_last; *(&usb_explore_tasks )->tqh_last = (task); (&usb_explore_tasks)->tqh_last = &(task)->next.tqe_next; } while (0); | |||
323 | break; | |||
324 | case USB_TASK_TYPE_GENERIC0: | |||
325 | TAILQ_INSERT_TAIL(&usb_generic_tasks, task, next)do { (task)->next.tqe_next = ((void *)0); (task)->next. tqe_prev = (&usb_generic_tasks)->tqh_last; *(&usb_generic_tasks )->tqh_last = (task); (&usb_generic_tasks)->tqh_last = &(task)->next.tqe_next; } while (0); | |||
326 | break; | |||
327 | } | |||
328 | task->state |= USB_TASK_STATE_ONQ0x1; | |||
329 | task->dev = dev; | |||
330 | } | |||
331 | if (task->type == USB_TASK_TYPE_ABORT2) | |||
332 | wakeup(&usb_run_abort_tasks); | |||
333 | else | |||
334 | wakeup(&usb_run_tasks); | |||
335 | splx(s)spllower(s); | |||
336 | } | |||
337 | ||||
338 | void | |||
339 | usb_rem_task(struct usbd_device *dev, struct usb_task *task) | |||
340 | { | |||
341 | int s; | |||
342 | ||||
343 | if (!(task->state & USB_TASK_STATE_ONQ0x1)) | |||
344 | return; | |||
345 | ||||
346 | DPRINTFN(2,("%s: task=%p state=%d type=%d\n", __func__, task, | |||
347 | task->state, task->type)); | |||
348 | ||||
349 | s = splusb()splraise(0x5); | |||
350 | ||||
351 | switch (task->type) { | |||
352 | case USB_TASK_TYPE_ABORT2: | |||
353 | TAILQ_REMOVE(&usb_abort_tasks, task, next)do { if (((task)->next.tqe_next) != ((void *)0)) (task)-> next.tqe_next->next.tqe_prev = (task)->next.tqe_prev; else (&usb_abort_tasks)->tqh_last = (task)->next.tqe_prev ; *(task)->next.tqe_prev = (task)->next.tqe_next; ((task )->next.tqe_prev) = ((void *)-1); ((task)->next.tqe_next ) = ((void *)-1); } while (0); | |||
354 | break; | |||
355 | case USB_TASK_TYPE_EXPLORE1: | |||
356 | TAILQ_REMOVE(&usb_explore_tasks, task, next)do { if (((task)->next.tqe_next) != ((void *)0)) (task)-> next.tqe_next->next.tqe_prev = (task)->next.tqe_prev; else (&usb_explore_tasks)->tqh_last = (task)->next.tqe_prev ; *(task)->next.tqe_prev = (task)->next.tqe_next; ((task )->next.tqe_prev) = ((void *)-1); ((task)->next.tqe_next ) = ((void *)-1); } while (0); | |||
357 | break; | |||
358 | case USB_TASK_TYPE_GENERIC0: | |||
359 | TAILQ_REMOVE(&usb_generic_tasks, task, next)do { if (((task)->next.tqe_next) != ((void *)0)) (task)-> next.tqe_next->next.tqe_prev = (task)->next.tqe_prev; else (&usb_generic_tasks)->tqh_last = (task)->next.tqe_prev ; *(task)->next.tqe_prev = (task)->next.tqe_next; ((task )->next.tqe_prev) = ((void *)-1); ((task)->next.tqe_next ) = ((void *)-1); } while (0); | |||
360 | break; | |||
361 | } | |||
362 | task->state &= ~USB_TASK_STATE_ONQ0x1; | |||
363 | if (task->state == USB_TASK_STATE_NONE0x0) | |||
364 | wakeup(task); | |||
365 | ||||
366 | splx(s)spllower(s); | |||
367 | } | |||
368 | ||||
369 | void | |||
370 | usb_wait_task(struct usbd_device *dev, struct usb_task *task) | |||
371 | { | |||
372 | int s; | |||
373 | ||||
374 | DPRINTFN(2,("%s: task=%p state=%d type=%d\n", __func__, task, | |||
375 | task->state, task->type)); | |||
376 | ||||
377 | if (task->state == USB_TASK_STATE_NONE0x0) | |||
378 | return; | |||
379 | ||||
380 | s = splusb()splraise(0x5); | |||
381 | while (task->state != USB_TASK_STATE_NONE0x0) { | |||
382 | DPRINTF(("%s: waiting for task to complete\n", __func__)); | |||
383 | tsleep_nsec(task, PWAIT32, "endtask", INFSLP0xffffffffffffffffULL); | |||
384 | } | |||
385 | splx(s)spllower(s); | |||
386 | } | |||
387 | ||||
388 | void | |||
389 | usb_rem_wait_task(struct usbd_device *dev, struct usb_task *task) | |||
390 | { | |||
391 | usb_rem_task(dev, task); | |||
392 | usb_wait_task(dev, task); | |||
393 | } | |||
394 | ||||
395 | void | |||
396 | usb_task_thread(void *arg) | |||
397 | { | |||
398 | struct usb_task *task; | |||
399 | int s; | |||
400 | ||||
401 | DPRINTF(("usb_task_thread: start\n")); | |||
402 | ||||
403 | s = splusb()splraise(0x5); | |||
404 | while (usb_run_tasks) { | |||
405 | if ((task = TAILQ_FIRST(&usb_explore_tasks)((&usb_explore_tasks)->tqh_first)) != NULL((void *)0)) | |||
406 | TAILQ_REMOVE(&usb_explore_tasks, task, next)do { if (((task)->next.tqe_next) != ((void *)0)) (task)-> next.tqe_next->next.tqe_prev = (task)->next.tqe_prev; else (&usb_explore_tasks)->tqh_last = (task)->next.tqe_prev ; *(task)->next.tqe_prev = (task)->next.tqe_next; ((task )->next.tqe_prev) = ((void *)-1); ((task)->next.tqe_next ) = ((void *)-1); } while (0); | |||
407 | else if ((task = TAILQ_FIRST(&usb_generic_tasks)((&usb_generic_tasks)->tqh_first)) != NULL((void *)0)) | |||
408 | TAILQ_REMOVE(&usb_generic_tasks, task, next)do { if (((task)->next.tqe_next) != ((void *)0)) (task)-> next.tqe_next->next.tqe_prev = (task)->next.tqe_prev; else (&usb_generic_tasks)->tqh_last = (task)->next.tqe_prev ; *(task)->next.tqe_prev = (task)->next.tqe_next; ((task )->next.tqe_prev) = ((void *)-1); ((task)->next.tqe_next ) = ((void *)-1); } while (0); | |||
409 | else { | |||
410 | tsleep_nsec(&usb_run_tasks, PWAIT32, "usbtsk", INFSLP0xffffffffffffffffULL); | |||
411 | continue; | |||
412 | } | |||
413 | /* | |||
414 | * Set the state run bit before clearing the onq bit. | |||
415 | * This avoids state == none between dequeue and | |||
416 | * execution, which could cause usb_wait_task() to do | |||
417 | * the wrong thing. | |||
418 | */ | |||
419 | task->state |= USB_TASK_STATE_RUN0x2; | |||
420 | task->state &= ~USB_TASK_STATE_ONQ0x1; | |||
421 | /* Don't actually execute the task if dying. */ | |||
422 | if (!usbd_is_dying(task->dev)) { | |||
423 | splx(s)spllower(s); | |||
424 | task->fun(task->arg); | |||
425 | s = splusb()splraise(0x5); | |||
426 | } | |||
427 | task->state &= ~USB_TASK_STATE_RUN0x2; | |||
428 | if (task->state == USB_TASK_STATE_NONE0x0) | |||
429 | wakeup(task); | |||
430 | } | |||
431 | splx(s)spllower(s); | |||
432 | ||||
433 | kthread_exit(0); | |||
434 | } | |||
435 | ||||
436 | /* | |||
437 | * This thread is ONLY for the HCI drivers to be able to abort xfers. | |||
438 | * Synchronous xfers sleep the task thread, so the aborts need to happen | |||
439 | * in a different thread. | |||
440 | */ | |||
441 | void | |||
442 | usb_abort_task_thread(void *arg) | |||
443 | { | |||
444 | struct usb_task *task; | |||
445 | int s; | |||
446 | ||||
447 | DPRINTF(("usb_xfer_abort_thread: start\n")); | |||
448 | ||||
449 | s = splusb()splraise(0x5); | |||
450 | while (usb_run_abort_tasks) { | |||
451 | if ((task = TAILQ_FIRST(&usb_abort_tasks)((&usb_abort_tasks)->tqh_first)) != NULL((void *)0)) | |||
452 | TAILQ_REMOVE(&usb_abort_tasks, task, next)do { if (((task)->next.tqe_next) != ((void *)0)) (task)-> next.tqe_next->next.tqe_prev = (task)->next.tqe_prev; else (&usb_abort_tasks)->tqh_last = (task)->next.tqe_prev ; *(task)->next.tqe_prev = (task)->next.tqe_next; ((task )->next.tqe_prev) = ((void *)-1); ((task)->next.tqe_next ) = ((void *)-1); } while (0); | |||
453 | else { | |||
454 | tsleep_nsec(&usb_run_abort_tasks, PWAIT32, "usbatsk", | |||
455 | INFSLP0xffffffffffffffffULL); | |||
456 | continue; | |||
457 | } | |||
458 | /* | |||
459 | * Set the state run bit before clearing the onq bit. | |||
460 | * This avoids state == none between dequeue and | |||
461 | * execution, which could cause usb_wait_task() to do | |||
462 | * the wrong thing. | |||
463 | */ | |||
464 | task->state |= USB_TASK_STATE_RUN0x2; | |||
465 | task->state &= ~USB_TASK_STATE_ONQ0x1; | |||
466 | splx(s)spllower(s); | |||
467 | task->fun(task->arg); | |||
468 | s = splusb()splraise(0x5); | |||
469 | task->state &= ~USB_TASK_STATE_RUN0x2; | |||
470 | if (task->state == USB_TASK_STATE_NONE0x0) | |||
471 | wakeup(task); | |||
472 | } | |||
473 | splx(s)spllower(s); | |||
474 | ||||
475 | kthread_exit(0); | |||
476 | } | |||
477 | ||||
478 | int | |||
479 | usbctlprint(void *aux, const char *pnp) | |||
480 | { | |||
481 | /* only "usb"es can attach to host controllers */ | |||
482 | if (pnp) | |||
483 | printf("usb at %s", pnp); | |||
484 | ||||
485 | return (UNCONF1); | |||
486 | } | |||
487 | ||||
488 | int | |||
489 | usbopen(dev_t dev, int flag, int mode, struct proc *p) | |||
490 | { | |||
491 | int unit = minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8)); | |||
492 | struct usb_softc *sc; | |||
493 | ||||
494 | if (unit >= usb_cd.cd_ndevs) | |||
495 | return (ENXIO6); | |||
496 | sc = usb_cd.cd_devs[unit]; | |||
497 | if (sc == NULL((void *)0)) | |||
498 | return (ENXIO6); | |||
499 | ||||
500 | if (sc->sc_bus->dying) | |||
501 | return (EIO5); | |||
502 | ||||
503 | return (0); | |||
504 | } | |||
505 | ||||
506 | int | |||
507 | usbclose(dev_t dev, int flag, int mode, struct proc *p) | |||
508 | { | |||
509 | return (0); | |||
510 | } | |||
511 | ||||
512 | void | |||
513 | usb_fill_udc_task(void *arg) | |||
514 | { | |||
515 | struct usb_device_cdesc *udc = (struct usb_device_cdesc *)arg; | |||
516 | struct usb_softc *sc; | |||
517 | struct usbd_device *dev; | |||
518 | int addr = udc->udc_addr, cdesc_len; | |||
519 | usb_config_descriptor_t *cdesc; | |||
520 | ||||
521 | /* check that the bus and device are still present */ | |||
522 | if (udc->udc_bus >= usb_cd.cd_ndevs) | |||
523 | return; | |||
524 | sc = usb_cd.cd_devs[udc->udc_bus]; | |||
525 | if (sc == NULL((void *)0)) | |||
526 | return; | |||
527 | dev = sc->sc_bus->devices[udc->udc_addr]; | |||
528 | if (dev == NULL((void *)0)) | |||
529 | return; | |||
530 | ||||
531 | cdesc = usbd_get_cdesc(sc->sc_bus->devices[addr], | |||
532 | udc->udc_config_index, &cdesc_len); | |||
533 | if (cdesc == NULL((void *)0)) | |||
534 | return; | |||
535 | udc->udc_desc = *cdesc; | |||
536 | free(cdesc, M_TEMP127, cdesc_len); | |||
537 | } | |||
538 | ||||
539 | void | |||
540 | usb_fill_udf_task(void *arg) | |||
541 | { | |||
542 | struct usb_device_fdesc *udf = (struct usb_device_fdesc *)arg; | |||
543 | struct usb_softc *sc; | |||
544 | struct usbd_device *dev; | |||
545 | int addr = udf->udf_addr; | |||
546 | usb_config_descriptor_t *cdesc; | |||
547 | ||||
548 | /* check that the bus and device are still present */ | |||
549 | if (udf->udf_bus >= usb_cd.cd_ndevs) | |||
550 | return; | |||
551 | sc = usb_cd.cd_devs[udf->udf_bus]; | |||
552 | if (sc == NULL((void *)0)) | |||
553 | return; | |||
554 | dev = sc->sc_bus->devices[udf->udf_addr]; | |||
555 | if (dev == NULL((void *)0)) | |||
556 | return; | |||
557 | ||||
558 | cdesc = usbd_get_cdesc(sc->sc_bus->devices[addr], | |||
559 | udf->udf_config_index, &udf->udf_size); | |||
560 | udf->udf_data = (char *)cdesc; | |||
561 | } | |||
562 | ||||
563 | int | |||
564 | usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p) | |||
565 | { | |||
566 | struct usb_softc *sc; | |||
567 | int unit = minor(devt)((unsigned)((devt) & 0xff) | (((devt) & 0xffff0000) >> 8)); | |||
568 | int error; | |||
569 | ||||
570 | sc = usb_cd.cd_devs[unit]; | |||
571 | ||||
572 | if (sc->sc_bus->dying) | |||
| ||||
573 | return (EIO5); | |||
574 | ||||
575 | error = 0; | |||
576 | switch (cmd) { | |||
577 | #ifdef USB_DEBUG | |||
578 | case USB_SETDEBUG((unsigned long)0x80000000 | ((sizeof(unsigned int) & 0x1fff ) << 16) | ((('U')) << 8) | ((2))): | |||
579 | /* only root can access to these debug flags */ | |||
580 | if ((error = suser(curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc)) != 0) | |||
581 | return (error); | |||
582 | if (!(flag & FWRITE0x0002)) | |||
583 | return (EBADF9); | |||
584 | usbdebug = ((*(unsigned int *)data) & 0x000000ff); | |||
585 | #if defined(UHCI_DEBUG) && NUHCI1 > 0 | |||
586 | uhcidebug = ((*(unsigned int *)data) & 0x0000ff00) >> 8; | |||
587 | #endif | |||
588 | #if defined(OHCI_DEBUG) && NOHCI1 > 0 | |||
589 | ohcidebug = ((*(unsigned int *)data) & 0x00ff0000) >> 16; | |||
590 | #endif | |||
591 | #if defined(EHCI_DEBUG) && NEHCI1 > 0 | |||
592 | ehcidebug = ((*(unsigned int *)data) & 0xff000000) >> 24; | |||
593 | #endif | |||
594 | break; | |||
595 | #endif /* USB_DEBUG */ | |||
596 | case USB_REQUEST(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct usb_ctl_request) & 0x1fff) << 16) | ((('U') ) << 8) | ((1))): | |||
597 | { | |||
598 | struct usb_ctl_request *ur = (void *)data; | |||
599 | size_t len = UGETW(ur->ucr_request.wLength)(*(u_int16_t *)(ur->ucr_request.wLength)), mlen; | |||
600 | struct iovec iov; | |||
601 | struct uio uio; | |||
602 | void *ptr = NULL((void *)0); | |||
603 | int addr = ur->ucr_addr; | |||
604 | usbd_status err; | |||
605 | ||||
606 | if (!(flag & FWRITE0x0002)) | |||
607 | return (EBADF9); | |||
608 | ||||
609 | DPRINTF(("%s: USB_REQUEST addr=%d len=%zu\n", __func__, addr, len)); | |||
610 | /* Avoid requests that would damage the bus integrity. */ | |||
611 | if ((ur->ucr_request.bmRequestType == UT_WRITE_DEVICE(0x00 | 0x00 | 0x00) && | |||
612 | ur->ucr_request.bRequest == UR_SET_ADDRESS0x05) || | |||
613 | (ur->ucr_request.bmRequestType == UT_WRITE_DEVICE(0x00 | 0x00 | 0x00) && | |||
614 | ur->ucr_request.bRequest == UR_SET_CONFIG0x09) || | |||
615 | (ur->ucr_request.bmRequestType == UT_WRITE_INTERFACE(0x00 | 0x00 | 0x01) && | |||
616 | ur->ucr_request.bRequest == UR_SET_INTERFACE0x0b)) | |||
617 | return (EINVAL22); | |||
618 | ||||
619 | if (len > 32767) | |||
620 | return (EINVAL22); | |||
621 | if (addr < 0 || addr >= USB_MAX_DEVICES128) | |||
622 | return (EINVAL22); | |||
623 | if (sc->sc_bus->devices[addr] == NULL((void *)0)) | |||
624 | return (ENXIO6); | |||
625 | if (len != 0) { | |||
626 | iov.iov_base = (caddr_t)ur->ucr_data; | |||
627 | iov.iov_len = len; | |||
628 | uio.uio_iov = &iov; | |||
629 | uio.uio_iovcnt = 1; | |||
630 | uio.uio_resid = len; | |||
631 | uio.uio_offset = 0; | |||
632 | uio.uio_segflg = UIO_USERSPACE; | |||
633 | uio.uio_rw = | |||
634 | ur->ucr_request.bmRequestType & UT_READ0x80 ? | |||
635 | UIO_READ : UIO_WRITE; | |||
636 | uio.uio_procp = p; | |||
637 | if ((ptr = malloc(len, M_TEMP127, M_NOWAIT0x0002)) == NULL((void *)0)) { | |||
638 | error = ENOMEM12; | |||
639 | goto ret; | |||
640 | } | |||
641 | if (uio.uio_rw == UIO_WRITE) { | |||
642 | error = uiomove(ptr, len, &uio); | |||
643 | if (error) | |||
644 | goto ret; | |||
645 | } | |||
646 | } | |||
647 | err = usbd_do_request_flags(sc->sc_bus->devices[addr], | |||
648 | &ur->ucr_request, ptr, ur->ucr_flags, | |||
649 | &ur->ucr_actlen, USBD_DEFAULT_TIMEOUT5000); | |||
650 | if (err) { | |||
651 | error = EIO5; | |||
652 | goto ret; | |||
653 | } | |||
654 | /* Only if USBD_SHORT_XFER_OK is set. */ | |||
655 | mlen = len; | |||
656 | if (mlen > ur->ucr_actlen) | |||
657 | mlen = ur->ucr_actlen; | |||
658 | if (mlen
| |||
659 | if (uio.uio_rw == UIO_READ) { | |||
| ||||
660 | error = uiomove(ptr, mlen, &uio); | |||
661 | if (error) | |||
662 | goto ret; | |||
663 | } | |||
664 | } | |||
665 | ret: | |||
666 | free(ptr, M_TEMP127, len); | |||
667 | return (error); | |||
668 | } | |||
669 | ||||
670 | case USB_DEVICEINFO(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct usb_device_info) & 0x1fff) << 16) | ((('U') ) << 8) | ((4))): | |||
671 | { | |||
672 | struct usb_device_info *di = (void *)data; | |||
673 | int addr = di->udi_addr; | |||
674 | struct usbd_device *dev; | |||
675 | ||||
676 | if (addr < 1 || addr >= USB_MAX_DEVICES128) | |||
677 | return (EINVAL22); | |||
678 | ||||
679 | dev = sc->sc_bus->devices[addr]; | |||
680 | if (dev == NULL((void *)0)) | |||
681 | return (ENXIO6); | |||
682 | ||||
683 | usbd_fill_deviceinfo(dev, di); | |||
684 | break; | |||
685 | } | |||
686 | ||||
687 | case USB_DEVICESTATS((unsigned long)0x40000000 | ((sizeof(struct usb_device_stats ) & 0x1fff) << 16) | ((('U')) << 8) | ((5))): | |||
688 | *(struct usb_device_stats *)data = sc->sc_bus->stats; | |||
689 | break; | |||
690 | ||||
691 | case USB_DEVICE_GET_DDESC(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct usb_device_ddesc) & 0x1fff) << 16) | ((('U' )) << 8) | ((8))): | |||
692 | { | |||
693 | struct usb_device_ddesc *udd = (struct usb_device_ddesc *)data; | |||
694 | int addr = udd->udd_addr; | |||
695 | struct usbd_device *dev; | |||
696 | ||||
697 | if (addr < 1 || addr >= USB_MAX_DEVICES128) | |||
698 | return (EINVAL22); | |||
699 | ||||
700 | dev = sc->sc_bus->devices[addr]; | |||
701 | if (dev == NULL((void *)0)) | |||
702 | return (ENXIO6); | |||
703 | ||||
704 | udd->udd_bus = unit; | |||
705 | ||||
706 | udd->udd_desc = *usbd_get_device_descriptor(dev); | |||
707 | break; | |||
708 | } | |||
709 | ||||
710 | case USB_DEVICE_GET_CDESC(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct usb_device_cdesc) & 0x1fff) << 16) | ((('U' )) << 8) | ((6))): | |||
711 | { | |||
712 | struct usb_device_cdesc *udc = (struct usb_device_cdesc *)data; | |||
713 | int addr = udc->udc_addr; | |||
714 | struct usb_task udc_task; | |||
715 | ||||
716 | if (addr < 1 || addr >= USB_MAX_DEVICES128) | |||
717 | return (EINVAL22); | |||
718 | if (sc->sc_bus->devices[addr] == NULL((void *)0)) | |||
719 | return (ENXIO6); | |||
720 | ||||
721 | udc->udc_bus = unit; | |||
722 | ||||
723 | udc->udc_desc.bLength = 0; | |||
724 | usb_init_task(&udc_task, usb_fill_udc_task, udc,((&udc_task)->fun = (usb_fill_udc_task), (&udc_task )->arg = (udc), (&udc_task)->type = (0), (&udc_task )->state = 0x0) | |||
725 | USB_TASK_TYPE_GENERIC)((&udc_task)->fun = (usb_fill_udc_task), (&udc_task )->arg = (udc), (&udc_task)->type = (0), (&udc_task )->state = 0x0); | |||
726 | usb_add_task(sc->sc_bus->root_hub, &udc_task); | |||
727 | usb_wait_task(sc->sc_bus->root_hub, &udc_task); | |||
728 | if (udc->udc_desc.bLength == 0) | |||
729 | return (EINVAL22); | |||
730 | break; | |||
731 | } | |||
732 | ||||
733 | case USB_DEVICE_GET_FDESC(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct usb_device_fdesc) & 0x1fff) << 16) | ((('U' )) << 8) | ((7))): | |||
734 | { | |||
735 | struct usb_device_fdesc *udf = (struct usb_device_fdesc *)data; | |||
736 | int addr = udf->udf_addr; | |||
737 | struct usb_task udf_task; | |||
738 | struct usb_device_fdesc save_udf; | |||
739 | usb_config_descriptor_t *cdesc; | |||
740 | struct iovec iov; | |||
741 | struct uio uio; | |||
742 | size_t len, cdesc_len; | |||
743 | ||||
744 | if (addr < 1 || addr >= USB_MAX_DEVICES128) | |||
745 | return (EINVAL22); | |||
746 | if (sc->sc_bus->devices[addr] == NULL((void *)0)) | |||
747 | return (ENXIO6); | |||
748 | ||||
749 | udf->udf_bus = unit; | |||
750 | ||||
751 | save_udf = *udf; | |||
752 | udf->udf_data = NULL((void *)0); | |||
753 | usb_init_task(&udf_task, usb_fill_udf_task, udf,((&udf_task)->fun = (usb_fill_udf_task), (&udf_task )->arg = (udf), (&udf_task)->type = (0), (&udf_task )->state = 0x0) | |||
754 | USB_TASK_TYPE_GENERIC)((&udf_task)->fun = (usb_fill_udf_task), (&udf_task )->arg = (udf), (&udf_task)->type = (0), (&udf_task )->state = 0x0); | |||
755 | usb_add_task(sc->sc_bus->root_hub, &udf_task); | |||
756 | usb_wait_task(sc->sc_bus->root_hub, &udf_task); | |||
757 | len = cdesc_len = udf->udf_size; | |||
758 | cdesc = (usb_config_descriptor_t *)udf->udf_data; | |||
759 | *udf = save_udf; | |||
760 | if (cdesc == NULL((void *)0)) | |||
761 | return (EINVAL22); | |||
762 | if (len > udf->udf_size) | |||
763 | len = udf->udf_size; | |||
764 | iov.iov_base = (caddr_t)udf->udf_data; | |||
765 | iov.iov_len = len; | |||
766 | uio.uio_iov = &iov; | |||
767 | uio.uio_iovcnt = 1; | |||
768 | uio.uio_resid = len; | |||
769 | uio.uio_offset = 0; | |||
770 | uio.uio_segflg = UIO_USERSPACE; | |||
771 | uio.uio_rw = UIO_READ; | |||
772 | uio.uio_procp = p; | |||
773 | error = uiomove((void *)cdesc, len, &uio); | |||
774 | free(cdesc, M_TEMP127, cdesc_len); | |||
775 | return (error); | |||
776 | } | |||
777 | ||||
778 | default: | |||
779 | return (EINVAL22); | |||
780 | } | |||
781 | return (0); | |||
782 | } | |||
783 | ||||
784 | /* | |||
785 | * Explore device tree from the root. We need mutual exclusion to this | |||
786 | * hub while traversing the device tree, but this is guaranteed since this | |||
787 | * function is only called from the task thread, with one exception: | |||
788 | * usb_attach() calls this function, but there shouldn't be anything else | |||
789 | * trying to explore this hub at that time. | |||
790 | */ | |||
791 | void | |||
792 | usb_explore(void *v) | |||
793 | { | |||
794 | struct usb_softc *sc = v; | |||
795 | struct timeval now, waited; | |||
796 | int pwrdly, waited_ms; | |||
797 | ||||
798 | DPRINTFN(2,("%s: %s\n", __func__, sc->sc_dev.dv_xname)); | |||
799 | #ifdef USB_DEBUG | |||
800 | if (usb_noexplore) | |||
801 | return; | |||
802 | #endif | |||
803 | ||||
804 | if (sc->sc_bus->dying) | |||
805 | return; | |||
806 | ||||
807 | if (sc->sc_bus->flags & USB_BUS_CONFIG_PENDING0x01) { | |||
808 | /* | |||
809 | * If this is a low/full speed hub and there is a high | |||
810 | * speed hub that hasn't explored yet, reschedule this | |||
811 | * task, allowing the high speed explore task to run. | |||
812 | */ | |||
813 | if (sc->sc_bus->usbrev < USBREV_2_04 && explore_pending > 0) { | |||
814 | usb_add_task(sc->sc_bus->root_hub, | |||
815 | &sc->sc_explore_task); | |||
816 | return; | |||
817 | } | |||
818 | ||||
819 | /* | |||
820 | * Wait for power to stabilize. | |||
821 | */ | |||
822 | getmicrouptime(&now); | |||
823 | timersub(&now, &sc->sc_ptime, &waited)do { (&waited)->tv_sec = (&now)->tv_sec - (& sc->sc_ptime)->tv_sec; (&waited)->tv_usec = (& now)->tv_usec - (&sc->sc_ptime)->tv_usec; if ((& waited)->tv_usec < 0) { (&waited)->tv_sec--; (& waited)->tv_usec += 1000000; } } while (0); | |||
824 | waited_ms = waited.tv_sec * 1000 + waited.tv_usec / 1000; | |||
825 | ||||
826 | pwrdly = sc->sc_bus->root_hub->hub->powerdelay + | |||
827 | USB_EXTRA_POWER_UP_TIME20; | |||
828 | if (pwrdly > waited_ms) | |||
829 | usb_delay_ms(sc->sc_bus, pwrdly - waited_ms); | |||
830 | } | |||
831 | ||||
832 | if (sc->sc_bus->flags & USB_BUS_DISCONNECTING0x02) { | |||
833 | /* Prevent new tasks from being scheduled. */ | |||
834 | sc->sc_bus->dying = 1; | |||
835 | ||||
836 | /* Make all devices disconnect. */ | |||
837 | if (sc->sc_port.device != NULL((void *)0)) { | |||
838 | usbd_detach(sc->sc_port.device, (struct device *)sc); | |||
839 | sc->sc_port.device = NULL((void *)0); | |||
840 | } | |||
841 | ||||
842 | sc->sc_bus->flags &= ~USB_BUS_DISCONNECTING0x02; | |||
843 | } else { | |||
844 | sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub); | |||
845 | } | |||
846 | ||||
847 | if (sc->sc_bus->flags & USB_BUS_CONFIG_PENDING0x01) { | |||
848 | DPRINTF(("%s: %s: first explore done\n", __func__, | |||
849 | sc->sc_dev.dv_xname)); | |||
850 | if (sc->sc_bus->usbrev == USBREV_2_04 && explore_pending) | |||
851 | explore_pending--; | |||
852 | config_pending_decr(); | |||
853 | sc->sc_bus->flags &= ~(USB_BUS_CONFIG_PENDING0x01); | |||
854 | } | |||
855 | } | |||
856 | ||||
857 | void | |||
858 | usb_needs_explore(struct usbd_device *dev, int first_explore) | |||
859 | { | |||
860 | struct usb_softc *usbctl = (struct usb_softc *)dev->bus->usbctl; | |||
861 | ||||
862 | DPRINTFN(3,("%s: %s\n", usbctl->sc_dev.dv_xname, __func__)); | |||
863 | ||||
864 | if (!first_explore && (dev->bus->flags & USB_BUS_CONFIG_PENDING0x01)) { | |||
865 | DPRINTF(("%s: %s: not exploring before first explore\n", | |||
866 | __func__, usbctl->sc_dev.dv_xname)); | |||
867 | return; | |||
868 | } | |||
869 | ||||
870 | usb_add_task(dev, &usbctl->sc_explore_task); | |||
871 | } | |||
872 | ||||
873 | void | |||
874 | usb_needs_reattach(struct usbd_device *dev) | |||
875 | { | |||
876 | DPRINTFN(2,("usb_needs_reattach\n")); | |||
877 | dev->powersrc->reattach = 1; | |||
878 | usb_needs_explore(dev, 0); | |||
879 | } | |||
880 | ||||
881 | void | |||
882 | usb_schedsoftintr(struct usbd_bus *bus) | |||
883 | { | |||
884 | DPRINTFN(10,("%s: polling=%d\n", __func__, bus->use_polling)); | |||
885 | ||||
886 | /* In case usb(4) is disabled */ | |||
887 | if (bus->soft == NULL((void *)0)) | |||
888 | return; | |||
889 | ||||
890 | if (bus->use_polling) { | |||
891 | bus->methods->soft_intr(bus); | |||
892 | } else { | |||
893 | softintr_schedule(bus->soft)do { struct x86_soft_intrhand *__sih = (bus->soft); struct x86_soft_intr *__si = __sih->sih_intrhead; mtx_enter(& __si->softintr_lock); if (__sih->sih_pending == 0) { do { (__sih)->sih_q.tqe_next = ((void *)0); (__sih)->sih_q .tqe_prev = (&__si->softintr_q)->tqh_last; *(&__si ->softintr_q)->tqh_last = (__sih); (&__si->softintr_q )->tqh_last = &(__sih)->sih_q.tqe_next; } while (0) ; __sih->sih_pending = 1; softintr(__si->softintr_ssir) ; } mtx_leave(&__si->softintr_lock); } while ( 0); | |||
894 | } | |||
895 | } | |||
896 | ||||
897 | int | |||
898 | usb_activate(struct device *self, int act) | |||
899 | { | |||
900 | struct usb_softc *sc = (struct usb_softc *)self; | |||
901 | int rv = 0; | |||
902 | ||||
903 | switch (act) { | |||
904 | case DVACT_QUIESCE2: | |||
905 | if (sc->sc_bus->root_hub != NULL((void *)0)) | |||
906 | usb_detach_roothub(sc); | |||
907 | break; | |||
908 | case DVACT_RESUME4: | |||
909 | sc->sc_bus->dying = 0; | |||
910 | ||||
911 | /* | |||
912 | * Make sure the root hub is present before interrupts | |||
913 | * get enabled. As long as the bus is in polling mode | |||
914 | * it is safe to call usbd_new_device() now since root | |||
915 | * hub transfers do not need to sleep. | |||
916 | */ | |||
917 | sc->sc_bus->use_polling++; | |||
918 | if (!usb_attach_roothub(sc)) | |||
919 | usb_needs_explore(sc->sc_bus->root_hub, 0); | |||
920 | sc->sc_bus->use_polling--; | |||
921 | break; | |||
922 | default: | |||
923 | rv = config_activate_children(self, act); | |||
924 | break; | |||
925 | } | |||
926 | return (rv); | |||
927 | } | |||
928 | ||||
929 | int | |||
930 | usb_detach(struct device *self, int flags) | |||
931 | { | |||
932 | struct usb_softc *sc = (struct usb_softc *)self; | |||
933 | ||||
934 | if (sc->sc_bus->root_hub != NULL((void *)0)) { | |||
935 | usb_detach_roothub(sc); | |||
936 | ||||
937 | if (--usb_nbuses == 0) { | |||
938 | usb_run_tasks = usb_run_abort_tasks = 0; | |||
939 | wakeup(&usb_run_abort_tasks); | |||
940 | wakeup(&usb_run_tasks); | |||
941 | } | |||
942 | } | |||
943 | ||||
944 | if (sc->sc_bus->soft != NULL((void *)0)) { | |||
945 | softintr_disestablish(sc->sc_bus->soft); | |||
946 | sc->sc_bus->soft = NULL((void *)0); | |||
947 | } | |||
948 | ||||
949 | #if NBPFILTER1 > 0 | |||
950 | bpfsdetach(sc->sc_bus->bpfif); | |||
951 | #endif | |||
952 | return (0); | |||
953 | } | |||
954 | ||||
955 | void | |||
956 | usb_tap(struct usbd_bus *bus, struct usbd_xfer *xfer, uint8_t dir) | |||
957 | { | |||
958 | #if NBPFILTER1 > 0 | |||
959 | struct usb_softc *sc = (struct usb_softc *)bus->usbctl; | |||
960 | usb_endpoint_descriptor_t *ed = xfer->pipe->endpoint->edesc; | |||
961 | union { | |||
962 | struct usbpcap_ctl_hdr uch; | |||
963 | struct usbpcap_iso_hdr_full uih; | |||
964 | } h; | |||
965 | struct usbpcap_pkt_hdr *uph = &h.uch.uch_hdr; | |||
966 | uint32_t nframes, offset; | |||
967 | unsigned int bpfdir; | |||
968 | void *data = NULL((void *)0); | |||
969 | size_t flen; | |||
970 | caddr_t bpf; | |||
971 | int i; | |||
972 | ||||
973 | bpf = bus->bpf; | |||
974 | if (bpf == NULL((void *)0)) | |||
975 | return; | |||
976 | ||||
977 | switch (UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03)) { | |||
978 | case UE_CONTROL0x00: | |||
979 | /* Control transfer headers include an extra byte */ | |||
980 | uph->uph_hlen = htole16(sizeof(struct usbpcap_ctl_hdr))((__uint16_t)(sizeof(struct usbpcap_ctl_hdr))); | |||
981 | uph->uph_xfertype = USBPCAP_TRANSFER_CONTROL2; | |||
982 | break; | |||
983 | case UE_ISOCHRONOUS0x01: | |||
984 | offset = 0; | |||
985 | nframes = xfer->nframes; | |||
986 | #ifdef DIAGNOSTIC1 | |||
987 | if (nframes > _USBPCAP_MAX_ISOFRAMES40) { | |||
988 | printf("%s: too many frames: %d > %d\n", __func__, | |||
989 | xfer->nframes, _USBPCAP_MAX_ISOFRAMES40); | |||
990 | nframes = _USBPCAP_MAX_ISOFRAMES40; | |||
991 | } | |||
992 | #endif | |||
993 | /* Isochronous transfer headers include space for one frame */ | |||
994 | flen = (nframes - 1) * sizeof(struct usbpcap_iso_pkt); | |||
995 | uph->uph_hlen = htole16(sizeof(struct usbpcap_iso_hdr) + flen)((__uint16_t)(sizeof(struct usbpcap_iso_hdr) + flen)); | |||
996 | uph->uph_xfertype = USBPCAP_TRANSFER_ISOCHRONOUS0; | |||
997 | h.uih.uih_startframe = 0; /* not yet used */ | |||
998 | h.uih.uih_nframes = nframes; | |||
999 | h.uih.uih_errors = 0; /* we don't have per-frame error */ | |||
1000 | for (i = 0; i < nframes; i++) { | |||
1001 | h.uih.uih_frames[i].uip_offset = offset; | |||
1002 | h.uih.uih_frames[i].uip_length = xfer->frlengths[i]; | |||
1003 | /* See above, we don't have per-frame error */ | |||
1004 | h.uih.uih_frames[i].uip_status = 0; | |||
1005 | offset += xfer->frlengths[i]; | |||
1006 | } | |||
1007 | break; | |||
1008 | case UE_BULK0x02: | |||
1009 | uph->uph_hlen = htole16(sizeof(*uph))((__uint16_t)(sizeof(*uph))); | |||
1010 | uph->uph_xfertype = USBPCAP_TRANSFER_BULK3; | |||
1011 | break; | |||
1012 | case UE_INTERRUPT0x03: | |||
1013 | uph->uph_hlen = htole16(sizeof(*uph))((__uint16_t)(sizeof(*uph))); | |||
1014 | uph->uph_xfertype = USBPCAP_TRANSFER_INTERRUPT1; | |||
1015 | break; | |||
1016 | default: | |||
1017 | return; | |||
1018 | } | |||
1019 | ||||
1020 | uph->uph_id = 0; /* not yet used */ | |||
1021 | uph->uph_status = htole32(xfer->status)((__uint32_t)(xfer->status)); | |||
1022 | uph->uph_function = 0; /* not yet used */ | |||
1023 | uph->uph_bus = htole32(sc->sc_dev.dv_unit)((__uint32_t)(sc->sc_dev.dv_unit)); | |||
1024 | uph->uph_devaddr = htole16(xfer->device->address)((__uint16_t)(xfer->device->address)); | |||
1025 | uph->uph_epaddr = ed->bEndpointAddress; | |||
1026 | uph->uph_info = 0; | |||
1027 | ||||
1028 | /* Outgoing control requests start with a STAGE dump. */ | |||
1029 | if ((xfer->rqflags & URQ_REQUEST0x01) && (dir == USBTAP_DIR_OUT0)) { | |||
1030 | h.uch.uch_stage = USBPCAP_CONTROL_STAGE_SETUP0; | |||
1031 | uph->uph_dlen = sizeof(usb_device_request_t); | |||
1032 | bpf_tap_hdr(bpf, uph, uph->uph_hlen, &xfer->request, | |||
1033 | uph->uph_dlen, BPF_DIRECTION_OUT(1 << 1)); | |||
1034 | } | |||
1035 | ||||
1036 | if (dir == USBTAP_DIR_OUT0) { | |||
1037 | bpfdir = BPF_DIRECTION_OUT(1 << 1); | |||
1038 | if (!usbd_xfer_isread(xfer)) { | |||
1039 | data = KERNADDR(&xfer->dmabuf, 0)((void *)((char *)((&xfer->dmabuf)->block->kaddr + (&xfer->dmabuf)->offs) + (0))); | |||
1040 | uph->uph_dlen = xfer->length; | |||
1041 | if (xfer->rqflags & URQ_REQUEST0x01) | |||
1042 | h.uch.uch_stage = USBPCAP_CONTROL_STAGE_DATA1; | |||
1043 | } else { | |||
1044 | data = NULL((void *)0); | |||
1045 | uph->uph_dlen = 0; | |||
1046 | if (xfer->rqflags & URQ_REQUEST0x01) | |||
1047 | h.uch.uch_stage = USBPCAP_CONTROL_STAGE_STATUS2; | |||
1048 | } | |||
1049 | } else { /* USBTAP_DIR_IN */ | |||
1050 | bpfdir = BPF_DIRECTION_IN(1 << 0); | |||
1051 | uph->uph_info = USBPCAP_INFO_DIRECTION_IN(1 << 0); | |||
1052 | if (usbd_xfer_isread(xfer)) { | |||
1053 | data = KERNADDR(&xfer->dmabuf, 0)((void *)((char *)((&xfer->dmabuf)->block->kaddr + (&xfer->dmabuf)->offs) + (0))); | |||
1054 | uph->uph_dlen = xfer->actlen; | |||
1055 | if (xfer->rqflags & URQ_REQUEST0x01) | |||
1056 | h.uch.uch_stage = USBPCAP_CONTROL_STAGE_DATA1; | |||
1057 | } else { | |||
1058 | data = NULL((void *)0); | |||
1059 | uph->uph_dlen = 0; | |||
1060 | if (xfer->rqflags & URQ_REQUEST0x01) | |||
1061 | h.uch.uch_stage = USBPCAP_CONTROL_STAGE_STATUS2; | |||
1062 | } | |||
1063 | } | |||
1064 | ||||
1065 | /* Dump bulk/intr/iso data, ctrl DATA or STATUS stage. */ | |||
1066 | bpf_tap_hdr(bpf, uph, uph->uph_hlen, data, uph->uph_dlen, bpfdir); | |||
1067 | ||||
1068 | /* Incoming control requests with DATA need a STATUS stage. */ | |||
1069 | if ((xfer->rqflags & URQ_REQUEST0x01) && (dir == USBTAP_DIR_IN1) && | |||
1070 | (h.uch.uch_stage == USBPCAP_CONTROL_STAGE_DATA1)) { | |||
1071 | h.uch.uch_stage = USBPCAP_CONTROL_STAGE_STATUS2; | |||
1072 | uph->uph_dlen = 0; | |||
1073 | bpf_tap_hdr(bpf, uph, uph->uph_hlen, NULL((void *)0), 0, BPF_DIRECTION_IN(1 << 0)); | |||
1074 | } | |||
1075 | #endif | |||
1076 | } |