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