summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/sys/usb/usba/usba_impl.h
blob: 8ad72b4f055598572505257fb431192382f30b5a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 *
 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
 * Copyright 2019, Joyent, Inc.
 */

#ifndef	_SYS_USB_USBA_USBA_IMPL_H
#define	_SYS_USB_USBA_USBA_IMPL_H


#include <sys/usb/usba.h>
#include <sys/usb/usba/hcdi.h>
#include <sys/usb/usba/hubdi.h>
#include <sys/usb/usba/usba_private.h>
#include <sys/usb/usba/usba_types.h>
#include <sys/usb/usba/bos.h>
#include <sys/taskq.h>
#include <sys/disp.h>

#ifdef	__cplusplus
extern "C" {
#endif


/*
 * UGEN binding values specified in <hcd>.conf files
 */
#define	USBA_UGEN_DEVICE_BINDING	1
#define	USBA_UGEN_INTERFACE_BINDING	2
#define	USBA_UGEN_INTERFACE_ASSOCIATION_BINDING		3

/*
 * Allocating a USB address
 */
#define	USBA_MAX_ADDRESS		127
#define	USBA_ADDRESS_ARRAY_SIZE	((USBA_MAX_ADDRESS+8)/8)

/*
 * async execution of usb_pipe_* functions which have a
 * completion callback parameter (eg. usb_pipe_close(),
 * usb_pipe_reset(), usb_pipe_stop_*_polling()
 */
typedef struct usba_pipe_async_req {
	dev_info_t		*dip;
	struct usba_ph_impl	*ph_impl;
	usb_opaque_t		arg;
	usb_flags_t		usb_flags;
	void			(*callback)(
					usb_pipe_handle_t	ph,
					usb_opaque_t		callback_arg,
					int			rval,
					usb_cb_flags_t		error_code);
	usb_opaque_t		callback_arg;
	int			(*sync_func)(dev_info_t *,
					usba_ph_impl_t *,
					struct usba_pipe_async_req *,
					usb_flags_t);
} usba_pipe_async_req_t;
_NOTE(SCHEME_PROTECTS_DATA("unique per call", usba_pipe_async_req_t))

/* per-pipe taskq */
int	usba_async_ph_req(usba_pipe_handle_data_t *, void (*func)(void *),
							void *, usb_flags_t);

/*
 * usb wrapper around pm_request_power_change to allow for
 * non blocking behavior
 */
typedef struct usba_pm_req {
	dev_info_t	*dip;
	int		comp;
	int		old_level;
	int		level;
	void		(*cb)(void *, int);
	void		*arg;
	uint_t		flags;
} usba_pm_req_t;
_NOTE(SCHEME_PROTECTS_DATA("unique per call", usba_pm_req_t))


/*
 * Request wrappers for control/bulk/interrupt and isoch pipes
 * These are hidden from client driver. They serve as place-holders
 * for doing callbacks
 *
 * Request allocation: wrapper + usb_*_req_t alloc'ed together:
 *
 *		+-----------------------+
 *		|	wr_queue	|		for callbacks
 *		+-----------------------+
 *		|	wr_req	|-------+	wr_req points to
 *		+-----------------------+	|	the req below.
 *		|			|	|
 *		|	....		|	|
 *		|	req_wrapper_t	|	|
 *		|			|	|
 *		+-----------------------+<------+
 *		|			|
 *		|	....		|
 *		| ctrl/bulk/intr/isoch	|
 *		|	req_t	|
 *		|			|
 *		|			|
 *		+-----------------------+
 */
typedef struct usba_req_wrapper {
	/* queueing in either a request or callback queue */
	usba_list_entry_t	wr_queue;

	/*
	 * The request could be control/bulk/intr/isoc
	 * See usbai.h usb_ctrl_req_t/usb_bulk_req_t
	 * usb_intr_req_t/usb_isoc_req_t
	 */
	usb_opaque_t		wr_req;

	/* for allocation tracking in usba_device_t */
	usba_list_entry_t	wr_allocated_list;

	/*
	 * All reqs that are synchronous sleep on this cv
	 * for completion notification.
	 * In hcdi soft interrupt handler we call cv_signal()
	 */
	kcondvar_t		wr_cv;

	/*
	 * This goes hand-in-hand with wr_cv. It is set by the soft intr hdlr
	 * before doing a cv_signal
	 */
	boolean_t		wr_done;
	dev_info_t		*wr_dip;	/* owner */

	usb_opaque_t		wr_hcd_private;	/* for HCD's use */

	usba_pipe_handle_data_t	*wr_ph_data;	/* ptr to pipe handle */

	usb_cr_t		wr_cr;		/* save cr from HCDI */
	usb_cb_flags_t		wr_cb_flags;	/* save cb_flags */
	usb_flags_t		wr_usb_flags;	/* save usb flags from HCDI */
	usb_req_attrs_t		wr_attrs;	/* save attrs from HCDI */

	/* total lenght of wrapper and request */
	size_t			wr_length;
} usba_req_wrapper_t;

_NOTE(SCHEME_PROTECTS_DATA("method", usba_req_wrapper))
_NOTE(SCHEME_PROTECTS_DATA("method", usb_ctrl_req))
_NOTE(SCHEME_PROTECTS_DATA("method", usb_bulk_req))
_NOTE(SCHEME_PROTECTS_DATA("method", usb_intr_req))
_NOTE(SCHEME_PROTECTS_DATA("method", usb_isoc_req))

/* additional flag for wr_usb_flags */
#define	USBA_WRP_FLAGS_WAIT	0x01

/* additional usb flags, not exposed to clients */
#define	USBA_FLAGS_PRIVILEGED	0x02	/* for default pipe operations */

/* Macros to convert wrapper to different request and vice-versa */

/* to get the wr->wr_req field */
#define	USBA_WRP2REQ(wrp)	((wrp)->wr_req)

/* to get the wrapper form the wr_req field */
#define	USBA_REQ2WRP(req)		(usba_req_wrapper_t *)\
				((uintptr_t)(req) - sizeof (usba_req_wrapper_t))

/* to set the the address in the wr_req field */
#define	USBA_SETREQ_ADDR(wrp)	((uintptr_t)(wrp) + sizeof (*(wrp)))

/* to get the 4 xfer type requests */
#define	USBA_WRP2CTRL_REQ(wrp)	((usb_ctrl_req_t *)USBA_WRP2REQ((wrp)))
#define	USBA_WRP2INTR_REQ(wrp)	((usb_intr_req_t *)USBA_WRP2REQ((wrp)))
#define	USBA_WRP2BULK_REQ(wrp)	((usb_bulk_req_t *)USBA_WRP2REQ((wrp)))
#define	USBA_WRP2ISOC_REQ(wrp)	((usb_isoc_req_t *)USBA_WRP2REQ((wrp)))

/* to get pipe_handle from the wrapper */
#define	USBA_WRP2PH_DATA(wrp) \
	(usba_pipe_handle_data_t *)((wrp)->wr_ph_data)

/* to get to the wr_queue from the wrapper */
#define	USBA_WRQUEUE2WRP(queue)	(usba_req_wrapper_t *)(queue)

/* to get to the wr_allocated queue from the wrapper */
#define	USBA_ALLOCQ2WRP(queue)	(usba_req_wrapper_t *)((uintptr_t) \
	(queue)  - sizeof (usba_list_entry_t) - sizeof (usb_opaque_t))


/* alias for pipe handle member p_usba_private */
#define	p_active_cntrl_req_wrp	p_usba_private

/*
 * This function is used to get the HCD private field maintained by USBA.
 * HCD calls this function.
 */
usb_opaque_t usba_hcdi_get_ctrl_req_hcd_private(usb_ctrl_req_t *);

/*
 * This function is used to set the HCD private field maintained by USBA.
 * HCD calls this function.
 */
void	usba_hcdi_set_ctrl_req_hcd_private(usb_ctrl_req_t *, usb_opaque_t);

int	usba_set_usb_address(usba_device_t *);
void	usba_unset_usb_address(usba_device_t *);

/*
 * Per Hub Data Structures
 */
typedef  struct usba_hubdi {
	usba_list_entry_t hubdi_list;	 /* linking in hubdi list */

	dev_info_t	*hubdi_dip;	 /* ptr to devinfo struct */

	int		hubdi_flags;	/* flag options */

} usba_hubdi_t;

/*
 * usba_get_mfg_prod_sn_str:
 *	Return a string containing mfg, product, serial number strings.
 */
char	*usba_get_mfg_prod_sn_str(dev_info_t *, char *, int);

/* return value when user doesn't specify configuration index */
#define	USBA_DEV_CONFIG_INDEX_UNDEFINED	-1

/*
 * prototypes
 */
void	usba_usba_initialization();
void	usba_usba_destroy();

void	usba_usbai_register_initialization();
void	usba_usbai_register_destroy();

void	usba_usbai_initialization();
void	usba_usbai_destroy();

void	usba_hubdi_initialization();
void	usba_hubdi_destroy();

void	usba_devdb_initialization();
void	usba_devdb_destroy();

int	usba_hubdi_register(dev_info_t	*, uint_t);
int	usba_hubdi_unregister(dev_info_t *);

int	usba_is_root_hub(dev_info_t *dip);

usba_device_t *usba_alloc_usba_device(dev_info_t *);
void	usba_free_usba_device(usba_device_t *usba_device_t);
void	usba_clear_data_toggle(usba_device_t *usba_device);

void	usba_start_next_req(usba_pipe_handle_data_t *ph);

int	usba_pipe_check_handle(usba_pipe_handle_data_t *);
int	usba_drain_cbs(usba_pipe_handle_data_t *, usb_cb_flags_t,
			usb_cr_t);
int	usba_pipe_setup_func_call(dev_info_t *,
			int (*sync_func)(dev_info_t *,
				usba_ph_impl_t *, usba_pipe_async_req_t *,
				usb_flags_t),
			usba_ph_impl_t *,
			usb_opaque_t,
			usb_flags_t,
			void (*cb)(usb_pipe_handle_t, usb_opaque_t,
			    int, usb_cb_flags_t),
			usb_opaque_t);


void	usba_pipe_new_state(usba_pipe_handle_data_t *, usb_pipe_state_t);

void usba_add_root_hub(dev_info_t *dip);
void usba_rem_root_hub(dev_info_t *dip);

/*
 * retrieve string descriptors for manufacturer, vendor and serial
 * number
 */
void usba_get_dev_string_descrs(dev_info_t *, usba_device_t *);

/*
 * Retrieve the binary object store for the device.
 */
void usba_get_binary_object_store(dev_info_t *, usba_device_t *);
void usba_add_binary_object_store_props(dev_info_t *, usba_device_t *);
void usba_free_binary_object_store(usba_device_t *);

/*
 * Check if we are not in interrupt context and have
 * USB_FLAGS_SLEEP flags set.
 */
#define	USBA_CHECK_CONTEXT()	ASSERT(!(servicing_interrupt()))

/*
 * USBA module Masks
 */
#define	DPRINT_MASK_USBA		0x00000001
#define	DPRINT_MASK_USBAI		0x00000002
#define	DPRINT_MASK_HUBDI		0x00000004
#define	DPRINT_MASK_HCDI		0x00000008
#define	DPRINT_MASK_HCDI_DUMPING	0x00000010
#define	DPRINT_MASK_HUBDI_DUMPING	0x00000020
#define	DPRINT_MASK_REGISTER		0x00000040
#define	DPRINT_MASK_DEVDB		0x00000080
#define	DPRINT_MASK_WHCDI		0x00000100
#define	DPRINT_MASK_ALL			0xFFFFFFFF

typedef struct usba_log_handle_impl {
	dev_info_t	*lh_dip;
	char		*lh_name;
	uint_t		*lh_errlevel;
	uint_t		*lh_mask;
	uint_t		*lh_instance_filter;
	uint_t		lh_flags;
} usba_log_handle_impl_t;

_NOTE(SCHEME_PROTECTS_DATA("USBA managed data", usba_log_handle_impl))

/*
 * Miscellaneous definitions.
 */

/* possible strlen of a USB driver's name */
#define	USBA_DRVNAME_LEN	40

/* strings passed to usb_dprintfN() are this long */
#define	USBA_PRINT_BUF_LEN	256

/*
 * usba_set_node_name() sets a device info node name
 * according to class, subclass, and protocol.
 * a subclass == -1 or protocol == -1 is considered a "don't care".
 */
#define	DONTCARE		((int16_t)-1)
#define	FLAG_INTERFACE_NODE	0
#define	FLAG_DEVICE_NODE	1
#define	FLAG_COMBINED_NODE	2
#define	FLAG_INTERFACE_ASSOCIATION_NODE		3

typedef struct node_name_entry {
	int16_t class;
	int16_t subclass;
	int16_t protocol;
	char	*name;
} node_name_entry_t;


/*
 * USB enumeration statistics support
 */

/* Flags telling which stats usba_update_hotplug_stats should update */
#define	USBA_TOTAL_HOTPLUG_SUCCESS	0x01
#define	USBA_HOTPLUG_SUCCESS		0x02
#define	USBA_TOTAL_HOTPLUG_FAILURE	0x04
#define	USBA_HOTPLUG_FAILURE		0x08

/*
 * Increment enumeration stats indicated by the flags
 */
void	usba_update_hotplug_stats(dev_info_t *, usb_flags_t);

/* Retrieve the current enumeration hotplug statistics */
void	usba_get_hotplug_stats(dev_info_t *,
		ulong_t	*, ulong_t *, ulong_t *,
		ulong_t	*, uchar_t *);

/* Reset the resetable hotplug stats */
void	usba_reset_hotplug_stats(dev_info_t *);


extern usb_log_handle_t usbai_log_handle;
extern	kmutex_t usbai_mutex;

void	usba_req_normal_cb(usba_req_wrapper_t *);
void	usba_req_exc_cb(usba_req_wrapper_t *, usb_cr_t, usb_cb_flags_t);
void	usba_do_req_exc_cb(usba_req_wrapper_t *, usb_cr_t,
						usb_cb_flags_t);
void	usba_req_set_cb_flags(usba_req_wrapper_t *, usb_cb_flags_t);

/*
 * Creating/Destroying children (root hub, and hub children)
 */
int	usba_create_child_devi(dev_info_t *, char *, usba_hcdi_ops_t *,
		dev_info_t *, usb_port_status_t,
		usba_device_t *, dev_info_t **);

int	usba_destroy_child_devi(dev_info_t *, uint_t);

/* utility function to map rval to a meaningful cr */
usb_cr_t usba_rval2cr(int);

/* various conversion functions */
usb_pipe_handle_t	usba_get_dflt_pipe_handle(dev_info_t *);
dev_info_t		*usba_get_dip(usb_pipe_handle_t);
usb_pipe_handle_t	usba_usbdev_to_dflt_pipe_handle(usba_device_t *);
usb_pipe_handle_t	usba_get_pipe_handle(usba_pipe_handle_data_t *);
usba_pipe_handle_data_t *usba_get_ph_data(usb_pipe_handle_t);
usb_pipe_state_t	usba_get_ph_state(usba_pipe_handle_data_t *);
int			usba_get_ph_ref_count(usba_pipe_handle_data_t *);

/* increment and decrement ref_count */
usba_pipe_handle_data_t *usba_hold_ph_data(usb_pipe_handle_t);
void			usba_release_ph_data(usba_ph_impl_t *);

/* close all pipe and mark them persistent */
void			usba_persistent_pipe_close(usba_device_t *);

/* reopen pipes that are marked persistent */
int			usba_persistent_pipe_open(usba_device_t *);

/* check for leaks in hubd and usb_mid */
void	usba_check_for_leaks(usba_device_t *);

/* free request wrappers */
void	usba_req_wrapper_free(usba_req_wrapper_t *);

/* usb device capture for the specific client driver */
typedef struct usb_dev_cap {
	dev_info_t			*dip;
	usb_dev_driver_callback_t	usba_dev_driver_cb;
} usb_dev_cap_t;

extern usb_dev_cap_t usb_cap;
_NOTE(SCHEME_PROTECTS_DATA("unique device capture data", usb_cap))

#ifdef __cplusplus
}
#endif

#endif /* _SYS_USB_USBA_USBA_IMPL_H */