| 1 | /* $NetBSD: usbdivar.h,v 1.113 2016/04/23 10:15:32 skrll Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (c) 1998, 2012 The NetBSD Foundation, Inc. |
| 5 | * All rights reserved. |
| 6 | * |
| 7 | * This code is derived from software contributed to The NetBSD Foundation |
| 8 | * by Lennart Augustsson (lennart@augustsson.net) at |
| 9 | * Carlstedt Research & Technology and Matthew R. Green (mrg@eterna.com.au). |
| 10 | * |
| 11 | * Redistribution and use in source and binary forms, with or without |
| 12 | * modification, are permitted provided that the following conditions |
| 13 | * are met: |
| 14 | * 1. Redistributions of source code must retain the above copyright |
| 15 | * notice, this list of conditions and the following disclaimer. |
| 16 | * 2. Redistributions in binary form must reproduce the above copyright |
| 17 | * notice, this list of conditions and the following disclaimer in the |
| 18 | * documentation and/or other materials provided with the distribution. |
| 19 | * |
| 20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
| 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| 22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
| 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 30 | * POSSIBILITY OF SUCH DAMAGE. |
| 31 | */ |
| 32 | |
| 33 | /* |
| 34 | * Discussion about locking in the USB code: |
| 35 | * |
| 36 | * The host controller presents one lock at IPL_SOFTUSB (aka IPL_SOFTNET). |
| 37 | * |
| 38 | * List of hardware interface methods, and whether the lock is held |
| 39 | * when each is called by this module: |
| 40 | * |
| 41 | * BUS METHOD LOCK NOTES |
| 42 | * ----------------------- ------- ------------------------- |
| 43 | * ubm_open - might want to take lock? |
| 44 | * ubm_softint x |
| 45 | * ubm_dopoll - might want to take lock? |
| 46 | * ubm_allocx - |
| 47 | * ubm_freex - |
| 48 | * ubm_getlock - Called at attach time |
| 49 | * ubm_newdev - Will take lock |
| 50 | ubm_rhctrl |
| 51 | * |
| 52 | * PIPE METHOD LOCK NOTES |
| 53 | * ----------------------- ------- ------------------------- |
| 54 | * upm_transfer - |
| 55 | * upm_start - might want to take lock? |
| 56 | * upm_abort x |
| 57 | * upm_close x |
| 58 | * upm_cleartoggle - |
| 59 | * upm_done x |
| 60 | * |
| 61 | * The above semantics are likely to change. Little performance |
| 62 | * evaluation has been done on this code and the locking strategy. |
| 63 | * |
| 64 | * USB functions known to expect the lock taken include (this list is |
| 65 | * probably not exhaustive): |
| 66 | * usb_transfer_complete() |
| 67 | * usb_insert_transfer() |
| 68 | * usb_start_next() |
| 69 | * |
| 70 | */ |
| 71 | |
| 72 | #include <sys/callout.h> |
| 73 | #include <sys/mutex.h> |
| 74 | #include <sys/bus.h> |
| 75 | |
| 76 | /* From usb_mem.h */ |
| 77 | struct usb_dma_block; |
| 78 | typedef struct { |
| 79 | struct usb_dma_block *udma_block; |
| 80 | u_int udma_offs; |
| 81 | } usb_dma_t; |
| 82 | |
| 83 | struct usbd_xfer; |
| 84 | struct usbd_pipe; |
| 85 | struct usbd_port; |
| 86 | |
| 87 | struct usbd_endpoint { |
| 88 | usb_endpoint_descriptor_t *ue_edesc; |
| 89 | int ue_refcnt; |
| 90 | int ue_toggle; |
| 91 | }; |
| 92 | |
| 93 | struct usbd_bus_methods { |
| 94 | usbd_status (*ubm_open)(struct usbd_pipe *); |
| 95 | void (*ubm_softint)(void *); |
| 96 | void (*ubm_dopoll)(struct usbd_bus *); |
| 97 | struct usbd_xfer *(*ubm_allocx)(struct usbd_bus *, unsigned int); |
| 98 | void (*ubm_freex)(struct usbd_bus *, struct usbd_xfer *); |
| 99 | void (*ubm_getlock)(struct usbd_bus *, kmutex_t **); |
| 100 | usbd_status (*ubm_newdev)(device_t, struct usbd_bus *, int, |
| 101 | int, int, struct usbd_port *); |
| 102 | |
| 103 | int (*ubm_rhctrl)(struct usbd_bus *, |
| 104 | usb_device_request_t *, void *, int); |
| 105 | }; |
| 106 | |
| 107 | struct usbd_pipe_methods { |
| 108 | int (*upm_init)(struct usbd_xfer *); |
| 109 | void (*upm_fini)(struct usbd_xfer *); |
| 110 | usbd_status (*upm_transfer)(struct usbd_xfer *); |
| 111 | usbd_status (*upm_start)(struct usbd_xfer *); |
| 112 | void (*upm_abort)(struct usbd_xfer *); |
| 113 | void (*upm_close)(struct usbd_pipe *); |
| 114 | void (*upm_cleartoggle)(struct usbd_pipe *); |
| 115 | void (*upm_done)(struct usbd_xfer *); |
| 116 | }; |
| 117 | |
| 118 | struct usbd_tt { |
| 119 | struct usbd_hub *utt_hub; |
| 120 | }; |
| 121 | |
| 122 | struct usbd_port { |
| 123 | usb_port_status_t up_status; |
| 124 | uint16_t up_power; /* mA of current on port */ |
| 125 | uint8_t up_portno; |
| 126 | uint8_t up_restartcnt; |
| 127 | #define USBD_RESTART_MAX 5 |
| 128 | uint8_t up_reattach; |
| 129 | struct usbd_device *up_dev; /* Connected device */ |
| 130 | struct usbd_device *up_parent; /* The ports hub */ |
| 131 | struct usbd_tt *up_tt; /* Transaction translator (if any) */ |
| 132 | }; |
| 133 | |
| 134 | struct usbd_hub { |
| 135 | usbd_status (*uh_explore)(struct usbd_device *hub); |
| 136 | void *uh_hubsoftc; |
| 137 | usb_hub_descriptor_t uh_hubdesc; |
| 138 | struct usbd_port uh_ports[1]; |
| 139 | }; |
| 140 | |
| 141 | /*****/ |
| 142 | |
| 143 | struct usbd_bus { |
| 144 | /* Filled by HC driver */ |
| 145 | void *ub_hcpriv; |
| 146 | int ub_revision; /* USB revision */ |
| 147 | #define USBREV_UNKNOWN 0 |
| 148 | #define USBREV_PRE_1_0 1 |
| 149 | #define USBREV_1_0 2 |
| 150 | #define USBREV_1_1 3 |
| 151 | #define USBREV_2_0 4 |
| 152 | #define USBREV_3_0 5 |
| 153 | #define USBREV_STR { "unknown", "pre 1.0", "1.0", "1.1", "2.0", "3.0" } |
| 154 | |
| 155 | const struct usbd_bus_methods |
| 156 | *ub_methods; |
| 157 | uint32_t ub_pipesize; /* size of a pipe struct */ |
| 158 | bool ub_usedma; /* Does this HC support DMA */ |
| 159 | int ub_dmaflags; |
| 160 | bus_dma_tag_t ub_dmatag; /* DMA tag */ |
| 161 | |
| 162 | /* Filled by usb driver */ |
| 163 | kmutex_t *ub_lock; |
| 164 | struct usbd_device *ub_roothub; |
| 165 | uint8_t ub_rhaddr; /* roothub address */ |
| 166 | uint8_t ub_rhconf; /* roothub configuration */ |
| 167 | struct usbd_device *ub_devices[USB_MAX_DEVICES]; |
| 168 | kcondvar_t ub_needsexplore_cv; |
| 169 | char ub_needsexplore;/* a hub a signalled a change */ |
| 170 | char ub_usepolling; |
| 171 | device_t ub_usbctl; |
| 172 | struct usb_device_stats ub_stats; |
| 173 | |
| 174 | void *ub_soft; /* soft interrupt cookie */ |
| 175 | }; |
| 176 | |
| 177 | struct usbd_device { |
| 178 | struct usbd_bus *ud_bus; /* our controller */ |
| 179 | struct usbd_pipe *ud_pipe0; /* pipe 0 */ |
| 180 | uint8_t ud_addr; /* device addess */ |
| 181 | uint8_t ud_config; /* current configuration # */ |
| 182 | uint8_t ud_depth; /* distance from root hub */ |
| 183 | uint8_t ud_speed; /* low/full/high speed */ |
| 184 | uint8_t ud_selfpowered; /* flag for self powered */ |
| 185 | uint16_t ud_power; /* mA the device uses */ |
| 186 | int16_t ud_langid; /* language for strings */ |
| 187 | #define USBD_NOLANG (-1) |
| 188 | usb_event_cookie_t ud_cookie; /* unique connection id */ |
| 189 | struct usbd_port *ud_powersrc; /* upstream hub port, or 0 */ |
| 190 | struct usbd_device *ud_myhub; /* upstream hub */ |
| 191 | struct usbd_port *ud_myhsport; /* closest high speed port */ |
| 192 | struct usbd_endpoint ud_ep0; /* for pipe 0 */ |
| 193 | usb_endpoint_descriptor_t |
| 194 | ud_ep0desc; /* for pipe 0 */ |
| 195 | struct usbd_interface *ud_ifaces; /* array of all interfaces */ |
| 196 | usb_device_descriptor_t ud_ddesc; /* device descriptor */ |
| 197 | usb_config_descriptor_t *ud_cdesc; /* full config descr */ |
| 198 | usb_bos_descriptor_t *ud_bdesc; /* full BOS descr */ |
| 199 | const struct usbd_quirks |
| 200 | *ud_quirks; /* device quirks, always set */ |
| 201 | struct usbd_hub *ud_hub; /* only if this is a hub */ |
| 202 | int ud_subdevlen; /* array length of following */ |
| 203 | device_t *ud_subdevs; /* sub-devices */ |
| 204 | int ud_nifaces_claimed; /* number of ifaces in use */ |
| 205 | void *ud_hcpriv; |
| 206 | |
| 207 | char *ud_serial; /* serial number, can be NULL */ |
| 208 | char *ud_vendor; /* vendor string, can be NULL */ |
| 209 | char *ud_product; /* product string can be NULL */ |
| 210 | }; |
| 211 | |
| 212 | struct usbd_interface { |
| 213 | struct usbd_device *ui_dev; |
| 214 | usb_interface_descriptor_t |
| 215 | *ui_idesc; |
| 216 | int ui_index; |
| 217 | int ui_altindex; |
| 218 | struct usbd_endpoint *ui_endpoints; |
| 219 | void *ui_priv; |
| 220 | LIST_HEAD(, usbd_pipe) ui_pipes; |
| 221 | }; |
| 222 | |
| 223 | struct usbd_pipe { |
| 224 | struct usbd_interface *up_iface; |
| 225 | struct usbd_device *up_dev; |
| 226 | struct usbd_endpoint *up_endpoint; |
| 227 | char up_running; |
| 228 | char up_aborting; |
| 229 | bool up_serialise; |
| 230 | SIMPLEQ_HEAD(, usbd_xfer) |
| 231 | up_queue; |
| 232 | LIST_ENTRY(usbd_pipe) up_next; |
| 233 | struct usb_task up_async_task; |
| 234 | |
| 235 | struct usbd_xfer *up_intrxfer; /* used for repeating requests */ |
| 236 | char up_repeat; |
| 237 | int up_interval; |
| 238 | uint8_t up_flags; |
| 239 | |
| 240 | /* Filled by HC driver. */ |
| 241 | const struct usbd_pipe_methods |
| 242 | *up_methods; |
| 243 | }; |
| 244 | |
| 245 | struct usbd_xfer { |
| 246 | struct usbd_pipe *ux_pipe; |
| 247 | void *ux_priv; |
| 248 | void *ux_buffer; |
| 249 | kcondvar_t ux_cv; |
| 250 | uint32_t ux_length; |
| 251 | uint32_t ux_actlen; |
| 252 | uint16_t ux_flags; |
| 253 | uint32_t ux_timeout; |
| 254 | usbd_status ux_status; |
| 255 | usbd_callback ux_callback; |
| 256 | volatile uint8_t ux_done; |
| 257 | uint8_t ux_state; /* used for DIAGNOSTIC */ |
| 258 | #define XFER_FREE 0x46 |
| 259 | #define XFER_BUSY 0x55 |
| 260 | #define XFER_ONQU 0x9e |
| 261 | |
| 262 | /* For control pipe */ |
| 263 | usb_device_request_t ux_request; |
| 264 | |
| 265 | /* For isoc */ |
| 266 | uint16_t *ux_frlengths; |
| 267 | int ux_nframes; |
| 268 | |
| 269 | const struct usbd_pipe_methods *ux_methods; |
| 270 | |
| 271 | /* For memory allocation and softc */ |
| 272 | struct usbd_bus *ux_bus; |
| 273 | usb_dma_t ux_dmabuf; |
| 274 | void *ux_buf; |
| 275 | uint32_t ux_bufsize; |
| 276 | |
| 277 | uint8_t ux_rqflags; |
| 278 | #define URQ_REQUEST 0x01 |
| 279 | |
| 280 | SIMPLEQ_ENTRY(usbd_xfer) |
| 281 | ux_next; |
| 282 | |
| 283 | void *ux_hcpriv; /* private use by the HC driver */ |
| 284 | uint8_t ux_hcflags; /* private use by the HC driver */ |
| 285 | #define UXFER_ABORTING 0x01 /* xfer is aborting. */ |
| 286 | #define UXFER_ABORTWAIT 0x02 /* abort completion is being awaited. */ |
| 287 | kcondvar_t ux_hccv; /* private use by the HC driver */ |
| 288 | |
| 289 | struct callout ux_callout; |
| 290 | }; |
| 291 | |
| 292 | void usbd_init(void); |
| 293 | void usbd_finish(void); |
| 294 | |
| 295 | #if defined(USB_DEBUG) |
| 296 | void usbd_dump_iface(struct usbd_interface *); |
| 297 | void usbd_dump_device(struct usbd_device *); |
| 298 | void usbd_dump_endpoint(struct usbd_endpoint *); |
| 299 | void usbd_dump_queue(struct usbd_pipe *); |
| 300 | void usbd_dump_pipe(struct usbd_pipe *); |
| 301 | #endif |
| 302 | |
| 303 | /* Routines from usb_subr.c */ |
| 304 | int usbctlprint(void *, const char *); |
| 305 | void usbd_get_device_strings(struct usbd_device *); |
| 306 | void usb_delay_ms_locked(struct usbd_bus *, u_int, kmutex_t *); |
| 307 | void usb_delay_ms(struct usbd_bus *, u_int); |
| 308 | void usbd_delay_ms_locked(struct usbd_device *, u_int, kmutex_t *); |
| 309 | void usbd_delay_ms(struct usbd_device *, u_int); |
| 310 | usbd_status usbd_reset_port(struct usbd_device *, int, usb_port_status_t *); |
| 311 | usbd_status usbd_setup_pipe(struct usbd_device *, |
| 312 | struct usbd_interface *, |
| 313 | struct usbd_endpoint *, int, |
| 314 | struct usbd_pipe **); |
| 315 | usbd_status usbd_setup_pipe_flags(struct usbd_device *, |
| 316 | struct usbd_interface *, |
| 317 | struct usbd_endpoint *, int, |
| 318 | struct usbd_pipe **, |
| 319 | uint8_t); |
| 320 | usbd_status usbd_new_device(device_t, struct usbd_bus *, int, int, int, |
| 321 | struct usbd_port *); |
| 322 | usbd_status usbd_reattach_device(device_t, struct usbd_device *, |
| 323 | int, const int *); |
| 324 | |
| 325 | void usbd_remove_device(struct usbd_device *, struct usbd_port *); |
| 326 | int usbd_printBCD(char *, size_t, int); |
| 327 | usbd_status usbd_fill_iface_data(struct usbd_device *, int, int); |
| 328 | void usb_free_device(struct usbd_device *); |
| 329 | |
| 330 | usbd_status usb_insert_transfer(struct usbd_xfer *); |
| 331 | void usb_transfer_complete(struct usbd_xfer *); |
| 332 | int usb_disconnect_port(struct usbd_port *, device_t, int); |
| 333 | |
| 334 | void usbd_kill_pipe(struct usbd_pipe *); |
| 335 | usbd_status usbd_attach_roothub(device_t, struct usbd_device *); |
| 336 | usbd_status usbd_probe_and_attach(device_t, struct usbd_device *, int, int); |
| 337 | usbd_status usbd_get_initial_ddesc(struct usbd_device *, |
| 338 | usb_device_descriptor_t *); |
| 339 | |
| 340 | /* Routines from usb.c */ |
| 341 | void usb_needs_explore(struct usbd_device *); |
| 342 | void usb_needs_reattach(struct usbd_device *); |
| 343 | void usb_schedsoftintr(struct usbd_bus *); |
| 344 | |
| 345 | static inline int |
| 346 | usbd_xfer_isread(struct usbd_xfer *xfer) |
| 347 | { |
| 348 | if (xfer->ux_rqflags & URQ_REQUEST) |
| 349 | return xfer->ux_request.bmRequestType & UT_READ; |
| 350 | |
| 351 | return xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress & |
| 352 | UE_DIR_IN; |
| 353 | } |
| 354 | |
| 355 | /* |
| 356 | * These macros reflect the current locking scheme. They might change. |
| 357 | */ |
| 358 | |
| 359 | #define usbd_lock_pipe(p) mutex_enter((p)->up_dev->ud_bus->ub_lock) |
| 360 | #define usbd_unlock_pipe(p) mutex_exit((p)->up_dev->ud_bus->ub_lock) |
| 361 | |