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