Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/usb/clients/audio/usb_ac/usb_ac.c
+++ new/usr/src/uts/common/io/usb/clients/audio/usb_ac/usb_ac.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * AUDIO CONTROL Driver:
28 28 *
29 29 * usb_ac is a multiplexor that sits on top of usb_as and hid and is
30 30 * responsible for (1) providing the entry points to audio mixer framework,
31 31 * (2) passing control commands to and from usb_as and hid and (3) processing
32 32 * control messages from hid/usb_ah that it can handle.
33 33 *
34 34 * 1. Mixer entry points are: usb_ac_setup(), usb_ac_teardown(),
35 35 * usb_ac_set_config(), usb_ac_set_format(), usb_ac_start_play(),
36 36 * usb_ac_pause_play(), usb_ac_stop_play, usb_ac_start_record(),
37 37 * usb_ac_stop_record().
38 38 * 2. usb_ac is a streams driver that passes streams messages down to
39 39 * usb_as that selects the correct alternate with passed format
40 40 * parameters, sets sample frequency, starts play/record, stops
41 41 * play/record, pause play/record, open/close isoc pipe.
42 42 * 3. usb_ac handles the set_config command through the default pipe
43 43 * of sound control interface of the audio device in a synchronous
44 44 * manner.
45 45 *
46 46 * Serialization: A competing thread can't be allowed to interfere with
47 47 * (1) pipe, (2) streams state.
48 48 * So we need some kind of serialization among the asynchronous
49 49 * threads that can run in the driver. The serialization is mostly
50 50 * needed to avoid races among open/close/events/power entry points
51 51 * etc. Once a routine takes control, it checks if the resource (pipe or
52 52 * stream or dev state) is still accessible. If so, it proceeds with
53 53 * its job and until it completes, no other thread requiring the same
54 54 * resource can run.
55 55 *
56 56 * PM model in usb_ac: Raise power during attach. If a device is not at full
57 57 * power, raise power in the entry points. After the command is over,
58 58 * pm_idle_component() is called. The power is lowered in detach().
59 59 */
60 60 #include <sys/usb/usba/usbai_version.h>
61 61 #include <sys/usb/usba.h>
62 62 #include <sys/sunndi.h>
63 63 #include <sys/strsubr.h>
64 64 #include <sys/strsun.h>
65 65 #include <sys/ddi.h>
66 66 #include <sys/sunddi.h>
67 67 #include <sys/sunldi.h>
68 68
69 69 #include <sys/audio/audio_driver.h>
70 70
71 71 #include <sys/usb/clients/audio/usb_audio.h>
72 72 #include <sys/usb/clients/audio/usb_mixer.h>
73 73 #include <sys/usb/clients/audio/usb_ac/usb_ac.h>
74 74
75 75 /* for getting the minor node info from hid */
76 76 #include <sys/usb/clients/hid/hidminor.h>
77 77 #include <sys/usb/clients/audio/usb_as/usb_as.h>
78 78
79 79
80 80 /* debug support */
81 81 uint_t usb_ac_errlevel = USB_LOG_L4;
82 82 uint_t usb_ac_errmask = (uint_t)-1;
83 83 uint_t usb_ac_instance_debug = (uint_t)-1;
84 84
85 85 /*
86 86 * wait period in seconds for the HID message processing thread
87 87 * used primarily to check when the stream has closed
88 88 */
89 89 uint_t usb_ac_wait_hid = 1;
90 90
91 91 /*
92 92 * table for converting term types of input and output terminals
93 93 * to OSS port types (pretty rough mapping)
94 94 */
95 95 static const char *usb_audio_dtypes[] = {
96 96 AUDIO_PORT_LINEIN,
97 97 AUDIO_PORT_LINEOUT,
98 98 AUDIO_PORT_SPEAKER,
99 99 AUDIO_PORT_HEADPHONES,
100 100 AUDIO_PORT_HANDSET,
101 101 AUDIO_PORT_CD,
102 102 AUDIO_PORT_MIC,
103 103 AUDIO_PORT_PHONE,
104 104 AUDIO_PORT_SPDIFIN,
105 105 AUDIO_PORT_OTHER,
106 106 NULL,
107 107 };
108 108 enum {
109 109 USB_PORT_LINEIN = 0,
110 110 USB_PORT_LINEOUT,
111 111 USB_PORT_SPEAKER,
112 112 USB_PORT_HEADPHONES,
113 113 USB_PORT_HANDSET,
114 114 USB_PORT_CD,
115 115 USB_PORT_MIC,
116 116 USB_PORT_PHONE,
117 117 USB_PORT_SPDIFIN,
118 118 USB_PORT_UNKNOWN
119 119 };
120 120
121 121 static struct {
122 122 ushort_t term_type;
123 123 uint_t port_type;
124 124 } usb_ac_term_type_map[] = {
125 125
126 126 /* Input Terminal Types */
127 127 { USB_AUDIO_TERM_TYPE_MICROPHONE, USB_PORT_MIC },
128 128 { USB_AUDIO_TERM_TYPE_DT_MICROPHONE, USB_PORT_MIC },
129 129 { USB_AUDIO_TERM_TYPE_PERS_MICROPHONE, USB_PORT_MIC },
130 130 { USB_AUDIO_TERM_TYPE_OMNI_DIR_MICROPHONE, USB_PORT_MIC },
131 131 { USB_AUDIO_TERM_TYPE_MICROPHONE_ARRAY, USB_PORT_MIC },
132 132 { USB_AUDIO_TERM_TYPE_PROCESSING_MIC_ARRAY, USB_PORT_MIC },
133 133
134 134 /* Output Terminal Types */
135 135 { USB_AUDIO_TERM_TYPE_SPEAKER, USB_PORT_SPEAKER },
136 136 { USB_AUDIO_TERM_TYPE_HEADPHONES, USB_PORT_HEADPHONES },
137 137 { USB_AUDIO_TERM_TYPE_DISPLAY_AUDIO, USB_PORT_LINEOUT },
138 138 { USB_AUDIO_TERM_TYPE_DT_SPEAKER, USB_PORT_SPEAKER },
139 139 { USB_AUDIO_TERM_TYPE_ROOM_SPEAKER, USB_PORT_SPEAKER },
140 140 { USB_AUDIO_TERM_TYPE_COMM_SPEAKER, USB_PORT_SPEAKER },
141 141 { USB_AUDIO_TERM_TYPE_LF_EFFECTS_SPEAKER, USB_PORT_SPEAKER },
142 142
143 143 /* Bi-directional Terminal Types */
144 144 { USB_AUDIO_TERM_TYPE_HANDSET, USB_PORT_HANDSET },
145 145
146 146 /* Telephony Terminal Types */
147 147 { USB_AUDIO_TERM_TYPE_PHONE_LINE, USB_PORT_PHONE},
148 148 { USB_AUDIO_TERM_TYPE_TELEPHONE, USB_PORT_PHONE},
149 149 { USB_AUDIO_TERM_TYPE_DOWN_LINE_PHONE, USB_PORT_PHONE },
150 150
151 151 /* External Terminal Types */
152 152 { USB_AUDIO_TERM_TYPE_SPDIF_IF, USB_PORT_SPDIFIN },
153 153 /* Embedded Function Terminal Types */
154 154 { USB_AUDIO_TERM_TYPE_CD_PLAYER, USB_PORT_CD },
155 155 { 0, 0 }
156 156 };
157 157
158 158
159 159 /*
160 160 * Module linkage routines for the kernel
161 161 */
162 162 static int usb_ac_attach(dev_info_t *, ddi_attach_cmd_t);
163 163 static int usb_ac_detach(dev_info_t *, ddi_detach_cmd_t);
164 164 static int usb_ac_power(dev_info_t *, int, int);
165 165
166 166 static uint_t usb_ac_get_featureID(usb_ac_state_t *, uchar_t, uint_t,
167 167 uint_t);
168 168
169 169 /* module entry points */
170 170 int usb_ac_open(dev_info_t *);
171 171 void usb_ac_close(dev_info_t *);
172 172
173 173 /* descriptor handling */
174 174 static int usb_ac_handle_descriptors(usb_ac_state_t *);
175 175 static void usb_ac_add_unit_descriptor(usb_ac_state_t *, uchar_t *, size_t);
176 176 static void usb_ac_alloc_unit(usb_ac_state_t *, uint_t);
177 177 static void usb_ac_free_all_units(usb_ac_state_t *);
178 178 static void usb_ac_setup_connections(usb_ac_state_t *);
179 179 static void usb_ac_map_termtype_to_port(usb_ac_state_t *, uint_t);
180 180
181 181 /* power management */
182 182 static int usb_ac_pwrlvl0(usb_ac_state_t *);
183 183 static int usb_ac_pwrlvl1(usb_ac_state_t *);
184 184 static int usb_ac_pwrlvl2(usb_ac_state_t *);
185 185 static int usb_ac_pwrlvl3(usb_ac_state_t *);
186 186 static void usb_ac_create_pm_components(dev_info_t *, usb_ac_state_t *);
187 187 static void usb_ac_pm_busy_component(usb_ac_state_t *);
188 188 static void usb_ac_pm_idle_component(usb_ac_state_t *);
189 189
190 190 /* event handling */
191 191 static int usb_ac_disconnect_event_cb(dev_info_t *);
192 192 static int usb_ac_reconnect_event_cb(dev_info_t *);
193 193 static int usb_ac_cpr_suspend(dev_info_t *);
194 194 static void usb_ac_cpr_resume(dev_info_t *);
195 195
196 196 static usb_event_t usb_ac_events = {
197 197 usb_ac_disconnect_event_cb,
198 198 usb_ac_reconnect_event_cb,
199 199 NULL, NULL
200 200 };
201 201
202 202 /* misc. support */
203 203 static void usb_ac_restore_device_state(dev_info_t *, usb_ac_state_t *);
204 204 static int usb_ac_cleanup(dev_info_t *, usb_ac_state_t *);
205 205 static void usb_ac_serialize_access(usb_ac_state_t *);
206 206 static void usb_ac_release_access(usb_ac_state_t *);
207 207
208 208 static void usb_ac_push_unit_id(usb_ac_state_t *, uint_t);
209 209 static void usb_ac_pop_unit_id(usb_ac_state_t *, uint_t);
210 210 static void usb_ac_show_traverse_path(usb_ac_state_t *);
211 211 static int usb_ac_check_path(usb_ac_state_t *, uint_t);
212 212
213 213 static uint_t usb_ac_traverse_connections(usb_ac_state_t *, uint_t, uint_t,
214 214 uint_t, uint_t, uint_t, uint_t,
215 215 uint_t *, uint_t, uint_t *,
216 216 int (*func)(usb_ac_state_t *, uint_t, uint_t,
217 217 uint_t, uint_t, uint_t, uint_t *));
218 218 static uint_t usb_ac_set_port(usb_ac_state_t *, uint_t, uint_t);
219 219 static uint_t usb_ac_set_control(usb_ac_state_t *, uint_t, uint_t,
220 220 uint_t, uint_t, uint_t,
221 221 uint_t *, uint_t,
222 222 int (*func)(usb_ac_state_t *, uint_t, uint_t,
223 223 uint_t, uint_t, uint_t, uint_t *));
224 224 static uint_t usb_ac_set_monitor_gain_control(usb_ac_state_t *, uint_t,
225 225 uint_t, uint_t, uint_t, uint_t,
226 226 uint_t *, uint_t,
227 227 int (*func)(usb_ac_state_t *, uint_t, uint_t,
228 228 uint_t, uint_t, uint_t, uint_t *));
229 229 static uint_t usb_ac_traverse_all_units(usb_ac_state_t *, uint_t, uint_t,
230 230 uint_t, uint_t, uint_t, uint_t *,
231 231 uint_t, uint_t *,
232 232 int (*func)(usb_ac_state_t *, uint_t, uint_t,
233 233 uint_t, uint_t, uint_t, uint_t *));
234 234 static int usb_ac_update_port(usb_ac_state_t *, uint_t,
235 235 uint_t, uint_t, uint_t, uint_t, uint_t *);
236 236 static int usb_ac_set_selector(usb_ac_state_t *, uint_t,
237 237 uint_t, uint_t, uint_t, uint_t, uint_t *);
238 238 static int usb_ac_feature_unit_check(usb_ac_state_t *, uint_t,
239 239 uint_t, uint_t, uint_t, uint_t, uint_t *);
240 240 static int usb_ac_set_gain(usb_ac_state_t *, uint_t,
241 241 uint_t, uint_t, uint_t, uint_t, uint_t *);
242 242 static int usb_ac_set_monitor_gain(usb_ac_state_t *, uint_t,
243 243 uint_t, uint_t, uint_t, uint_t, uint_t *);
244 244 static int usb_ac_set_volume(usb_ac_state_t *, uint_t, short, int dir,
245 245 int);
246 246 static int usb_ac_get_maxmin_volume(usb_ac_state_t *, uint_t, int, int,
247 247 int, short *);
248 248 static int usb_ac_send_as_cmd(usb_ac_state_t *, usb_audio_eng_t *,
249 249 int, void *);
250 250 static int usb_ac_set_format(usb_ac_state_t *, usb_audio_eng_t *);
251 251 static int usb_ac_do_setup(usb_ac_state_t *, usb_audio_eng_t *);
252 252
253 253 /* usb audio basic function entries */
254 254 static int usb_ac_setup(usb_ac_state_t *, usb_audio_eng_t *);
255 255 static void usb_ac_teardown(usb_ac_state_t *, usb_audio_eng_t *);
256 256 static int usb_ac_start_play(usb_ac_state_t *, usb_audio_eng_t *);
257 257 static int usb_ac_start_record(usb_ac_state_t *, usb_audio_eng_t *);
258 258 static void usb_ac_stop_record(usb_ac_state_t *, usb_audio_eng_t *);
259 259 static int usb_ac_restore_audio_state(usb_ac_state_t *, int);
260 260
261 261 static int usb_ac_ctrl_restore(usb_ac_state_t *);
262 262 /*
263 263 * Mux
264 264 */
265 265 static int usb_ac_mux_walk_siblings(usb_ac_state_t *);
266 266 static void usb_ac_print_reg_data(usb_ac_state_t *,
267 267 usb_as_registration_t *);
268 268 static int usb_ac_get_reg_data(usb_ac_state_t *, ldi_handle_t, int);
269 269 static int usb_ac_setup_plumbed(usb_ac_state_t *, int, int);
270 270 static int usb_ac_mixer_registration(usb_ac_state_t *);
271 271 static void usb_ac_hold_siblings(usb_ac_state_t *);
272 272 static int usb_ac_online_siblings(usb_ac_state_t *);
273 273 static void usb_ac_rele_siblings(usb_ac_state_t *);
274 274 static int usb_ac_mux_plumbing(usb_ac_state_t *);
275 275 static void usb_ac_mux_plumbing_tq(void *);
276 276 static int usb_ac_mux_unplumbing(usb_ac_state_t *);
277 277 static void usb_ac_mux_unplumbing_tq(void *);
278 278 static int usb_ac_plumb(usb_ac_plumbed_t *);
279 279 static void usb_ac_unplumb(usb_ac_plumbed_t *);
280 280 static void usb_ac_reader(void *);
281 281 static int usb_ac_read_msg(usb_ac_plumbed_t *, mblk_t *);
282 282 static int usb_ac_do_plumbing(usb_ac_state_t *);
283 283 static int usb_ac_do_unplumbing(usb_ac_state_t *);
284 284
285 285
286 286 static int usb_change_phy_vol(usb_ac_state_t *, int);
287 287 static void usb_restore_engine(usb_ac_state_t *);
288 288
289 289 /* anchor for soft state structures */
290 290 void *usb_ac_statep;
291 291
292 292 /*
293 293 * DDI Structures
294 294 */
295 295
296 296 /* Device operations structure */
297 297 static struct dev_ops usb_ac_dev_ops = {
298 298 DEVO_REV, /* devo_rev */
299 299 0, /* devo_refcnt */
300 300 NULL, /* devo_getinfo */
301 301 nulldev, /* devo_identify - obsolete */
302 302 nulldev, /* devo_probe - not needed */
303 303 usb_ac_attach, /* devo_attach */
304 304 usb_ac_detach, /* devo_detach */
305 305 nodev, /* devo_reset */
306 306 NULL, /* devi_cb_ops */
307 307 NULL, /* devo_busb_ac_ops */
308 308 usb_ac_power, /* devo_power */
309 309 ddi_quiesce_not_needed, /* devo_quiesce */
310 310 };
↓ open down ↓ |
310 lines elided |
↑ open up ↑ |
311 311
312 312 /* Linkage structure for loadable drivers */
313 313 static struct modldrv usb_ac_modldrv = {
314 314 &mod_driverops, /* drv_modops */
315 315 "USB Audio Control Driver", /* drv_linkinfo */
316 316 &usb_ac_dev_ops /* drv_dev_ops */
317 317 };
318 318
319 319 /* Module linkage structure */
320 320 static struct modlinkage usb_ac_modlinkage = {
321 - MODREV_1, /* ml_rev */
322 - (void *)&usb_ac_modldrv, /* ml_linkage */
323 - NULL /* NULL terminates the list */
321 + MODREV_1, /* ml_rev */
322 + { (void *)&usb_ac_modldrv, NULL } /* ml_linkage */
324 323 };
325 324
326 325 static int usb_audio_register(usb_ac_state_t *);
327 326 static int usb_audio_unregister(usb_ac_state_t *);
328 327
329 328 static int usb_engine_open(void *, int, unsigned *, caddr_t *);
330 329 static void usb_engine_close(void *);
331 330 static uint64_t usb_engine_count(void *);
332 331 static int usb_engine_start(void *);
333 332 static void usb_engine_stop(void *);
334 333 static int usb_engine_format(void *);
335 334 static int usb_engine_channels(void *);
336 335 static int usb_engine_rate(void *);
337 336 static void usb_engine_sync(void *, unsigned);
338 337 static unsigned usb_engine_qlen(void *);
339 338
340 339 /* engine buffer size in terms of fragments */
341 340
342 341 audio_engine_ops_t usb_engine_ops = {
343 342 AUDIO_ENGINE_VERSION,
344 343 usb_engine_open,
345 344 usb_engine_close,
346 345 usb_engine_start,
347 346 usb_engine_stop,
348 347 usb_engine_count,
349 348 usb_engine_format,
350 349 usb_engine_channels,
351 350 usb_engine_rate,
352 351 usb_engine_sync,
353 352 usb_engine_qlen,
354 353 };
355 354
356 355
357 356
358 357 _NOTE(SCHEME_PROTECTS_DATA("unique per call", mblk_t))
359 358
360 359 /* standard entry points */
361 360 int
362 361 _init(void)
363 362 {
364 363 int rval;
365 364
366 365 /* initialize the soft state */
367 366 if ((rval = ddi_soft_state_init(&usb_ac_statep,
368 367 sizeof (usb_ac_state_t), 1)) != DDI_SUCCESS) {
369 368 return (rval);
370 369 }
371 370
372 371 audio_init_ops(&usb_ac_dev_ops, "usb_ac");
373 372
374 373 if ((rval = mod_install(&usb_ac_modlinkage)) != 0) {
375 374 ddi_soft_state_fini(&usb_ac_statep);
376 375 audio_fini_ops(&usb_ac_dev_ops);
377 376 }
378 377
379 378 return (rval);
380 379 }
381 380
382 381 int
383 382 _fini(void)
384 383 {
385 384 int rval;
386 385
387 386 if ((rval = mod_remove(&usb_ac_modlinkage)) == 0) {
388 387 /* Free the soft state internal structures */
389 388 ddi_soft_state_fini(&usb_ac_statep);
390 389 audio_fini_ops(&usb_ac_dev_ops);
391 390 }
392 391
393 392 return (rval);
394 393 }
395 394
396 395 int
397 396 _info(struct modinfo *modinfop)
398 397 {
399 398 return (mod_info(&usb_ac_modlinkage, modinfop));
400 399 }
401 400
402 401 extern uint_t nproc;
403 402 #define INIT_PROCESS_CNT 3
404 403
405 404 static int
406 405 usb_ac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
407 406 {
408 407 usb_ac_state_t *uacp = NULL;
409 408 int instance = ddi_get_instance(dip);
410 409
411 410 switch (cmd) {
412 411 case DDI_ATTACH:
413 412 break;
414 413 case DDI_RESUME:
415 414 usb_ac_cpr_resume(dip);
416 415
417 416 return (DDI_SUCCESS);
418 417 default:
419 418 return (DDI_FAILURE);
420 419 }
421 420
422 421 /*
423 422 * wait until all processes are started from main.
424 423 * USB enumerates early in boot (ie. consconfig time).
425 424 * If the plumbing takes place early, the file descriptors
426 425 * are owned by the init process and can never be closed anymore
427 426 * Consequently, hot removal is not possible and the dips
428 427 * never go away. By waiting some time, e.g. INIT_PROCESS_CNT,
429 428 * the problem is avoided.
430 429 */
431 430 if (nproc < INIT_PROCESS_CNT) {
432 431 USB_DPRINTF_L2(PRINT_MASK_ATTA, NULL,
433 432 "usb_ac%d attach too early", instance);
434 433
435 434 return (DDI_FAILURE);
436 435 }
437 436
438 437 /*
439 438 * Allocate soft state information.
440 439 */
441 440 if (ddi_soft_state_zalloc(usb_ac_statep, instance) != DDI_SUCCESS) {
442 441
443 442 goto fail;
444 443 }
445 444
446 445 /*
447 446 * get soft state space and initialize
448 447 */
449 448 uacp = (usb_ac_state_t *)ddi_get_soft_state(usb_ac_statep, instance);
450 449 if (uacp == NULL) {
451 450
452 451 goto fail;
453 452 }
454 453
455 454 /* get log handle */
456 455 uacp->usb_ac_log_handle = usb_alloc_log_hdl(dip, "ac",
457 456 &usb_ac_errlevel,
458 457 &usb_ac_errmask, &usb_ac_instance_debug,
459 458 0);
460 459
461 460 uacp->usb_ac_instance = instance;
462 461 uacp->usb_ac_dip = dip;
463 462
464 463 (void) snprintf(uacp->dstr, sizeof (uacp->dstr), "%s#%d",
465 464 ddi_driver_name(dip), instance);
466 465
467 466 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
468 467 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
469 468 "usb_client_attach failed");
470 469
471 470 usb_free_log_hdl(uacp->usb_ac_log_handle);
472 471 ddi_soft_state_free(usb_ac_statep, uacp->usb_ac_instance);
473 472
474 473 return (DDI_FAILURE);
475 474 }
476 475
477 476 if (usb_get_dev_data(dip, &uacp->usb_ac_dev_data,
478 477 USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
479 478 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
480 479 "usb_get_dev_data failed");
481 480
482 481 usb_client_detach(dip, NULL);
483 482 usb_free_log_hdl(uacp->usb_ac_log_handle);
484 483 ddi_soft_state_free(usb_ac_statep, uacp->usb_ac_instance);
485 484
486 485 return (DDI_FAILURE);
487 486 }
488 487
489 488 /* initialize mutex & cv */
490 489 mutex_init(&uacp->usb_ac_mutex, NULL, MUTEX_DRIVER,
491 490 uacp->usb_ac_dev_data->dev_iblock_cookie);
492 491
493 492 uacp->usb_ac_default_ph = uacp->usb_ac_dev_data->dev_default_ph;
494 493
495 494 /* parse all class specific descriptors */
496 495 if (usb_ac_handle_descriptors(uacp) != USB_SUCCESS) {
497 496
498 497 goto fail;
499 498 }
500 499
501 500 /* we no longer need the descr tree */
502 501 usb_free_descr_tree(dip, uacp->usb_ac_dev_data);
503 502
504 503 uacp->usb_ac_ser_acc = usb_init_serialization(dip,
505 504 USB_INIT_SER_CHECK_SAME_THREAD);
506 505
507 506 mutex_enter(&uacp->usb_ac_mutex);
508 507
509 508 /* we are online */
510 509 uacp->usb_ac_dev_state = USB_DEV_ONLINE;
511 510
512 511 /*
513 512 * safe guard the postattach to be executed
514 513 * only two states arepossible: plumbed / unplumbed
515 514 */
516 515 uacp->usb_ac_plumbing_state = USB_AC_STATE_UNPLUMBED;
517 516 uacp->usb_ac_current_plumbed_index = -1;
518 517
519 518 mutex_exit(&uacp->usb_ac_mutex);
520 519
521 520 /* create components to power manage this device */
522 521 usb_ac_create_pm_components(dip, uacp);
523 522
524 523 /* Register for events */
525 524 if (usb_register_event_cbs(dip, &usb_ac_events, 0) != USB_SUCCESS) {
526 525 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
527 526 "usb_ac_attach: couldn't register for events");
528 527
529 528 goto fail;
530 529 }
531 530
532 531 USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
533 532 "usb_ac_attach: End");
534 533
535 534 /* report device */
536 535 ddi_report_dev(dip);
537 536
538 537 if (usb_ac_do_plumbing(uacp) != USB_SUCCESS)
539 538 goto fail;
540 539
541 540 return (DDI_SUCCESS);
542 541
543 542 fail:
544 543 if (uacp) {
545 544 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
546 545 "attach failed");
547 546
548 547 /* wait for plumbing thread to finish */
549 548 if (uacp->tqp != NULL) {
550 549 ddi_taskq_wait(uacp->tqp);
551 550 ddi_taskq_destroy(uacp->tqp);
552 551 uacp->tqp = NULL;
553 552 }
554 553 (void) usb_ac_cleanup(dip, uacp);
555 554 }
556 555
557 556 return (DDI_FAILURE);
558 557 }
559 558
560 559
561 560 static int
562 561 usb_ac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
563 562 {
564 563 int instance = ddi_get_instance(dip);
565 564 usb_ac_state_t *uacp;
566 565 int rval = USB_FAILURE;
567 566
568 567 uacp = ddi_get_soft_state(usb_ac_statep, instance);
569 568
570 569 switch (cmd) {
571 570 case DDI_DETACH:
572 571 USB_DPRINTF_L4(PRINT_MASK_ATTA,
573 572 uacp->usb_ac_log_handle, "usb_ac_detach: detach");
574 573
575 574 /* wait for plumbing thread to finish */
576 575 if (uacp->tqp != NULL)
577 576 ddi_taskq_wait(uacp->tqp);
578 577
579 578 mutex_enter(&uacp->usb_ac_mutex);
580 579
581 580 /* do not allow detach if still busy */
582 581 if (uacp->usb_ac_busy_count) {
583 582 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
584 583 "usb_ac_detach:still busy, usb_ac_busy_count = %d",
585 584 uacp->usb_ac_busy_count);
586 585
587 586 mutex_exit(&uacp->usb_ac_mutex);
588 587 return (USB_FAILURE);
589 588 }
590 589 mutex_exit(&uacp->usb_ac_mutex);
591 590
592 591 (void) usb_audio_unregister(uacp);
593 592
594 593
595 594
596 595 /*
597 596 * unplumb to stop activity from other modules, then
598 597 * cleanup, which will also teardown audio framework state
599 598 */
600 599 if (usb_ac_do_unplumbing(uacp) == USB_SUCCESS)
601 600 rval = usb_ac_cleanup(dip, uacp);
602 601
603 602 if (rval != USB_SUCCESS) {
604 603 USB_DPRINTF_L2(PRINT_MASK_ATTA,
605 604 uacp->usb_ac_log_handle, "detach failed: %s%d",
606 605 ddi_driver_name(dip), instance);
607 606 }
608 607
609 608 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
610 609 case DDI_SUSPEND:
611 610 USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
612 611 "usb_ac_detach: suspending");
613 612
614 613 rval = usb_ac_cpr_suspend(dip);
615 614
616 615 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
617 616 default:
618 617
619 618 return (DDI_FAILURE);
620 619 }
621 620 }
622 621
623 622
624 623 /*
625 624 * usb_ac_cleanup:
626 625 * cleanup on attach failure and detach
627 626 */
628 627 static int
629 628 usb_ac_cleanup(dev_info_t *dip, usb_ac_state_t *uacp)
630 629 {
631 630 usb_ac_power_t *uacpm;
632 631 int rval = USB_FAILURE;
633 632
634 633
635 634 mutex_enter(&uacp->usb_ac_mutex);
636 635 uacpm = uacp->usb_ac_pm;
637 636
638 637 USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
639 638 "usb_ac_cleanup:begain");
640 639
641 640 ASSERT(uacp->usb_ac_busy_count == 0);
642 641
643 642 ASSERT(uacp->usb_ac_plumbing_state == USB_AC_STATE_UNPLUMBED);
644 643
645 644 mutex_exit(&uacp->usb_ac_mutex);
646 645
647 646 /*
648 647 * Disable the event callbacks, after this point, event
649 648 * callbacks will never get called. Note we shouldn't hold
650 649 * the mutex while unregistering events because there may be a
651 650 * competing event callback thread. Event callbacks are done
652 651 * with ndi mutex held and this can cause a potential deadlock.
653 652 */
654 653 usb_unregister_event_cbs(dip, &usb_ac_events);
655 654
656 655 mutex_enter(&uacp->usb_ac_mutex);
657 656
658 657 if (uacpm && (uacp->usb_ac_dev_state != USB_DEV_DISCONNECTED)) {
659 658 if (uacpm->acpm_wakeup_enabled) {
660 659 mutex_exit(&uacp->usb_ac_mutex);
661 660 usb_ac_pm_busy_component(uacp);
662 661 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
663 662
664 663 rval = usb_handle_remote_wakeup(dip,
665 664 USB_REMOTE_WAKEUP_DISABLE);
666 665 if (rval != USB_SUCCESS) {
667 666 USB_DPRINTF_L2(PRINT_MASK_PM,
668 667 uacp->usb_ac_log_handle,
669 668 "usb_ac_cleanup: disable remote "
670 669 "wakeup failed, rval=%d", rval);
671 670 }
672 671 usb_ac_pm_idle_component(uacp);
673 672 } else {
674 673 mutex_exit(&uacp->usb_ac_mutex);
675 674 }
676 675
677 676 (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
678 677
679 678 mutex_enter(&uacp->usb_ac_mutex);
680 679 }
681 680
682 681 if (uacpm) {
683 682 kmem_free(uacpm, sizeof (usb_ac_power_t));
684 683 uacp->usb_ac_pm = NULL;
685 684 }
686 685
687 686 usb_client_detach(dip, uacp->usb_ac_dev_data);
688 687
689 688 /* free descriptors */
690 689 usb_ac_free_all_units(uacp);
691 690
692 691 mutex_exit(&uacp->usb_ac_mutex);
693 692
694 693 mutex_destroy(&uacp->usb_ac_mutex);
695 694
696 695 usb_fini_serialization(uacp->usb_ac_ser_acc);
697 696
698 697 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
699 698 "usb_ac_cleanup: Ending");
700 699
701 700 usb_free_log_hdl(uacp->usb_ac_log_handle);
702 701 kmem_free(uacp->usb_ac_connections, uacp->usb_ac_connections_len);
703 702 kmem_free(uacp->usb_ac_connections_a, uacp->usb_ac_connections_a_len);
704 703 kmem_free(uacp->usb_ac_unit_type, uacp->usb_ac_max_unit);
705 704 kmem_free(uacp->usb_ac_traverse_path, uacp->usb_ac_max_unit);
706 705
707 706 ddi_soft_state_free(usb_ac_statep, uacp->usb_ac_instance);
708 707
709 708 ddi_prop_remove_all(dip);
710 709
711 710 return (USB_SUCCESS);
712 711 }
713 712
714 713
715 714 int
716 715 usb_ac_open(dev_info_t *dip)
717 716 {
718 717 int inst = ddi_get_instance(dip);
719 718 usb_ac_state_t *uacp = ddi_get_soft_state(usb_ac_statep, inst);
720 719
721 720 mutex_enter(&uacp->usb_ac_mutex);
722 721
723 722 uacp->usb_ac_busy_count++;
724 723
725 724 mutex_exit(&uacp->usb_ac_mutex);
726 725
727 726 usb_ac_pm_busy_component(uacp);
728 727 (void) pm_raise_power(uacp->usb_ac_dip, 0, USB_DEV_OS_FULL_PWR);
729 728
730 729 return (0);
731 730 }
732 731
733 732
734 733 void
735 734 usb_ac_close(dev_info_t *dip)
736 735 {
737 736 int inst = ddi_get_instance(dip);
738 737 usb_ac_state_t *uacp = ddi_get_soft_state(usb_ac_statep, inst);
739 738
740 739 mutex_enter(&uacp->usb_ac_mutex);
741 740
742 741 if (uacp->usb_ac_busy_count > 0)
743 742 uacp->usb_ac_busy_count--;
744 743
745 744 mutex_exit(&uacp->usb_ac_mutex);
746 745
747 746 usb_ac_pm_idle_component(uacp);
748 747 }
749 748
750 749
751 750 /*
752 751 * usb_ac_read_msg:
753 752 * Handle asynchronous response from opened streams
754 753 */
755 754 static int
756 755 usb_ac_read_msg(usb_ac_plumbed_t *plumb_infop, mblk_t *mp)
757 756 {
758 757 usb_ac_state_t *uacp = plumb_infop->acp_uacp;
759 758 int error = DDI_SUCCESS;
760 759 int val;
761 760 char val1;
762 761 struct iocblk *iocp;
763 762
764 763
765 764 ASSERT(mutex_owned(&uacp->usb_ac_mutex));
766 765
767 766 /*
768 767 * typically an M_CTL is used between modules but in order to pass
769 768 * through the streamhead, an M_PROTO type must be used instead
770 769 */
771 770 switch (mp->b_datap->db_type) {
772 771 case M_PROTO:
773 772 case M_ERROR:
774 773 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
775 774 "M_CTL/M_ERROR");
776 775
777 776 switch (plumb_infop->acp_driver) {
778 777 case USB_AH_PLUMBED:
779 778 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
780 779 "message from hid, instance=%d",
781 780 ddi_get_instance(plumb_infop->acp_dip));
782 781
783 782 iocp = (struct iocblk *)(void *)mp->b_rptr;
784 783 ASSERT(mp->b_cont != NULL);
785 784
786 785 if (uacp->usb_ac_registered_with_mixer) {
787 786
788 787 val1 = *((char *)mp->b_cont->b_rptr);
789 788 val = (int)val1;
790 789
791 790 USB_DPRINTF_L4(PRINT_MASK_ALL,
792 791 uacp->usb_ac_log_handle, "val1=0x%x(%d),"
793 792 "val=0x%x(%d)", val1, val1, val, val);
794 793
795 794 switch (iocp->ioc_cmd) {
796 795 /* Handle relative volume change */
797 796 case USB_AUDIO_VOL_CHANGE:
798 797 /* prevent unplumbing */
799 798 uacp->usb_ac_busy_count++;
800 799 if (uacp->usb_ac_plumbing_state ==
801 800 USB_AC_STATE_PLUMBED) {
802 801 mutex_exit(&uacp->usb_ac_mutex);
803 802 (void) usb_change_phy_vol(
804 803 uacp, val);
805 804 mutex_enter(&uacp->
806 805 usb_ac_mutex);
807 806 }
808 807 uacp->usb_ac_busy_count--;
809 808 /* FALLTHRU */
810 809 case USB_AUDIO_MUTE:
811 810 default:
812 811 freemsg(mp);
813 812 break;
814 813 }
815 814 } else {
816 815 freemsg(mp);
817 816 }
818 817
819 818 break;
820 819 default:
821 820 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
822 821 "message from unknown module(%s)",
823 822 ddi_driver_name(plumb_infop->acp_dip));
824 823 freemsg(mp);
825 824 }
826 825
827 826 break;
828 827 default:
829 828 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
830 829 "Unknown type=%d", mp->b_datap->db_type);
831 830 freemsg(mp);
832 831 }
833 832
834 833
835 834 return (error);
836 835 }
837 836
838 837
839 838 /*
840 839 * Power Management
841 840 * usb_ac_power:
842 841 * power entry point
843 842 */
844 843 static int
845 844 usb_ac_power(dev_info_t *dip, int comp, int level)
846 845 {
847 846 _NOTE(ARGUNUSED(comp));
848 847 int instance = ddi_get_instance(dip);
849 848 usb_ac_state_t *uacp;
850 849 usb_ac_power_t *uacpm;
851 850 int rval = DDI_FAILURE;
852 851
853 852 uacp = ddi_get_soft_state(usb_ac_statep, instance);
854 853
855 854 mutex_enter(&uacp->usb_ac_mutex);
856 855 uacpm = uacp->usb_ac_pm;
857 856
858 857 if (USB_DEV_PWRSTATE_OK(uacpm->acpm_pwr_states, level)) {
859 858 USB_DPRINTF_L2(PRINT_MASK_PM, uacp->usb_ac_log_handle,
860 859 "usb_ac_power: illegal level=%d pwr_states=%d",
861 860 level, uacpm->acpm_pwr_states);
862 861
863 862 goto done;
864 863 }
865 864
866 865 switch (level) {
867 866 case USB_DEV_OS_PWR_OFF:
868 867 rval = usb_ac_pwrlvl0(uacp);
869 868 break;
870 869 case USB_DEV_OS_PWR_1:
871 870 rval = usb_ac_pwrlvl1(uacp);
872 871 break;
873 872 case USB_DEV_OS_PWR_2:
874 873 rval = usb_ac_pwrlvl2(uacp);
875 874 break;
876 875 case USB_DEV_OS_FULL_PWR:
877 876 rval = usb_ac_pwrlvl3(uacp);
878 877 break;
879 878 }
880 879
881 880 done:
882 881 mutex_exit(&uacp->usb_ac_mutex);
883 882
884 883 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
885 884 }
886 885
887 886
888 887 /*
889 888 * functions to handle power transition for various levels
890 889 * These functions act as place holders to issue USB commands
891 890 * to the devices to change their power levels
892 891 * Level 0 = Device is powered off
893 892 * Level 3 = Device if full powered
894 893 * Level 1,2 = Intermediate power level of the device as implemented
895 894 * by the hardware.
896 895 * Note that Level 0 is OS power-off and Level 3 is OS full-power.
897 896 */
898 897 static int
899 898 usb_ac_pwrlvl0(usb_ac_state_t *uacp)
900 899 {
901 900 usb_ac_power_t *uacpm;
902 901 int rval;
903 902
904 903 uacpm = uacp->usb_ac_pm;
905 904
906 905 switch (uacp->usb_ac_dev_state) {
907 906 case USB_DEV_ONLINE:
908 907 /* Deny the powerdown request if the device is busy */
909 908 if (uacpm->acpm_pm_busy != 0) {
910 909
911 910 return (USB_FAILURE);
912 911 }
913 912
914 913 /* Issue USB D3 command to the device here */
915 914 rval = usb_set_device_pwrlvl3(uacp->usb_ac_dip);
916 915 ASSERT(rval == USB_SUCCESS);
917 916
918 917 uacp->usb_ac_dev_state = USB_DEV_PWRED_DOWN;
919 918 uacpm->acpm_current_power = USB_DEV_OS_PWR_OFF;
920 919
921 920 /* FALLTHRU */
922 921 case USB_DEV_DISCONNECTED:
923 922 case USB_DEV_SUSPENDED:
924 923 case USB_DEV_PWRED_DOWN:
925 924 default:
926 925 return (USB_SUCCESS);
927 926 }
928 927 }
929 928
930 929
931 930 /* ARGSUSED */
932 931 static int
933 932 usb_ac_pwrlvl1(usb_ac_state_t *uacp)
934 933 {
935 934 int rval;
936 935
937 936 /* Issue USB D2 command to the device here */
938 937 rval = usb_set_device_pwrlvl2(uacp->usb_ac_dip);
939 938 ASSERT(rval == USB_SUCCESS);
940 939
941 940 return (USB_FAILURE);
942 941 }
943 942
944 943
945 944 /* ARGSUSED */
946 945 static int
947 946 usb_ac_pwrlvl2(usb_ac_state_t *uacp)
948 947 {
949 948 int rval;
950 949
951 950 rval = usb_set_device_pwrlvl1(uacp->usb_ac_dip);
952 951 ASSERT(rval == USB_SUCCESS);
953 952
954 953 return (USB_FAILURE);
955 954 }
956 955
957 956
958 957 static int
959 958 usb_ac_pwrlvl3(usb_ac_state_t *uacp)
960 959 {
961 960 usb_ac_power_t *uacpm;
962 961 int rval;
963 962
964 963 uacpm = uacp->usb_ac_pm;
965 964
966 965 switch (uacp->usb_ac_dev_state) {
967 966 case USB_DEV_PWRED_DOWN:
968 967 /* Issue USB D0 command to the device here */
969 968 rval = usb_set_device_pwrlvl0(uacp->usb_ac_dip);
970 969 ASSERT(rval == USB_SUCCESS);
971 970
972 971 uacp->usb_ac_dev_state = USB_DEV_ONLINE;
973 972 uacpm->acpm_current_power = USB_DEV_OS_FULL_PWR;
974 973 /* FALLTHRU */
975 974 case USB_DEV_ONLINE:
976 975 /* we are already in full power */
977 976
978 977 /* FALLTHRU */
979 978 case USB_DEV_DISCONNECTED:
980 979 case USB_DEV_SUSPENDED:
981 980
982 981 return (USB_SUCCESS);
983 982 default:
984 983 USB_DPRINTF_L2(PRINT_MASK_PM, uacp->usb_ac_log_handle,
985 984 "usb_ac_pwerlvl3: Illegal dev_state");
986 985
987 986 return (USB_FAILURE);
988 987 }
989 988 }
990 989
991 990
992 991 static void
993 992 usb_ac_create_pm_components(dev_info_t *dip, usb_ac_state_t *uacp)
994 993 {
995 994 usb_ac_power_t *uacpm;
996 995 uint_t pwr_states;
997 996
998 997 USB_DPRINTF_L4(PRINT_MASK_PM, uacp->usb_ac_log_handle,
999 998 "usb_ac_create_pm_components: begin");
1000 999
1001 1000 /* Allocate the state structure */
1002 1001 uacpm = kmem_zalloc(sizeof (usb_ac_power_t), KM_SLEEP);
1003 1002 uacp->usb_ac_pm = uacpm;
1004 1003 uacpm->acpm_state = uacp;
1005 1004 uacpm->acpm_capabilities = 0;
1006 1005 uacpm->acpm_current_power = USB_DEV_OS_FULL_PWR;
1007 1006
1008 1007 if (usb_create_pm_components(dip, &pwr_states) ==
1009 1008 USB_SUCCESS) {
1010 1009 if (usb_handle_remote_wakeup(dip,
1011 1010 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
1012 1011 uacpm->acpm_wakeup_enabled = 1;
1013 1012
1014 1013 USB_DPRINTF_L4(PRINT_MASK_PM,
1015 1014 uacp->usb_ac_log_handle,
1016 1015 "remote Wakeup enabled");
1017 1016 }
1018 1017 uacpm->acpm_pwr_states = (uint8_t)pwr_states;
1019 1018 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1020 1019 } else {
1021 1020 if (uacpm) {
1022 1021 kmem_free(uacpm, sizeof (usb_ac_power_t));
1023 1022 uacp->usb_ac_pm = NULL;
1024 1023 }
1025 1024 USB_DPRINTF_L2(PRINT_MASK_PM, uacp->usb_ac_log_handle,
1026 1025 "pm not enabled");
1027 1026 }
1028 1027
1029 1028 }
1030 1029
1031 1030 /*
1032 1031 * usb_ac_get_featureID:
1033 1032 * find out if there is at least one feature unit that supports
1034 1033 * the request controls.
1035 1034 * Return featureID or USB_AC_ID_NONE.
1036 1035 */
1037 1036 static uint_t
1038 1037 usb_ac_get_featureID(usb_ac_state_t *uacp, uchar_t dir,
1039 1038 uint_t channel, uint_t control)
1040 1039 {
1041 1040 uint_t count = 0;
1042 1041
1043 1042 return (usb_ac_set_control(uacp, dir, USB_AUDIO_FEATURE_UNIT,
1044 1043 channel, control, USB_AC_FIND_ONE, &count, 0,
1045 1044 usb_ac_feature_unit_check));
1046 1045 }
1047 1046
1048 1047
1049 1048 /*
1050 1049 * usb_ac_feature_unit_check:
1051 1050 * check if a feature unit can support the required channel
1052 1051 * and control combination. Return USB_SUCCESS or USB_FAILURE.
1053 1052 * Called for each matching unit from usb_ac_traverse_connections.
1054 1053 */
1055 1054 /*ARGSUSED*/
1056 1055 static int
1057 1056 usb_ac_feature_unit_check(usb_ac_state_t *uacp, uint_t featureID,
1058 1057 uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth)
1059 1058 {
1060 1059 usb_audio_feature_unit_descr1_t *feature_descrp;
1061 1060 int n_channel_controls;
1062 1061
1063 1062
1064 1063 ASSERT(featureID < uacp->usb_ac_max_unit);
1065 1064
1066 1065 /*
1067 1066 * check if this control is supported on this channel
1068 1067 */
1069 1068 feature_descrp = (usb_audio_feature_unit_descr1_t *)
1070 1069 uacp->usb_ac_units[featureID].acu_descriptor;
1071 1070 ASSERT(feature_descrp->bUnitID == featureID);
1072 1071
1073 1072 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1074 1073 "bControlSize=%d", feature_descrp->bControlSize);
1075 1074
1076 1075 if (feature_descrp->bControlSize == 0) {
1077 1076 featureID = USB_AC_ID_NONE;
1078 1077 } else {
1079 1078 uint_t index;
1080 1079
1081 1080 n_channel_controls = (feature_descrp->bLength -
1082 1081 offsetof(usb_audio_feature_unit_descr1_t,
1083 1082 bmaControls))/feature_descrp->bControlSize;
1084 1083
1085 1084 USB_DPRINTF_L3(PRINT_MASK_ALL,
1086 1085 uacp->usb_ac_log_handle,
1087 1086 "#controls: %d index=%d", n_channel_controls,
1088 1087 feature_descrp->bControlSize * channel);
1089 1088
1090 1089 if (channel > n_channel_controls) {
1091 1090 featureID = USB_AC_ID_NONE;
1092 1091 } else {
1093 1092 /*
1094 1093 * we only support MUTE and VOLUME
1095 1094 * which are in the first byte
1096 1095 */
1097 1096 index = feature_descrp->bControlSize *
1098 1097 channel;
1099 1098
1100 1099 USB_DPRINTF_L3(PRINT_MASK_ALL,
1101 1100 uacp->usb_ac_log_handle,
1102 1101 "control: 0x%x",
1103 1102 feature_descrp->bmaControls[index]);
1104 1103
1105 1104 if ((feature_descrp->bmaControls[index] &
1106 1105 control) == 0) {
1107 1106 featureID = USB_AC_ID_NONE;
1108 1107 }
1109 1108 }
1110 1109 }
1111 1110
1112 1111 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1113 1112 "usb_ac_feature_unit_check: dir=%d featureID=0x%x",
1114 1113 dir, featureID);
1115 1114
1116 1115 return ((featureID != USB_AC_ID_NONE) ?
1117 1116 USB_SUCCESS : USB_FAILURE);
1118 1117 }
1119 1118
1120 1119
1121 1120 /*
1122 1121 * Descriptor Management
1123 1122 *
1124 1123 * usb_ac_handle_descriptors:
1125 1124 * extract interesting descriptors from the config cloud
1126 1125 */
1127 1126 static int
1128 1127 usb_ac_handle_descriptors(usb_ac_state_t *uacp)
1129 1128 {
1130 1129 int len, index;
1131 1130 int rval = USB_FAILURE;
1132 1131 usb_audio_cs_if_descr_t descr;
1133 1132 usb_client_dev_data_t *dev_data = uacp->usb_ac_dev_data;
1134 1133 usb_alt_if_data_t *altif_data;
1135 1134 usb_cvs_data_t *cvs;
1136 1135
1137 1136
1138 1137 altif_data = &dev_data->dev_curr_cfg->
1139 1138 cfg_if[dev_data->dev_curr_if].if_alt[0];
1140 1139
1141 1140 uacp->usb_ac_ifno = dev_data->dev_curr_if;
1142 1141 uacp->usb_ac_if_descr = altif_data->altif_descr;
1143 1142
1144 1143 /* find USB_AUDIO_CS_INTERFACE type descriptor */
1145 1144 for (index = 0; index < altif_data->altif_n_cvs; index++) {
1146 1145 cvs = &altif_data->altif_cvs[index];
1147 1146 if (cvs->cvs_buf == NULL) {
1148 1147 continue;
1149 1148 }
1150 1149 if (cvs->cvs_buf[1] == USB_AUDIO_CS_INTERFACE) {
1151 1150 break;
1152 1151 }
1153 1152 }
1154 1153
1155 1154 if (index == altif_data->altif_n_cvs) {
1156 1155 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1157 1156 "usb_ac_handle_descriptors:cannot find descriptor type %d",
1158 1157 USB_AUDIO_CS_INTERFACE);
1159 1158
1160 1159 return (rval);
1161 1160 }
1162 1161
1163 1162 len = usb_parse_data(
1164 1163 CS_AC_IF_HEADER_FORMAT,
1165 1164 cvs->cvs_buf, cvs->cvs_buf_len,
1166 1165 (void *)&descr, sizeof (usb_audio_cs_if_descr_t));
1167 1166
1168 1167 /* is this a sane header descriptor */
1169 1168 if (!((len >= CS_AC_IF_HEADER_SIZE) &&
1170 1169 (descr.bDescriptorType == USB_AUDIO_CS_INTERFACE) &&
1171 1170 (descr.bDescriptorSubType == USB_AUDIO_HEADER))) {
1172 1171 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1173 1172 "invalid header");
1174 1173
1175 1174 return (rval);
1176 1175 }
1177 1176
1178 1177 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1179 1178 "index %d, header: type=0x%x subtype=0x%x bcdADC=0x%x\n\t"
1180 1179 "total=0x%x InCol=0x%x",
1181 1180 index,
1182 1181 descr.bDescriptorType,
1183 1182 descr.bDescriptorSubType,
1184 1183 descr.bcdADC,
1185 1184 descr.wTotalLength,
1186 1185 descr.blnCollection);
1187 1186
1188 1187 /*
1189 1188 * we read descriptors by index and store them in ID array.
1190 1189 * the actual parsing is done in usb_ac_add_unit_descriptor()
1191 1190 */
1192 1191 for (index++; index < altif_data->altif_n_cvs; index++) {
1193 1192 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1194 1193 "index=%d", index);
1195 1194
1196 1195 cvs = &altif_data->altif_cvs[index];
1197 1196 if (cvs->cvs_buf == NULL) {
1198 1197 continue;
1199 1198 }
1200 1199
1201 1200 /* add to ID array */
1202 1201 usb_ac_add_unit_descriptor(uacp, cvs->cvs_buf,
1203 1202 cvs->cvs_buf_len);
1204 1203 }
1205 1204 rval = USB_SUCCESS;
1206 1205
1207 1206 usb_ac_setup_connections(uacp);
1208 1207
1209 1208 /* determine port types */
1210 1209 usb_ac_map_termtype_to_port(uacp, USB_AUDIO_PLAY);
1211 1210 usb_ac_map_termtype_to_port(uacp, USB_AUDIO_RECORD);
1212 1211
1213 1212
1214 1213 return (rval);
1215 1214 }
1216 1215
1217 1216
1218 1217 /*
1219 1218 * usb_ac_setup_connections:
1220 1219 * build a matrix reflecting all connections
1221 1220 */
1222 1221 static void
1223 1222 usb_ac_setup_connections(usb_ac_state_t *uacp)
1224 1223 {
1225 1224 usb_ac_unit_list_t *units = uacp->usb_ac_units;
1226 1225 uchar_t *a, **p, i, unit;
1227 1226 size_t a_len, p_len;
1228 1227
1229 1228 /* allocate array for unit types for quick reference */
1230 1229 uacp->usb_ac_unit_type = kmem_zalloc(uacp->usb_ac_max_unit,
1231 1230 KM_SLEEP);
1232 1231 /* allocate array for traversal path */
1233 1232 uacp->usb_ac_traverse_path = kmem_zalloc(uacp->usb_ac_max_unit,
1234 1233 KM_SLEEP);
1235 1234
1236 1235
1237 1236 /* allocate the connection matrix and set it up */
1238 1237 a_len = uacp->usb_ac_max_unit * uacp->usb_ac_max_unit;
1239 1238 p_len = uacp->usb_ac_max_unit * sizeof (uchar_t *);
1240 1239
1241 1240 /* trick to create a 2 dimensional array */
1242 1241 a = kmem_zalloc(a_len, KM_SLEEP);
1243 1242 p = kmem_zalloc(p_len, KM_SLEEP);
1244 1243 for (i = 0; i < uacp->usb_ac_max_unit; i++) {
1245 1244 p[i] = a + i * uacp->usb_ac_max_unit;
1246 1245 }
1247 1246 uacp->usb_ac_connections = p;
1248 1247 uacp->usb_ac_connections_len = p_len;
1249 1248 uacp->usb_ac_connections_a = a;
1250 1249 uacp->usb_ac_connections_a_len = a_len;
1251 1250
1252 1251 /* traverse all units and set connections */
1253 1252 for (unit = 0; unit < uacp->usb_ac_max_unit; unit++) {
1254 1253
1255 1254 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1256 1255 "--------traversing unit=0x%x type=0x%x--------",
1257 1256 unit, units[unit].acu_type);
1258 1257
1259 1258 /* store type in the first unused column */
1260 1259 uacp->usb_ac_unit_type[unit] = units[unit].acu_type;
1261 1260
1262 1261 /* save the Unit ID in the unit it points to */
1263 1262 switch (units[unit].acu_type) {
1264 1263 case USB_AUDIO_FEATURE_UNIT:
1265 1264 {
1266 1265 usb_audio_feature_unit_descr1_t *d =
1267 1266 units[unit].acu_descriptor;
1268 1267
1269 1268 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1270 1269 "USB_AUDIO_FEATURE_UNIT:sourceID=0x%x type=0x%x",
1271 1270 d->bSourceID, units[d->bSourceID].acu_type);
1272 1271
1273 1272 if (d->bSourceID != 0) {
1274 1273 ASSERT(p[unit][d->bSourceID] == B_FALSE);
1275 1274 p[unit][d->bSourceID] = B_TRUE;
1276 1275 }
1277 1276
1278 1277 break;
1279 1278 }
1280 1279 case USB_AUDIO_OUTPUT_TERMINAL:
1281 1280 {
1282 1281 usb_audio_output_term_descr_t *d =
1283 1282 units[unit].acu_descriptor;
1284 1283
1285 1284 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1286 1285 "USB_AUDIO_OUTPUT_TERMINAL:sourceID=0x%x type=0x%x",
1287 1286 d->bSourceID, units[d->bSourceID].acu_type);
1288 1287
1289 1288 if (d->bSourceID != 0) {
1290 1289 ASSERT(p[unit][d->bSourceID] == B_FALSE);
1291 1290 p[unit][d->bSourceID] = B_TRUE;
1292 1291 }
1293 1292
1294 1293 break;
1295 1294 }
1296 1295 case USB_AUDIO_MIXER_UNIT:
1297 1296 {
1298 1297 usb_audio_mixer_unit_descr1_t *d =
1299 1298 units[unit].acu_descriptor;
1300 1299 int n_sourceID = d->bNrInPins;
1301 1300 int id;
1302 1301
1303 1302 for (id = 0; id < n_sourceID; id++) {
1304 1303 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1305 1304 uacp->usb_ac_log_handle,
1306 1305 "USB_AUDIO_MIXER_UNIT:sourceID=0x%x"
1307 1306 "type=0x%x c=%d",
1308 1307 d->baSourceID[id],
1309 1308 units[d->baSourceID[id]].acu_type,
1310 1309 p[unit][d->baSourceID[id]]);
1311 1310
1312 1311 if (d->baSourceID[id] != 0) {
1313 1312 ASSERT(p[unit][d->baSourceID[id]] ==
1314 1313 B_FALSE);
1315 1314 p[unit][d->baSourceID[id]] = B_TRUE;
1316 1315 }
1317 1316 }
1318 1317
1319 1318 break;
1320 1319 }
1321 1320 case USB_AUDIO_SELECTOR_UNIT:
1322 1321 {
1323 1322 usb_audio_selector_unit_descr1_t *d =
1324 1323 units[unit].acu_descriptor;
1325 1324 int n_sourceID = d->bNrInPins;
1326 1325 int id;
1327 1326
1328 1327 for (id = 0; id < n_sourceID; id++) {
1329 1328 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1330 1329 uacp->usb_ac_log_handle,
1331 1330 "USB_AUDIO_SELECTOR_UNIT:sourceID=0x%x"
1332 1331 " type=0x%x", d->baSourceID[id],
1333 1332 units[d->baSourceID[id]].acu_type);
1334 1333
1335 1334 if (d->baSourceID[id] != 0) {
1336 1335 ASSERT(p[unit][d->baSourceID[id]] ==
1337 1336 B_FALSE);
1338 1337 p[unit][d->baSourceID[id]] = B_TRUE;
1339 1338 }
1340 1339 }
1341 1340
1342 1341 break;
1343 1342 }
1344 1343 case USB_AUDIO_PROCESSING_UNIT:
1345 1344 {
1346 1345 usb_audio_mixer_unit_descr1_t *d =
1347 1346 units[unit].acu_descriptor;
1348 1347 int n_sourceID = d->bNrInPins;
1349 1348 int id;
1350 1349
1351 1350 for (id = 0; id < n_sourceID; id++) {
1352 1351 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1353 1352 uacp->usb_ac_log_handle,
1354 1353 "USB_AUDIO_PROCESSING_UNIT:sourceID=0x%x"
1355 1354 " type=0x%x", d->baSourceID[id],
1356 1355 units[d->baSourceID[id]].acu_type);
1357 1356
1358 1357 if (d->baSourceID[id] != 0) {
1359 1358 ASSERT(p[unit][d->baSourceID[id]] ==
1360 1359 B_FALSE);
1361 1360 p[unit][d->baSourceID[id]] = B_TRUE;
1362 1361 }
1363 1362 }
1364 1363
1365 1364 break;
1366 1365 }
1367 1366 case USB_AUDIO_EXTENSION_UNIT:
1368 1367 {
1369 1368 usb_audio_extension_unit_descr1_t *d =
1370 1369 units[unit].acu_descriptor;
1371 1370 int n_sourceID = d->bNrInPins;
1372 1371 int id;
1373 1372
1374 1373 for (id = 0; id < n_sourceID; id++) {
1375 1374 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1376 1375 uacp->usb_ac_log_handle,
1377 1376 "USB_AUDIO_EXTENSION_UNIT:sourceID=0x%x"
1378 1377 "type=0x%x", d->baSourceID[id],
1379 1378 units[d->baSourceID[id]].acu_type);
1380 1379
1381 1380 if (d->baSourceID[id] != 0) {
1382 1381 ASSERT(p[unit][d->baSourceID[id]] ==
1383 1382 B_TRUE);
1384 1383 p[unit][d->baSourceID[id]] = B_FALSE;
1385 1384 }
1386 1385 }
1387 1386
1388 1387 break;
1389 1388 }
1390 1389 case USB_AUDIO_INPUT_TERMINAL:
1391 1390
1392 1391 break;
1393 1392 default:
1394 1393 /*
1395 1394 * Ignore the rest because they are not support yet
1396 1395 */
1397 1396 break;
1398 1397 }
1399 1398 }
1400 1399
1401 1400 #ifdef DEBUG
1402 1401 /* display topology in log buffer */
1403 1402 {
1404 1403 uint_t i, j, l;
1405 1404 char *buf;
1406 1405
1407 1406 l = uacp->usb_ac_max_unit * 5;
1408 1407
1409 1408 buf = kmem_alloc(l, KM_SLEEP);
1410 1409
1411 1410 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1412 1411 "unit types:");
1413 1412
1414 1413 /* two strings so they won't be replaced accidentily by tab */
1415 1414 (void) sprintf(&buf[0], " "" ");
1416 1415 for (i = 1; i < uacp->usb_ac_max_unit; i++) {
1417 1416 (void) sprintf(&buf[2 + (i*3)], "%02d ", i);
1418 1417 }
1419 1418 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
1420 1419
1421 1420 (void) sprintf(&buf[0], " +-------");
1422 1421 for (i = 1; i < uacp->usb_ac_max_unit; i++) {
1423 1422 (void) sprintf(&buf[5+((i-1)*3)], "---");
1424 1423 }
1425 1424 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
1426 1425
1427 1426 (void) sprintf(&buf[0], " "" ");
1428 1427 for (i = 1; i < uacp->usb_ac_max_unit; i++) {
1429 1428 (void) sprintf(&buf[2 + (i*3)], "%02d ",
1430 1429 uacp->usb_ac_unit_type[i]);
1431 1430 }
1432 1431 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
1433 1432 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, " ");
1434 1433
1435 1434 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1436 1435 "adjacency matrix:");
1437 1436 (void) sprintf(&buf[0], " "" ");
1438 1437 for (i = 1; i < uacp->usb_ac_max_unit; i++) {
1439 1438 (void) sprintf(&buf[2 + (i*3)], "%02d ", i);
1440 1439 }
1441 1440 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
1442 1441
1443 1442 (void) sprintf(&buf[0], " +-------");
1444 1443 for (i = 1; i < uacp->usb_ac_max_unit; i++) {
1445 1444 (void) sprintf(&buf[5+((i-1)*3)], "---");
1446 1445 }
1447 1446 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
1448 1447
1449 1448 for (i = 1; i < uacp->usb_ac_max_unit; i++) {
1450 1449 (void) sprintf(&buf[0], "%02d| "" ", i);
1451 1450 for (j = 1; j < uacp->usb_ac_max_unit; j++) {
1452 1451 (void) sprintf(&buf[1+(j * 3)], "%2d ", p[i][j]);
1453 1452 }
1454 1453 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
1455 1454 }
1456 1455 kmem_free(buf, l);
1457 1456 }
1458 1457 #endif
1459 1458 }
1460 1459
1461 1460
1462 1461 /*
1463 1462 * usb_ac_add_unit_descriptor:
1464 1463 * take the parsed descriptor in the buffer and store it in the ID unit
1465 1464 * array. we grow the unit array if the ID exceeds the current max
1466 1465 */
1467 1466 static void
1468 1467 usb_ac_add_unit_descriptor(usb_ac_state_t *uacp, uchar_t *buffer,
1469 1468 size_t buflen)
1470 1469 {
1471 1470 void *descr;
1472 1471 int len;
1473 1472 char *format;
1474 1473 size_t size;
1475 1474
1476 1475
1477 1476 /* doubling the length should allow for padding */
1478 1477 len = 2 * buffer[0];
1479 1478 descr = kmem_zalloc(len, KM_SLEEP);
1480 1479
1481 1480 switch (buffer[2]) {
1482 1481 case USB_AUDIO_INPUT_TERMINAL:
1483 1482 format = CS_AC_INPUT_TERM_FORMAT;
1484 1483 size = CS_AC_INPUT_TERM_SIZE;
1485 1484
1486 1485 break;
1487 1486 case USB_AUDIO_OUTPUT_TERMINAL:
1488 1487 format = CS_AC_OUTPUT_TERM_FORMAT;
1489 1488 size = CS_AC_OUTPUT_TERM_SIZE;
1490 1489
1491 1490 break;
1492 1491 case USB_AUDIO_MIXER_UNIT:
1493 1492 format = CS_AC_MIXER_UNIT_DESCR1_FORMAT "255c";
1494 1493 size = CS_AC_MIXER_UNIT_DESCR1_SIZE + buffer[4] - 1;
1495 1494
1496 1495 break;
1497 1496 case USB_AUDIO_SELECTOR_UNIT:
1498 1497 format = CS_AC_SELECTOR_UNIT_DESCR1_FORMAT "255c";
1499 1498 size = CS_AC_SELECTOR_UNIT_DESCR1_SIZE + buffer[4] - 1;
1500 1499
1501 1500 break;
1502 1501 case USB_AUDIO_FEATURE_UNIT:
1503 1502 format = CS_AC_FEATURE_UNIT_FORMAT "255c";
1504 1503 size = CS_AC_FEATURE_UNIT_SIZE;
1505 1504
1506 1505 break;
1507 1506 case USB_AUDIO_PROCESSING_UNIT:
1508 1507 format = CS_AC_PROCESSING_UNIT_DESCR1_FORMAT "255c";
1509 1508 size = CS_AC_PROCESSING_UNIT_DESCR1_SIZE + buffer[6] - 1;
1510 1509
1511 1510 break;
1512 1511 case USB_AUDIO_EXTENSION_UNIT:
1513 1512 format = CS_AC_EXTENSION_UNIT_DESCR1_FORMAT "255c";
1514 1513 size = CS_AC_EXTENSION_UNIT_DESCR1_SIZE + buffer[6] - 1;
1515 1514
1516 1515 break;
1517 1516 default:
1518 1517 USB_DPRINTF_L2(PRINT_MASK_ATTA,
1519 1518 uacp->usb_ac_log_handle,
1520 1519 "unsupported descriptor %d", buffer[2]);
1521 1520
1522 1521 /* ignore this descriptor */
1523 1522 kmem_free(descr, len);
1524 1523
1525 1524 return;
1526 1525 }
1527 1526
1528 1527 if (usb_parse_data(format, buffer, buflen, descr, len) < size) {
1529 1528 /* ignore this descriptor */
1530 1529 kmem_free(descr, len);
1531 1530
1532 1531 return;
1533 1532 }
1534 1533
1535 1534 switch (buffer[2]) {
1536 1535 case USB_AUDIO_INPUT_TERMINAL:
1537 1536 {
1538 1537 usb_audio_input_term_descr_t *d =
1539 1538 (usb_audio_input_term_descr_t *)descr;
1540 1539
1541 1540 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1542 1541 uacp->usb_ac_log_handle,
1543 1542 "usb_ac_units[%d] ---input term: type=0x%x sub=0x%x"
1544 1543 "termid=0x%x\n\t"
1545 1544 "termtype=0x%x assoc=0x%x #ch=%d "
1546 1545 "chconf=0x%x ich=0x%x iterm=0x%x",
1547 1546 d->bTerminalID,
1548 1547 d->bDescriptorType, d->bDescriptorSubType,
1549 1548 d->bTerminalID, d->wTerminalType,
1550 1549 d->bAssocTerminal, d->bNrChannels,
1551 1550 d->wChannelConfig, d->iChannelNames,
1552 1551 d->iTerminal);
1553 1552
1554 1553 usb_ac_alloc_unit(uacp, d->bTerminalID);
1555 1554 uacp->usb_ac_units[d->bTerminalID].acu_descriptor = descr;
1556 1555 uacp->usb_ac_units[d->bTerminalID].acu_type = buffer[2];
1557 1556 uacp->usb_ac_units[d->bTerminalID].acu_descr_length = len;
1558 1557
1559 1558 break;
1560 1559 }
1561 1560 case USB_AUDIO_OUTPUT_TERMINAL:
1562 1561 {
1563 1562 usb_audio_output_term_descr_t *d =
1564 1563 (usb_audio_output_term_descr_t *)descr;
1565 1564
1566 1565 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1567 1566 uacp->usb_ac_log_handle,
1568 1567 "usb_ac_units[%d] ---output term: type=0x%x sub=0x%x"
1569 1568 " termid=0x%x\n\t"
1570 1569 "termtype=0x%x assoc=0x%x sourceID=0x%x iterm=0x%x",
1571 1570 d->bTerminalID,
1572 1571 d->bDescriptorType, d->bDescriptorSubType,
1573 1572 d->bTerminalID, d->wTerminalType,
1574 1573 d->bAssocTerminal, d->bSourceID,
1575 1574 d->iTerminal);
1576 1575
1577 1576 usb_ac_alloc_unit(uacp, d->bTerminalID);
1578 1577 uacp->usb_ac_units[d->bTerminalID].acu_descriptor = descr;
1579 1578 uacp->usb_ac_units[d->bTerminalID].acu_type = buffer[2];
1580 1579 uacp->usb_ac_units[d->bTerminalID].acu_descr_length = len;
1581 1580
1582 1581 break;
1583 1582 }
1584 1583 case USB_AUDIO_MIXER_UNIT:
1585 1584 {
1586 1585 usb_audio_mixer_unit_descr1_t *d =
1587 1586 (usb_audio_mixer_unit_descr1_t *)descr;
1588 1587
1589 1588 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1590 1589 uacp->usb_ac_log_handle,
1591 1590 "usb_ac_units[%d] ---mixer unit: type=0x%x sub=0x%x"
1592 1591 " unitid=0x%x\n\t"
1593 1592 "#pins=0x%x sourceid[0]=0x%x",
1594 1593 d->bUnitID,
1595 1594 d->bDescriptorType, d->bDescriptorSubType,
1596 1595 d->bUnitID, d->bNrInPins, d->baSourceID[0]);
1597 1596 usb_ac_alloc_unit(uacp, d->bUnitID);
1598 1597 uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
1599 1598 uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
1600 1599 uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
1601 1600
1602 1601 break;
1603 1602 }
1604 1603 case USB_AUDIO_SELECTOR_UNIT:
1605 1604 {
1606 1605 usb_audio_selector_unit_descr1_t *d =
1607 1606 (usb_audio_selector_unit_descr1_t *)descr;
1608 1607
1609 1608 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1610 1609 uacp->usb_ac_log_handle,
1611 1610 "usb_ac_units[%d] ---selector unit: type=0x%x sub=0x%x"
1612 1611 " unitid=0x%x\n\t"
1613 1612 "#pins=0x%x sourceid[0]=0x%x",
1614 1613 d->bUnitID,
1615 1614 d->bDescriptorType, d->bDescriptorSubType,
1616 1615 d->bUnitID, d->bNrInPins, d->baSourceID[0]);
1617 1616 usb_ac_alloc_unit(uacp, d->bUnitID);
1618 1617 uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
1619 1618 uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
1620 1619 uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
1621 1620
1622 1621 break;
1623 1622 }
1624 1623 case USB_AUDIO_FEATURE_UNIT:
1625 1624 {
1626 1625 usb_audio_feature_unit_descr1_t *d =
1627 1626 (usb_audio_feature_unit_descr1_t *)descr;
1628 1627
1629 1628 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1630 1629 uacp->usb_ac_log_handle,
1631 1630 "usb_ac_units[%d] ---feature unit: type=0x%x sub=0x%x"
1632 1631 " unitid=0x%x\n\t"
1633 1632 "sourceid=0x%x size=0x%x",
1634 1633 d->bUnitID,
1635 1634 d->bDescriptorType, d->bDescriptorSubType,
1636 1635 d->bUnitID, d->bSourceID, d->bControlSize);
1637 1636
1638 1637 usb_ac_alloc_unit(uacp, d->bUnitID);
1639 1638 uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
1640 1639 uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
1641 1640 uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
1642 1641
1643 1642 break;
1644 1643 }
1645 1644 case USB_AUDIO_PROCESSING_UNIT:
1646 1645 {
1647 1646 usb_audio_processing_unit_descr1_t *d =
1648 1647 (usb_audio_processing_unit_descr1_t *)descr;
1649 1648
1650 1649 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1651 1650 uacp->usb_ac_log_handle,
1652 1651 "usb_ac_units[%d] ---processing unit: type=0x%x sub=0x%x"
1653 1652 " unitid=0x%x\n\t"
1654 1653 "#pins=0x%x sourceid[0]=0x%x",
1655 1654 d->bUnitID,
1656 1655 d->bDescriptorType, d->bDescriptorSubType,
1657 1656 d->bUnitID, d->bNrInPins, d->baSourceID[0]);
1658 1657 usb_ac_alloc_unit(uacp, d->bUnitID);
1659 1658 uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
1660 1659 uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
1661 1660 uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
1662 1661
1663 1662 break;
1664 1663 }
1665 1664 case USB_AUDIO_EXTENSION_UNIT:
1666 1665 {
1667 1666 usb_audio_extension_unit_descr1_t *d =
1668 1667 (usb_audio_extension_unit_descr1_t *)descr;
1669 1668
1670 1669 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1671 1670 uacp->usb_ac_log_handle,
1672 1671 "usb_ac_units[%d] ---mixer unit: type=0x%x sub=0x%x"
1673 1672 " unitid=0x%x\n\t"
1674 1673 "#pins=0x%x sourceid[0]=0x%x",
1675 1674 d->bUnitID,
1676 1675 d->bDescriptorType, d->bDescriptorSubType,
1677 1676 d->bUnitID, d->bNrInPins, d->baSourceID[0]);
1678 1677 usb_ac_alloc_unit(uacp, d->bUnitID);
1679 1678 uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
1680 1679 uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
1681 1680 uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
1682 1681
1683 1682 break;
1684 1683 }
1685 1684 default:
1686 1685 break;
1687 1686 }
1688 1687 }
1689 1688
1690 1689
1691 1690 /*
1692 1691 * usb_ac_alloc_unit:
1693 1692 * check if the unit ID is less than max_unit in which case no
1694 1693 * extra entries are needed. If more entries are needed, copy over
1695 1694 * the existing array into a new larger array
1696 1695 */
1697 1696 static void
1698 1697 usb_ac_alloc_unit(usb_ac_state_t *uacp, uint_t unit)
1699 1698 {
1700 1699 usb_ac_unit_list_t *old = NULL;
1701 1700 uint_t max_unit;
1702 1701
1703 1702
1704 1703 if (uacp->usb_ac_units) {
1705 1704 if (unit < uacp->usb_ac_max_unit) {
1706 1705 /* existing array is big enough */
1707 1706
1708 1707 return;
1709 1708 }
1710 1709 old = uacp->usb_ac_units;
1711 1710 max_unit = uacp->usb_ac_max_unit;
1712 1711 }
1713 1712
1714 1713 /* allocate two extra ones */
1715 1714 unit += 2;
1716 1715 uacp->usb_ac_max_unit = unit;
1717 1716 uacp->usb_ac_units = kmem_zalloc(unit *
1718 1717 sizeof (usb_ac_unit_list_t), KM_SLEEP);
1719 1718
1720 1719 if (old) {
1721 1720 size_t len = max_unit * sizeof (usb_ac_unit_list_t);
1722 1721 bcopy(old, uacp->usb_ac_units, len);
1723 1722
1724 1723 kmem_free(old, len);
1725 1724 }
1726 1725 }
1727 1726
1728 1727
1729 1728 /*
1730 1729 * usb_ac_free_all_units:
1731 1730 * free the entire unit list
1732 1731 */
1733 1732 static void
1734 1733 usb_ac_free_all_units(usb_ac_state_t *uacp)
1735 1734 {
1736 1735 uint_t unit;
1737 1736 usb_ac_unit_list_t *unitp;
1738 1737
1739 1738 if (uacp->usb_ac_units == NULL) {
1740 1739
1741 1740 return;
1742 1741 }
1743 1742
1744 1743
1745 1744 for (unit = 0; unit < uacp->usb_ac_max_unit; unit++) {
1746 1745 unitp = &uacp->usb_ac_units[unit];
1747 1746 if (unitp) {
1748 1747 if (unitp->acu_descriptor) {
1749 1748 kmem_free(unitp->acu_descriptor,
1750 1749 unitp->acu_descr_length);
1751 1750 }
1752 1751 }
1753 1752 }
1754 1753
1755 1754 kmem_free(uacp->usb_ac_units, uacp->usb_ac_max_unit *
1756 1755 sizeof (usb_ac_unit_list_t));
1757 1756 }
1758 1757
1759 1758
1760 1759 /*
1761 1760 * usb_ac_lookup_port_type:
1762 1761 * map term type to port type
1763 1762 * default just return LINE_IN + LINE_OUT
1764 1763 */
1765 1764 static int
1766 1765 usb_ac_lookup_port_type(ushort_t termtype)
1767 1766 {
1768 1767 uint_t i;
1769 1768
1770 1769 /*
1771 1770 * Looking for a input/ouput terminal type to match the port
1772 1771 * type, it should not be common streaming type
1773 1772 */
1774 1773 ASSERT(termtype != USB_AUDIO_TERM_TYPE_STREAMING);
1775 1774
1776 1775 for (i = 0; ; i++) {
1777 1776 if (usb_ac_term_type_map[i].term_type == 0) {
1778 1777
1779 1778 break;
1780 1779 }
1781 1780
1782 1781 if (usb_ac_term_type_map[i].term_type == termtype) {
1783 1782
1784 1783 return (usb_ac_term_type_map[i].port_type);
1785 1784 }
1786 1785 }
1787 1786
1788 1787 return (USB_PORT_UNKNOWN);
1789 1788 }
1790 1789
1791 1790
1792 1791 /*
1793 1792 * usb_ac_update_port:
1794 1793 * called for each terminal
1795 1794 */
1796 1795 /*ARGSUSED*/
1797 1796 static int
1798 1797 usb_ac_update_port(usb_ac_state_t *uacp, uint_t id,
1799 1798 uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth)
1800 1799 {
1801 1800 if (dir & USB_AUDIO_PLAY) {
1802 1801 usb_audio_output_term_descr_t *d =
1803 1802 (usb_audio_output_term_descr_t *)
1804 1803 uacp->usb_ac_units[id].acu_descriptor;
1805 1804 uint_t port_type =
1806 1805 usb_ac_lookup_port_type(d->wTerminalType);
1807 1806
1808 1807 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1809 1808 "usb_ac_update_port: dir=%d wTerminalType=0x%x, name=%s",
1810 1809 dir, d->wTerminalType, usb_audio_dtypes[port_type]);
1811 1810
1812 1811 uacp->usb_ac_output_ports |= (1U << port_type);
1813 1812 } else {
1814 1813 usb_audio_input_term_descr_t *d =
1815 1814 (usb_audio_input_term_descr_t *)
1816 1815 uacp->usb_ac_units[id].acu_descriptor;
1817 1816 uint_t port_type =
1818 1817 usb_ac_lookup_port_type(d->wTerminalType);
1819 1818
1820 1819 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1821 1820 "usb_ac_update_port: dir=%d wTerminalType=0x%x, name=%s",
1822 1821 dir, d->wTerminalType, usb_audio_dtypes[port_type]);
1823 1822
1824 1823 uacp->usb_ac_input_ports |= (1U << port_type);
1825 1824
1826 1825 }
1827 1826
1828 1827 return (USB_SUCCESS);
1829 1828 }
1830 1829
1831 1830
1832 1831 /*
1833 1832 * usb_ac_map_termtype_to_port:
1834 1833 * starting from a streaming termtype find all
1835 1834 * input or output terminals and OR into uacp->usb_ac_input_ports
1836 1835 * or uacp->usb_ac_output_ports;
1837 1836 */
1838 1837 static void
1839 1838 usb_ac_map_termtype_to_port(usb_ac_state_t *uacp, uint_t dir)
1840 1839 {
1841 1840 uint_t count = 0;
1842 1841 uint_t depth = 0;
1843 1842 uint_t search_type = (dir & USB_AUDIO_PLAY) ?
1844 1843 USB_AUDIO_OUTPUT_TERMINAL : USB_AUDIO_INPUT_TERMINAL;
1845 1844
1846 1845
1847 1846 (void) usb_ac_traverse_all_units(uacp, dir, search_type, 0,
1848 1847 0, USB_AC_FIND_ALL, &count, 0, &depth, usb_ac_update_port);
1849 1848
1850 1849 ASSERT(depth == 0);
1851 1850 }
1852 1851
1853 1852
1854 1853 /*
1855 1854 * usb_ac_set_port:
1856 1855 * find a selector port (record side only) and set the
1857 1856 * input to the matching pin
1858 1857 */
1859 1858 static uint_t
1860 1859 usb_ac_set_port(usb_ac_state_t *uacp, uint_t dir, uint_t port)
1861 1860 {
1862 1861 uint_t count = 0;
1863 1862 uint_t id;
1864 1863 uint_t depth = 0;
1865 1864
1866 1865
1867 1866 /* we only support the selector for the record side */
1868 1867 if (dir & USB_AUDIO_RECORD) {
1869 1868 id = usb_ac_traverse_all_units(uacp, dir,
1870 1869 USB_AUDIO_SELECTOR_UNIT, 0,
1871 1870 0, USB_AC_FIND_ONE, &count, port, &depth,
1872 1871 usb_ac_set_selector);
1873 1872
1874 1873 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1875 1874 "usb_ac_set_port: id=%d count=%d port=%d",
1876 1875 id, count, port);
1877 1876
1878 1877 ASSERT(depth == 0);
1879 1878 }
1880 1879
1881 1880 return (USB_SUCCESS);
1882 1881 }
1883 1882
1884 1883
1885 1884 /*
1886 1885 * usb_ac_match_port:
1887 1886 * given the requested port type, find a correspondig term type
1888 1887 * Called from usb_ac_traverse_all_units()
1889 1888 */
1890 1889 /*ARGSUSED*/
1891 1890 static int
1892 1891 usb_ac_match_port(usb_ac_state_t *uacp, uint_t id,
1893 1892 uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth)
1894 1893 {
1895 1894 uint_t port_type;
1896 1895
1897 1896
1898 1897 if (dir & USB_AUDIO_PLAY) {
1899 1898 usb_audio_output_term_descr_t *d =
1900 1899 (usb_audio_output_term_descr_t *)
1901 1900 uacp->usb_ac_units[id].acu_descriptor;
1902 1901 port_type = usb_ac_lookup_port_type(d->wTerminalType);
1903 1902
1904 1903 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1905 1904 "usb_ac_match_port: "
1906 1905 "dir=%d type=0x%x port_type=%d port=%d",
1907 1906 dir, d->wTerminalType, port_type, arg1);
1908 1907 } else {
1909 1908 usb_audio_output_term_descr_t *d =
1910 1909 (usb_audio_output_term_descr_t *)
1911 1910 uacp->usb_ac_units[id].acu_descriptor;
1912 1911 port_type = usb_ac_lookup_port_type(d->wTerminalType);
1913 1912
1914 1913 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1915 1914 "usb_ac_match_port: "
1916 1915 "dir=%d type=0x%x port_type=%d port=%d",
1917 1916 dir, d->wTerminalType, port_type, arg1);
1918 1917 }
1919 1918
1920 1919 return (((1U << port_type) & arg1) ? USB_SUCCESS : USB_FAILURE);
1921 1920 }
1922 1921
1923 1922
1924 1923 /*
1925 1924 * usb_ac_set_selector:
1926 1925 * Called from usb_ac_traverse_all_units()
1927 1926 * Find the correct pin and set selector to this pin
1928 1927 */
1929 1928 /*ARGSUSED*/
1930 1929 static int
1931 1930 usb_ac_set_selector(usb_ac_state_t *uacp, uint_t id,
1932 1931 uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth)
1933 1932 {
1934 1933 uint_t count = 0;
1935 1934 uint_t unit = USB_AC_ID_NONE;
1936 1935 uint_t pin;
1937 1936 uint_t search_target =
1938 1937 (dir & USB_AUDIO_PLAY) ? USB_AUDIO_OUTPUT_TERMINAL :
1939 1938 USB_AUDIO_INPUT_TERMINAL;
1940 1939 usb_audio_selector_unit_descr1_t *d =
1941 1940 (usb_audio_selector_unit_descr1_t *)
1942 1941 uacp->usb_ac_units[id].acu_descriptor;
1943 1942 int n_sourceID = d->bNrInPins;
1944 1943 int rval = USB_FAILURE;
1945 1944
1946 1945
1947 1946 /*
1948 1947 * for each pin, find a term type that matches the
1949 1948 * requested port type
1950 1949 */
1951 1950 for (pin = 0; pin < n_sourceID; pin++) {
1952 1951 if (d->baSourceID[pin] == 0) {
1953 1952
1954 1953 break;
1955 1954 }
1956 1955 unit = d->baSourceID[pin];
1957 1956
1958 1957 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1959 1958 "usb_ac_set_selector: pin=%d unit=%d", pin, unit);
1960 1959
1961 1960 if (uacp->usb_ac_unit_type[unit] == search_target) {
1962 1961 if (usb_ac_match_port(uacp, unit, dir, channel,
1963 1962 control, arg1, depth) == USB_SUCCESS) {
1964 1963
1965 1964 break;
1966 1965 } else {
1967 1966 unit = USB_AC_ID_NONE;
1968 1967
1969 1968 continue;
1970 1969 }
1971 1970 }
1972 1971
1973 1972 /* find units connected to this unit */
1974 1973 unit = usb_ac_traverse_connections(uacp, unit,
1975 1974 dir, search_target, channel, control,
1976 1975 USB_AC_FIND_ONE, &count, arg1, depth,
1977 1976 usb_ac_match_port);
1978 1977
1979 1978 if (unit != USB_AC_ID_NONE) {
1980 1979
1981 1980 break;
1982 1981 }
1983 1982 }
1984 1983
1985 1984
1986 1985 if (unit != USB_AC_ID_NONE) {
1987 1986 mblk_t *data;
1988 1987 usb_cr_t cr;
1989 1988 usb_cb_flags_t cb_flags;
1990 1989
1991 1990 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1992 1991 "usb_ac_set_selector: found id=%d at pin %d", unit, pin);
1993 1992
1994 1993 mutex_exit(&uacp->usb_ac_mutex);
1995 1994
1996 1995 data = allocb(1, BPRI_HI);
1997 1996 if (!data) {
1998 1997 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1999 1998 "usb_ac_set_selector: allocate data failed");
2000 1999 mutex_enter(&uacp->usb_ac_mutex);
2001 2000
2002 2001 return (USB_FAILURE);
2003 2002 }
2004 2003
2005 2004 /* pins are 1-based */
2006 2005 *(data->b_rptr) = (char)++pin;
2007 2006
2008 2007 if (usb_pipe_sync_ctrl_xfer(
2009 2008 uacp->usb_ac_dip,
2010 2009 uacp->usb_ac_default_ph,
2011 2010 USB_DEV_REQ_HOST_TO_DEV |
2012 2011 USB_DEV_REQ_TYPE_CLASS |
2013 2012 USB_DEV_REQ_RCPT_IF, /* bmRequestType */
2014 2013 USB_AUDIO_SET_CUR, /* bRequest */
2015 2014 0, /* wValue */
2016 2015 /* feature unit and id */
2017 2016 (id << 8)| uacp->usb_ac_ifno, /* wIndex */
2018 2017 1, /* wLength */
2019 2018 &data,
2020 2019 USB_ATTRS_NONE,
2021 2020 &cr, &cb_flags,
2022 2021 USB_FLAGS_SLEEP) == USB_SUCCESS) {
2023 2022 USB_DPRINTF_L3(PRINT_MASK_ALL,
2024 2023 uacp->usb_ac_log_handle,
2025 2024 "set current selection: %d", *data->b_rptr);
2026 2025
2027 2026 rval = USB_SUCCESS;
2028 2027 } else {
2029 2028 USB_DPRINTF_L2(PRINT_MASK_ALL,
2030 2029 uacp->usb_ac_log_handle,
2031 2030 "set current pin selection failed");
2032 2031 }
2033 2032 freemsg(data);
2034 2033
2035 2034 mutex_enter(&uacp->usb_ac_mutex);
2036 2035 } else {
2037 2036 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2038 2037 "usb_ac_set_selector: nothing found");
2039 2038 }
2040 2039
2041 2040 return (rval);
2042 2041 }
2043 2042
2044 2043
2045 2044 /*
2046 2045 * usb_ac_set_control:
2047 2046 * apply func to all units of search_target type for both the
2048 2047 * requested channel and master channel
2049 2048 */
2050 2049 static uint_t
2051 2050 usb_ac_set_control(usb_ac_state_t *uacp, uint_t dir, uint_t search_target,
2052 2051 uint_t channel, uint_t control, uint_t all_or_one,
2053 2052 uint_t *count, uint_t arg1,
2054 2053 int (*func)(usb_ac_state_t *uacp, uint_t unit, uint_t dir,
2055 2054 uint_t channel, uint_t control, uint_t arg1, uint_t *depth))
2056 2055 {
2057 2056 uint_t id;
2058 2057 uint_t depth = 0;
2059 2058
2060 2059 id = usb_ac_traverse_all_units(uacp, dir, search_target, channel,
2061 2060 control, all_or_one, count, arg1, &depth, func);
2062 2061
2063 2062 if ((channel != 0) &&
2064 2063 (((id == USB_AC_ID_NONE) && (all_or_one == USB_AC_FIND_ONE)) ||
2065 2064 (all_or_one == USB_AC_FIND_ALL))) {
2066 2065 /* try master channel */
2067 2066 channel = 0;
2068 2067 id = usb_ac_traverse_all_units(uacp, dir, search_target,
2069 2068 channel, control, all_or_one, count, arg1,
2070 2069 &depth, func);
2071 2070 }
2072 2071
2073 2072 ASSERT(depth == 0);
2074 2073
2075 2074 return (id);
2076 2075 }
2077 2076
2078 2077
2079 2078 /*
2080 2079 * usb_ac_traverse_all_units:
2081 2080 * traverse all units starting with all IT or OT depending on direction.
2082 2081 * If no unit is found for the particular channel, try master channel
2083 2082 * If a matching unit is found, apply the function passed by
2084 2083 * the caller
2085 2084 */
2086 2085 static uint_t
2087 2086 usb_ac_traverse_all_units(usb_ac_state_t *uacp, uint_t dir,
2088 2087 uint_t search_target, uint_t channel, uint_t control,
2089 2088 uint_t all_or_one, uint_t *count, uint_t arg1, uint_t *depth,
2090 2089 int (*func)(usb_ac_state_t *uacp, uint_t unit, uint_t dir,
2091 2090 uint_t channel, uint_t control, uint_t arg1, uint_t *depth))
2092 2091 {
2093 2092 uint_t unit, start_type, id;
2094 2093
2095 2094 start_type = (dir & USB_AUDIO_PLAY) ? USB_AUDIO_INPUT_TERMINAL :
2096 2095 USB_AUDIO_OUTPUT_TERMINAL;
2097 2096
2098 2097 /* keep track of recursion */
2099 2098 if ((*depth)++ > USB_AC_MAX_DEPTH) {
2100 2099 USB_DPRINTF_L1(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2101 2100 "Unit topology too complex, giving up");
2102 2101
2103 2102 return (USB_AC_ID_NONE);
2104 2103 }
2105 2104
2106 2105 for (unit = 1; unit < uacp->usb_ac_max_unit; unit++) {
2107 2106 /* is this an IT or OT? */
2108 2107 if (uacp->usb_ac_unit_type[unit] != start_type) {
2109 2108
2110 2109 continue;
2111 2110 }
2112 2111
2113 2112 /* start at streaming term types */
2114 2113 if (dir & USB_AUDIO_PLAY) {
2115 2114 usb_audio_input_term_descr_t *d =
2116 2115 uacp->usb_ac_units[unit].acu_descriptor;
2117 2116 if (d->wTerminalType !=
2118 2117 USB_AUDIO_TERM_TYPE_STREAMING) {
2119 2118
2120 2119 continue;
2121 2120 }
2122 2121 } else {
2123 2122 usb_audio_output_term_descr_t *d =
2124 2123 uacp->usb_ac_units[unit].acu_descriptor;
2125 2124 if (d->wTerminalType !=
2126 2125 USB_AUDIO_TERM_TYPE_STREAMING) {
2127 2126
2128 2127 continue;
2129 2128 }
2130 2129 }
2131 2130
2132 2131 /* find units connected to this unit */
2133 2132 id = usb_ac_traverse_connections(uacp, unit, dir,
2134 2133 search_target, channel, control, all_or_one, count,
2135 2134 arg1, depth, func);
2136 2135
2137 2136 if ((all_or_one == USB_AC_FIND_ONE) &&
2138 2137 (id != USB_AC_ID_NONE)) {
2139 2138 unit = id;
2140 2139
2141 2140 break;
2142 2141 }
2143 2142 }
2144 2143
2145 2144 (*depth)--;
2146 2145
2147 2146 return ((unit < uacp->usb_ac_max_unit) ? unit : USB_AC_ID_NONE);
2148 2147 }
2149 2148
2150 2149
2151 2150 /*
2152 2151 * usb_ac_set_monitor_gain_control:
2153 2152 * search for a feature unit between output terminal (OT) and
2154 2153 * input terminal. We are looking for a path between
2155 2154 * for example a microphone and a speaker through a feature unit
2156 2155 * and mixer
2157 2156 */
2158 2157 static uint_t
2159 2158 usb_ac_set_monitor_gain_control(usb_ac_state_t *uacp, uint_t dir,
2160 2159 uint_t search_target, uint_t channel, uint_t control,
2161 2160 uint_t all_or_one, uint_t *count, uint_t arg1,
2162 2161 int (*func)(usb_ac_state_t *uacp, uint_t unit, uint_t dir,
2163 2162 uint_t channel, uint_t control, uint_t arg1, uint_t *depth))
2164 2163 {
2165 2164 uint_t unit, id;
2166 2165 uint_t depth = 0;
2167 2166
2168 2167
2169 2168 for (unit = 1; unit < uacp->usb_ac_max_unit; unit++) {
2170 2169 usb_audio_output_term_descr_t *d =
2171 2170 uacp->usb_ac_units[unit].acu_descriptor;
2172 2171
2173 2172 /* is this an OT and not stream type? */
2174 2173 if ((uacp->usb_ac_unit_type[unit] ==
2175 2174 USB_AUDIO_OUTPUT_TERMINAL) &&
2176 2175 (d->wTerminalType != USB_AUDIO_TERM_TYPE_STREAMING)) {
2177 2176
2178 2177 /* find units connected to this unit */
2179 2178 id = usb_ac_traverse_connections(uacp, unit, dir,
2180 2179 search_target, channel, control, all_or_one, count,
2181 2180 arg1, &depth, func);
2182 2181
2183 2182 if ((all_or_one == USB_AC_FIND_ONE) &&
2184 2183 (id != USB_AC_ID_NONE)) {
2185 2184
2186 2185 break;
2187 2186 }
2188 2187 }
2189 2188 }
2190 2189
2191 2190 ASSERT(depth == 0);
2192 2191
2193 2192 return (id);
2194 2193 }
2195 2194
2196 2195
2197 2196 /*
2198 2197 * usb_ac_push/pop_unit
2199 2198 * add/remove unit ID to the traverse path
2200 2199 */
2201 2200 static void
2202 2201 usb_ac_push_unit_id(usb_ac_state_t *uacp, uint_t unit)
2203 2202 {
2204 2203 uacp->usb_ac_traverse_path[uacp->usb_ac_traverse_path_index++] =
2205 2204 (uchar_t)unit;
2206 2205 ASSERT(uacp->usb_ac_traverse_path_index < uacp->usb_ac_max_unit);
2207 2206 }
2208 2207
2209 2208
2210 2209 /* ARGSUSED */
2211 2210 static void
2212 2211 usb_ac_pop_unit_id(usb_ac_state_t *uacp, uint_t unit)
2213 2212 {
2214 2213 uacp->usb_ac_traverse_path[uacp->usb_ac_traverse_path_index--] = 0;
2215 2214 }
2216 2215
2217 2216
2218 2217 /*
2219 2218 * usb_ac_show_traverse_path:
2220 2219 * display entire path, just for debugging
2221 2220 */
2222 2221 static void
2223 2222 usb_ac_show_traverse_path(usb_ac_state_t *uacp)
2224 2223 {
2225 2224 int i;
2226 2225
2227 2226 for (i = 0; i < uacp->usb_ac_traverse_path_index; i++) {
2228 2227 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2229 2228 "traverse path %d: unit=%d type=%d",
2230 2229 i, uacp->usb_ac_traverse_path[i],
2231 2230 uacp->usb_ac_unit_type[uacp->usb_ac_traverse_path[i]]);
2232 2231 }
2233 2232 }
2234 2233
2235 2234
2236 2235 /*
2237 2236 * usb_ac_check_path:
2238 2237 * check for a specified type in the traverse path
2239 2238 */
2240 2239 static int
2241 2240 usb_ac_check_path(usb_ac_state_t *uacp, uint_t type)
2242 2241 {
2243 2242 int i;
2244 2243
2245 2244 for (i = 0; i < uacp->usb_ac_traverse_path_index; i++) {
2246 2245 uint_t unit = uacp->usb_ac_traverse_path[i];
2247 2246
2248 2247 if (uacp->usb_ac_unit_type[unit] == type) {
2249 2248
2250 2249 return (USB_SUCCESS);
2251 2250 }
2252 2251 }
2253 2252
2254 2253 return (USB_FAILURE);
2255 2254 }
2256 2255
2257 2256
2258 2257 /*
2259 2258 * usb_ac_traverse_connections:
2260 2259 * traverse all units and for each unit with the right type, call
2261 2260 * func. If the func returns a success and search == USB_AC_FIND_ONE,
2262 2261 * we are done. If all is set then we continue until we terminate
2263 2262 * and input or output terminal.
2264 2263 * For audio play, we traverse columns starting from an input terminal
2265 2264 * to an output terminal while for record we traverse rows from output
2266 2265 * terminal to input terminal.
2267 2266 */
2268 2267 static uint_t
2269 2268 usb_ac_traverse_connections(usb_ac_state_t *uacp, uint_t start_unit, uint_t dir,
2270 2269 uint_t search_target, uint_t channel, uint_t control,
2271 2270 uint_t all_or_one, uint_t *count, uint_t arg1, uint_t *depth,
2272 2271 int (*func)(usb_ac_state_t *uacp, uint_t unit, uint_t dir,
2273 2272 uint_t channel, uint_t control, uint_t arg1, uint_t *depth))
2274 2273 {
2275 2274 uint_t unit, id;
2276 2275 uint_t done = (dir & USB_AUDIO_PLAY) ? USB_AUDIO_OUTPUT_TERMINAL :
2277 2276 USB_AUDIO_INPUT_TERMINAL;
2278 2277
2279 2278
2280 2279 /* keep track of recursion depth */
2281 2280 if ((*depth)++ > USB_AC_MAX_DEPTH) {
2282 2281 USB_DPRINTF_L1(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2283 2282 "Unit topology too complex, giving up");
2284 2283
2285 2284 return (USB_AC_ID_NONE);
2286 2285 }
2287 2286
2288 2287 usb_ac_push_unit_id(uacp, start_unit);
2289 2288
2290 2289 for (unit = 1; unit < uacp->usb_ac_max_unit; unit++) {
2291 2290 uint_t entry = (dir & USB_AUDIO_PLAY) ?
2292 2291 uacp->usb_ac_connections[unit][start_unit] :
2293 2292 uacp->usb_ac_connections[start_unit][unit];
2294 2293
2295 2294 if (entry) {
2296 2295 USB_DPRINTF_L3(PRINT_MASK_ALL,
2297 2296 uacp->usb_ac_log_handle,
2298 2297 "start=%d unit=%d entry=%d type=%d "
2299 2298 "done=%d found=%d",
2300 2299 start_unit, unit, entry, search_target, done,
2301 2300 uacp->usb_ac_unit_type[unit]);
2302 2301
2303 2302 /* did we find a matching type? */
2304 2303 if (uacp->usb_ac_unit_type[unit] == search_target) {
2305 2304 USB_DPRINTF_L3(PRINT_MASK_ALL,
2306 2305 uacp->usb_ac_log_handle,
2307 2306 "match: dir=%d unit=%d type=%d",
2308 2307 dir, unit, search_target);
2309 2308
2310 2309 /* yes, no apply function to this unit */
2311 2310 if (func(uacp, unit, dir, channel,
2312 2311 control, arg1, depth) == USB_SUCCESS) {
2313 2312 (*count)++;
2314 2313
2315 2314 USB_DPRINTF_L3(PRINT_MASK_ALL,
2316 2315 uacp->usb_ac_log_handle,
2317 2316 "func returned success, "
2318 2317 "unit=%d all=%d", unit,
2319 2318 all_or_one);
2320 2319
2321 2320 /* are we done? */
2322 2321 if (all_or_one == USB_AC_FIND_ONE) {
2323 2322
2324 2323 break;
2325 2324 }
2326 2325 }
2327 2326 }
2328 2327
2329 2328 /* did we find the terminating unit */
2330 2329 if (uacp->usb_ac_unit_type[unit] == done) {
2331 2330
2332 2331 continue;
2333 2332 }
2334 2333 id = usb_ac_traverse_connections(uacp, unit, dir,
2335 2334 search_target, channel, control,
2336 2335 all_or_one, count, arg1, depth, func);
2337 2336 if ((id != USB_AC_ID_NONE) &&
2338 2337 (all_or_one == USB_AC_FIND_ONE)) {
2339 2338 unit = id;
2340 2339
2341 2340 break;
2342 2341 }
2343 2342 }
2344 2343 }
2345 2344
2346 2345 (*depth)--;
2347 2346 usb_ac_pop_unit_id(uacp, start_unit);
2348 2347
2349 2348 return ((unit < uacp->usb_ac_max_unit) ? unit : USB_AC_ID_NONE);
2350 2349 }
2351 2350
2352 2351
2353 2352 /*
2354 2353 * Event Management
2355 2354 *
2356 2355 * usb_ac_disconnect_event_cb:
2357 2356 * The device has been disconnected. we either wait for
2358 2357 * detach or a reconnect event.
2359 2358 */
2360 2359 static int
2361 2360 usb_ac_disconnect_event_cb(dev_info_t *dip)
2362 2361 {
2363 2362 usb_ac_state_t *uacp = (usb_ac_state_t *)ddi_get_soft_state(
2364 2363 usb_ac_statep, ddi_get_instance(dip));
2365 2364
2366 2365 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2367 2366 "usb_ac_disconnect_event_cb:start");
2368 2367
2369 2368 usb_ac_serialize_access(uacp);
2370 2369 mutex_enter(&uacp->usb_ac_mutex);
2371 2370
2372 2371 /* setting to disconnect state will prevent replumbing */
2373 2372 uacp->usb_ac_dev_state = USB_DEV_DISCONNECTED;
2374 2373
2375 2374 if (uacp->usb_ac_busy_count) {
2376 2375 USB_DPRINTF_L0(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2377 2376 "device was disconnected while busy. "
2378 2377 "Data may have been lost");
2379 2378 }
2380 2379 mutex_exit(&uacp->usb_ac_mutex);
2381 2380
2382 2381 usb_ac_release_access(uacp);
2383 2382 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2384 2383 "usb_ac_disconnect_event_cb:done");
2385 2384
2386 2385
2387 2386 return (USB_SUCCESS);
2388 2387 }
2389 2388
2390 2389
2391 2390 /*
2392 2391 * usb_ac_cpr_suspend:
2393 2392 */
2394 2393 static int
2395 2394 usb_ac_cpr_suspend(dev_info_t *dip)
2396 2395 {
2397 2396 usb_ac_state_t *uacp = (usb_ac_state_t *)ddi_get_soft_state(
2398 2397 usb_ac_statep, ddi_get_instance(dip));
2399 2398
2400 2399 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2401 2400 "usb_ac_cpr_suspend: Begin");
2402 2401
2403 2402 mutex_enter(&uacp->usb_ac_mutex);
2404 2403 uacp->usb_ac_dev_state = USB_DEV_SUSPENDED;
2405 2404 mutex_exit(&uacp->usb_ac_mutex);
2406 2405
2407 2406 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2408 2407 "usb_ac_cpr_suspend: End");
2409 2408
2410 2409 return (USB_SUCCESS);
2411 2410 }
2412 2411
2413 2412
2414 2413
2415 2414 /*
2416 2415 * usb_ac_reconnect_event_cb:
2417 2416 * The device was disconnected but this instance not detached, probably
2418 2417 * because the device was busy.
2419 2418 * if the same device, continue with restoring state
2420 2419 * We should either be in the unplumbed state or the plumbed open
2421 2420 * state.
2422 2421 */
2423 2422 static int
2424 2423 usb_ac_reconnect_event_cb(dev_info_t *dip)
2425 2424 {
2426 2425 usb_ac_state_t *uacp = (usb_ac_state_t *)ddi_get_soft_state(
2427 2426 usb_ac_statep, ddi_get_instance(dip));
2428 2427
2429 2428 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2430 2429 "usb_ac_reconnect_event_cb:begain");
2431 2430
2432 2431 mutex_enter(&uacp->usb_ac_mutex);
2433 2432 mutex_exit(&uacp->usb_ac_mutex);
2434 2433
2435 2434 usb_ac_serialize_access(uacp);
2436 2435
2437 2436 /* check the plumbing state */
2438 2437 mutex_enter(&uacp->usb_ac_mutex);
2439 2438 uacp->usb_ac_busy_count++;
2440 2439 if (uacp->usb_ac_plumbing_state ==
2441 2440 USB_AC_STATE_PLUMBED) {
2442 2441 mutex_exit(&uacp->usb_ac_mutex);
2443 2442 usb_ac_restore_device_state(dip, uacp);
2444 2443 mutex_enter(&uacp->usb_ac_mutex);
2445 2444 }
2446 2445 uacp->usb_ac_busy_count--;
2447 2446
2448 2447 if (uacp->usb_ac_busy_count) {
2449 2448 USB_DPRINTF_L0(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2450 2449 "busy device has been reconnected");
2451 2450 }
2452 2451
2453 2452 mutex_exit(&uacp->usb_ac_mutex);
2454 2453
2455 2454 usb_ac_release_access(uacp);
2456 2455 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2457 2456 "usb_ac_reconnect_event_cb:done");
2458 2457
2459 2458 return (USB_SUCCESS);
2460 2459 }
2461 2460
2462 2461
2463 2462 /*
2464 2463 * usb_ac_cpr_resume:
2465 2464 * Restore device state
2466 2465 */
2467 2466 static void
2468 2467 usb_ac_cpr_resume(dev_info_t *dip)
2469 2468 {
2470 2469 usb_ac_state_t *uacp = (usb_ac_state_t *)ddi_get_soft_state(
2471 2470 usb_ac_statep, ddi_get_instance(dip));
2472 2471
2473 2472 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2474 2473 "usb_ac_cpr_resume");
2475 2474
2476 2475 usb_ac_serialize_access(uacp);
2477 2476
2478 2477 usb_ac_restore_device_state(dip, uacp);
2479 2478
2480 2479 usb_ac_release_access(uacp);
2481 2480 }
2482 2481
2483 2482
2484 2483 /*
2485 2484 * usb_ac_restore_device_state:
2486 2485 * Set original configuration of the device
2487 2486 * enable wrq - this starts new transactions on the control pipe
2488 2487 */
2489 2488 static void
2490 2489 usb_ac_restore_device_state(dev_info_t *dip, usb_ac_state_t *uacp)
2491 2490 {
2492 2491 usb_ac_power_t *uacpm;
2493 2492 int rval;
2494 2493
2495 2494 USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
2496 2495 "usb_ac_restore_device_state:");
2497 2496
2498 2497 usb_ac_pm_busy_component(uacp);
2499 2498 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2500 2499
2501 2500 /* Check if we are talking to the same device */
2502 2501 if (usb_check_same_device(dip, uacp->usb_ac_log_handle,
2503 2502 USB_LOG_L0, PRINT_MASK_ALL,
2504 2503 USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) {
2505 2504 usb_ac_pm_idle_component(uacp);
2506 2505
2507 2506 /* change the device state from suspended to disconnected */
2508 2507 mutex_enter(&uacp->usb_ac_mutex);
2509 2508 uacp->usb_ac_dev_state = USB_DEV_DISCONNECTED;
2510 2509 mutex_exit(&uacp->usb_ac_mutex);
2511 2510
2512 2511 return;
2513 2512 }
2514 2513
2515 2514 mutex_enter(&uacp->usb_ac_mutex);
2516 2515 uacpm = uacp->usb_ac_pm;
2517 2516 if (uacpm) {
2518 2517 if (uacpm->acpm_wakeup_enabled) {
2519 2518 mutex_exit(&uacp->usb_ac_mutex);
2520 2519
2521 2520 if ((rval = usb_handle_remote_wakeup(uacp->usb_ac_dip,
2522 2521 USB_REMOTE_WAKEUP_ENABLE)) != USB_SUCCESS) {
2523 2522
2524 2523 USB_DPRINTF_L4(PRINT_MASK_ATTA,
2525 2524 uacp->usb_ac_log_handle,
2526 2525 "usb_ac_restore_device_state: "
2527 2526 "remote wakeup "
2528 2527 "enable failed, rval=%d", rval);
2529 2528 }
2530 2529
2531 2530 mutex_enter(&uacp->usb_ac_mutex);
2532 2531 }
2533 2532 }
2534 2533
2535 2534 /* prevent unplumbing */
2536 2535 uacp->usb_ac_busy_count++;
2537 2536 uacp->usb_ac_dev_state = USB_DEV_ONLINE;
2538 2537 if (uacp->usb_ac_plumbing_state == USB_AC_STATE_PLUMBED) {
2539 2538 (void) usb_ac_restore_audio_state(uacp, 0);
2540 2539 }
2541 2540 uacp->usb_ac_busy_count--;
2542 2541 mutex_exit(&uacp->usb_ac_mutex);
2543 2542 usb_ac_pm_idle_component(uacp);
2544 2543 }
2545 2544
2546 2545
2547 2546 /*
2548 2547 * usb_ac_am_restore_state
2549 2548 */
2550 2549 static void
2551 2550 usb_ac_am_restore_state(void *arg)
2552 2551 {
2553 2552 usb_ac_state_t *uacp = (usb_ac_state_t *)arg;
2554 2553
2555 2554 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2556 2555 "usb_ac_am_restore_state: Begin");
2557 2556
2558 2557 usb_ac_serialize_access(uacp);
2559 2558
2560 2559 mutex_enter(&uacp->usb_ac_mutex);
2561 2560
2562 2561 if (uacp->usb_ac_plumbing_state ==
2563 2562 USB_AC_STATE_PLUMBED_RESTORING) {
2564 2563 mutex_exit(&uacp->usb_ac_mutex);
2565 2564
2566 2565 /*
2567 2566 * allow hid and usb_as to restore themselves
2568 2567 * (some handshake would have been preferable though)
2569 2568 */
2570 2569 delay(USB_AC_RESTORE_DELAY);
2571 2570
2572 2571 usb_restore_engine(uacp);
2573 2572
2574 2573 mutex_enter(&uacp->usb_ac_mutex);
2575 2574 uacp->usb_ac_plumbing_state = USB_AC_STATE_PLUMBED;
2576 2575 }
2577 2576
2578 2577 /* allow unplumbing */
2579 2578 uacp->usb_ac_busy_count--;
2580 2579 mutex_exit(&uacp->usb_ac_mutex);
2581 2580
2582 2581 usb_ac_release_access(uacp);
2583 2582
2584 2583 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2585 2584 "usb_ac_am_restore_state: End");
2586 2585 }
2587 2586
2588 2587
2589 2588 /*
2590 2589 * usb_ac_restore_audio_state:
2591 2590 */
2592 2591 static int
2593 2592 usb_ac_restore_audio_state(usb_ac_state_t *uacp, int flag)
2594 2593 {
2595 2594 ASSERT(mutex_owned(&uacp->usb_ac_mutex));
2596 2595
2597 2596
2598 2597 switch (uacp->usb_ac_plumbing_state) {
2599 2598 case USB_AC_STATE_PLUMBED:
2600 2599 uacp->usb_ac_plumbing_state =
2601 2600 USB_AC_STATE_PLUMBED_RESTORING;
2602 2601
2603 2602 break;
2604 2603 case USB_AC_STATE_UNPLUMBED:
2605 2604
2606 2605 return (USB_SUCCESS);
2607 2606 case USB_AC_STATE_PLUMBED_RESTORING:
2608 2607 default:
2609 2608
2610 2609 return (USB_FAILURE);
2611 2610 }
2612 2611
2613 2612 /*
2614 2613 * increment busy_count again, it will be decremented
2615 2614 * in usb_ac_am_restore_state
2616 2615 */
2617 2616 uacp->usb_ac_busy_count++;
2618 2617
2619 2618 if (flag & USB_FLAGS_SLEEP) {
2620 2619 mutex_exit(&uacp->usb_ac_mutex);
2621 2620 usb_ac_am_restore_state((void *)uacp);
2622 2621 mutex_enter(&uacp->usb_ac_mutex);
2623 2622 } else {
2624 2623 mutex_exit(&uacp->usb_ac_mutex);
2625 2624 if (usb_async_req(uacp->usb_ac_dip,
2626 2625 usb_ac_am_restore_state,
2627 2626 (void *)uacp, USB_FLAGS_SLEEP) != USB_SUCCESS) {
2628 2627
2629 2628 mutex_enter(&uacp->usb_ac_mutex);
2630 2629 uacp->usb_ac_busy_count--;
2631 2630
2632 2631 return (USB_FAILURE);
2633 2632 }
2634 2633 mutex_enter(&uacp->usb_ac_mutex);
2635 2634 }
2636 2635
2637 2636 return (USB_SUCCESS);
2638 2637 }
2639 2638
2640 2639
2641 2640 /*
2642 2641 * Mixer Callback Management
2643 2642 * NOTE: all mixer callbacks are serialized. we cannot be closed while
2644 2643 * we are in the middle of a callback. There needs to be a
2645 2644 * teardown first. We cannot be unplumbed as long as we are
2646 2645 * still open.
2647 2646 *
2648 2647 * usb_ac_setup:
2649 2648 * Send setup to usb_as if the first setup
2650 2649 * Check power is done in usb_ac_send_as_cmd()
2651 2650 */
2652 2651 static int
2653 2652 usb_ac_setup(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
2654 2653 {
2655 2654 int rval = USB_SUCCESS;
2656 2655
2657 2656
2658 2657 mutex_enter(&uacp->usb_ac_mutex);
2659 2658
2660 2659 if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
2661 2660 mutex_exit(&uacp->usb_ac_mutex);
2662 2661
2663 2662 return (USB_FAILURE);
2664 2663 }
2665 2664 mutex_exit(&uacp->usb_ac_mutex);
2666 2665
2667 2666 usb_ac_serialize_access(uacp);
2668 2667
2669 2668
2670 2669 rval = usb_ac_do_setup(uacp, engine);
2671 2670
2672 2671 usb_ac_release_access(uacp);
2673 2672
2674 2673 return (rval);
2675 2674 }
2676 2675
2677 2676
2678 2677 /*
2679 2678 * usb_ac_do_setup:
2680 2679 * Wrapper function for usb_ac_setup which can be called
2681 2680 * either from audio framework for usb_ac_set_format
2682 2681 */
2683 2682 static int
2684 2683 usb_ac_do_setup(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
2685 2684 {
2686 2685 usb_ac_streams_info_t *streams_infop = NULL;
2687 2686
2688 2687
2689 2688 mutex_enter(&uacp->usb_ac_mutex);
2690 2689
2691 2690
2692 2691 streams_infop = (usb_ac_streams_info_t *)engine->streams;
2693 2692
2694 2693 /*
2695 2694 * Handle multiple setup calls. Pass the setup call to usb_as only
2696 2695 * the first time so isoc pipe will be opened only once
2697 2696 */
2698 2697 if (streams_infop->acs_setup_teardown_count++) {
2699 2698 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2700 2699 "usb_ac_do_setup: more than one setup, cnt=%d",
2701 2700 streams_infop->acs_setup_teardown_count);
2702 2701
2703 2702 mutex_exit(&uacp->usb_ac_mutex);
2704 2703
2705 2704 return (USB_SUCCESS);
2706 2705 }
2707 2706
2708 2707 /* Send setup command to usb_as */
2709 2708 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_SETUP, 0) !=
2710 2709 USB_SUCCESS) {
2711 2710 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2712 2711 "usb_ac_do_setup: failure");
2713 2712
2714 2713 streams_infop->acs_setup_teardown_count--;
2715 2714
2716 2715 mutex_exit(&uacp->usb_ac_mutex);
2717 2716
2718 2717 return (USB_FAILURE);
2719 2718 }
2720 2719
2721 2720 mutex_exit(&uacp->usb_ac_mutex);
2722 2721
2723 2722 return (USB_SUCCESS);
2724 2723 }
2725 2724
2726 2725
2727 2726 /*
2728 2727 * usb_ac_teardown:
2729 2728 * Send teardown to usb_as if the last teardown
2730 2729 * Check power is done in usb_ac_send_as_cmd()
2731 2730 * NOTE: allow teardown when disconnected
2732 2731 */
2733 2732 static void
2734 2733 usb_ac_teardown(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
2735 2734 {
2736 2735
2737 2736 usb_ac_streams_info_t *streams_infop = NULL;
2738 2737
2739 2738 usb_ac_serialize_access(uacp);
2740 2739
2741 2740
2742 2741 streams_infop = engine->streams;
2743 2742
2744 2743
2745 2744 mutex_enter(&uacp->usb_ac_mutex);
2746 2745
2747 2746
2748 2747
2749 2748 /* There should be at least one matching setup call */
2750 2749 ASSERT(streams_infop->acs_setup_teardown_count);
2751 2750
2752 2751 /*
2753 2752 * Handle multiple setup/teardown calls. Pass the call to usb_as
2754 2753 * only this is the last teardown so that isoc pipe is closed
2755 2754 * only once
2756 2755 */
2757 2756 if (--(streams_infop->acs_setup_teardown_count)) {
2758 2757 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2759 2758 "usb_ac_teardown: more than one setup/teardown, "
2760 2759 "cnt=%d",
2761 2760 streams_infop->acs_setup_teardown_count);
2762 2761
2763 2762 goto done;
2764 2763 }
2765 2764
2766 2765 /* Send teardown command to usb_as */
2767 2766 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_TEARDOWN,
2768 2767 (void *)NULL) != USB_SUCCESS) {
2769 2768
2770 2769 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2771 2770 "usb_ac_teardown: failure");
2772 2771
2773 2772 streams_infop->acs_setup_teardown_count++;
2774 2773
2775 2774
2776 2775 goto done;
2777 2776 }
2778 2777 done:
2779 2778
2780 2779 mutex_exit(&uacp->usb_ac_mutex);
2781 2780
2782 2781 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2783 2782 "usb_ac_teardown: End");
2784 2783 usb_ac_release_access(uacp);
2785 2784 }
2786 2785
2787 2786
2788 2787 /*
2789 2788 * usb_ac_set_monitor_gain:
2790 2789 * called for each output terminal which supports
2791 2790 * from usb_ac_traverse_connections
2792 2791 */
2793 2792 static int
2794 2793 usb_ac_set_monitor_gain(usb_ac_state_t *uacp, uint_t unit,
2795 2794 uint_t dir, uint_t channel, uint_t control, uint_t gain, uint_t *depth)
2796 2795 {
2797 2796 usb_audio_output_term_descr_t *d =
2798 2797 uacp->usb_ac_units[unit].acu_descriptor;
2799 2798
2800 2799 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2801 2800 "usb_ac_set_monitor_gain: ");
2802 2801
2803 2802 /* log how we got here */
2804 2803 usb_ac_push_unit_id(uacp, unit);
2805 2804 usb_ac_show_traverse_path(uacp);
2806 2805 usb_ac_pop_unit_id(uacp, unit);
2807 2806
2808 2807 /* we only care about the ITs connected to real hw inputs */
2809 2808 switch (d->wTerminalType) {
2810 2809 case USB_AUDIO_TERM_TYPE_STREAMING:
2811 2810
2812 2811 return (USB_FAILURE);
2813 2812
2814 2813 case USB_AUDIO_TERM_TYPE_DT_MICROPHONE:
2815 2814 case USB_AUDIO_TERM_TYPE_PERS_MICROPHONE:
2816 2815 case USB_AUDIO_TERM_TYPE_OMNI_DIR_MICROPHONE:
2817 2816 case USB_AUDIO_TERM_TYPE_MICROPHONE_ARRAY:
2818 2817 case USB_AUDIO_TERM_TYPE_PROCESSING_MIC_ARRAY:
2819 2818 default:
2820 2819
2821 2820 break;
2822 2821 }
2823 2822
2824 2823 /*
2825 2824 * we can only do this if the microphone is mixed into the
2826 2825 * audio output so look for a mixer first
2827 2826 */
2828 2827 if (usb_ac_check_path(uacp, USB_AUDIO_MIXER_UNIT) ==
2829 2828 USB_SUCCESS) {
2830 2829 int i, id;
2831 2830
2832 2831 /* now look for a feature unit */
2833 2832 for (i = uacp->usb_ac_traverse_path_index - 1; i >= 0;
2834 2833 i--) {
2835 2834 id = uacp->usb_ac_traverse_path[i];
2836 2835
2837 2836 switch (uacp->usb_ac_unit_type[id]) {
2838 2837 case USB_AUDIO_MIXER_UNIT:
2839 2838
2840 2839 /* the FU should be before the mixer */
2841 2840 return (USB_FAILURE);
2842 2841
2843 2842 case USB_AUDIO_FEATURE_UNIT:
2844 2843 /*
2845 2844 * now set the volume
2846 2845 */
2847 2846 if (usb_ac_set_gain(uacp, id, dir, channel,
2848 2847 control, gain, depth) != USB_SUCCESS) {
2849 2848
2850 2849 /* try master channel */
2851 2850 if (usb_ac_set_gain(uacp, id, dir,
2852 2851 0, control, gain, depth) !=
2853 2852 USB_SUCCESS) {
2854 2853
2855 2854 return (USB_FAILURE);
2856 2855 }
2857 2856 }
2858 2857
2859 2858 return (USB_SUCCESS);
2860 2859
2861 2860 default:
2862 2861 continue;
2863 2862 }
2864 2863 }
2865 2864 }
2866 2865
2867 2866 return (USB_FAILURE);
2868 2867 }
2869 2868
2870 2869
2871 2870 /*
2872 2871 * usb_ac_set_gain is called for each feature unit which supports
2873 2872 * the requested controls from usb_ac_traverse_connections
2874 2873 * we still need to check whether this unit supports the requested
2875 2874 * control.
2876 2875 */
2877 2876 static int
2878 2877 usb_ac_set_gain(usb_ac_state_t *uacp, uint_t featureID,
2879 2878 uint_t dir, uint_t channel, uint_t control, uint_t gain, uint_t *depth)
2880 2879 {
2881 2880 short max, min, current;
2882 2881
2883 2882 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2884 2883 "usb_ac_set_gain: id=%d dir=%d ch=%d cntl=%d gain=%d",
2885 2884 featureID, dir, channel, control, gain);
2886 2885
2887 2886 if (usb_ac_feature_unit_check(uacp, featureID,
2888 2887 dir, channel, control, gain, depth) != USB_SUCCESS) {
2889 2888
2890 2889 return (USB_FAILURE);
2891 2890 }
2892 2891
2893 2892 if (usb_ac_get_maxmin_volume(uacp, channel,
2894 2893 USB_AUDIO_GET_MAX, dir, featureID, &max) != USB_SUCCESS) {
2895 2894 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2896 2895 "usb_ac_set_gain: getting max gain failed");
2897 2896
2898 2897 return (USB_FAILURE);
2899 2898 }
2900 2899
2901 2900 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2902 2901 "usb_ac_set_gain: channel %d, max=%d", channel, max);
2903 2902
2904 2903 if (usb_ac_get_maxmin_volume(uacp, channel,
2905 2904 USB_AUDIO_GET_MIN, dir, featureID, &min) != USB_SUCCESS) {
2906 2905 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2907 2906 "usb_ac_set_gain: getting min gain failed");
2908 2907
2909 2908 return (USB_FAILURE);
2910 2909 }
2911 2910
2912 2911 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2913 2912 "usb_ac_set_gain: channel=%d, min=%d", channel, min);
2914 2913
2915 2914 if (usb_ac_get_maxmin_volume(uacp, channel,
2916 2915 USB_AUDIO_GET_CUR, dir, featureID, ¤t) != USB_SUCCESS) {
2917 2916 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2918 2917 "usb_ac_set_gain: getting cur gain failed");
2919 2918
2920 2919 return (USB_FAILURE);
2921 2920 }
2922 2921
2923 2922 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2924 2923 "usb_ac_set_gain: channel=%d, cur=%d", channel, current);
2925 2924
2926 2925 /*
2927 2926 * Set the gain for a channel. The audio mixer calculates the
2928 2927 * impact, if any, on the channel's gain.
2929 2928 *
2930 2929 * 0 <= gain <= AUDIO_MAX_GAIN
2931 2930 *
2932 2931 * channel #, 0 == left, 1 == right
2933 2932 */
2934 2933
2935 2934 if (gain == 0) {
2936 2935 gain = USB_AUDIO_VOLUME_SILENCE;
2937 2936 } else {
2938 2937 gain = max - ((max - min) * (AF_MAX_GAIN - gain))/AF_MAX_GAIN;
2939 2938 }
2940 2939
2941 2940 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2942 2941 "usb_ac_set_gain: ch=%d dir=%d max=%d min=%d gain=%d",
2943 2942 channel, dir, max, min, gain);
2944 2943
2945 2944 if (usb_ac_set_volume(uacp, channel, gain, dir,
2946 2945 featureID) != USB_SUCCESS) {
2947 2946 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2948 2947 "usb_ac_set_gain: setting volume failed");
2949 2948
2950 2949 return (USB_FAILURE);
2951 2950 }
2952 2951
2953 2952 /* just curious, read it back, device may round up/down */
2954 2953 if (usb_ac_get_maxmin_volume(uacp, channel,
2955 2954 USB_AUDIO_GET_CUR, dir, featureID, ¤t) != USB_SUCCESS) {
2956 2955 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2957 2956 "usb_ac_set_gain: getting cur gain failed");
2958 2957 }
2959 2958
2960 2959 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2961 2960 "usb_ac_set_gain done: "
2962 2961 "id=%d channel=%d, cur=%d gain=%d", featureID, channel,
2963 2962 (ushort_t)current, (ushort_t)gain);
2964 2963
2965 2964 return (USB_SUCCESS);
2966 2965 }
2967 2966
2968 2967
2969 2968 /*
2970 2969 * usb_ac_set_format
2971 2970 * This mixer callback initiates a command to be sent to
2972 2971 * usb_as to select an alternate with the passed characteristics
2973 2972 * and also to set the sample frequency.
2974 2973 * Note that this may be called when a playing is going on in
2975 2974 * the streaming interface. To handle that, first stop
2976 2975 * playing/recording, close the pipe by sending a teardown
2977 2976 * command, send the set_format command down and then reopen
2978 2977 * the pipe. Note : (1) audio framework will restart play/record
2979 2978 * after a set_format command. (2) Check power is done in
2980 2979 * usb_ac_send_as_cmd().
2981 2980 */
2982 2981 int
2983 2982 usb_ac_set_format(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
2984 2983 {
2985 2984 usb_ac_streams_info_t *streams_infop = NULL;
2986 2985 usb_audio_formats_t format;
2987 2986 int old_setup_teardown_count = 0;
2988 2987
2989 2988 mutex_enter(&uacp->usb_ac_mutex);
2990 2989 streams_infop = (usb_ac_streams_info_t *)engine->streams;
2991 2990
2992 2991 if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
2993 2992 mutex_exit(&uacp->usb_ac_mutex);
2994 2993
2995 2994 return (USB_FAILURE);
2996 2995 }
2997 2996 mutex_exit(&uacp->usb_ac_mutex);
2998 2997
2999 2998 usb_ac_serialize_access(uacp);
3000 2999 mutex_enter(&uacp->usb_ac_mutex);
3001 3000
3002 3001 bzero(&format, sizeof (usb_audio_formats_t));
3003 3002
3004 3003 /* save format info */
3005 3004 format.fmt_n_srs = 1;
3006 3005 format.fmt_srs = (uint_t *)&(engine->fmt.sr);
3007 3006 format.fmt_chns = (uchar_t)engine->fmt.ch;
3008 3007 format.fmt_precision = (uchar_t)engine->fmt.prec;
3009 3008 format.fmt_encoding = (uchar_t)engine->fmt.enc;
3010 3009
3011 3010 old_setup_teardown_count = streams_infop->acs_setup_teardown_count;
3012 3011
3013 3012 /* isoc pipe not open and playing is not in progress */
3014 3013 if (old_setup_teardown_count) {
3015 3014 streams_infop->acs_setup_teardown_count = 1;
3016 3015
3017 3016 mutex_exit(&uacp->usb_ac_mutex);
3018 3017 usb_ac_release_access(uacp);
3019 3018
3020 3019 usb_ac_stop_play(uacp, engine);
3021 3020 usb_ac_teardown(uacp, engine);
3022 3021
3023 3022 usb_ac_serialize_access(uacp);
3024 3023 mutex_enter(&uacp->usb_ac_mutex);
3025 3024 }
3026 3025
3027 3026 /*
3028 3027 * Set format for the streaming interface with lower write queue
3029 3028 * This boils down to set_alternate interface command in
3030 3029 * usb_as and the reply mp contains the currently active
3031 3030 * alternate number that is stored in the as_req structure
3032 3031 */
3033 3032 if (usb_ac_send_as_cmd(uacp, engine,
3034 3033 USB_AUDIO_SET_FORMAT, &format) != USB_SUCCESS) {
3035 3034 USB_DPRINTF_L2(PRINT_MASK_ALL,
3036 3035 uacp->usb_ac_log_handle,
3037 3036 "usb_ac_set_format: failed");
3038 3037 goto fail;
3039 3038
3040 3039 }
3041 3040 int sample = engine->fmt.sr;
3042 3041
3043 3042 /* Set the sample rate */
3044 3043 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_SET_SAMPLE_FREQ,
3045 3044 &sample) != USB_SUCCESS) {
3046 3045 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3047 3046 "usb_ac_set_format: setting format failed");
3048 3047 goto fail;
3049 3048
3050 3049 }
3051 3050
3052 3051 mutex_exit(&uacp->usb_ac_mutex);
3053 3052
3054 3053 usb_ac_release_access(uacp);
3055 3054
3056 3055 /* This should block until successful */
3057 3056 if (old_setup_teardown_count) {
3058 3057 (void) usb_ac_setup(uacp, engine);
3059 3058 }
3060 3059
3061 3060 mutex_enter(&uacp->usb_ac_mutex);
3062 3061 streams_infop->acs_setup_teardown_count = old_setup_teardown_count;
3063 3062 mutex_exit(&uacp->usb_ac_mutex);
3064 3063
3065 3064 return (USB_SUCCESS);
3066 3065 fail:
3067 3066 streams_infop->acs_setup_teardown_count = old_setup_teardown_count;
3068 3067 mutex_exit(&uacp->usb_ac_mutex);
3069 3068 usb_ac_release_access(uacp);
3070 3069
3071 3070 return (USB_FAILURE);
3072 3071
3073 3072 }
3074 3073
3075 3074 /*
3076 3075 * usb_ac_start_play
3077 3076 * Send a start_play command down to usb_as
3078 3077 * Check power is done in usb_ac_send_as_cmd()
3079 3078 */
3080 3079 static int
3081 3080 usb_ac_start_play(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
3082 3081 {
3083 3082 int samples;
3084 3083 usb_audio_play_req_t play_req;
3085 3084
3086 3085
3087 3086 mutex_enter(&uacp->usb_ac_mutex);
3088 3087 if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
3089 3088 mutex_exit(&uacp->usb_ac_mutex);
3090 3089
3091 3090 return (USB_FAILURE);
3092 3091 }
3093 3092 mutex_exit(&uacp->usb_ac_mutex);
3094 3093
3095 3094 usb_ac_serialize_access(uacp);
3096 3095
3097 3096 mutex_enter(&uacp->usb_ac_mutex);
3098 3097
3099 3098
3100 3099
3101 3100 /* Check for continuous sample rate done in usb_as */
3102 3101 samples = engine->fmt.sr * engine->fmt.ch / engine->intrate;
3103 3102 if (samples & engine->fmt.ch) {
3104 3103 samples++;
3105 3104 }
3106 3105
3107 3106 play_req.up_samples = samples;
3108 3107 play_req.up_handle = uacp;
3109 3108
3110 3109 /* Send setup command to usb_as */
3111 3110 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_START_PLAY,
3112 3111 (void *)&play_req) != USB_SUCCESS) {
3113 3112
3114 3113 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3115 3114 "usb_ac_start_play: failure");
3116 3115
3117 3116 mutex_exit(&uacp->usb_ac_mutex);
3118 3117
3119 3118 usb_ac_release_access(uacp);
3120 3119
3121 3120 return (USB_FAILURE);
3122 3121 }
3123 3122
3124 3123 mutex_exit(&uacp->usb_ac_mutex);
3125 3124
3126 3125 usb_ac_release_access(uacp);
3127 3126
3128 3127 return (USB_SUCCESS);
3129 3128 }
3130 3129
3131 3130
3132 3131 /*
3133 3132 * usb_ac_stop_play:
3134 3133 * Stop the play engine
3135 3134 * called from mixer framework.
3136 3135 */
3137 3136 void
3138 3137 usb_ac_stop_play(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
3139 3138 {
3140 3139
3141 3140 if (engine == NULL) {
3142 3141 engine = &(uacp->engines[0]);
3143 3142 }
3144 3143 mutex_enter(&uacp->usb_ac_mutex);
3145 3144 if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
3146 3145 mutex_exit(&uacp->usb_ac_mutex);
3147 3146
3148 3147 return;
3149 3148 }
3150 3149 mutex_exit(&uacp->usb_ac_mutex);
3151 3150
3152 3151 usb_ac_serialize_access(uacp);
3153 3152 mutex_enter(&uacp->usb_ac_mutex);
3154 3153
3155 3154 /* Send setup command to usb_as */
3156 3155 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_PAUSE_PLAY,
3157 3156 (void *)NULL) != USB_SUCCESS) {
3158 3157
3159 3158 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3160 3159 "usb_ac_do_pause_play: failure");
3161 3160 }
3162 3161
3163 3162 mutex_exit(&uacp->usb_ac_mutex);
3164 3163 usb_ac_release_access(uacp);
3165 3164 }
3166 3165
3167 3166
3168 3167 /*
3169 3168 * usb_ac_start_record:
3170 3169 * Sends a start record command down to usb_as.
3171 3170 * Check power is done in usb_ac_send_as_cmd()
3172 3171 */
3173 3172 static int
3174 3173 usb_ac_start_record(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
3175 3174 {
3176 3175
3177 3176
3178 3177 mutex_enter(&uacp->usb_ac_mutex);
3179 3178 if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
3180 3179 mutex_exit(&uacp->usb_ac_mutex);
3181 3180
3182 3181 return (USB_FAILURE);
3183 3182 }
3184 3183 mutex_exit(&uacp->usb_ac_mutex);
3185 3184
3186 3185 usb_ac_serialize_access(uacp);
3187 3186 mutex_enter(&uacp->usb_ac_mutex);
3188 3187
3189 3188
3190 3189 /* Send setup command to usb_as */
3191 3190 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_START_RECORD,
3192 3191 (void *)uacp) != USB_SUCCESS) {
3193 3192
3194 3193 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3195 3194 "usb_ac_start_record: failure");
3196 3195
3197 3196 mutex_exit(&uacp->usb_ac_mutex);
3198 3197
3199 3198 usb_ac_release_access(uacp);
3200 3199
3201 3200 return (USB_FAILURE);
3202 3201 }
3203 3202
3204 3203 mutex_exit(&uacp->usb_ac_mutex);
3205 3204 usb_ac_release_access(uacp);
3206 3205
3207 3206 return (USB_SUCCESS);
3208 3207 }
3209 3208
3210 3209
3211 3210 /*
3212 3211 * usb_ac_stop_record:
3213 3212 * Wrapper function for usb_ac_do_stop_record and is
3214 3213 * called form mixer framework.
3215 3214 */
3216 3215 static void
3217 3216 usb_ac_stop_record(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
3218 3217 {
3219 3218
3220 3219 usb_ac_serialize_access(uacp);
3221 3220 mutex_enter(&uacp->usb_ac_mutex);
3222 3221
3223 3222 /* Send setup command to usb_as */
3224 3223 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_STOP_RECORD,
3225 3224 NULL) != USB_SUCCESS) {
3226 3225
3227 3226 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3228 3227 "usb_ac_do_stop_record: failure");
3229 3228 }
3230 3229
3231 3230 mutex_exit(&uacp->usb_ac_mutex);
3232 3231 usb_ac_release_access(uacp);
3233 3232 }
3234 3233
3235 3234
3236 3235 /*
3237 3236 * Helper Functions for Mixer callbacks
3238 3237 *
3239 3238 * usb_ac_get_maxmin_volume:
3240 3239 * Send USBA command down to get the maximum or minimum gain balance
3241 3240 * Calculate min or max gain balance and return that. Return
3242 3241 * USB_FAILURE for failure cases
3243 3242 */
3244 3243 /* ARGSUSED */
3245 3244 static int
3246 3245 usb_ac_get_maxmin_volume(usb_ac_state_t *uacp, uint_t channel, int cmd,
3247 3246 int dir, int feature_unitID, short *max_or_minp)
3248 3247 {
3249 3248 mblk_t *data = NULL;
3250 3249 usb_cr_t cr;
3251 3250 usb_cb_flags_t cb_flags;
3252 3251
3253 3252
3254 3253 mutex_exit(&uacp->usb_ac_mutex);
3255 3254
3256 3255 if (usb_pipe_sync_ctrl_xfer(
3257 3256 uacp->usb_ac_dip,
3258 3257 uacp->usb_ac_default_ph,
3259 3258 USB_DEV_REQ_DEV_TO_HOST |
3260 3259 USB_DEV_REQ_TYPE_CLASS |
3261 3260 USB_DEV_REQ_RCPT_IF, /* bmRequestType */
3262 3261 cmd, /* bRequest */
3263 3262 (USB_AUDIO_VOLUME_CONTROL << 8) | channel, /* wValue */
3264 3263 /* feature unit and id */
3265 3264 (feature_unitID << 8)| uacp->usb_ac_ifno, /* wIndex */
3266 3265 2, /* wLength */
3267 3266 &data,
3268 3267 USB_ATTRS_NONE,
3269 3268 &cr, &cb_flags,
3270 3269 USB_FLAGS_SLEEP) != USB_SUCCESS) {
3271 3270 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3272 3271 "usb_ac_get_maxmin_volume: failed, "
3273 3272 "cr=%d, cb=0x%x cmd=%d, data=0x%p",
3274 3273 cr, cb_flags, cmd, (void *)data);
3275 3274
3276 3275 freemsg(data);
3277 3276 mutex_enter(&uacp->usb_ac_mutex);
3278 3277
3279 3278 return (USB_FAILURE);
3280 3279 }
3281 3280
3282 3281 mutex_enter(&uacp->usb_ac_mutex);
3283 3282 ASSERT(MBLKL(data) == 2);
3284 3283
3285 3284 *max_or_minp = (*(data->b_rptr+1) << 8) | *data->b_rptr;
3286 3285
3287 3286 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3288 3287 "usb_ac_get_maxmin_volume: max_or_min=0x%x", *max_or_minp);
3289 3288
3290 3289 freemsg(data);
3291 3290
3292 3291 return (USB_SUCCESS);
3293 3292 }
3294 3293
3295 3294
3296 3295 /*
3297 3296 * usb_ac_set_volume:
3298 3297 * Send USBA command down to set the gain balance
3299 3298 */
3300 3299 /* ARGSUSED */
3301 3300 static int
3302 3301 usb_ac_set_volume(usb_ac_state_t *uacp, uint_t channel, short gain, int dir,
3303 3302 int feature_unitID)
3304 3303 {
3305 3304 mblk_t *data = NULL;
3306 3305 usb_cr_t cr;
3307 3306 usb_cb_flags_t cb_flags;
3308 3307 int rval = USB_FAILURE;
3309 3308
3310 3309
3311 3310 mutex_exit(&uacp->usb_ac_mutex);
3312 3311
3313 3312 /* Construct the mblk_t from gain for sending to USBA */
3314 3313 data = allocb(4, BPRI_HI);
3315 3314 if (!data) {
3316 3315 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3317 3316 "usb_ac_set_volume: allocate data failed");
3318 3317 mutex_enter(&uacp->usb_ac_mutex);
3319 3318
3320 3319 return (USB_FAILURE);
3321 3320 }
3322 3321
3323 3322
3324 3323
3325 3324 *(data->b_wptr++) = (char)gain;
3326 3325 *(data->b_wptr++) = (char)(gain >> 8);
3327 3326
3328 3327 if ((rval = usb_pipe_sync_ctrl_xfer(
3329 3328 uacp->usb_ac_dip,
3330 3329 uacp->usb_ac_default_ph,
3331 3330 USB_DEV_REQ_HOST_TO_DEV |
3332 3331 USB_DEV_REQ_TYPE_CLASS |
3333 3332 USB_DEV_REQ_RCPT_IF, /* bmRequestType */
3334 3333 USB_AUDIO_SET_CUR, /* bRequest */
3335 3334 (USB_AUDIO_VOLUME_CONTROL << 8) | channel, /* wValue */
3336 3335 /* feature unit and id */
3337 3336 (feature_unitID << 8) | uacp->usb_ac_ifno, /* wIndex */
3338 3337 2, /* wLength */
3339 3338 &data, 0,
3340 3339 &cr, &cb_flags, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
3341 3340 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3342 3341 "usb_ac_set_volume: failed, cr=%d cb=0x%x",
3343 3342 cr, cb_flags);
3344 3343 }
3345 3344
3346 3345 freemsg(data);
3347 3346 mutex_enter(&uacp->usb_ac_mutex);
3348 3347
3349 3348 return (rval);
3350 3349 }
3351 3350
3352 3351
3353 3352 /*
3354 3353 * usb_ac_set_mute is called for each unit that supports the
3355 3354 * requested control from usb_ac_traverse_connections
3356 3355 */
3357 3356 int
3358 3357 usb_ac_set_mute(usb_ac_state_t *uacp, uint_t featureID, uint_t dir,
3359 3358 uint_t channel, uint_t control, uint_t muteval, uint_t *depth)
3360 3359 {
3361 3360 mblk_t *data;
3362 3361 usb_cr_t cr;
3363 3362 usb_cb_flags_t cb_flags;
3364 3363 int rval = USB_FAILURE;
3365 3364
3366 3365
3367 3366 if (usb_ac_feature_unit_check(uacp, featureID,
3368 3367 dir, channel, control, 0, depth) != USB_SUCCESS) {
3369 3368
3370 3369 return (USB_FAILURE);
3371 3370 }
3372 3371 mutex_exit(&uacp->usb_ac_mutex);
3373 3372
3374 3373 /* Construct the mblk_t for sending to USBA */
3375 3374 data = allocb(1, BPRI_HI);
3376 3375
3377 3376 if (!data) {
3378 3377 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3379 3378 "usb_ac_set_mute: allocate data failed");
3380 3379 mutex_enter(&uacp->usb_ac_mutex);
3381 3380
3382 3381 return (USB_FAILURE);
3383 3382 }
3384 3383
3385 3384
3386 3385 *(data->b_wptr++) = (char)muteval;
3387 3386
3388 3387 if ((rval = usb_pipe_sync_ctrl_xfer(
3389 3388 uacp->usb_ac_dip,
3390 3389 uacp->usb_ac_default_ph,
3391 3390 USB_DEV_REQ_HOST_TO_DEV |
3392 3391 USB_DEV_REQ_TYPE_CLASS |
3393 3392 USB_DEV_REQ_RCPT_IF, /* bmRequestType */
3394 3393 USB_AUDIO_SET_CUR, /* bRequest */
3395 3394 (USB_AUDIO_MUTE_CONTROL << 8) | channel, /* wValue */
3396 3395 /* feature unit and id */
3397 3396 (featureID << 8) | uacp->usb_ac_ifno, /* wIndex */
3398 3397 1, /* wLength */
3399 3398 &data,
3400 3399 0, /* attributes */
3401 3400 &cr, &cb_flags, 0)) != USB_SUCCESS) {
3402 3401
3403 3402 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3404 3403 "usb_ac_set_mute: failed, cr=%d cb=0x%x", cr, cb_flags);
3405 3404 }
3406 3405 freemsg(data);
3407 3406
3408 3407 mutex_enter(&uacp->usb_ac_mutex);
3409 3408
3410 3409 return (rval);
3411 3410 }
3412 3411
3413 3412
3414 3413 /*
3415 3414 * usb_ac_send_as_cmd:
3416 3415 * Allocate message blk, send a command down to usb_as,
3417 3416 * wait for the reply and free the message
3418 3417 *
3419 3418 * although not really needed to raise power if sending to as
3420 3419 * it seems better to ensure that both interfaces are at full power
3421 3420 */
3422 3421 static int
3423 3422 usb_ac_send_as_cmd(usb_ac_state_t *uacp, usb_audio_eng_t *engine,
3424 3423 int cmd, void *arg)
3425 3424 {
3426 3425 usb_ac_streams_info_t *streams_infop;
3427 3426 usb_ac_plumbed_t *plumb_infop;
3428 3427 int rv;
3429 3428 int rval;
3430 3429 ldi_handle_t lh;
3431 3430
3432 3431 ASSERT(mutex_owned(&uacp->usb_ac_mutex));
3433 3432 streams_infop = engine->streams;
3434 3433 plumb_infop = streams_infop->acs_plumbed;
3435 3434
3436 3435
3437 3436 lh = plumb_infop->acp_lh;
3438 3437
3439 3438 rv = ldi_ioctl(lh, cmd, (intptr_t)arg, FKIOCTL, kcred, &rval);
3440 3439 if (rv != 0) {
3441 3440 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3442 3441 "usb_ac_send_as_cmd: ldi_ioctl failed, error=%d", rv);
3443 3442
3444 3443 return (USB_FAILURE);
3445 3444 }
3446 3445
3447 3446 return (USB_SUCCESS);
3448 3447 }
3449 3448
3450 3449
3451 3450 /*
3452 3451 * usb_ac_serialize/release_access:
3453 3452 */
3454 3453 static void
3455 3454 usb_ac_serialize_access(usb_ac_state_t *uacp)
3456 3455 {
3457 3456 (void) usb_serialize_access(uacp->usb_ac_ser_acc, USB_WAIT, 0);
3458 3457 }
3459 3458
3460 3459 static void
3461 3460 usb_ac_release_access(usb_ac_state_t *uacp)
3462 3461 {
3463 3462 usb_release_access(uacp->usb_ac_ser_acc);
3464 3463 }
3465 3464
3466 3465
3467 3466 static void
3468 3467 usb_ac_pm_busy_component(usb_ac_state_t *usb_ac_statep)
3469 3468 {
3470 3469 ASSERT(!mutex_owned(&usb_ac_statep->usb_ac_mutex));
3471 3470
3472 3471 if (usb_ac_statep->usb_ac_pm != NULL) {
3473 3472 mutex_enter(&usb_ac_statep->usb_ac_mutex);
3474 3473 usb_ac_statep->usb_ac_pm->acpm_pm_busy++;
3475 3474
3476 3475 USB_DPRINTF_L4(PRINT_MASK_PM,
3477 3476 usb_ac_statep->usb_ac_log_handle,
3478 3477 "usb_ac_pm_busy_component: %d",
3479 3478 usb_ac_statep->usb_ac_pm->acpm_pm_busy);
3480 3479
3481 3480 mutex_exit(&usb_ac_statep->usb_ac_mutex);
3482 3481
3483 3482 if (pm_busy_component(usb_ac_statep->usb_ac_dip, 0) !=
3484 3483 DDI_SUCCESS) {
3485 3484 mutex_enter(&usb_ac_statep->usb_ac_mutex);
3486 3485 usb_ac_statep->usb_ac_pm->acpm_pm_busy--;
3487 3486
3488 3487 USB_DPRINTF_L2(PRINT_MASK_PM,
3489 3488 usb_ac_statep->usb_ac_log_handle,
3490 3489 "usb_ac_pm_busy_component failed: %d",
3491 3490 usb_ac_statep->usb_ac_pm->acpm_pm_busy);
3492 3491
3493 3492 mutex_exit(&usb_ac_statep->usb_ac_mutex);
3494 3493 }
3495 3494 }
3496 3495 }
3497 3496
3498 3497
3499 3498 static void
3500 3499 usb_ac_pm_idle_component(usb_ac_state_t *usb_ac_statep)
3501 3500 {
3502 3501 ASSERT(!mutex_owned(&usb_ac_statep->usb_ac_mutex));
3503 3502
3504 3503 if (usb_ac_statep->usb_ac_pm != NULL) {
3505 3504 if (pm_idle_component(usb_ac_statep->usb_ac_dip, 0) ==
3506 3505 DDI_SUCCESS) {
3507 3506 mutex_enter(&usb_ac_statep->usb_ac_mutex);
3508 3507 ASSERT(usb_ac_statep->usb_ac_pm->acpm_pm_busy > 0);
3509 3508 usb_ac_statep->usb_ac_pm->acpm_pm_busy--;
3510 3509
3511 3510 USB_DPRINTF_L4(PRINT_MASK_PM,
3512 3511 usb_ac_statep->usb_ac_log_handle,
3513 3512 "usb_ac_pm_idle_component: %d",
3514 3513 usb_ac_statep->usb_ac_pm->acpm_pm_busy);
3515 3514
3516 3515 mutex_exit(&usb_ac_statep->usb_ac_mutex);
3517 3516 }
3518 3517 }
3519 3518 }
3520 3519
3521 3520
3522 3521 /*
3523 3522 * handle read from plumbed drivers
3524 3523 */
3525 3524 static void
3526 3525 usb_ac_reader(void *argp)
3527 3526 {
3528 3527 usb_ac_plumbed_t *acp = (usb_ac_plumbed_t *)argp;
3529 3528 usb_ac_state_t *uacp = acp->acp_uacp;
3530 3529 ldi_handle_t lh;
3531 3530 mblk_t *mp;
3532 3531 int rv;
3533 3532 timestruc_t tv = {0};
3534 3533
3535 3534 mutex_enter(&uacp->usb_ac_mutex);
3536 3535 lh = acp->acp_lh;
3537 3536 tv.tv_sec = usb_ac_wait_hid;
3538 3537
3539 3538 while (acp->acp_flags & ACP_ENABLED) {
3540 3539 mp = NULL;
3541 3540
3542 3541 mutex_exit(&uacp->usb_ac_mutex);
3543 3542
3544 3543 rv = ldi_getmsg(lh, &mp, &tv);
3545 3544
3546 3545 mutex_enter(&uacp->usb_ac_mutex);
3547 3546
3548 3547 if (rv == ENODEV) {
3549 3548 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3550 3549 "Device is not availabe");
3551 3550 break;
3552 3551 }
3553 3552
3554 3553
3555 3554 if ((acp->acp_flags & ACP_ENABLED) && mp != NULL && rv == 0)
3556 3555 rv = usb_ac_read_msg(acp, mp);
3557 3556
3558 3557 }
3559 3558 mutex_exit(&uacp->usb_ac_mutex);
3560 3559 }
3561 3560
3562 3561
3563 3562 /*
3564 3563 * setup threads to read from the other usb modules that may send unsolicited
3565 3564 * or asynchronous messages, which is only hid currently
3566 3565 */
3567 3566 static int
3568 3567 usb_ac_plumb(usb_ac_plumbed_t *acp)
3569 3568 {
3570 3569 usb_ac_state_t *uacp = acp->acp_uacp;
3571 3570 dev_info_t *dip;
3572 3571 dev_info_t *acp_dip;
3573 3572 int acp_inst;
3574 3573 char *acp_name;
3575 3574 char tq_nm[128];
3576 3575 int rv = USB_FAILURE;
3577 3576
3578 3577 mutex_enter(&uacp->usb_ac_mutex);
3579 3578
3580 3579 dip = uacp->usb_ac_dip;
3581 3580
3582 3581 acp_dip = acp->acp_dip;
3583 3582 acp_inst = ddi_get_instance(acp_dip);
3584 3583 acp_name = (char *)ddi_driver_name(acp_dip);
3585 3584
3586 3585 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3587 3586 "usb_ac_plumb:begin");
3588 3587
3589 3588 if (strcmp(acp_name, "hid") != 0) {
3590 3589 rv = USB_SUCCESS;
3591 3590 goto OUT;
3592 3591 }
3593 3592
3594 3593 (void) snprintf(tq_nm, sizeof (tq_nm), "%s_%d_tq",
3595 3594 ddi_driver_name(acp_dip), acp_inst);
3596 3595
3597 3596 acp->acp_tqp = ddi_taskq_create(dip, tq_nm, 1, TASKQ_DEFAULTPRI, 0);
3598 3597 if (acp->acp_tqp == NULL)
3599 3598 goto OUT;
3600 3599
3601 3600 if (ddi_taskq_dispatch(acp->acp_tqp, usb_ac_reader, (void *)acp,
3602 3601 DDI_SLEEP) != DDI_SUCCESS)
3603 3602 goto OUT;
3604 3603
3605 3604 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3606 3605 "usb_ac_plumb: dispatched reader");
3607 3606
3608 3607 rv = USB_SUCCESS;
3609 3608
3610 3609 OUT:
3611 3610 mutex_exit(&uacp->usb_ac_mutex);
3612 3611
3613 3612 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3614 3613 "usb_ac_plumb: done, rv=%d", rv);
3615 3614
3616 3615 return (rv);
3617 3616 }
3618 3617
3619 3618
3620 3619 static void
3621 3620 usb_ac_mux_plumbing_tq(void *arg)
3622 3621 {
3623 3622 usb_ac_state_t *uacp = (usb_ac_state_t *)arg;
3624 3623
3625 3624 if (usb_ac_mux_plumbing(uacp) != USB_SUCCESS)
3626 3625 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3627 3626 "usb_ac_mux_plumbing_tq:failed");
3628 3627 }
3629 3628
3630 3629
3631 3630 static int
3632 3631 usb_ac_do_plumbing(usb_ac_state_t *uacp)
3633 3632 {
3634 3633 dev_info_t *dip = uacp->usb_ac_dip;
3635 3634 int inst = ddi_get_instance(dip);
3636 3635 char tq_nm[128];
3637 3636 int rv = USB_FAILURE;
3638 3637
3639 3638 (void) snprintf(tq_nm, sizeof (tq_nm), "%s_%d_tq",
3640 3639 ddi_driver_name(dip), inst);
3641 3640
3642 3641 uacp->tqp = ddi_taskq_create(dip, tq_nm, 1, TASKQ_DEFAULTPRI, 0);
3643 3642 if (uacp->tqp == NULL) {
3644 3643 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3645 3644 "usb_ac_do_plumbing: ddi_taskq_create failed");
3646 3645 goto OUT;
3647 3646 }
3648 3647
3649 3648 if (ddi_taskq_dispatch(uacp->tqp, usb_ac_mux_plumbing_tq, (void *)uacp,
3650 3649 DDI_SLEEP) != DDI_SUCCESS) {
3651 3650 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3652 3651 "usb_ac_do_plumbing: ddi_taskq_dispatch failed");
3653 3652 goto OUT;
3654 3653 }
3655 3654
3656 3655 rv = USB_SUCCESS;
3657 3656
3658 3657 OUT:
3659 3658 return (rv);
3660 3659 }
3661 3660
3662 3661
3663 3662
3664 3663 static void
3665 3664 usb_ac_mux_unplumbing_tq(void *arg)
3666 3665 {
3667 3666 usb_ac_state_t *uacp = (usb_ac_state_t *)arg;
3668 3667
3669 3668 if (usb_ac_mux_unplumbing(uacp) != USB_SUCCESS)
3670 3669 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3671 3670 "usb_ac_mux_unplumbing:failed");
3672 3671 }
3673 3672
3674 3673
3675 3674 static int
3676 3675 usb_ac_do_unplumbing(usb_ac_state_t *uacp)
3677 3676 {
3678 3677 int rv = USB_FAILURE;
3679 3678
3680 3679 if (uacp->tqp == NULL)
3681 3680 return (USB_SUCCESS);
3682 3681
3683 3682 if (ddi_taskq_dispatch(uacp->tqp, usb_ac_mux_unplumbing_tq,
3684 3683 (void *)uacp, DDI_SLEEP) != DDI_SUCCESS) {
3685 3684 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3686 3685 "usb_ac_do_unplumbing: ddi_taskq_dispatch failed");
3687 3686 goto OUT;
3688 3687 }
3689 3688
3690 3689 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3691 3690 "usb_ac_do_unplumbing: waiting for unplumb thread");
3692 3691
3693 3692 ddi_taskq_wait(uacp->tqp);
3694 3693 rv = USB_SUCCESS;
3695 3694
3696 3695 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3697 3696 "usb_ac_do_unplumbing: unplumb thread done");
3698 3697
3699 3698 OUT:
3700 3699 if (uacp->tqp != NULL) {
3701 3700 ddi_taskq_destroy(uacp->tqp);
3702 3701 uacp->tqp = NULL;
3703 3702 }
3704 3703 return (rv);
3705 3704 }
3706 3705
3707 3706
3708 3707 /*
3709 3708 * teardown threads to the other usb modules
3710 3709 * and clear structures as part of unplumbing
3711 3710 */
3712 3711 static void
3713 3712 usb_ac_unplumb(usb_ac_plumbed_t *acp)
3714 3713 {
3715 3714 usb_ac_streams_info_t *streams_infop;
3716 3715 usb_ac_state_t *uacp = acp->acp_uacp;
3717 3716
3718 3717
3719 3718 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3720 3719 "usb_ac_unplumb: begin");
3721 3720
3722 3721 if (acp->acp_tqp != NULL) {
3723 3722 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3724 3723 "usb_ac_unplumb: destroying taskq");
3725 3724
3726 3725 ddi_taskq_destroy(acp->acp_tqp);
3727 3726 }
3728 3727
3729 3728 mutex_enter(&uacp->usb_ac_mutex);
3730 3729
3731 3730 if (acp->acp_driver == USB_AS_PLUMBED) {
3732 3731 /*
3733 3732 * we bzero the streams info and plumbed structure
3734 3733 * since there is no guarantee that the next plumbing
3735 3734 * will be identical
3736 3735 */
3737 3736 streams_infop = (usb_ac_streams_info_t *)acp->acp_data;
3738 3737
3739 3738 /* bzero the relevant plumbing structure */
3740 3739 bzero(streams_infop, sizeof (usb_ac_streams_info_t));
3741 3740 }
3742 3741 bzero(acp, sizeof (usb_ac_plumbed_t));
3743 3742
3744 3743 mutex_exit(&uacp->usb_ac_mutex);
3745 3744
3746 3745 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3747 3746 "usb_ac_unplumb: done");
3748 3747 }
3749 3748
3750 3749
3751 3750 /*ARGSUSED*/
3752 3751 static int
3753 3752 usb_ac_mux_plumbing(usb_ac_state_t *uacp)
3754 3753 {
3755 3754 dev_info_t *dip;
3756 3755
3757 3756 /* get the usb_ac dip */
3758 3757 dip = uacp->usb_ac_dip;
3759 3758
3760 3759 /* Access to the global variables is synchronized */
3761 3760 mutex_enter(&uacp->usb_ac_mutex);
3762 3761
3763 3762 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3764 3763 "usb_ac_mux_plumbing:state = %d",
3765 3764 uacp->usb_ac_plumbing_state);
3766 3765
3767 3766 if (uacp->usb_ac_plumbing_state >= USB_AC_STATE_PLUMBED) {
3768 3767 mutex_exit(&uacp->usb_ac_mutex);
3769 3768 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3770 3769 "usb_ac_mux_plumbing: audio streams driver"
3771 3770 " already plumbed");
3772 3771
3773 3772 return (USB_SUCCESS);
3774 3773 }
3775 3774
3776 3775 /* usb_as and hid should be attached but double check */
3777 3776 if (usb_ac_online_siblings(uacp) != USB_SUCCESS) {
3778 3777 mutex_exit(&uacp->usb_ac_mutex);
3779 3778 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3780 3779 "usb_ac_mux_plumbing:no audio streams driver plumbed");
3781 3780
3782 3781 return (USB_FAILURE);
3783 3782 }
3784 3783
3785 3784 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3786 3785 "usb_ac_mux_plumbing: raising power");
3787 3786 mutex_exit(&uacp->usb_ac_mutex);
3788 3787
3789 3788 /* bring the device to full power */
3790 3789 usb_ac_pm_busy_component(uacp);
3791 3790 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
3792 3791
3793 3792 /* avoid dips disappearing while we are plumbing */
3794 3793 usb_ac_hold_siblings(uacp);
3795 3794
3796 3795 mutex_enter(&uacp->usb_ac_mutex);
3797 3796
3798 3797 /*
3799 3798 * walk all siblings and create the usb_ac<->usb_as and
3800 3799 * usb_ac<->hid streams. return of 0 indicates no or
3801 3800 * partial/failed plumbing
3802 3801 */
3803 3802 if (usb_ac_mux_walk_siblings(uacp) == 0) {
3804 3803 /* pretend that we are plumbed so we can unplumb */
3805 3804 uacp->usb_ac_plumbing_state = USB_AC_STATE_PLUMBED;
3806 3805
3807 3806 mutex_exit(&uacp->usb_ac_mutex);
3808 3807
3809 3808 (void) usb_ac_mux_unplumbing(uacp);
3810 3809
3811 3810 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3812 3811 "usb_ac_mux_plumbing: no audio streams driver plumbed");
3813 3812
3814 3813 usb_ac_rele_siblings(uacp);
3815 3814
3816 3815 usb_ac_pm_idle_component(uacp);
3817 3816
3818 3817 return (USB_FAILURE);
3819 3818 }
3820 3819 uacp->usb_ac_plumbing_state = USB_AC_STATE_PLUMBED;
3821 3820
3822 3821 /* restore state if we have already registered with the mixer */
3823 3822 if (uacp->usb_ac_registered_with_mixer) {
3824 3823 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3825 3824 "usb_ac_mux_plumbing:already registered with mixer,"
3826 3825 "restoring state");
3827 3826
3828 3827 (void) usb_ac_restore_audio_state(uacp, USB_FLAGS_SLEEP);
3829 3828
3830 3829 } else if (usb_ac_mixer_registration(uacp) != USB_SUCCESS) {
3831 3830 mutex_exit(&uacp->usb_ac_mutex);
3832 3831
3833 3832 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3834 3833 "usb_ac_mux_plumbing: mixer registration failed");
3835 3834
3836 3835 (void) usb_ac_mux_unplumbing(uacp);
3837 3836
3838 3837 usb_ac_rele_siblings(uacp);
3839 3838
3840 3839 usb_ac_pm_idle_component(uacp);
3841 3840
3842 3841 return (USB_FAILURE);
3843 3842 }
3844 3843
3845 3844 mutex_exit(&uacp->usb_ac_mutex);
3846 3845 usb_ac_rele_siblings(uacp);
3847 3846
3848 3847 usb_ac_pm_idle_component(uacp);
3849 3848
3850 3849 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3851 3850 "usb_ac_mux_plumbing:done");
3852 3851
3853 3852 return (USB_SUCCESS);
3854 3853 }
3855 3854
3856 3855
3857 3856 static int
3858 3857 usb_ac_mux_unplumbing(usb_ac_state_t *uacp)
3859 3858 {
3860 3859 usb_ac_plumbed_t *acp;
3861 3860 ldi_handle_t lh;
3862 3861 dev_info_t *acp_dip;
3863 3862 int inst;
3864 3863 int i;
3865 3864 dev_t devt;
3866 3865 minor_t minor;
3867 3866 int maxlinked = 0;
3868 3867
3869 3868 mutex_enter(&uacp->usb_ac_mutex);
3870 3869
3871 3870
3872 3871 if (uacp->usb_ac_plumbing_state == USB_AC_STATE_UNPLUMBED) {
3873 3872 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3874 3873 "usb_ac_mux_unplumbing: already unplumbed!");
3875 3874 mutex_exit(&uacp->usb_ac_mutex);
3876 3875
3877 3876 return (USB_SUCCESS);
3878 3877 }
3879 3878
3880 3879 /* usb_ac might not have anything plumbed yet */
3881 3880 if (uacp->usb_ac_current_plumbed_index == -1) {
3882 3881 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3883 3882 "usb_ac_mux_unplumbing: nothing plumbed");
3884 3883 uacp->usb_ac_plumbing_state = USB_AC_STATE_UNPLUMBED;
3885 3884 mutex_exit(&uacp->usb_ac_mutex);
3886 3885
3887 3886 return (USB_SUCCESS);
3888 3887 }
3889 3888
3890 3889 /* do not allow detach if still busy */
3891 3890 if (uacp->usb_ac_busy_count) {
3892 3891 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3893 3892 "usb_ac_mux_unplumbing: mux still busy (%d)",
3894 3893 uacp->usb_ac_busy_count);
3895 3894 mutex_exit(&uacp->usb_ac_mutex);
3896 3895
3897 3896 return (USB_FAILURE);
3898 3897 }
3899 3898
3900 3899 uacp->usb_ac_plumbing_state = USB_AC_STATE_UNPLUMBED;
3901 3900
3902 3901 /* close ac-as and ac-hid streams */
3903 3902 maxlinked = uacp->usb_ac_current_plumbed_index + 1;
3904 3903 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3905 3904 "usb_ac_mux_unplumbing: maxlinked = %d", maxlinked);
3906 3905
3907 3906 for (i = 0; i < maxlinked; i++) {
3908 3907 /*
3909 3908 * we must save members of usb_ac_plumbed[] before calling
3910 3909 * usb_ac_unplumb() because it clears the structure
3911 3910 */
3912 3911 acp = &uacp->usb_ac_plumbed[i];
3913 3912 lh = acp->acp_lh;
3914 3913 acp_dip = acp->acp_dip;
3915 3914 devt = acp->acp_devt;
3916 3915
3917 3916 if (acp_dip == NULL) {
3918 3917 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3919 3918 "usb_ac_mux_unplumbing: [%d] - skipping", i);
3920 3919 continue;
3921 3920 }
3922 3921
3923 3922 minor = getminor(devt);
3924 3923 inst = ddi_get_instance(acp_dip);
3925 3924
3926 3925 uacp->usb_ac_current_plumbed_index = i;
3927 3926
3928 3927 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3929 3928 "usb_ac_mux_unplumbing: [%d] - %s%d minor 0x%x", i,
3930 3929 ddi_driver_name(acp_dip), inst, minor);
3931 3930
3932 3931 if (lh != NULL) {
3933 3932
3934 3933 acp->acp_flags &= ~ACP_ENABLED;
3935 3934
3936 3935 mutex_exit(&uacp->usb_ac_mutex);
3937 3936
3938 3937 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3939 3938 "usb_ac_mux_unplumbing:[%d] - closing", i);
3940 3939
3941 3940 /*
3942 3941 * ldi_close will cause panic if ldi_getmsg
3943 3942 * is not finished. ddi_taskq_destroy will wait
3944 3943 * for the thread to complete.
3945 3944 */
3946 3945 usb_ac_unplumb(acp);
3947 3946 (void) ldi_close(lh, FREAD|FWRITE, kcred);
3948 3947
3949 3948
3950 3949 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3951 3950 "usb_ac_mux_unplumbing: [%d] - unplumbed", i);
3952 3951
3953 3952 mutex_enter(&uacp->usb_ac_mutex);
3954 3953 }
3955 3954 }
3956 3955
3957 3956 mutex_exit(&uacp->usb_ac_mutex);
3958 3957
3959 3958 /* Wait till all activity in the default pipe has drained */
3960 3959 usb_ac_serialize_access(uacp);
3961 3960 usb_ac_release_access(uacp);
3962 3961
3963 3962 mutex_enter(&uacp->usb_ac_mutex);
3964 3963 uacp->usb_ac_current_plumbed_index = -1;
3965 3964 mutex_exit(&uacp->usb_ac_mutex);
3966 3965
3967 3966 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3968 3967 "usb_ac_mux_unplumbing: done");
3969 3968
3970 3969 return (USB_SUCCESS);
3971 3970 }
3972 3971
3973 3972
3974 3973 /*
3975 3974 * walk all siblings and create the ac<->as and ac<->hid streams
3976 3975 */
3977 3976 static int
3978 3977 usb_ac_mux_walk_siblings(usb_ac_state_t *uacp)
3979 3978 {
3980 3979 dev_info_t *pdip;
3981 3980 dev_info_t *child_dip;
3982 3981 major_t drv_major;
3983 3982 minor_t drv_minor;
3984 3983 int drv_instance;
3985 3984 char *drv_name;
3986 3985 dev_t drv_devt;
3987 3986 ldi_handle_t drv_lh;
3988 3987 ldi_ident_t li;
3989 3988 int error;
3990 3989 int count = 0;
3991 3990
3992 3991 ASSERT(mutex_owned(&uacp->usb_ac_mutex));
3993 3992
3994 3993 pdip = ddi_get_parent(uacp->usb_ac_dip);
3995 3994 child_dip = ddi_get_child(pdip);
3996 3995
3997 3996 while ((child_dip != NULL) && (count < USB_AC_MAX_PLUMBED)) {
3998 3997 drv_instance = ddi_get_instance(child_dip);
3999 3998 drv_name = (char *)ddi_driver_name(child_dip);
4000 3999
4001 4000 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4002 4001 "usb_ac_mux_walk_siblings: plumbing %s%d count=%d",
4003 4002 drv_name, drv_instance, count);
4004 4003
4005 4004 /* ignore own dip */
4006 4005 if (child_dip == uacp->usb_ac_dip) {
4007 4006 child_dip = ddi_get_next_sibling(child_dip);
4008 4007 continue;
4009 4008 }
4010 4009 drv_instance = ddi_get_instance(child_dip);
4011 4010
4012 4011 /* ignore other dip other than usb_as and hid */
4013 4012 if (strcmp(ddi_driver_name(child_dip), "usb_as") == 0) {
4014 4013 uacp->usb_ac_plumbed[count].acp_driver = USB_AS_PLUMBED;
4015 4014 drv_minor = USB_AS_CONSTRUCT_MINOR(drv_instance);
4016 4015 } else if (strcmp(ddi_driver_name(child_dip), "hid") == 0) {
4017 4016 uacp->usb_ac_plumbed[count].acp_driver = USB_AH_PLUMBED;
4018 4017 drv_minor = HID_CONSTRUCT_EXTERNAL_MINOR(drv_instance);
4019 4018 } else {
4020 4019 drv_minor = drv_instance;
4021 4020 uacp->usb_ac_plumbed[count].acp_driver =
4022 4021 UNKNOWN_PLUMBED;
4023 4022 child_dip = ddi_get_next_sibling(child_dip);
4024 4023
4025 4024 continue;
4026 4025 }
4027 4026
4028 4027 if (!i_ddi_devi_attached(child_dip)) {
4029 4028 child_dip = ddi_get_next_sibling(child_dip);
4030 4029
4031 4030 continue;
4032 4031 }
4033 4032
4034 4033 if (DEVI_IS_DEVICE_REMOVED(child_dip)) {
4035 4034 child_dip = ddi_get_next_sibling(child_dip);
4036 4035
4037 4036 continue;
4038 4037 }
4039 4038
4040 4039 drv_major = ddi_driver_major(child_dip);
4041 4040
4042 4041 uacp->usb_ac_current_plumbed_index = count;
4043 4042
4044 4043 mutex_exit(&uacp->usb_ac_mutex);
4045 4044
4046 4045 drv_devt = makedevice(drv_major, drv_minor);
4047 4046
4048 4047 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4049 4048 "usb_ac_mux_walk_siblings:: opening %s%d devt=(%d, 0x%x)",
4050 4049 drv_name, drv_instance, drv_major, drv_minor);
4051 4050
4052 4051 error = ldi_ident_from_dip(uacp->usb_ac_dip, &li);
4053 4052 if (error == 0) {
4054 4053 mutex_enter(&uacp->usb_ac_mutex);
4055 4054 uacp->usb_ac_plumbed[count].acp_flags |= ACP_ENABLED;
4056 4055 mutex_exit(&uacp->usb_ac_mutex);
4057 4056
4058 4057 error = ldi_open_by_dev(&drv_devt, OTYP_CHR,
4059 4058 FREAD|FWRITE, kcred, &drv_lh, li);
4060 4059 ldi_ident_release(li);
4061 4060 }
4062 4061
4063 4062 mutex_enter(&uacp->usb_ac_mutex);
4064 4063 if (error) {
4065 4064 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4066 4065 "usb_ac_mux_walk_siblings: open of devt=(%d, 0x%x)"
4067 4066 " failed error=%d", drv_major, drv_minor, error);
4068 4067
4069 4068 return (0);
4070 4069 }
4071 4070
4072 4071 uacp->usb_ac_plumbed[count].acp_uacp = uacp;
4073 4072 uacp->usb_ac_plumbed[count].acp_devt = drv_devt;
4074 4073 uacp->usb_ac_plumbed[count].acp_lh = drv_lh;
4075 4074 uacp->usb_ac_plumbed[count].acp_dip = child_dip;
4076 4075 uacp->usb_ac_plumbed[count].acp_ifno =
4077 4076 usb_get_if_number(child_dip);
4078 4077
4079 4078 if (uacp->usb_ac_plumbed[count].acp_driver == USB_AS_PLUMBED) {
4080 4079 /* get registration data */
4081 4080 if (usb_ac_get_reg_data(uacp, drv_lh, count) !=
4082 4081 USB_SUCCESS) {
4083 4082
4084 4083 USB_DPRINTF_L3(PRINT_MASK_ALL,
4085 4084 uacp->usb_ac_log_handle,
4086 4085 "usb_ac_mux_walk_siblings:"
4087 4086 "usb_ac_get_reg_data failed on %s%d",
4088 4087 drv_name, drv_instance);
4089 4088
4090 4089 uacp->usb_ac_plumbed[count].acp_dip = NULL;
4091 4090
4092 4091 return (0);
4093 4092 }
4094 4093 } else if (uacp->usb_ac_plumbed[count].acp_driver ==
4095 4094 USB_AH_PLUMBED) {
4096 4095 int rval;
4097 4096
4098 4097 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4099 4098 "usb_ac_mux_walk_siblings: pushing usb_ah on %s%d",
4100 4099 drv_name, drv_instance);
4101 4100
4102 4101 mutex_exit(&uacp->usb_ac_mutex);
4103 4102
4104 4103 /* push usb_ah module on top of hid */
4105 4104 error = ldi_ioctl(drv_lh, I_PUSH, (intptr_t)"usb_ah",
4106 4105 FKIOCTL, kcred, &rval);
4107 4106 mutex_enter(&uacp->usb_ac_mutex);
4108 4107
4109 4108 if (error) {
4110 4109 USB_DPRINTF_L2(PRINT_MASK_ALL,
4111 4110 uacp->usb_ac_log_handle,
4112 4111 "usb_ac_mux_walk_siblings: ldi_ioctl"
4113 4112 "I_PUSH failed on %s%d, error=%d",
4114 4113 drv_name, drv_instance, error);
4115 4114
4116 4115 uacp->usb_ac_plumbed[count].acp_dip = NULL;
4117 4116
4118 4117 /* skip plumbing the hid driver */
4119 4118 child_dip = ddi_get_next_sibling(child_dip);
4120 4119 continue;
4121 4120 }
4122 4121 } else {
4123 4122 /* should not be here */
4124 4123 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4125 4124 "usb_ac_mux_walk_siblings:- unknown module %s%d",
4126 4125 drv_name, drv_instance);
4127 4126 count--;
4128 4127
4129 4128 uacp->usb_ac_plumbed[count].acp_dip = NULL;
4130 4129
4131 4130 /* skip plumbing an unknown module */
4132 4131 child_dip = ddi_get_next_sibling(child_dip);
4133 4132 continue;
4134 4133 }
4135 4134
4136 4135 mutex_exit(&uacp->usb_ac_mutex);
4137 4136 error = usb_ac_plumb(&uacp->usb_ac_plumbed[count]);
4138 4137 mutex_enter(&uacp->usb_ac_mutex);
4139 4138
4140 4139 if (error != USB_SUCCESS) {
4141 4140 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4142 4141 "usb_ac_mux_walk_siblings: usb_ac_plumb "
4143 4142 "failed for %s%d", drv_name, drv_instance);
4144 4143
4145 4144 return (0);
4146 4145 }
4147 4146
4148 4147 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4149 4148 "usb_ac_mux_walk_siblings:plumbed %d, minor 0x%x",
4150 4149 drv_instance, drv_minor);
4151 4150
4152 4151 child_dip = ddi_get_next_sibling(child_dip);
4153 4152 count++;
4154 4153 }
4155 4154
4156 4155 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4157 4156 "usb_ac_mux_walk_siblings: %d drivers plumbed under usb_ac mux",
4158 4157 count);
4159 4158
4160 4159 return (count);
4161 4160 }
4162 4161
4163 4162
4164 4163 /*
4165 4164 * Register with mixer only after first plumbing.
4166 4165 * Also do not register if earlier reg data
4167 4166 * couldn't be received from at least one
4168 4167 * streaming interface
4169 4168 */
4170 4169
4171 4170 static int
4172 4171 usb_ac_mixer_registration(usb_ac_state_t *uacp)
4173 4172 {
4174 4173 usb_as_registration_t *asreg;
4175 4174 int n;
4176 4175
4177 4176 if (uacp->usb_ac_registered_with_mixer) {
4178 4177 return (USB_SUCCESS);
4179 4178 }
4180 4179
4181 4180 for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) {
4182 4181 if (uacp->usb_ac_streams[n].acs_rcvd_reg_data) {
4183 4182 break;
4184 4183 }
4185 4184 }
4186 4185
4187 4186 /* Haven't found a streaming interface; fail mixer registration */
4188 4187 if (n > USB_AC_MAX_AS_PLUMBED) {
4189 4188 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4190 4189 "usb_ac_mixer_registration:- no streaming interface found");
4191 4190
4192 4191 return (USB_FAILURE);
4193 4192 }
4194 4193
4195 4194 /*
4196 4195 * Fill out streaming interface specific stuff
4197 4196 * Note that we handle only one playing and one recording
4198 4197 * streaming interface at the most
4199 4198 */
4200 4199 for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) {
4201 4200 int ch, chs, id;
4202 4201
4203 4202 if (uacp->usb_ac_streams[n].acs_rcvd_reg_data == 0) {
4204 4203 continue;
4205 4204 }
4206 4205
4207 4206 asreg = &(uacp->usb_ac_streams[n].acs_streams_reg);
4208 4207 if (asreg->reg_valid == 0) {
4209 4208 continue;
4210 4209 }
4211 4210
4212 4211
4213 4212 chs = asreg->reg_formats[0].fmt_chns;
4214 4213
4215 4214 /* check if any channel supports vol. control for this fmt */
4216 4215 for (ch = 0; ch <= chs; ch++) {
4217 4216 if ((id = usb_ac_get_featureID(uacp,
4218 4217 asreg->reg_mode, ch,
4219 4218 USB_AUDIO_VOLUME_CONTROL)) != -1) {
4220 4219 USB_DPRINTF_L3(PRINT_MASK_ALL,
4221 4220 uacp->usb_ac_log_handle,
4222 4221 "usb_ac_mixer_registration:n= [%d]"
4223 4222 "- dir=%d featureID=%d",
4224 4223 n, asreg->reg_mode, id);
4225 4224
4226 4225 break;
4227 4226 }
4228 4227 }
4229 4228
4230 4229 uacp->usb_ac_streams[n].acs_default_gain =
4231 4230 (id == USB_AC_ID_NONE) ? (AF_MAX_GAIN): (AF_MAX_GAIN*3/4);
4232 4231
4233 4232 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4234 4233 "usb_ac_mixer_registration:n= [%d] - mode=%d chs=%d"
4235 4234 "default_gain=%d id=%d",
4236 4235 n, asreg->reg_mode, chs,
4237 4236 uacp->usb_ac_streams[n].acs_default_gain, id);
4238 4237
4239 4238 }
4240 4239
4241 4240 /* the rest */
4242 4241
4243 4242 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4244 4243 "usb_ac_mixer_registration: calling usb_audio_register");
4245 4244
4246 4245 mutex_exit(&uacp->usb_ac_mutex);
4247 4246
4248 4247 if (usb_audio_register(uacp) != USB_SUCCESS) {
4249 4248 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4250 4249 "usb_ac_mixer_registration: usb_audio_register failed");
4251 4250
4252 4251 mutex_enter(&uacp->usb_ac_mutex);
4253 4252
4254 4253 return (USB_FAILURE);
4255 4254 }
4256 4255
4257 4256 mutex_enter(&uacp->usb_ac_mutex);
4258 4257
4259 4258 uacp->usb_ac_registered_with_mixer = 1;
4260 4259
4261 4260 return (USB_SUCCESS);
4262 4261 }
4263 4262
4264 4263
4265 4264 /*
4266 4265 * Get registriations data when driver attach
4267 4266 */
4268 4267 static int
4269 4268 usb_ac_get_reg_data(usb_ac_state_t *uacp, ldi_handle_t drv_lh, int index)
4270 4269 {
4271 4270 int n, error, rval;
4272 4271 usb_as_registration_t *streams_reg;
4273 4272
4274 4273
4275 4274 ASSERT(uacp->usb_ac_registered_with_mixer == 0);
4276 4275
4277 4276 for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) {
4278 4277 /*
4279 4278 * We haven't received registration data
4280 4279 * from n-th streaming interface in the array
4281 4280 */
4282 4281 if (!uacp->usb_ac_streams[n].acs_rcvd_reg_data) {
4283 4282 break;
4284 4283 }
4285 4284 }
4286 4285
4287 4286 if (n >= USB_AC_MAX_AS_PLUMBED) {
4288 4287 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4289 4288 "More than 2 streaming interfaces (play "
4290 4289 "and/or record) currently not supported");
4291 4290
4292 4291 return (USB_FAILURE);
4293 4292 }
4294 4293
4295 4294 /* take the stream reg struct with the same index */
4296 4295 streams_reg = &uacp->usb_ac_streams[n].acs_streams_reg;
4297 4296
4298 4297 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4299 4298 "usb_ac_get_reg_data:regdata from usb_as: streams_reg=0x%p, n=%d",
4300 4299 (void *)streams_reg, n);
4301 4300
4302 4301 mutex_exit(&uacp->usb_ac_mutex);
4303 4302
4304 4303 if ((error = ldi_ioctl(drv_lh, USB_AUDIO_MIXER_REGISTRATION,
4305 4304 (intptr_t)streams_reg, FKIOCTL, kcred, &rval)) != 0) {
4306 4305 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4307 4306 "usb_ac_get_reg_data: ldi_ioctl failed for"
4308 4307 "mixer registration error=%d", error);
4309 4308
4310 4309 mutex_enter(&uacp->usb_ac_mutex);
4311 4310
4312 4311 return (USB_FAILURE);
4313 4312 } else {
4314 4313 mutex_enter(&uacp->usb_ac_mutex);
4315 4314
4316 4315 rval = usb_ac_setup_plumbed(uacp, index, n);
4317 4316
4318 4317 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4319 4318 "usb_ac_get_reg_data:usb_ac_streams[%d]: "
4320 4319 "received_reg_data=%d type=%s", index,
4321 4320 uacp->usb_ac_streams[n].acs_rcvd_reg_data,
4322 4321 ((streams_reg->reg_mode == USB_AUDIO_PLAY) ?
4323 4322 "play" : "record"));
4324 4323
4325 4324 usb_ac_print_reg_data(uacp, streams_reg);
4326 4325
4327 4326 return (rval);
4328 4327 }
4329 4328 }
4330 4329
4331 4330
4332 4331 /*
4333 4332 * setup plumbed and stream info structure
4334 4333 */
4335 4334 static int
4336 4335 usb_ac_setup_plumbed(usb_ac_state_t *uacp, int plb_idx, int str_idx)
4337 4336 {
4338 4337 uacp->usb_ac_plumbed[plb_idx].acp_data =
4339 4338 &uacp->usb_ac_streams[str_idx];
4340 4339 uacp->usb_ac_streams[str_idx].acs_plumbed =
4341 4340 &uacp->usb_ac_plumbed[plb_idx];
4342 4341 uacp->usb_ac_streams[str_idx].acs_rcvd_reg_data = 1;
4343 4342
4344 4343
4345 4344 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4346 4345 "usb_ac_setup_plumbed: done - plb_idx=%d str_idx=%d ",
4347 4346 plb_idx, str_idx);
4348 4347
4349 4348 return (USB_SUCCESS);
4350 4349 }
4351 4350
4352 4351
4353 4352 /*
4354 4353 * function to dump registration data
4355 4354 */
4356 4355 static void
4357 4356 usb_ac_print_reg_data(usb_ac_state_t *uacp,
4358 4357 usb_as_registration_t *reg)
4359 4358 {
4360 4359 int n;
4361 4360
4362 4361 for (n = 0; n < reg->reg_n_formats; n++) {
4363 4362 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4364 4363 "format%d: alt=%d chns=%d prec=%d enc=%d", n,
4365 4364 reg->reg_formats[n].fmt_alt,
4366 4365 reg->reg_formats[n].fmt_chns,
4367 4366 reg->reg_formats[n].fmt_precision,
4368 4367 reg->reg_formats[n].fmt_encoding);
4369 4368 }
4370 4369
4371 4370 for (n = 0; n < USB_AS_N_FORMATS; n++) {
4372 4371 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4373 4372 "reg_formats[%d] ptr=0x%p", n,
4374 4373 (void *)®->reg_formats[n]);
4375 4374 }
4376 4375
4377 4376 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4378 4377 "usb_ac_print_reg_data: End");
4379 4378 }
4380 4379
4381 4380
4382 4381 static int
4383 4382 usb_ac_online_siblings(usb_ac_state_t *uacp)
4384 4383 {
4385 4384 dev_info_t *pdip, *child_dip;
4386 4385 int rval = USB_SUCCESS;
4387 4386
4388 4387 ASSERT(mutex_owned(&uacp->usb_ac_mutex));
4389 4388
4390 4389 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4391 4390 "usb_ac_online_siblings:start");
4392 4391
4393 4392 pdip = ddi_get_parent(uacp->usb_ac_dip);
4394 4393
4395 4394 child_dip = ddi_get_child(pdip);
4396 4395 while (child_dip != NULL) {
4397 4396
4398 4397 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4399 4398 "usb_ac_online_siblings: onlining %s%d ref=%d",
4400 4399 ddi_driver_name(child_dip),
4401 4400 ddi_get_instance(child_dip),
4402 4401 DEVI(child_dip)->devi_ref);
4403 4402
4404 4403 /* Online the child_dip of usb_as and hid, if not already */
4405 4404 if ((strcmp(ddi_driver_name(child_dip), "usb_as") == 0) ||
4406 4405 (strcmp(ddi_driver_name(child_dip), "hid") == 0)) {
4407 4406
4408 4407 mutex_exit(&uacp->usb_ac_mutex);
4409 4408 if (ndi_devi_online(child_dip, NDI_ONLINE_ATTACH) !=
4410 4409 NDI_SUCCESS) {
4411 4410 USB_DPRINTF_L3(PRINT_MASK_ALL,
4412 4411 uacp->usb_ac_log_handle,
4413 4412 "usb_ac_online_siblings:failed to online"
4414 4413 "device %s%d", ddi_driver_name(child_dip),
4415 4414 ddi_get_instance(child_dip));
4416 4415
4417 4416 /* only onlining usb_as is fatal */
4418 4417 if (strcmp(ddi_driver_name(child_dip),
4419 4418 "usb_as") == 0) {
4420 4419 mutex_enter(&uacp->usb_ac_mutex);
4421 4420 rval = USB_FAILURE;
4422 4421 break;
4423 4422 }
4424 4423 }
4425 4424 mutex_enter(&uacp->usb_ac_mutex);
4426 4425 }
4427 4426 child_dip = ddi_get_next_sibling(child_dip);
4428 4427 }
4429 4428
4430 4429 return (rval);
4431 4430 }
4432 4431
4433 4432
4434 4433 /*
4435 4434 * hold all audio children before or after plumbing
4436 4435 * online usb_as and hid, if not already
4437 4436 */
4438 4437 static void
4439 4438 usb_ac_hold_siblings(usb_ac_state_t *uacp)
4440 4439 {
4441 4440 int circ;
4442 4441 dev_info_t *pdip, *child_dip;
4443 4442
4444 4443 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4445 4444 "usb_ac_hold_siblings:start");
4446 4445
4447 4446 /* hold all siblings and ourselves */
4448 4447 pdip = ddi_get_parent(uacp->usb_ac_dip);
4449 4448
4450 4449 /* hold the children */
4451 4450 ndi_devi_enter(pdip, &circ);
4452 4451 child_dip = ddi_get_child(pdip);
4453 4452 while (child_dip != NULL) {
4454 4453 ndi_hold_devi(child_dip);
4455 4454
4456 4455 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4457 4456 "usb_ac_hold_siblings: held %s%d ref=%d",
4458 4457 ddi_driver_name(child_dip), ddi_get_instance(child_dip),
4459 4458 DEVI(child_dip)->devi_ref);
4460 4459
4461 4460 child_dip = ddi_get_next_sibling(child_dip);
4462 4461 }
4463 4462 ndi_devi_exit(pdip, circ);
4464 4463 }
4465 4464
4466 4465
4467 4466 /*
4468 4467 * release all audio children before or after plumbing
4469 4468 */
4470 4469 static void
4471 4470 usb_ac_rele_siblings(usb_ac_state_t *uacp)
4472 4471 {
4473 4472 int circ;
4474 4473 dev_info_t *pdip, *child_dip;
4475 4474
4476 4475 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4477 4476 "usb_ac_rele_siblings: start");
4478 4477
4479 4478 /* release all siblings and ourselves */
4480 4479 pdip = ddi_get_parent(uacp->usb_ac_dip);
4481 4480 ndi_devi_enter(pdip, &circ);
4482 4481 child_dip = ddi_get_child(pdip);
4483 4482 while (child_dip != NULL) {
4484 4483 ndi_rele_devi(child_dip);
4485 4484
4486 4485 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4487 4486 "usb_ac_rele_siblings: released %s%d ref=%d",
4488 4487 ddi_driver_name(child_dip), ddi_get_instance(child_dip),
4489 4488 DEVI(child_dip)->devi_ref);
4490 4489
4491 4490 child_dip = ddi_get_next_sibling(child_dip);
4492 4491 }
4493 4492 ndi_devi_exit(pdip, circ);
4494 4493 }
4495 4494 static void
4496 4495 usb_restore_engine(usb_ac_state_t *statep)
4497 4496 {
4498 4497 usb_audio_eng_t *engp;
4499 4498 int i;
4500 4499
4501 4500 for (i = 0; i < USB_AC_ENG_MAX; i++) {
4502 4501
4503 4502 mutex_enter(&statep->usb_ac_mutex);
4504 4503 engp = &statep->engines[i];
4505 4504 mutex_exit(&statep->usb_ac_mutex);
4506 4505
4507 4506 if (engp->af_engp == NULL)
4508 4507 continue;
4509 4508 if (usb_ac_set_format(statep, engp) != USB_SUCCESS) {
4510 4509 USB_DPRINTF_L2(PRINT_MASK_ATTA,
4511 4510 statep->usb_ac_log_handle,
4512 4511 "usb_restore_engine:set format fail, i=%d", i);
4513 4512 return;
4514 4513 }
4515 4514 if (engp->started) {
4516 4515 (void) usb_engine_start(engp);
4517 4516 }
4518 4517
4519 4518 }
4520 4519
4521 4520 (void) usb_ac_ctrl_restore(statep);
4522 4521 }
4523 4522
4524 4523
4525 4524 /*
4526 4525 * get the maximum format specification the device supports
4527 4526 */
4528 4527 static void
4529 4528 usb_ac_max_fmt(usb_as_registration_t *reg_data,
4530 4529 usb_audio_format_t *fmtp)
4531 4530 {
4532 4531
4533 4532 uint_t ch = 0, sr = 0, prec = 0, enc = 0;
4534 4533 int i;
4535 4534
4536 4535 usb_audio_formats_t *reg_formats = reg_data->reg_formats;
4537 4536
4538 4537 /* format priority: channels, sample rate, precision, encoding */
4539 4538 for (i = 0; i < reg_data->reg_n_formats; i++) {
4540 4539 uint_t val, fmt_sr;
4541 4540 int n, keep;
4542 4541
4543 4542 val = reg_formats[i].fmt_chns;
4544 4543 if (val < ch)
4545 4544 continue;
4546 4545 if (val > ch)
4547 4546 keep = 1;
4548 4547
4549 4548 for (n = 0, fmt_sr = 0; n < reg_formats[i].fmt_n_srs; n++) {
4550 4549 if (fmt_sr < reg_formats[i].fmt_srs[n]) {
4551 4550 fmt_sr = reg_formats[i].fmt_srs[n];
4552 4551 }
4553 4552 }
4554 4553 if (!keep && fmt_sr < sr)
4555 4554 continue;
4556 4555 if (fmt_sr > sr)
4557 4556 keep = 1;
4558 4557
4559 4558 val = reg_formats[i].fmt_precision;
4560 4559 if (!keep && (val < prec))
4561 4560 continue;
4562 4561 if (val > prec)
4563 4562 keep = 1;
4564 4563
4565 4564 val = reg_formats[i].fmt_encoding;
4566 4565 if (!keep && (val < enc))
4567 4566 continue;
4568 4567
4569 4568 ch = reg_formats[i].fmt_chns;
4570 4569 sr = fmt_sr;
4571 4570 prec = reg_formats[i].fmt_precision;
4572 4571 enc = reg_formats[i].fmt_encoding;
4573 4572 }
4574 4573
4575 4574 fmtp->ch = ch;
4576 4575 fmtp->sr = sr;
4577 4576 fmtp->prec = prec;
4578 4577 fmtp->enc = enc;
4579 4578 }
4580 4579
4581 4580
4582 4581 static void
4583 4582 usb_ac_rem_eng(usb_ac_state_t *statep, usb_audio_eng_t *engp)
4584 4583 {
4585 4584 if (statep->usb_ac_audio_dev == NULL || engp->af_engp == NULL)
4586 4585 return;
4587 4586
4588 4587 audio_dev_remove_engine(statep->usb_ac_audio_dev, engp->af_engp);
4589 4588 audio_engine_free(engp->af_engp);
4590 4589
4591 4590 mutex_enter(&engp->lock);
4592 4591 engp->af_engp = NULL;
4593 4592 engp->streams = NULL;
4594 4593 mutex_exit(&engp->lock);
4595 4594
4596 4595 mutex_destroy(&engp->lock);
4597 4596 cv_destroy(&engp->usb_audio_cv);
4598 4597 }
4599 4598
4600 4599
4601 4600 static int
4602 4601 usb_ac_add_eng(usb_ac_state_t *uacp, usb_ac_streams_info_t *asinfo)
4603 4602 {
4604 4603 audio_dev_t *af_devp = uacp->usb_ac_audio_dev;
4605 4604 usb_audio_eng_t *engp;
4606 4605 audio_engine_t *af_engp;
4607 4606 int rv = USB_FAILURE;
4608 4607 int dir = asinfo->acs_streams_reg.reg_mode;
4609 4608 uint_t defgain;
4610 4609
4611 4610 if (asinfo->acs_rcvd_reg_data == 0) {
4612 4611
4613 4612 return (USB_SUCCESS);
4614 4613 }
4615 4614 if (dir == USB_AUDIO_PLAY) {
4616 4615 engp = &(uacp->engines[0]);
4617 4616 } else {
4618 4617 engp = &(uacp->engines[1]);
4619 4618 }
4620 4619
4621 4620 cv_init(&engp->usb_audio_cv, NULL, CV_DRIVER, NULL);
4622 4621
4623 4622 mutex_init(&engp->lock, NULL, MUTEX_DRIVER, NULL);
4624 4623
4625 4624 mutex_enter(&engp->lock);
4626 4625
4627 4626 engp->af_eflags =
4628 4627 (dir == USB_AUDIO_PLAY)?ENGINE_OUTPUT_CAP:ENGINE_INPUT_CAP;
4629 4628 engp->statep = uacp;
4630 4629
4631 4630 /* Set the format for the engine */
4632 4631 usb_ac_max_fmt(&(asinfo->acs_streams_reg), &engp->fmt);
4633 4632
4634 4633 /* init the default gain */
4635 4634 defgain = asinfo->acs_default_gain;
4636 4635 if (engp->fmt.ch == 2) {
4637 4636 engp->af_defgain = AUDIO_CTRL_STEREO_VAL(defgain, defgain);
4638 4637 } else {
4639 4638 engp->af_defgain = defgain;
4640 4639 }
4641 4640 engp->streams = asinfo;
4642 4641
4643 4642 mutex_exit(&engp->lock);
4644 4643
4645 4644 af_engp = audio_engine_alloc(&usb_engine_ops, engp->af_eflags);
4646 4645 if (af_engp == NULL) {
4647 4646
4648 4647 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
4649 4648 "audio_engine_alloc failed");
4650 4649 goto OUT;
4651 4650 }
4652 4651 ASSERT(engp->af_engp == 0);
4653 4652
4654 4653 mutex_enter(&engp->lock);
4655 4654 engp->af_engp = af_engp;
4656 4655 mutex_exit(&engp->lock);
4657 4656
4658 4657 audio_engine_set_private(af_engp, engp);
4659 4658 audio_dev_add_engine(af_devp, af_engp);
4660 4659
4661 4660 /*
4662 4661 * Set the format for this engine
4663 4662 */
4664 4663 if (usb_ac_set_format(uacp, engp) != USB_SUCCESS) {
4665 4664 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
4666 4665 "set format failed, dir = %d", dir);
4667 4666 goto OUT;
4668 4667 }
4669 4668 rv = USB_SUCCESS;
4670 4669
4671 4670 OUT:
4672 4671 if (rv != USB_SUCCESS)
4673 4672 usb_ac_rem_eng(uacp, engp);
4674 4673
4675 4674 return (rv);
4676 4675 }
4677 4676
4678 4677
4679 4678 static int
4680 4679 usb_ac_ctrl_set_defaults(usb_ac_state_t *statep)
4681 4680 {
4682 4681 usb_audio_ctrl_t *ctrlp;
4683 4682 int rv = USB_SUCCESS;
4684 4683 USB_DPRINTF_L4(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
4685 4684 "usb_ac_ctrl_set_defaults:begin");
4686 4685
4687 4686 for (int i = 0; i < CTL_NUM; i++) {
4688 4687 ctrlp = statep->controls[i];
4689 4688 if (!ctrlp) {
4690 4689 continue;
4691 4690 }
4692 4691 if (audio_control_write(ctrlp->af_ctrlp, ctrlp->cval)) {
4693 4692 USB_DPRINTF_L2(PRINT_MASK_ATTA,
4694 4693 statep->usb_ac_log_handle,
4695 4694 "usb_ac_ctrl_set_defaults:control write failed");
4696 4695 rv = USB_FAILURE;
4697 4696 }
4698 4697
4699 4698 }
4700 4699 USB_DPRINTF_L4(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
4701 4700 "usb_ac_ctrl_set_defaults:end");
4702 4701 return (rv);
4703 4702 }
4704 4703
4705 4704
4706 4705 static int
4707 4706 usb_ac_ctrl_restore(usb_ac_state_t *statep)
4708 4707 {
4709 4708 usb_audio_ctrl_t *ctrlp;
4710 4709 int rv = USB_SUCCESS;
4711 4710
4712 4711 for (int i = 0; i < CTL_NUM; i++) {
4713 4712 ctrlp = statep->controls[i];
4714 4713 if (ctrlp) {
4715 4714 USB_DPRINTF_L3(PRINT_MASK_ATTA,
4716 4715 statep->usb_ac_log_handle,
4717 4716 "usb_ac_ctrl_restore:i = %d", i);
4718 4717 if (audio_control_write(ctrlp->af_ctrlp, ctrlp->cval)) {
4719 4718 rv = USB_FAILURE;
4720 4719 }
4721 4720 }
4722 4721 }
4723 4722 return (rv);
4724 4723 }
4725 4724
4726 4725
4727 4726
4728 4727
4729 4728 /*
4730 4729 * moves data between driver buffer and framework/shim buffer
4731 4730 */
4732 4731 static void
4733 4732 usb_eng_bufio(usb_audio_eng_t *engp, void *buf, size_t sz)
4734 4733 {
4735 4734 size_t cpsz = sz;
4736 4735 caddr_t *src, *dst;
4737 4736
4738 4737 if (engp->af_eflags & ENGINE_OUTPUT_CAP) {
4739 4738 src = &engp->bufpos;
4740 4739 dst = (caddr_t *)&buf;
4741 4740 } else {
4742 4741 src = (caddr_t *)&buf;
4743 4742 dst = &engp->bufpos;
4744 4743 }
4745 4744
4746 4745 /*
4747 4746 * Wrap. If sz is exactly the remainder of the buffer
4748 4747 * (bufpos + sz == bufendp) then the second cpsz should be 0 and so
4749 4748 * the second memcpy() should have no effect, with bufpos updated
4750 4749 * to the head of the buffer.
4751 4750 */
4752 4751 if (engp->bufpos + sz >= engp->bufendp) {
4753 4752 cpsz = (size_t)engp->bufendp - (size_t)engp->bufpos;
4754 4753 (void) memcpy(*dst, *src, cpsz);
4755 4754
4756 4755
4757 4756 buf = (caddr_t)buf + cpsz;
4758 4757 engp->bufpos = engp->bufp;
4759 4758 cpsz = sz - cpsz;
4760 4759 }
4761 4760
4762 4761 if (cpsz) {
4763 4762 (void) memcpy(*dst, *src, cpsz);
4764 4763
4765 4764
4766 4765 engp->bufpos += cpsz;
4767 4766 }
4768 4767 engp->bufio_count++;
4769 4768 }
4770 4769
4771 4770
4772 4771 /*
4773 4772 * control read callback
4774 4773 */
4775 4774 static int
4776 4775 usb_audio_ctrl_read(void *arg, uint64_t *cvalp)
4777 4776 {
4778 4777 usb_audio_ctrl_t *ctrlp = arg;
4779 4778
4780 4779 mutex_enter(&ctrlp->ctrl_mutex);
4781 4780 *cvalp = ctrlp->cval;
4782 4781 mutex_exit(&ctrlp->ctrl_mutex);
4783 4782
4784 4783 return (0);
4785 4784 }
4786 4785
4787 4786
4788 4787 /*
4789 4788 * stereo level control callback
4790 4789 */
4791 4790 static int
4792 4791 usb_audio_write_stero_rec(void *arg, uint64_t cval)
4793 4792 {
4794 4793 usb_audio_ctrl_t *ctrlp = arg;
4795 4794 usb_ac_state_t *statep = ctrlp->statep;
4796 4795 int rv = EIO;
4797 4796 int left, right;
4798 4797 uint_t count = 0;
4799 4798
4800 4799
4801 4800 left = AUDIO_CTRL_STEREO_LEFT(cval);
4802 4801 right = AUDIO_CTRL_STEREO_RIGHT(cval);
4803 4802
4804 4803 if (left < AF_MIN_GAIN || left > AF_MAX_GAIN ||
4805 4804 right < AF_MIN_GAIN || right > AF_MAX_GAIN) {
4806 4805
4807 4806 return (EINVAL);
4808 4807 }
4809 4808
4810 4809 mutex_enter(&ctrlp->ctrl_mutex);
4811 4810 ctrlp->cval = cval;
4812 4811 mutex_exit(&ctrlp->ctrl_mutex);
4813 4812
4814 4813 mutex_enter(&statep->usb_ac_mutex);
4815 4814 (void) usb_ac_set_control(statep, USB_AUDIO_RECORD,
4816 4815 USB_AUDIO_FEATURE_UNIT, 1,
4817 4816 USB_AUDIO_VOLUME_CONTROL,
4818 4817 USB_AC_FIND_ALL, &count, left, usb_ac_set_gain);
4819 4818
4820 4819 (void) usb_ac_set_control(statep, USB_AUDIO_RECORD,
4821 4820 USB_AUDIO_FEATURE_UNIT, 2,
4822 4821 USB_AUDIO_VOLUME_CONTROL,
4823 4822 USB_AC_FIND_ALL, &count, right, usb_ac_set_gain);
4824 4823 rv = 0;
4825 4824
4826 4825 done:
4827 4826 mutex_exit(&statep->usb_ac_mutex);
4828 4827 return (rv);
4829 4828 }
4830 4829
4831 4830 static int
4832 4831 usb_audio_write_ster_vol(void *arg, uint64_t cval)
4833 4832 {
4834 4833 usb_audio_ctrl_t *ctrlp = arg;
4835 4834 usb_ac_state_t *statep = ctrlp->statep;
4836 4835 int rv = EIO;
4837 4836 int left, right;
4838 4837 uint_t count = 0;
4839 4838
4840 4839 left = AUDIO_CTRL_STEREO_LEFT(cval);
4841 4840 right = AUDIO_CTRL_STEREO_RIGHT(cval);
4842 4841
4843 4842 if (left < AF_MIN_GAIN || left > AF_MAX_GAIN ||
4844 4843 right < AF_MIN_GAIN || right > AF_MAX_GAIN) {
4845 4844 return (EINVAL);
4846 4845 }
4847 4846
4848 4847 mutex_enter(&ctrlp->ctrl_mutex);
4849 4848 ctrlp->cval = cval;
4850 4849 mutex_exit(&ctrlp->ctrl_mutex);
4851 4850
4852 4851
4853 4852 mutex_enter(&statep->usb_ac_mutex);
4854 4853 (void) usb_ac_set_control(statep, USB_AUDIO_PLAY,
4855 4854 USB_AUDIO_FEATURE_UNIT, 1,
4856 4855 USB_AUDIO_VOLUME_CONTROL,
4857 4856 USB_AC_FIND_ALL, &count, left, usb_ac_set_gain);
4858 4857
4859 4858 (void) usb_ac_set_control(statep, USB_AUDIO_PLAY,
4860 4859 USB_AUDIO_FEATURE_UNIT, 2,
4861 4860 USB_AUDIO_VOLUME_CONTROL,
4862 4861 USB_AC_FIND_ALL, &count, right, usb_ac_set_gain);
4863 4862 rv = 0;
4864 4863
4865 4864 OUT:
4866 4865 mutex_exit(&statep->usb_ac_mutex);
4867 4866 return (rv);
4868 4867 }
4869 4868
4870 4869
4871 4870 /*
4872 4871 * mono level control callback
4873 4872 */
4874 4873 static int
4875 4874 usb_audio_write_mono_vol(void *arg, uint64_t cval)
4876 4875 {
4877 4876 usb_audio_ctrl_t *ctrlp = arg;
4878 4877 usb_ac_state_t *statep = ctrlp->statep;
4879 4878 int rv = EIO;
4880 4879 int gain;
4881 4880
4882 4881 uint_t count = 0;
4883 4882
4884 4883 if (cval < (uint64_t)AF_MIN_GAIN || cval > (uint64_t)AF_MAX_GAIN) {
4885 4884 return (EINVAL);
4886 4885 }
4887 4886
4888 4887 mutex_enter(&ctrlp->ctrl_mutex);
4889 4888 ctrlp->cval = cval;
4890 4889 mutex_exit(&ctrlp->ctrl_mutex);
4891 4890
4892 4891 gain = (int)(cval);
4893 4892
4894 4893 mutex_enter(&statep->usb_ac_mutex);
4895 4894 (void) usb_ac_set_control(statep, USB_AUDIO_PLAY,
4896 4895 USB_AUDIO_FEATURE_UNIT, 1,
4897 4896 USB_AUDIO_VOLUME_CONTROL,
4898 4897 USB_AC_FIND_ALL, &count, gain, usb_ac_set_gain);
4899 4898
4900 4899 rv = 0;
4901 4900 OUT:
4902 4901 mutex_exit(&statep->usb_ac_mutex);
4903 4902
4904 4903 return (rv);
4905 4904 }
4906 4905
4907 4906
4908 4907 /*
4909 4908 * mono level control callback
4910 4909 */
4911 4910 static int
4912 4911 usb_audio_write_monitor_gain(void *arg, uint64_t cval)
4913 4912 {
4914 4913 usb_audio_ctrl_t *ctrlp = arg;
4915 4914 usb_ac_state_t *statep = ctrlp->statep;
4916 4915 int rv = EIO;
4917 4916 int gain;
4918 4917 uint_t count = 0;
4919 4918
4920 4919 if (cval < (uint64_t)AF_MIN_GAIN || cval > (uint64_t)AF_MAX_GAIN) {
4921 4920
4922 4921 return (EINVAL);
4923 4922 }
4924 4923
4925 4924 mutex_enter(&ctrlp->ctrl_mutex);
4926 4925 ctrlp->cval = cval;
4927 4926 mutex_exit(&ctrlp->ctrl_mutex);
4928 4927
4929 4928 gain = (int)(cval);
4930 4929
4931 4930 mutex_enter(&statep->usb_ac_mutex);
4932 4931 (void) usb_ac_set_monitor_gain_control(statep, USB_AUDIO_RECORD,
4933 4932 USB_AUDIO_INPUT_TERMINAL, 1,
4934 4933 USB_AUDIO_VOLUME_CONTROL,
4935 4934 USB_AC_FIND_ALL, &count, gain,
4936 4935 usb_ac_set_monitor_gain);
4937 4936
4938 4937 rv = 0;
4939 4938 OUT:
4940 4939 mutex_exit(&statep->usb_ac_mutex);
4941 4940 return (rv);
4942 4941 }
4943 4942
4944 4943 static int
4945 4944 usb_audio_write_mono_rec(void *arg, uint64_t cval)
4946 4945 {
4947 4946 usb_audio_ctrl_t *ctrlp = arg;
4948 4947 usb_ac_state_t *statep = ctrlp->statep;
4949 4948 int rv = EIO;
4950 4949 int gain;
4951 4950
4952 4951 uint_t count = 0;
4953 4952
4954 4953 if (cval < (uint64_t)AF_MIN_GAIN || cval > (uint64_t)AF_MAX_GAIN) {
4955 4954
4956 4955 return (EINVAL);
4957 4956 }
4958 4957
4959 4958 mutex_enter(&ctrlp->ctrl_mutex);
4960 4959 ctrlp->cval = cval;
4961 4960 mutex_exit(&ctrlp->ctrl_mutex);
4962 4961
4963 4962 gain = (int)(cval);
4964 4963
4965 4964 mutex_enter(&statep->usb_ac_mutex);
4966 4965 (void) usb_ac_set_control(statep, USB_AUDIO_RECORD,
4967 4966 USB_AUDIO_FEATURE_UNIT, 1,
4968 4967 USB_AUDIO_VOLUME_CONTROL,
4969 4968 USB_AC_FIND_ALL, &count, gain, usb_ac_set_gain);
4970 4969
4971 4970 rv = 0;
4972 4971
4973 4972 mutex_exit(&statep->usb_ac_mutex);
4974 4973 return (rv);
4975 4974 }
4976 4975
4977 4976 static int
4978 4977 usb_audio_write_mic_boost(void *arg, uint64_t cval)
4979 4978 {
4980 4979 usb_audio_ctrl_t *ctrlp = arg;
4981 4980
4982 4981 mutex_enter(&ctrlp->ctrl_mutex);
4983 4982 ctrlp->cval = cval;
4984 4983 mutex_exit(&ctrlp->ctrl_mutex);
4985 4984 /* do nothing here */
4986 4985 return (0);
4987 4986 }
4988 4987
4989 4988 static int
4990 4989 usb_audio_write_rec_src(void *arg, uint64_t cval)
4991 4990 {
4992 4991 usb_audio_ctrl_t *ctrlp = arg;
4993 4992 usb_ac_state_t *statep = ctrlp->statep;
4994 4993 int rv = 0;
4995 4994
4996 4995 if (cval & ~(statep->usb_ac_input_ports))
4997 4996 return (EINVAL);
4998 4997
4999 4998 mutex_enter(&ctrlp->ctrl_mutex);
5000 4999 ctrlp->cval = cval;
5001 5000 mutex_exit(&ctrlp->ctrl_mutex);
5002 5001
5003 5002 mutex_enter(&statep->usb_ac_mutex);
5004 5003 if (usb_ac_set_port(statep, USB_AUDIO_RECORD, cval) != USB_SUCCESS) {
5005 5004
5006 5005 USB_DPRINTF_L2(PRINT_MASK_ALL, statep->usb_ac_log_handle,
5007 5006 "usb_audio_write_rec_src: failed");
5008 5007 rv = EINVAL;
5009 5008 }
5010 5009 mutex_exit(&statep->usb_ac_mutex);
5011 5010 rv = 0;
5012 5011
5013 5012 OUT:
5014 5013 return (rv);
5015 5014
5016 5015 }
5017 5016
5018 5017
5019 5018 int
5020 5019 usb_audio_set_mute(usb_ac_state_t *statep, uint64_t cval)
5021 5020 {
5022 5021 short muteval;
5023 5022 int rval;
5024 5023
5025 5024 uint_t count;
5026 5025 muteval = (cval == 0) ? USB_AUDIO_MUTE_ON : USB_AUDIO_MUTE_OFF;
5027 5026 count = 0;
5028 5027 /* only support AUDIO_PLAY */
5029 5028
5030 5029 mutex_enter(&statep->usb_ac_mutex);
5031 5030 (void) usb_ac_set_control(statep, USB_AUDIO_PLAY,
5032 5031 USB_AUDIO_FEATURE_UNIT, 0,
5033 5032 USB_AUDIO_MUTE_CONTROL,
5034 5033 USB_AC_FIND_ALL, &count, muteval,
5035 5034 usb_ac_set_mute);
5036 5035 mutex_exit(&statep->usb_ac_mutex);
5037 5036
5038 5037 rval = (count == 0) ? USB_SUCCESS : USB_FAILURE;
5039 5038
5040 5039 return (rval);
5041 5040 }
5042 5041
5043 5042
5044 5043 /*
5045 5044 * port selection control callback
5046 5045 */
5047 5046 /*
5048 5047 * audio control registration related routines
5049 5048 */
5050 5049
5051 5050 static usb_audio_ctrl_t *
5052 5051 usb_audio_ctrl_alloc(usb_ac_state_t *statep, uint32_t num, uint64_t val)
5053 5052 {
5054 5053 audio_ctrl_desc_t desc;
5055 5054 audio_ctrl_wr_t fn;
5056 5055 usb_audio_ctrl_t *pc;
5057 5056
5058 5057 pc = kmem_zalloc(sizeof (usb_audio_ctrl_t), KM_SLEEP);
5059 5058
5060 5059 mutex_init(&pc->ctrl_mutex, NULL, MUTEX_DRIVER, NULL);
5061 5060
5062 5061 bzero(&desc, sizeof (desc));
5063 5062
5064 5063 switch (num) {
5065 5064 case CTL_VOLUME_MONO:
5066 5065 desc.acd_name = AUDIO_CTRL_ID_VOLUME;
5067 5066 desc.acd_type = AUDIO_CTRL_TYPE_MONO;
5068 5067 desc.acd_minvalue = 0;
5069 5068 desc.acd_maxvalue = AF_MAX_GAIN;
5070 5069 desc.acd_flags = AUDIO_CTRL_FLAG_MAINVOL | AUDIO_CTRL_FLAG_RW
5071 5070 | AUDIO_CTRL_FLAG_PLAY | AUDIO_CTRL_FLAG_POLL;
5072 5071 fn = usb_audio_write_mono_vol;
5073 5072 break;
5074 5073
5075 5074 case CTL_VOLUME_STERO:
5076 5075 desc.acd_name = AUDIO_CTRL_ID_VOLUME;
5077 5076 desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
5078 5077 desc.acd_minvalue = 0;
5079 5078 desc.acd_maxvalue = AF_MAX_GAIN;
5080 5079 desc.acd_flags = AUDIO_CTRL_FLAG_MAINVOL | AUDIO_CTRL_FLAG_RW
5081 5080 | AUDIO_CTRL_FLAG_PLAY | AUDIO_CTRL_FLAG_POLL;
5082 5081 fn = usb_audio_write_ster_vol;
5083 5082
5084 5083 break;
5085 5084
5086 5085 case CTL_REC_MONO:
5087 5086 desc.acd_name = AUDIO_CTRL_ID_RECGAIN;
5088 5087 desc.acd_type = AUDIO_CTRL_TYPE_MONO;
5089 5088 desc.acd_minvalue = 0;
5090 5089 desc.acd_maxvalue = AF_MAX_GAIN;
5091 5090 desc.acd_flags = AUDIO_CTRL_FLAG_RECVOL|AUDIO_CTRL_FLAG_REC
5092 5091 | AUDIO_CTRL_FLAG_RW;
5093 5092 fn = usb_audio_write_mono_rec;
5094 5093 break;
5095 5094 case CTL_REC_STERO:
5096 5095
5097 5096 desc.acd_name = AUDIO_CTRL_ID_RECGAIN;
5098 5097 desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
5099 5098 desc.acd_minvalue = 0;
5100 5099 desc.acd_maxvalue = AF_MAX_GAIN;
5101 5100 desc.acd_flags = AUDIO_CTRL_FLAG_RECVOL|AUDIO_CTRL_FLAG_REC
5102 5101 | AUDIO_CTRL_FLAG_RW;
5103 5102 fn = usb_audio_write_stero_rec;
5104 5103 break;
5105 5104
5106 5105 case CTL_MONITOR_GAIN:
5107 5106
5108 5107 desc.acd_name = AUDIO_CTRL_ID_MONGAIN;
5109 5108 desc.acd_type = AUDIO_CTRL_TYPE_MONO;
5110 5109 desc.acd_minvalue = 0;
5111 5110 desc.acd_maxvalue = AF_MAX_GAIN;
5112 5111 desc.acd_flags = AUDIO_CTRL_FLAG_MONVOL |AUDIO_CTRL_FLAG_MONITOR
5113 5112 |AUDIO_CTRL_FLAG_RW;
5114 5113 fn = usb_audio_write_monitor_gain;
5115 5114 break;
5116 5115
5117 5116 case CTL_MIC_BOOST:
5118 5117
5119 5118 desc.acd_name = AUDIO_CTRL_ID_MICBOOST;
5120 5119 desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
5121 5120 desc.acd_minvalue = 0;
5122 5121 desc.acd_maxvalue = 1;
5123 5122 desc.acd_flags = AUDIO_CTRL_FLAG_RW;
5124 5123 fn = usb_audio_write_mic_boost;
5125 5124 break;
5126 5125 case CTL_REC_SRC:
5127 5126
5128 5127 desc.acd_name = AUDIO_CTRL_ID_RECSRC;
5129 5128 desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
5130 5129 desc.acd_minvalue = statep->usb_ac_input_ports;
5131 5130 desc.acd_maxvalue = statep->usb_ac_input_ports;
5132 5131 desc.acd_flags = AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC;
5133 5132 for (int i = 0; usb_audio_dtypes[i]; i++) {
5134 5133 desc.acd_enum[i] = usb_audio_dtypes[i];
5135 5134 }
5136 5135
5137 5136 fn = usb_audio_write_rec_src;
5138 5137 break;
5139 5138
5140 5139
5141 5140
5142 5141 default:
5143 5142
5144 5143 break;
5145 5144 }
5146 5145
5147 5146 mutex_enter(&pc->ctrl_mutex);
5148 5147
5149 5148 pc->statep = statep;
5150 5149 pc->cval = val;
5151 5150 pc->af_ctrlp = audio_dev_add_control(statep->usb_ac_audio_dev, &desc,
5152 5151 usb_audio_ctrl_read, fn, pc);
5153 5152
5154 5153 mutex_exit(&pc->ctrl_mutex);
5155 5154
5156 5155 mutex_enter(&statep->usb_ac_mutex);
5157 5156 statep->controls[num] = pc;
5158 5157 mutex_exit(&statep->usb_ac_mutex);
5159 5158
5160 5159
5161 5160 return (pc);
5162 5161 }
5163 5162
5164 5163
5165 5164 static void
5166 5165 usb_audio_ctrl_free(usb_audio_ctrl_t *ctrlp)
5167 5166 {
5168 5167 kmem_free(ctrlp, sizeof (usb_audio_ctrl_t));
5169 5168 }
5170 5169
5171 5170 static void
5172 5171 usb_ac_rem_controls(usb_ac_state_t *statep)
5173 5172 {
5174 5173 usb_audio_ctrl_t *ctrlp;
5175 5174
5176 5175 for (int i = 0; i < CTL_NUM; i++) {
5177 5176 ctrlp = statep->controls[i];
5178 5177 if (ctrlp) {
5179 5178 if (ctrlp->af_ctrlp != NULL)
5180 5179 audio_dev_del_control(ctrlp->af_ctrlp);
5181 5180
5182 5181 usb_audio_ctrl_free(ctrlp);
5183 5182 mutex_enter(&statep->usb_ac_mutex);
5184 5183 statep->controls[i] = NULL;
5185 5184 mutex_exit(&statep->usb_ac_mutex);
5186 5185 }
5187 5186 }
5188 5187
5189 5188 }
5190 5189
5191 5190
5192 5191 static int
5193 5192 usb_ac_add_controls(usb_ac_state_t *statep)
5194 5193 {
5195 5194 int rv = USB_FAILURE;
5196 5195 usb_audio_format_t *format;
5197 5196
5198 5197
5199 5198 if (statep->engines[0].af_engp) {
5200 5199 /* Init controls for play format */
5201 5200 format = &(statep->engines[0].fmt);
5202 5201 if (format->ch == 2) {
5203 5202 (void) usb_audio_ctrl_alloc(statep, CTL_VOLUME_STERO,
5204 5203 statep->engines[0].af_defgain);
5205 5204 } else {
5206 5205 (void) usb_audio_ctrl_alloc(statep, CTL_VOLUME_MONO,
5207 5206 statep->engines[0].af_defgain);
5208 5207 }
5209 5208
5210 5209 }
5211 5210
5212 5211 /* Init controls for rec format */
5213 5212 if (statep->engines[1].af_engp) {
5214 5213 format = &(statep->engines[1].fmt);
5215 5214 if (format->ch == 2) {
5216 5215 (void) usb_audio_ctrl_alloc(statep, CTL_REC_STERO,
5217 5216 statep->engines[1].af_defgain);
5218 5217 } else {
5219 5218 (void) usb_audio_ctrl_alloc(statep, CTL_REC_MONO,
5220 5219 statep->engines[1].af_defgain);
5221 5220 }
5222 5221
5223 5222 /* Add monitor control */
5224 5223 {
5225 5224 (void) usb_audio_ctrl_alloc(statep,
5226 5225 CTL_MONITOR_GAIN, 0);
5227 5226 }
5228 5227
5229 5228 /* Add ports control */
5230 5229 {
5231 5230 (void) usb_audio_ctrl_alloc(statep, CTL_REC_SRC,
5232 5231 statep->usb_ac_input_ports);
5233 5232 }
5234 5233
5235 5234 }
5236 5235
5237 5236
5238 5237 rv = USB_SUCCESS;
5239 5238
5240 5239 OUT:
5241 5240 if (rv != USB_SUCCESS)
5242 5241 usb_ac_rem_controls(statep);
5243 5242 return (rv);
5244 5243 }
5245 5244
5246 5245
5247 5246
5248 5247
5249 5248
5250 5249 /*ARGSUSED*/
5251 5250 static int
5252 5251 usb_audio_unregister(usb_ac_state_t *statep)
5253 5252 {
5254 5253 int i;
5255 5254
5256 5255 if (statep == NULL)
5257 5256 return (USB_SUCCESS);
5258 5257
5259 5258 if (statep->usb_ac_audio_dev == NULL)
5260 5259 return (USB_SUCCESS);
5261 5260
5262 5261 if ((statep->flags & AF_REGISTERED) &&
5263 5262 audio_dev_unregister(statep->usb_ac_audio_dev) != DDI_SUCCESS) {
5264 5263 return (USB_FAILURE);
5265 5264 }
5266 5265 mutex_enter(&statep->usb_ac_mutex);
5267 5266 statep->flags &= ~AF_REGISTERED;
5268 5267 mutex_exit(&statep->usb_ac_mutex);
5269 5268
5270 5269 for (i = 0; i < USB_AC_ENG_MAX; i++)
5271 5270 usb_ac_rem_eng(statep, &statep->engines[i]);
5272 5271
5273 5272 usb_ac_rem_controls(statep);
5274 5273
5275 5274 audio_dev_free(statep->usb_ac_audio_dev);
5276 5275
5277 5276 mutex_enter(&statep->usb_ac_mutex);
5278 5277 statep->usb_ac_audio_dev = NULL;
5279 5278 mutex_exit(&statep->usb_ac_mutex);
5280 5279
5281 5280 return (USB_SUCCESS);
5282 5281 }
5283 5282
5284 5283
5285 5284 static int
5286 5285 usb_audio_register(usb_ac_state_t *statep) {
5287 5286 audio_dev_t *af_devp;
5288 5287 int rv = USB_FAILURE;
5289 5288 int n;
5290 5289
5291 5290 af_devp = audio_dev_alloc(statep->usb_ac_dip, 0);
5292 5291 audio_dev_set_description(af_devp, "USB Audio");
5293 5292 audio_dev_set_version(af_devp, "1.0");
5294 5293
5295 5294 mutex_enter(&statep->usb_ac_mutex);
5296 5295 statep->usb_ac_audio_dev = af_devp;
5297 5296 mutex_exit(&statep->usb_ac_mutex);
5298 5297
5299 5298
5300 5299 for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) {
5301 5300 if (usb_ac_add_eng(statep, &(statep->usb_ac_streams[n]))
5302 5301 != USB_SUCCESS) {
5303 5302 USB_DPRINTF_L2(PRINT_MASK_ATTA,
5304 5303 statep->usb_ac_log_handle,
5305 5304 "usb_audio_register: add engine n =%d failed", n);
5306 5305 goto OUT;
5307 5306 }
5308 5307 }
5309 5308
5310 5309
5311 5310 if (usb_ac_add_controls(statep) != USB_SUCCESS) {
5312 5311 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5313 5312 "usb_audio_register: add controls failed");
5314 5313 goto OUT;
5315 5314 }
5316 5315
5317 5316 if (usb_ac_ctrl_set_defaults(statep) != USB_SUCCESS) {
5318 5317 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5319 5318 "usb_audio_register: set defaults failed");
5320 5319 goto OUT;
5321 5320 }
5322 5321
5323 5322 if (audio_dev_register(af_devp) != DDI_SUCCESS) {
5324 5323 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5325 5324 "audio_dev_register() failed");
5326 5325 goto OUT;
5327 5326 }
5328 5327 mutex_enter(&statep->usb_ac_mutex);
5329 5328 statep->flags |= AF_REGISTERED;
5330 5329 mutex_exit(&statep->usb_ac_mutex);
5331 5330
5332 5331 rv = USB_SUCCESS;
5333 5332
5334 5333 OUT:
5335 5334 if (rv != USB_SUCCESS) {
5336 5335 (void) usb_audio_unregister(statep);
5337 5336 }
5338 5337 return (rv);
5339 5338 }
5340 5339
5341 5340
5342 5341 int
5343 5342 usb_ac_get_audio(void *handle, void *buf, int samples)
5344 5343 {
5345 5344 usb_ac_state_t *statep = (usb_ac_state_t *)(handle);
5346 5345 usb_audio_eng_t *engp = &(statep->engines[0]);
5347 5346 unsigned reqframes = samples >> engp->frsmshift;
5348 5347 unsigned frames;
5349 5348 unsigned i;
5350 5349 size_t sz;
5351 5350 caddr_t bp = buf;
5352 5351
5353 5352 mutex_enter(&engp->lock);
5354 5353 if (!engp->started) {
5355 5354 mutex_exit(&engp->lock);
5356 5355
5357 5356 return (0);
5358 5357 }
5359 5358 engp->busy = B_TRUE;
5360 5359 mutex_exit(&engp->lock);
5361 5360
5362 5361 /* break requests from the driver into fragment sized chunks */
5363 5362 for (i = 0; i < reqframes; i += frames) {
5364 5363
5365 5364 mutex_enter(&engp->lock);
5366 5365 frames = reqframes - i;
5367 5366 if (frames > engp->fragfr)
5368 5367 frames = engp->fragfr;
5369 5368
5370 5369 sz = (frames << engp->frsmshift) << engp->smszshift;
5371 5370
5372 5371 /* must move data before updating framework */
5373 5372 usb_eng_bufio(engp, bp, sz);
5374 5373 engp->frames += frames;
5375 5374 bp += sz;
5376 5375
5377 5376 mutex_exit(&engp->lock);
5378 5377 }
5379 5378
5380 5379 mutex_enter(&engp->lock);
5381 5380 engp->io_count++;
5382 5381 engp->busy = B_FALSE;
5383 5382 cv_signal(&engp->usb_audio_cv);
5384 5383 mutex_exit(&engp->lock);
5385 5384
5386 5385 return (samples);
5387 5386 }
5388 5387
5389 5388
5390 5389
5391 5390 void
5392 5391 usb_ac_send_audio(void *handle, void *buf, int samples)
5393 5392 {
5394 5393 usb_ac_state_t *statep = (usb_ac_state_t *)(handle);
5395 5394 usb_audio_eng_t *engp = &(statep->engines[1]);
5396 5395 unsigned reqframes = samples >> engp->frsmshift;
5397 5396 unsigned frames;
5398 5397 unsigned i;
5399 5398 size_t sz;
5400 5399 caddr_t bp = buf;
5401 5400
5402 5401 mutex_enter(&engp->lock);
5403 5402
5404 5403 if (!engp->started) {
5405 5404
5406 5405 mutex_exit(&engp->lock);
5407 5406 return;
5408 5407 }
5409 5408 engp->busy = B_TRUE;
5410 5409 mutex_exit(&engp->lock);
5411 5410
5412 5411 /* break requests from the driver into fragment sized chunks */
5413 5412 for (i = 0; i < reqframes; i += frames) {
5414 5413 mutex_enter(&engp->lock);
5415 5414
5416 5415 frames = reqframes - i;
5417 5416 if (frames > engp->fragfr)
5418 5417 frames = engp->fragfr;
5419 5418
5420 5419 sz = (frames << engp->frsmshift) << engp->smszshift;
5421 5420
5422 5421 /* must move data before updating framework */
5423 5422 usb_eng_bufio(engp, bp, sz);
5424 5423 engp->frames += frames;
5425 5424 bp += sz;
5426 5425
5427 5426 mutex_exit(&engp->lock);
5428 5427 }
5429 5428
5430 5429 mutex_enter(&engp->lock);
5431 5430 engp->io_count++;
5432 5431 engp->busy = B_FALSE;
5433 5432 cv_signal(&engp->usb_audio_cv);
5434 5433 mutex_exit(&engp->lock);
5435 5434 }
5436 5435
5437 5436
5438 5437 /*
5439 5438 * **************************************************************************
5440 5439 * audio framework engine callbacks
5441 5440 */
5442 5441 static int
5443 5442 usb_engine_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
5444 5443 {
5445 5444 usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5446 5445 usb_ac_state_t *statep = engp->statep;
5447 5446 int rv = EIO;
5448 5447
5449 5448 _NOTE(ARGUNUSED(flag));
5450 5449
5451 5450 if (usb_ac_open(statep->usb_ac_dip) != USB_SUCCESS) {
5452 5451
5453 5452 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5454 5453 "usb_ac_open() failed");
5455 5454 return (EIO);
5456 5455 }
5457 5456
5458 5457 mutex_enter(&engp->lock);
5459 5458
5460 5459 engp->intrate = 150;
5461 5460 engp->sampsz = engp->fmt.prec / 8;
5462 5461 engp->framesz = engp->sampsz * engp->fmt.ch;
5463 5462
5464 5463 engp->frsmshift = engp->fmt.ch / 2;
5465 5464 engp->smszshift = engp->sampsz / 2;
5466 5465
5467 5466 /*
5468 5467 * In order to match the requested number of samples per interrupt
5469 5468 * from SADA drivers when computing the fragment size,
5470 5469 * we need to first truncate the floating point result from
5471 5470 * sample rate * channels / intr rate
5472 5471 * then adjust up to an even number, before multiplying it
5473 5472 * with the sample size
5474 5473 */
5475 5474 engp->fragsz = engp->fmt.sr * engp->fmt.ch / engp->intrate;
5476 5475 if (engp->fragsz & 1)
5477 5476 engp->fragsz++;
5478 5477 engp->fragsz *= engp->sampsz;
5479 5478 engp->fragfr = engp->fragsz / engp->framesz;
5480 5479
5481 5480 engp->nfrags = 10;
5482 5481 engp->bufsz = engp->fragsz * engp->nfrags;
5483 5482
5484 5483 engp->bufp = kmem_zalloc(engp->bufsz, KM_SLEEP);
5485 5484 engp->bufpos = engp->bufp;
5486 5485 engp->bufendp = engp->bufp + engp->bufsz;
5487 5486 engp->frames = 0;
5488 5487 engp->io_count = 0;
5489 5488 engp->bufio_count = 0;
5490 5489 engp->started = B_FALSE;
5491 5490 engp->busy = B_FALSE;
5492 5491
5493 5492 *nframesp = engp->nfrags * engp->fragfr;
5494 5493 *bufp = engp->bufp;
5495 5494
5496 5495 mutex_exit(&engp->lock);
5497 5496
5498 5497 if (usb_ac_setup(statep, engp) != USB_SUCCESS) {
5499 5498 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5500 5499 "device setup failed");
5501 5500 goto OUT;
5502 5501 }
5503 5502
5504 5503
5505 5504
5506 5505 mutex_enter(&statep->usb_ac_mutex);
5507 5506 statep->flags |= AD_SETUP;
5508 5507 mutex_exit(&statep->usb_ac_mutex);
5509 5508
5510 5509 rv = 0;
5511 5510
5512 5511
5513 5512 OUT:
5514 5513 if (rv != 0)
5515 5514 usb_engine_close(arg);
5516 5515
5517 5516 return (rv);
5518 5517 }
5519 5518
5520 5519
5521 5520 static void
5522 5521 usb_engine_close(void *arg)
5523 5522 {
5524 5523 usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5525 5524 usb_ac_state_t *statep = engp->statep;
5526 5525
5527 5526 mutex_enter(&engp->lock);
5528 5527 while (engp->busy) {
5529 5528 cv_wait(&engp->usb_audio_cv, &engp->lock);
5530 5529 }
5531 5530
5532 5531 mutex_exit(&engp->lock);
5533 5532
5534 5533 if (statep->flags & AD_SETUP) {
5535 5534 usb_ac_teardown(statep, engp);
5536 5535 mutex_enter(&statep->usb_ac_mutex);
5537 5536 statep->flags &= ~AD_SETUP;
5538 5537 mutex_exit(&statep->usb_ac_mutex);
5539 5538 }
5540 5539 mutex_enter(&engp->lock);
5541 5540
5542 5541 if (engp->bufp != NULL) {
5543 5542 kmem_free(engp->bufp, engp->bufsz);
5544 5543 engp->bufp = NULL;
5545 5544 engp->bufpos = NULL;
5546 5545 engp->bufendp = NULL;
5547 5546 }
5548 5547
5549 5548 mutex_exit(&engp->lock);
5550 5549
5551 5550 usb_ac_close(statep->usb_ac_dip);
5552 5551 }
5553 5552
5554 5553
5555 5554
5556 5555 static int
5557 5556 usb_engine_start(void *arg)
5558 5557 {
5559 5558 usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5560 5559 int rv = 0;
5561 5560 int (*start)(usb_ac_state_t *, usb_audio_eng_t *);
5562 5561
5563 5562 mutex_enter(&engp->lock);
5564 5563 engp->started = B_TRUE;
5565 5564 mutex_exit(&engp->lock);
5566 5565
5567 5566 usb_ac_state_t *statep = engp->statep;
5568 5567
5569 5568 start = ((engp)->af_eflags & ENGINE_OUTPUT_CAP) ?
5570 5569 usb_ac_start_play : usb_ac_start_record;
5571 5570
5572 5571 if ((*start)(statep, engp) != USB_SUCCESS) {
5573 5572 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5574 5573 "failed to start %d engine", engp->af_eflags);
5575 5574 rv = EIO;
5576 5575 }
5577 5576
5578 5577
5579 5578 return (rv);
5580 5579 }
5581 5580
5582 5581
5583 5582 static void
5584 5583 usb_engine_stop(void *arg)
5585 5584 {
5586 5585 usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5587 5586
5588 5587 mutex_enter(&engp->lock);
5589 5588 engp->started = B_FALSE;
5590 5589 mutex_exit(&engp->lock);
5591 5590
5592 5591 usb_ac_state_t *statep = engp->statep;
5593 5592 void (*stop)(usb_ac_state_t *, usb_audio_eng_t *);
5594 5593
5595 5594 stop = ((engp)->af_eflags & ENGINE_OUTPUT_CAP) ?
5596 5595 usb_ac_stop_play : usb_ac_stop_record;
5597 5596
5598 5597 (*stop)(statep, engp);
5599 5598 }
5600 5599
5601 5600
5602 5601 static uint64_t
5603 5602 usb_engine_count(void *arg)
5604 5603 {
5605 5604 usb_audio_eng_t *engp = arg;
5606 5605 uint64_t val;
5607 5606
5608 5607 mutex_enter(&engp->lock);
5609 5608 val = engp->frames;
5610 5609 mutex_exit(&engp->lock);
5611 5610
5612 5611 return (val);
5613 5612 }
5614 5613
5615 5614
5616 5615 static int
5617 5616 usb_engine_format(void *arg)
5618 5617 {
5619 5618 usb_audio_eng_t *engp = arg;
5620 5619
5621 5620 switch (engp->fmt.enc) {
5622 5621 case USB_AUDIO_FORMAT_TYPE1_MULAW:
5623 5622 return (AUDIO_FORMAT_ULAW);
5624 5623 case USB_AUDIO_FORMAT_TYPE1_ALAW:
5625 5624 return (AUDIO_FORMAT_ALAW);
5626 5625 case USB_AUDIO_FORMAT_TYPE1_PCM8:
5627 5626 return (AUDIO_FORMAT_U8);
5628 5627
5629 5628 case USB_AUDIO_FORMAT_TYPE1_PCM:
5630 5629 break;
5631 5630 default:
5632 5631 return (AUDIO_FORMAT_NONE);
5633 5632 }
5634 5633
5635 5634 switch (engp->fmt.prec) {
5636 5635 case USB_AUDIO_PRECISION_8:
5637 5636 return (AUDIO_FORMAT_S8);
5638 5637 case USB_AUDIO_PRECISION_16:
5639 5638 return (AUDIO_FORMAT_S16_LE);
5640 5639 case USB_AUDIO_PRECISION_24:
5641 5640 return (AUDIO_FORMAT_S24_LE);
5642 5641 case USB_AUDIO_PRECISION_32:
5643 5642 return (AUDIO_FORMAT_S32_LE);
5644 5643 default:
5645 5644 break;
5646 5645 }
5647 5646 return (AUDIO_FORMAT_NONE);
5648 5647
5649 5648
5650 5649 }
5651 5650
5652 5651 static int
5653 5652 usb_engine_channels(void *arg)
5654 5653 {
5655 5654 usb_audio_eng_t *engp = arg;
5656 5655
5657 5656 return (engp->fmt.ch);
5658 5657 }
5659 5658
5660 5659
5661 5660 static int
5662 5661 usb_engine_rate(void *arg)
5663 5662 {
5664 5663 usb_audio_eng_t *engp = arg;
5665 5664
5666 5665 return (engp->fmt.sr);
5667 5666 }
5668 5667
5669 5668
5670 5669 /*ARGSUSED*/
5671 5670 static void
5672 5671 usb_engine_sync(void *arg, unsigned nframes)
5673 5672 {
5674 5673 /* Do nothing */
5675 5674 }
5676 5675
5677 5676
5678 5677 static unsigned
5679 5678 usb_engine_qlen(void *arg)
5680 5679 {
5681 5680 usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5682 5681
5683 5682 return (engp->fragfr);
5684 5683 }
5685 5684
5686 5685 /*
5687 5686 * **************************************************************************
5688 5687 * interfaces used by USB audio
5689 5688 */
5690 5689
5691 5690 /*ARGSUSED*/
5692 5691 static int
5693 5692 usb_change_phy_vol(usb_ac_state_t *statep, int value)
5694 5693 {
5695 5694 usb_audio_ctrl_t *ctrlp;
5696 5695 uint64_t cval = 0;
5697 5696 int64_t left, right, delta = 0;
5698 5697
5699 5698 ctrlp = statep->controls[CTL_VOLUME_STERO];
5700 5699
5701 5700 ASSERT(value != 0);
5702 5701
5703 5702 delta = (value < 0)?-1:1;
5704 5703
5705 5704 left = AUDIO_CTRL_STEREO_LEFT(ctrlp->cval) + delta;
5706 5705 right = AUDIO_CTRL_STEREO_RIGHT(ctrlp->cval) + delta;
5707 5706
5708 5707 if (left > AF_MAX_GAIN)
5709 5708 left = AF_MAX_GAIN;
5710 5709 if (right > AF_MAX_GAIN)
5711 5710 right = AF_MAX_GAIN;
5712 5711
5713 5712 if (left < AF_MIN_GAIN)
5714 5713 left = AF_MIN_GAIN;
5715 5714 if (right < AF_MIN_GAIN)
5716 5715 right = AF_MIN_GAIN;
5717 5716
5718 5717 cval = AUDIO_CTRL_STEREO_VAL(left, right);
5719 5718
5720 5719 if (audio_control_write(ctrlp->af_ctrlp, cval)) {
5721 5720 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5722 5721 "updateing control to value 0x%llx by driver failed",
5723 5722 (long long unsigned)cval);
5724 5723 return (USB_FAILURE);
5725 5724 }
5726 5725 return (USB_SUCCESS);
5727 5726 }
↓ open down ↓ |
5394 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX