| 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 | } |