| 1 | /*- |
| 2 | * SPDX-License-Identifier: BSD-2-Clause |
| 3 | * |
| 4 | * Copyright (c) 2008-2019 Hans Petter Selasky. All rights reserved. |
| 5 | * |
| 6 | * Redistribution and use in source and binary forms, with or without |
| 7 | * modification, are permitted provided that the following conditions |
| 8 | * are met: |
| 9 | * 1. Redistributions of source code must retain the above copyright |
| 10 | * notice, this list of conditions and the following disclaimer. |
| 11 | * 2. Redistributions in binary form must reproduce the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer in the |
| 13 | * documentation and/or other materials provided with the distribution. |
| 14 | * |
| 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 25 | * SUCH DAMAGE. |
| 26 | */ |
| 27 | |
| 28 | #ifndef _USB_DEVICE_H_ |
| 29 | #define	_USB_DEVICE_H_ |
| 30 | |
| 31 | #ifndef USB_GLOBAL_INCLUDE_FILE |
| 32 | #include <dev/usb/usb_core.h> |
| 33 | #include <dev/usb/usb_busdma.h> |
| 34 | #include <dev/usb/usb_transfer.h> |
| 35 | #endif |
| 36 | |
| 37 | struct usb_bus_methods; |
| 38 | struct usb_config_descriptor; |
| 39 | struct usb_device;		/* linux compat */ |
| 40 | struct usb_fs_privdata; |
| 41 | struct usb_hw_ep_profile; |
| 42 | struct usb_symlink;		/* UGEN */ |
| 43 | |
| 44 | #define	USB_CTRL_XFER_MAX 2 |
| 45 | |
| 46 | /* "usb_config_parse()" commands */ |
| 47 | |
| 48 | #define	USB_CFG_ALLOC 0 |
| 49 | #define	USB_CFG_FREE 1 |
| 50 | #define	USB_CFG_INIT 2 |
| 51 | |
| 52 | /* "usb_unconfigure()" flags */ |
| 53 | |
| 54 | #define	USB_UNCFG_FLAG_NONE 0x00 |
| 55 | #define	USB_UNCFG_FLAG_FREE_EP0	0x02		/* endpoint zero is freed */ |
| 56 | |
| 57 | struct usb_udev_msg { |
| 58 | 	struct usb_proc_msg hdr; |
| 59 | 	struct usb_device *udev; |
| 60 | }; |
| 61 | |
| 62 | /* The following four structures makes up a tree, where we have the |
| 63 | * leaf structure, "usb_host_endpoint", first, and the root structure, |
| 64 | * "usb_device", last. The four structures below mirror the structure |
| 65 | * of the USB descriptors belonging to an USB configuration. Please |
| 66 | * refer to the USB specification for a definition of "endpoints" and |
| 67 | * "interfaces". |
| 68 | */ |
| 69 | struct usb_host_endpoint { |
| 70 | 	struct usb_endpoint_descriptor desc; |
| 71 | 	TAILQ_HEAD(, urb) bsd_urb_list; |
| 72 | 	struct usb_xfer *bsd_xfer[2]; |
| 73 | 	uint8_t *extra;			/* Extra descriptors */ |
| 74 | 	usb_frlength_t fbsd_buf_size; |
| 75 | 	uint16_t extralen; |
| 76 | 	uint8_t	bsd_iface_index; |
| 77 | } __aligned(USB_HOST_ALIGN); |
| 78 | |
| 79 | struct usb_host_interface { |
| 80 | 	struct usb_interface_descriptor desc; |
| 81 | 	/* the following array has size "desc.bNumEndpoint" */ |
| 82 | 	struct usb_host_endpoint *endpoint; |
| 83 | 	const char *string;		/* iInterface string, if present */ |
| 84 | 	uint8_t *extra;			/* Extra descriptors */ |
| 85 | 	uint16_t extralen; |
| 86 | 	uint8_t	bsd_iface_index; |
| 87 | } __aligned(USB_HOST_ALIGN); |
| 88 | |
| 89 | /* |
| 90 | * The following structure defines the USB device flags. |
| 91 | */ |
| 92 | struct usb_device_flags { |
| 93 | 	enum usb_hc_mode usb_mode;	/* host or device mode */ |
| 94 | 	uint8_t	self_powered:1;		/* set if USB device is self powered */ |
| 95 | 	uint8_t	no_strings:1;		/* set if USB device does not support |
| 96 | 					 * strings */ |
| 97 | 	uint8_t	remote_wakeup:1;	/* set if remote wakeup is enabled */ |
| 98 | 	uint8_t	uq_bus_powered:1;	/* set if BUS powered quirk is present */ |
| 99 | |
| 100 | 	/* |
| 101 | 	 * NOTE: Although the flags below will reach the same value |
| 102 | 	 * over time, but the instant values may differ, and |
| 103 | 	 * consequently the flags cannot be merged into one! |
| 104 | 	 */ |
| 105 | 	uint8_t peer_suspended:1;	/* set if peer is suspended */ |
| 106 | 	uint8_t self_suspended:1;	/* set if self is suspended */ |
| 107 | }; |
| 108 | |
| 109 | /* |
| 110 | * The following structure is used for power-save purposes. The data |
| 111 | * in this structure is protected by the USB BUS lock. |
| 112 | */ |
| 113 | struct usb_power_save { |
| 114 | 	usb_ticks_t last_xfer_time;	/* copy of "ticks" */ |
| 115 | 	usb_size_t type_refs[4];	/* transfer reference count */ |
| 116 | 	usb_size_t read_refs;		/* data read references */ |
| 117 | 	usb_size_t write_refs;		/* data write references */ |
| 118 | }; |
| 119 | |
| 120 | /* |
| 121 | * The following structure is used when trying to allocate hardware |
| 122 | * endpoints for an USB configuration in USB device side mode. |
| 123 | */ |
| 124 | struct usb_hw_ep_scratch_sub { |
| 125 | 	const struct usb_hw_ep_profile *pf; |
| 126 | 	uint16_t max_frame_size; |
| 127 | 	uint8_t	hw_endpoint_out; |
| 128 | 	uint8_t	hw_endpoint_in; |
| 129 | 	uint8_t	needs_ep_type; |
| 130 | 	uint8_t	needs_in:1; |
| 131 | 	uint8_t	needs_out:1; |
| 132 | }; |
| 133 | |
| 134 | /* |
| 135 | * The following structure is used when trying to allocate hardware |
| 136 | * endpoints for an USB configuration in USB device side mode. |
| 137 | */ |
| 138 | struct usb_hw_ep_scratch { |
| 139 | 	struct usb_hw_ep_scratch_sub ep[USB_EP_MAX]; |
| 140 | 	struct usb_hw_ep_scratch_sub *ep_max; |
| 141 | 	struct usb_config_descriptor *cd; |
| 142 | 	struct usb_device *udev; |
| 143 | 	const struct usb_bus_methods *methods; |
| 144 | 	uint8_t	bmOutAlloc[(USB_EP_MAX + 15) / 16]; |
| 145 | 	uint8_t	bmInAlloc[(USB_EP_MAX + 15) / 16]; |
| 146 | }; |
| 147 | |
| 148 | /* |
| 149 | * The following structure is used when generating USB descriptors |
| 150 | * from USB templates. |
| 151 | */ |
| 152 | struct usb_temp_setup { |
| 153 | 	void *buf; |
| 154 | 	usb_size_t size; |
| 155 | 	enum usb_dev_speed	usb_speed; |
| 156 | 	uint8_t	self_powered; |
| 157 | 	uint8_t	bNumEndpoints; |
| 158 | 	uint8_t	bInterfaceNumber; |
| 159 | 	uint8_t	bAlternateSetting; |
| 160 | 	uint8_t	bConfigurationValue; |
| 161 | 	usb_error_t err; |
| 162 | }; |
| 163 | |
| 164 | /* |
| 165 | * The scratch area for USB devices. Access to this structure is |
| 166 | * protected by the control SX lock. |
| 167 | */ |
| 168 | union usb_device_scratch { |
| 169 | 	struct usb_hw_ep_scratch hw_ep_scratch[1]; |
| 170 | 	struct usb_temp_setup temp_setup[1]; |
| 171 | 	struct { |
| 172 | 		struct usb_xfer dummy; |
| 173 | 		struct usb_setup_params parm; |
| 174 | 	} xfer_setup[1]; |
| 175 | 	uint8_t	data[255]; |
| 176 | }; |
| 177 | |
| 178 | /* |
| 179 | * Helper structure to keep track of USB device statistics. |
| 180 | */ |
| 181 | struct usb_device_statistics { |
| 182 | 	uint32_t uds_requests[4]; |
| 183 | }; |
| 184 | |
| 185 | /* |
| 186 | * The following structure defines an USB device. There exists one of |
| 187 | * these structures for every USB device. |
| 188 | */ |
| 189 | struct usb_device { |
| 190 | 	/* statistics */ |
| 191 | 	struct usb_device_statistics stats_err; |
| 192 | 	struct usb_device_statistics stats_ok; |
| 193 | 	struct usb_device_statistics stats_cancelled; |
| 194 | |
| 195 | 	/* generic clear stall message */ |
| 196 | 	struct usb_udev_msg cs_msg[2]; |
| 197 | 	struct sx enum_sx; |
| 198 | 	struct sx sr_sx; |
| 199 | 	struct sx ctrl_sx; |
| 200 | 	struct mtx device_mtx; |
| 201 | 	struct cv ctrlreq_cv; |
| 202 | 	struct cv ref_cv; |
| 203 | #if (USB_HAVE_FIXED_IFACE == 0) |
| 204 | 	struct usb_interface *ifaces; |
| 205 | #else |
| 206 | 	struct usb_interface ifaces[USB_IFACE_MAX]; |
| 207 | #endif |
| 208 | 	struct usb_endpoint ctrl_ep;	/* Control Endpoint 0 */ |
| 209 | #if (USB_HAVE_FIXED_ENDPOINT == 0) |
| 210 | 	struct usb_endpoint *endpoints; |
| 211 | #else |
| 212 | 	struct usb_endpoint endpoints[USB_MAX_EP_UNITS]; |
| 213 | #endif |
| 214 | 	struct usb_power_save pwr_save;/* power save data */ |
| 215 | 	struct usb_bus *bus;		/* our USB BUS */ |
| 216 | 	device_t parent_dev;		/* parent device */ |
| 217 | 	struct usb_device *parent_hub; |
| 218 | 	struct usb_device *parent_hs_hub;	/* high-speed parent HUB */ |
| 219 | 	struct usb_config_descriptor *cdesc;	/* full config descr */ |
| 220 | 	struct usb_hub *hub;		/* only if this is a hub */ |
| 221 | 	struct usb_xfer *ctrl_xfer[USB_CTRL_XFER_MAX]; |
| 222 | 	struct usb_temp_data *usb_template_ptr; |
| 223 | 	struct usb_endpoint *ep_curr;	/* current clear stall endpoint */ |
| 224 | #if USB_HAVE_UGEN |
| 225 | 	struct usb_fifo *fifo[USB_FIFO_MAX]; |
| 226 | 	struct usb_symlink *ugen_symlink;	/* our generic symlink */ |
| 227 | 	struct usb_fs_privdata *ctrl_dev;	/* Control Endpoint 0 device node */ |
| 228 | 	SLIST_HEAD(,usb_fs_privdata) pd_list; |
| 229 | 	char	ugen_name[20];		/* name of ugenX.X device */ |
| 230 | #endif |
| 231 | 	usb_ticks_t plugtime;		/* copy of "ticks" */ |
| 232 | |
| 233 | 	enum usb_dev_state state; |
| 234 | 	enum usb_dev_speed speed; |
| 235 | 	uint16_t refcount; |
| 236 | #define	USB_DEV_REF_MAX 0xffff |
| 237 | |
| 238 | 	uint16_t power;			/* mA the device uses */ |
| 239 | 	uint16_t langid;		/* language for strings */ |
| 240 | 	uint16_t autoQuirk[USB_MAX_AUTO_QUIRK];		/* dynamic quirks */ |
| 241 | |
| 242 | 	uint8_t	address;		/* device addess */ |
| 243 | 	uint8_t	device_index;		/* device index in "bus->devices" */ |
| 244 | 	uint8_t	controller_slot_id;	/* controller specific value */ |
| 245 | 	uint8_t next_config_index;	/* used by USB_RE_ENUM_SET_CONFIG */ |
| 246 | 	uint8_t	curr_config_index;	/* current configuration index */ |
| 247 | 	uint8_t	curr_config_no;		/* current configuration number */ |
| 248 | 	uint8_t	depth;			/* distance from root HUB */ |
| 249 | 	uint8_t	port_index;		/* parent HUB port index */ |
| 250 | 	uint8_t	port_no;		/* parent HUB port number */ |
| 251 | 	uint8_t	hs_hub_addr;		/* high-speed HUB address */ |
| 252 | 	uint8_t	hs_port_no;		/* high-speed HUB port number */ |
| 253 | 	uint8_t	driver_added_refcount;	/* our driver added generation count */ |
| 254 | 	uint8_t	power_mode;		/* see USB_POWER_XXX */ |
| 255 | 	uint8_t re_enumerate_wait;	/* set if re-enum. is in progress */ |
| 256 | #define	USB_RE_ENUM_DONE	0 |
| 257 | #define	USB_RE_ENUM_START	1 |
| 258 | #define	USB_RE_ENUM_PWR_OFF	2 |
| 259 | #define	USB_RE_ENUM_SET_CONFIG	3 |
| 260 | 	uint8_t ifaces_max;		/* number of interfaces present */ |
| 261 | 	uint8_t endpoints_max;		/* number of endpoints present */ |
| 262 | |
| 263 | 	/* the "flags" field is write-protected by "bus->mtx" */ |
| 264 | |
| 265 | 	struct usb_device_flags flags; |
| 266 | |
| 267 | 	struct usb_endpoint_descriptor ctrl_ep_desc;	/* for endpoint 0 */ |
| 268 | 	struct usb_endpoint_ss_comp_descriptor ctrl_ep_comp_desc;	/* for endpoint 0 */ |
| 269 | 	struct usb_device_descriptor ddesc;	/* device descriptor */ |
| 270 | |
| 271 | 	char	*serial;		/* serial number, can be NULL */ |
| 272 | 	char	*manufacturer;		/* manufacturer string, can be NULL */ |
| 273 | 	char	*product;		/* product string, can be NULL */ |
| 274 | |
| 275 | #if USB_HAVE_COMPAT_LINUX |
| 276 | 	/* Linux compat */ |
| 277 | 	struct usb_device_descriptor descriptor; |
| 278 | 	struct usb_host_endpoint ep0; |
| 279 | 	struct usb_interface *linux_iface_start; |
| 280 | 	struct usb_interface *linux_iface_end; |
| 281 | 	struct usb_host_endpoint *linux_endpoint_start; |
| 282 | 	struct usb_host_endpoint *linux_endpoint_end; |
| 283 | 	uint16_t devnum; |
| 284 | #endif |
| 285 | |
| 286 | 	uint32_t clear_stall_errors;	/* number of clear-stall failures */ |
| 287 | |
| 288 | 	union usb_device_scratch scratch; |
| 289 | |
| 290 | #if (USB_HAVE_FIXED_CONFIG != 0) |
| 291 | 	uint32_t config_data[(USB_CONFIG_MAX + 3) / 4]; |
| 292 | #endif |
| 293 | }; |
| 294 | |
| 295 | /* globals */ |
| 296 | |
| 297 | extern int usb_template; |
| 298 | |
| 299 | /* function prototypes */ |
| 300 | |
| 301 | const char *usb_statestr(enum usb_dev_state state); |
| 302 | struct usb_device *usb_alloc_device(device_t parent_dev, struct usb_bus *bus, |
| 303 | 		 struct usb_device *parent_hub, uint8_t depth, |
| 304 | 		 uint8_t port_index, uint8_t port_no, |
| 305 | 		 enum usb_dev_speed speed, enum usb_hc_mode mode); |
| 306 | #if USB_HAVE_UGEN |
| 307 | struct usb_fs_privdata *usb_make_dev(struct usb_device *, const char *, |
| 308 | 		 int, int, int, uid_t, gid_t, int); |
| 309 | void	usb_destroy_dev(struct usb_fs_privdata *); |
| 310 | void	usb_destroy_dev_sync(struct usb_fs_privdata *); |
| 311 | #endif |
| 312 | usb_error_t	usb_probe_and_attach(struct usb_device *udev, |
| 313 | 		 uint8_t iface_index); |
| 314 | void		usb_detach_device(struct usb_device *, uint8_t, uint8_t); |
| 315 | usb_error_t	usb_reset_iface_endpoints(struct usb_device *udev, |
| 316 | 		 uint8_t iface_index); |
| 317 | usb_error_t	usbd_set_config_index(struct usb_device *udev, uint8_t index); |
| 318 | usb_error_t	usbd_set_endpoint_stall(struct usb_device *udev, |
| 319 | 		 struct usb_endpoint *ep, uint8_t do_stall); |
| 320 | usb_error_t	usb_suspend_resume(struct usb_device *udev, |
| 321 | 		 uint8_t do_suspend); |
| 322 | void	usb_devinfo(struct usb_device *udev, char *dst_ptr, uint16_t dst_len); |
| 323 | void	usb_free_device(struct usb_device *, uint8_t); |
| 324 | void	usb_linux_free_device(struct usb_device *dev); |
| 325 | uint8_t	usb_peer_can_wakeup(struct usb_device *udev); |
| 326 | struct usb_endpoint *usb_endpoint_foreach(struct usb_device *udev, struct usb_endpoint *ep); |
| 327 | void	usb_set_device_state(struct usb_device *, enum usb_dev_state); |
| 328 | enum usb_dev_state usb_get_device_state(struct usb_device *); |
| 329 | |
| 330 | void	usb_set_device_strings(struct usb_device *); |
| 331 | void	usb_get_langid(struct usb_device *); |
| 332 | |
| 333 | uint8_t	usbd_enum_lock(struct usb_device *); |
| 334 | #if USB_HAVE_UGEN |
| 335 | uint8_t	usbd_enum_lock_sig(struct usb_device *); |
| 336 | #endif |
| 337 | void	usbd_enum_unlock(struct usb_device *); |
| 338 | void	usbd_sr_lock(struct usb_device *); |
| 339 | void	usbd_sr_unlock(struct usb_device *); |
| 340 | uint8_t	usbd_ctrl_lock(struct usb_device *); |
| 341 | void	usbd_ctrl_unlock(struct usb_device *); |
| 342 | uint8_t usbd_enum_is_locked(struct usb_device *); |
| 343 | |
| 344 | #if USB_HAVE_TT_SUPPORT |
| 345 | void	uhub_tt_buffer_reset_async_locked(struct usb_device *, struct usb_endpoint *); |
| 346 | #endif |
| 347 | |
| 348 | uint8_t uhub_count_active_host_ports(struct usb_device *, enum usb_dev_speed); |
| 349 | |
| 350 | #endif					/* _USB_DEVICE_H_ */ |