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 */
|