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