usb_as.c revision 9484:fbd5ddc28e96
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 Streams Interface Driver: 28 * This driver is derived from the legacy SADA streams-based usb_as 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. 32 * 33 * usb_as is responsible for (1) Processing audio data messages during 34 * play and record and management of isoc pipe, (2) Selecting correct 35 * alternate that matches a set of parameters and management of control pipe. 36 * This driver is opened by usb_ac and interacts with usb_ac synchronously 37 * using ioctls. If the processing involves an async USBA command, the ioctl 38 * returns after completion of the command. 39 * 40 * Note: When there is a play/record, usb_as calls framework routines 41 * directly for data (play) or sends data to mixer (record). 42 * 43 * Serialization: A competing thread can't be allowed to interfere with 44 * (1) pipe, (2) streams state. 45 * So we need some kind of serialization among the asynchronous 46 * threads that can run in the driver. The serialization is mostly 47 * needed to avoid races among open/close/events/power entry points 48 * etc. Once a routine grabs access, if checks if the resource (pipe or 49 * stream or dev state) is still accessible. If so, it proceeds with 50 * its job and until it completes, no other thread requiring the same 51 * resource can run. 52 * 53 * PM Model in usb_as: Raise power during attach and lower power in detach. 54 * If device is not fully powered, synchronous raise power in wsrv entry points. 55 */ 56#include <sys/usb/usba/usbai_version.h> 57#include <sys/usb/usba.h> 58#include <sys/ddi.h> 59#include <sys/sunddi.h> 60 61#include <sys/audio.h> 62#include <sys/audio/audio_support.h> 63#include <sys/mixer.h> 64#include <sys/audio/audio_mixer.h> 65 66#include <sys/usb/clients/audio/usb_audio.h> 67#include <sys/usb/clients/audio/usb_mixer.h> 68#include <sys/usb/clients/audio/usb_as/usb_as.h> 69 70#include "../usb_ac/audio_shim.h" 71 72/* debug support */ 73uint_t usb_as_errlevel = USB_LOG_L4; 74uint_t usb_as_errmask = (uint_t)-1; 75uint_t usb_as_instance_debug = (uint_t)-1; 76 77/* 78 * Module linkage routines for the kernel 79 */ 80static int usb_as_attach(dev_info_t *, ddi_attach_cmd_t); 81static int usb_as_detach(dev_info_t *, ddi_detach_cmd_t); 82static int usb_as_power(dev_info_t *, int, int); 83static int usb_as_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 84 85static int usb_as_open(dev_t *, int, int, cred_t *); 86static int usb_as_close(dev_t, int, int, cred_t *); 87 88 89/* support functions */ 90static void usb_as_cleanup(dev_info_t *, usb_as_state_t *); 91 92static int usb_as_handle_descriptors(usb_as_state_t *); 93static void usb_as_prepare_registration_data(usb_as_state_t *); 94static int usb_as_valid_format(usb_as_state_t *, uint_t, 95 uint_t *, uint_t); 96static void usb_as_free_alts(usb_as_state_t *); 97static int usb_audio_fmt_convert(int); 98 99static void usb_as_create_pm_components(dev_info_t *, usb_as_state_t *); 100static int usb_as_disconnect_event_cb(dev_info_t *); 101static int usb_as_reconnect_event_cb(dev_info_t *); 102static int usb_as_cpr_suspend(dev_info_t *); 103static void usb_as_cpr_resume(dev_info_t *); 104 105static int usb_as_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 106 107static int usb_as_pwrlvl0(usb_as_state_t *); 108static int usb_as_pwrlvl1(usb_as_state_t *); 109static int usb_as_pwrlvl2(usb_as_state_t *); 110static int usb_as_pwrlvl3(usb_as_state_t *); 111static void usb_as_pm_busy_component(usb_as_state_t *); 112static void usb_as_pm_idle_component(usb_as_state_t *); 113 114static void usb_as_restore_device_state(dev_info_t *, usb_as_state_t *); 115static int usb_as_setup(usb_as_state_t *); 116static void usb_as_teardown(usb_as_state_t *); 117static int usb_as_start_play(usb_as_state_t *, usb_audio_play_req_t *); 118static void usb_as_continue_play(usb_as_state_t *); 119static void usb_as_pause_play(usb_as_state_t *); 120 121static int usb_as_set_format(usb_as_state_t *, usb_audio_formats_t *); 122static int usb_as_set_sample_freq(usb_as_state_t *, int); 123static int usb_as_send_ctrl_cmd(usb_as_state_t *, uchar_t, uchar_t, 124 ushort_t, ushort_t, ushort_t, mblk_t *, boolean_t); 125 126static int usb_as_start_record(usb_as_state_t *, audiohdl_t); 127static int usb_as_stop_record(usb_as_state_t *); 128static void usb_as_play_cb(usb_pipe_handle_t, usb_isoc_req_t *); 129static void usb_as_record_cb(usb_pipe_handle_t, usb_isoc_req_t *); 130static void usb_as_play_exc_cb(usb_pipe_handle_t, usb_isoc_req_t *); 131static void usb_as_record_exc_cb(usb_pipe_handle_t, usb_isoc_req_t *); 132static int usb_as_get_pktsize(usb_as_state_t *, usb_audio_formats_t *, 133 usb_frame_number_t); 134static void usb_as_handle_shutdown(usb_as_state_t *); 135static int usb_as_play_isoc_data(usb_as_state_t *, 136 usb_audio_play_req_t *); 137 138/* anchor for soft state structures */ 139static void *usb_as_statep; 140 141 142/* 143 * DDI Structures 144 */ 145 146/* Entry points structure */ 147static struct cb_ops usb_as_cb_ops = { 148 usb_as_open, /* cb_open */ 149 usb_as_close, /* cb_close */ 150 nodev, /* cb_strategy */ 151 nodev, /* cb_print */ 152 nodev, /* cb_dump */ 153 nodev, /* cb_read */ 154 nodev, /* cb_write */ 155 usb_as_ioctl, /* cb_ioctl */ 156 nodev, /* cb_devmap */ 157 nodev, /* cb_mmap */ 158 nodev, /* cb_segmap */ 159 nochpoll, /* cb_chpoll */ 160 ddi_prop_op, /* cb_prop_op */ 161 NULL, /* cb_str */ 162 D_MP | D_64BIT, /* cb_flag */ 163 CB_REV, /* cb_rev */ 164 nodev, /* cb_aread */ 165 nodev, /* cb_arwite */ 166}; 167 168/* Device operations structure */ 169static struct dev_ops usb_as_dev_ops = { 170 DEVO_REV, /* devo_rev */ 171 0, /* devo_refcnt */ 172 usb_as_getinfo, /* devo_getinfo */ 173 nulldev, /* devo_identify - obsolete */ 174 nulldev, /* devo_probe - not needed */ 175 usb_as_attach, /* devo_attach */ 176 usb_as_detach, /* devo_detach */ 177 nodev, /* devo_reset */ 178 &usb_as_cb_ops, /* devi_cb_ops */ 179 NULL, /* devo_busb_as_ops */ 180 usb_as_power, /* devo_power */ 181 ddi_quiesce_not_needed, /* devo_quiesce */ 182}; 183 184/* Linkage structure for loadable drivers */ 185static struct modldrv usb_as_modldrv = { 186 &mod_driverops, /* drv_modops */ 187 "USB Audio Streaming Driver", /* drv_linkinfo */ 188 &usb_as_dev_ops /* drv_dev_ops */ 189}; 190 191/* Module linkage structure */ 192static struct modlinkage usb_as_modlinkage = { 193 MODREV_1, /* ml_rev */ 194 (void *)&usb_as_modldrv, /* ml_linkage */ 195 NULL /* NULL terminates the list */ 196}; 197 198 199static usb_event_t usb_as_events = { 200 usb_as_disconnect_event_cb, 201 usb_as_reconnect_event_cb, 202 NULL, NULL 203}; 204 205/* 206 * Mixer registration Management 207 * use defaults as much as possible 208 */ 209 210/* default sample rates that must be supported */ 211static uint_t usb_as_default_srs[] = { 212 8000, 9600, 11025, 16000, 18900, 22050, 213 32000, 33075, 37800, 44100, 48000, 0 214}; 215 216 217int 218_init(void) 219{ 220 int rval; 221 222 /* initialize the soft state */ 223 if ((rval = ddi_soft_state_init(&usb_as_statep, 224 sizeof (usb_as_state_t), 1)) != DDI_SUCCESS) { 225 226 return (rval); 227 } 228 229 if ((rval = mod_install(&usb_as_modlinkage)) != 0) { 230 ddi_soft_state_fini(&usb_as_statep); 231 } 232 233 return (rval); 234} 235 236 237int 238_fini(void) 239{ 240 int rval; 241 242 if ((rval = mod_remove(&usb_as_modlinkage)) == 0) { 243 /* Free the soft state internal structures */ 244 ddi_soft_state_fini(&usb_as_statep); 245 } 246 247 return (rval); 248} 249 250 251int 252_info(struct modinfo *modinfop) 253{ 254 return (mod_info(&usb_as_modlinkage, modinfop)); 255} 256 257 258/*ARGSUSED*/ 259static int 260usb_as_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, 261 void *arg, void **result) 262{ 263 usb_as_state_t *uasp = NULL; 264 int error = DDI_FAILURE; 265 int instance = USB_AS_MINOR_TO_INSTANCE( 266 getminor((dev_t)arg)); 267 268 switch (infocmd) { 269 case DDI_INFO_DEVT2DEVINFO: 270 271 if ((uasp = ddi_get_soft_state(usb_as_statep, 272 instance)) != NULL) { 273 *result = uasp->usb_as_dip; 274 if (*result != NULL) { 275 error = DDI_SUCCESS; 276 } 277 } else { 278 *result = NULL; 279 } 280 break; 281 case DDI_INFO_DEVT2INSTANCE: 282 *result = (void *)(uintptr_t)instance; 283 error = DDI_SUCCESS; 284 break; 285 default: 286 break; 287 } 288 289 return (error); 290} 291 292 293static int 294usb_as_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 295{ 296 int instance = ddi_get_instance(dip); 297 usb_as_state_t *uasp; 298 299 switch (cmd) { 300 case DDI_ATTACH: 301 302 break; 303 case DDI_RESUME: 304 usb_as_cpr_resume(dip); 305 306 return (DDI_SUCCESS); 307 default: 308 309 return (DDI_FAILURE); 310 } 311 312 /* 313 * Allocate soft state information. 314 */ 315 if (ddi_soft_state_zalloc(usb_as_statep, instance) != DDI_SUCCESS) { 316 317 return (DDI_FAILURE); 318 } 319 320 /* 321 * get soft state space and initialize 322 */ 323 uasp = (usb_as_state_t *)ddi_get_soft_state(usb_as_statep, instance); 324 if (uasp == NULL) { 325 326 return (DDI_FAILURE); 327 } 328 329 uasp->usb_as_log_handle = usb_alloc_log_hdl(dip, "as", 330 &usb_as_errlevel, 331 &usb_as_errmask, &usb_as_instance_debug, 0); 332 333 uasp->usb_as_instance = instance; 334 uasp->usb_as_dip = dip; 335 336 (void) snprintf(uasp->dstr, sizeof (uasp->dstr), "%s#%d", 337 ddi_driver_name(dip), instance); 338 339 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) { 340 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 341 "usb_client_attach failed"); 342 343 usb_free_log_hdl(uasp->usb_as_log_handle); 344 ddi_soft_state_free(usb_as_statep, uasp->usb_as_instance); 345 346 return (DDI_FAILURE); 347 } 348 349 if (usb_get_dev_data(dip, &uasp->usb_as_dev_data, 350 USB_PARSE_LVL_IF, 0) != USB_SUCCESS) { 351 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 352 "usb_get_dev_data failed"); 353 usb_client_detach(dip, NULL); 354 usb_free_log_hdl(uasp->usb_as_log_handle); 355 ddi_soft_state_free(usb_as_statep, uasp->usb_as_instance); 356 357 return (DDI_FAILURE); 358 } 359 360 /* initialize mutex */ 361 mutex_init(&uasp->usb_as_mutex, NULL, MUTEX_DRIVER, 362 uasp->usb_as_dev_data->dev_iblock_cookie); 363 uasp->usb_as_ser_acc = usb_init_serialization(dip, 364 USB_INIT_SER_CHECK_SAME_THREAD); 365 366 uasp->usb_as_default_ph = uasp->usb_as_dev_data->dev_default_ph; 367 uasp->usb_as_isoc_pp.pp_max_async_reqs = 1; 368 369 /* parse all descriptors */ 370 if (usb_as_handle_descriptors(uasp) != USB_SUCCESS) { 371 372 goto fail; 373 } 374 375 usb_free_descr_tree(dip, uasp->usb_as_dev_data); 376 377 if ((ddi_create_minor_node(dip, "usb_as", S_IFCHR, 378 USB_AS_CONSTRUCT_MINOR(instance), 379 NULL, 0)) != DDI_SUCCESS) { 380 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 381 "usb_as_attach: couldn't create minor node"); 382 383 goto fail; 384 } 385 386 /* we are online */ 387 uasp->usb_as_dev_state = USB_DEV_ONLINE; 388 389 /* create components to power manage this device */ 390 usb_as_create_pm_components(dip, uasp); 391 392 /* Register for events */ 393 if (usb_register_event_cbs(dip, &usb_as_events, 0) != USB_SUCCESS) { 394 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 395 "usb_as_attach: couldn't register for events"); 396 397 goto fail; 398 } 399 400 /* report device */ 401 ddi_report_dev(dip); 402 403 USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 404 "usb_as_attach: End"); 405 406 return (DDI_SUCCESS); 407 408fail: 409 if (uasp) { 410 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 411 "attach failed"); 412 usb_as_cleanup(dip, uasp); 413 } 414 415 return (DDI_FAILURE); 416} 417 418 419/*ARGSUSED*/ 420static int 421usb_as_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 422{ 423 int instance = ddi_get_instance(dip); 424 usb_as_state_t *uasp; 425 int rval; 426 427 uasp = ddi_get_soft_state(usb_as_statep, instance); 428 429 switch (cmd) { 430 case DDI_DETACH: 431 usb_as_cleanup(dip, uasp); 432 433 return (DDI_SUCCESS); 434 case DDI_SUSPEND: 435 rval = usb_as_cpr_suspend(dip); 436 437 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 438 default: 439 440 return (DDI_FAILURE); 441 } 442} 443 444 445static void 446usb_as_cleanup(dev_info_t *dip, usb_as_state_t *uasp) 447{ 448 usb_as_power_t *uaspm; 449 450 if (uasp == NULL) { 451 452 return; 453 } 454 455 uaspm = uasp->usb_as_pm; 456 457 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 458 "usb_as_cleanup: uaspm=0x%p", (void *)uaspm); 459 460 if (uasp->usb_as_isoc_ph) { 461 usb_pipe_close(dip, uasp->usb_as_isoc_ph, 462 USB_FLAGS_SLEEP, NULL, NULL); 463 } 464 /* 465 * Disable the event callbacks first, after this point, event 466 * callbacks will never get called. Note we shouldn't hold 467 * mutex while unregistering events because there may be a 468 * competing event callback thread. Event callbacks are done 469 * with ndi mutex held and this can cause a potential deadlock. 470 */ 471 usb_unregister_event_cbs(dip, &usb_as_events); 472 473 mutex_enter(&uasp->usb_as_mutex); 474 475 if (uaspm && (uasp->usb_as_dev_state != USB_DEV_DISCONNECTED)) { 476 if (uaspm->aspm_wakeup_enabled) { 477 mutex_exit(&uasp->usb_as_mutex); 478 479 /* 480 * We need to raise power first because 481 * we need to send down a command to disable 482 * remote wakeup 483 */ 484 usb_as_pm_busy_component(uasp); 485 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 486 487 if (usb_handle_remote_wakeup(dip, 488 USB_REMOTE_WAKEUP_DISABLE)) { 489 USB_DPRINTF_L2(PRINT_MASK_ALL, 490 uasp->usb_as_log_handle, 491 "disable remote wake up failed"); 492 } 493 usb_as_pm_idle_component(uasp); 494 } else { 495 mutex_exit(&uasp->usb_as_mutex); 496 } 497 498 (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF); 499 500 mutex_enter(&uasp->usb_as_mutex); 501 } 502 503 if (uaspm) { 504 kmem_free(uaspm, sizeof (usb_as_power_t)); 505 uasp->usb_as_pm = NULL; 506 } 507 508 usb_client_detach(dip, uasp->usb_as_dev_data); 509 510 usb_as_free_alts(uasp); 511 512 mutex_exit(&uasp->usb_as_mutex); 513 mutex_destroy(&uasp->usb_as_mutex); 514 515 usb_fini_serialization(uasp->usb_as_ser_acc); 516 517 ddi_remove_minor_node(dip, NULL); 518 usb_free_log_hdl(uasp->usb_as_log_handle); 519 ddi_soft_state_free(usb_as_statep, uasp->usb_as_instance); 520 521 ddi_prop_remove_all(dip); 522} 523 524 525/* 526 * usb_as_open: 527 * Open entry point for plumbing only 528 */ 529/*ARGSUSED*/ 530static int 531usb_as_open(dev_t *devp, int flag, int otyp, cred_t *credp) 532{ 533 int inst = USB_AS_MINOR_TO_INSTANCE(getminor(*devp)); 534 usb_as_state_t *uasp = ddi_get_soft_state(usb_as_statep, inst); 535 char *nm = "usb_as_open"; 536 537 if (uasp == NULL) { 538 539 return (ENXIO); 540 } 541 542 /* Do mux plumbing stuff */ 543 dinfo("%s: %s\n", uasp->dstr, nm); 544 545 mutex_enter(&uasp->usb_as_mutex); 546 547 if (uasp->usb_as_flag == USB_AS_OPEN || credp != kcred) { 548 dwarn("%s: multiple opens or opens from userspace not " 549 "supported\n", uasp->dstr); 550 mutex_exit(&uasp->usb_as_mutex); 551 552 return (ENXIO); 553 } 554 555 /* fail open on a disconnected device */ 556 if (uasp->usb_as_dev_state == USB_DEV_DISCONNECTED) { 557 dinfo("%s: %s disconnected\n", uasp->dstr, nm); 558 mutex_exit(&uasp->usb_as_mutex); 559 560 return (ENODEV); 561 } 562 563 /* Initialize state */ 564 uasp->usb_as_flag = USB_AS_OPEN; 565 mutex_exit(&uasp->usb_as_mutex); 566 567 /* 568 * go to full power, and remain pm_busy till close 569 */ 570 usb_as_pm_busy_component(uasp); 571 (void) pm_raise_power(uasp->usb_as_dip, 0, USB_DEV_OS_FULL_PWR); 572 573 dinfo("%s: %s done\n", uasp->dstr, nm); 574 575 return (0); 576} 577 578 579/* 580 * usb_as_close: 581 * Close entry point for plumbing 582 */ 583/*ARGSUSED*/ 584static int 585usb_as_close(dev_t dev, int flag, int otyp, cred_t *credp) 586{ 587 int inst = USB_AS_MINOR_TO_INSTANCE(getminor(dev)); 588 usb_as_state_t *uasp = ddi_get_soft_state(usb_as_statep, inst); 589 590 USB_DPRINTF_L4(PRINT_MASK_CLOSE, uasp->usb_as_log_handle, 591 "usb_as_close: inst=%d", inst); 592 593 mutex_enter(&uasp->usb_as_mutex); 594 uasp->usb_as_flag = USB_AS_DISMANTLING; 595 mutex_exit(&uasp->usb_as_mutex); 596 597 /* 598 * Avoid races with other routines. 599 * For example, if a control transfer is going on, wait 600 * for that to be completed 601 * At this point default pipe cannot be open. 602 */ 603 (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0); 604 605 usb_release_access(uasp->usb_as_ser_acc); 606 607 /* we can now power down */ 608 usb_as_pm_idle_component(uasp); 609 610 mutex_enter(&uasp->usb_as_mutex); 611 uasp->usb_as_flag = 0; 612 mutex_exit(&uasp->usb_as_mutex); 613 614 return (0); 615} 616 617 618/* 619 * 620 */ 621/*ARGSUSED*/ 622static int 623usb_as_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 624 int *rvalp) 625{ 626 int inst = USB_AS_MINOR_TO_INSTANCE(getminor(dev)); 627 usb_as_state_t *uasp = ddi_get_soft_state(usb_as_statep, inst); 628 int rv = USB_SUCCESS; 629 630 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 631 "usb_as_ioctl: Begin inst=%d, cmd=0x%x, arg=0x%p", 632 inst, cmd, (void *)arg); 633 634 if (!(mode & FKIOCTL)) { 635 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 636 "usb_as_ioctl: inst=%d, user space not supported", inst); 637 return (ENXIO); 638 } 639 640 mutex_enter(&uasp->usb_as_mutex); 641 642 switch (cmd) { 643 case USB_AUDIO_MIXER_REGISTRATION: 644 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 645 "usb_as_ioctl(mixer reg): inst=%d", inst); 646 647 /* 648 * Copy the usb_as_reg structure to the structure 649 * that usb_ac passed. Note that this is a structure 650 * assignment and not a pointer assignment! 651 */ 652 *(usb_as_registration_t *)arg = uasp->usb_as_reg; 653 654 break; 655 case USB_AUDIO_SET_FORMAT: 656 rv = usb_as_set_format(uasp, (usb_audio_formats_t *)arg); 657 break; 658 case USB_AUDIO_SET_SAMPLE_FREQ: 659 rv = usb_as_set_sample_freq(uasp, *(int *)arg); 660 break; 661 case USB_AUDIO_SETUP: 662 rv = usb_as_setup(uasp); 663 break; 664 case USB_AUDIO_TEARDOWN: 665 usb_as_teardown(uasp); 666 break; 667 case USB_AUDIO_START_PLAY: 668 rv = usb_as_start_play(uasp, (usb_audio_play_req_t *)arg); 669 break; 670 case USB_AUDIO_STOP_PLAY: 671 case USB_AUDIO_PAUSE_PLAY: 672 usb_as_pause_play(uasp); 673 break; 674 case USB_AUDIO_START_RECORD: 675 rv = usb_as_start_record(uasp, *(audiohdl_t *)arg); 676 break; 677 case USB_AUDIO_STOP_RECORD: 678 rv = usb_as_stop_record(uasp); 679 break; 680 default: 681 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 682 "usb_as_ioctl: unknown IOCTL, cmd=%d", cmd); 683 break; 684 } 685 686 mutex_exit(&uasp->usb_as_mutex); 687 688 return (rv == USB_SUCCESS ? 0 : ENXIO); 689} 690 691 692/* 693 * usb_as_set_sample_freq: 694 * Sets the sample freq by sending a control command to interface 695 * Although not required for continuous sample rate devices, some 696 * devices such as plantronics devices do need this. 697 * On the other hand, the TI chip which does not support continuous 698 * sample rate stalls on this request 699 * Therefore, we ignore errors and carry on regardless 700 */ 701static int 702usb_as_set_sample_freq(usb_as_state_t *uasp, int freq) 703{ 704 int alt, ep; 705 mblk_t *data; 706 int rval = USB_FAILURE; 707 boolean_t ignore_errors; 708 709 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 710 711 alt = uasp->usb_as_alternate; 712 713 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 714 "usb_as_set_sample_freq: inst=%d cont_sr=%d freq=%d", 715 ddi_get_instance(uasp->usb_as_dip), 716 uasp->usb_as_alts[alt].alt_continuous_sr, freq); 717 718 ignore_errors = B_TRUE; 719 720 ep = uasp->usb_as_alts[alt].alt_ep->bEndpointAddress; 721 722 data = allocb(4, BPRI_HI); 723 if (data) { 724 *(data->b_wptr++) = (char)freq; 725 *(data->b_wptr++) = (char)(freq >> 8); 726 *(data->b_wptr++) = (char)(freq >> 16); 727 728 mutex_exit(&uasp->usb_as_mutex); 729 730 if ((rval = usb_as_send_ctrl_cmd(uasp, 731 USB_DEV_REQ_HOST_TO_DEV | 732 USB_DEV_REQ_TYPE_CLASS | 733 USB_DEV_REQ_RCPT_EP, /* bmRequestType */ 734 USB_AUDIO_SET_CUR, /* bRequest */ 735 USB_AUDIO_SAMPLING_FREQ_CONTROL << 8, /* wValue */ 736 ep, /* wIndex */ 737 3, /* wLength */ 738 data, 739 ignore_errors)) != USB_SUCCESS) { 740 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 741 "usb_as_set_sample_freq: set sample freq failed"); 742 } 743 mutex_enter(&uasp->usb_as_mutex); 744 } 745 freemsg(data); 746 747 return (rval); 748} 749 750 751/* 752 * usb_as_set_format: 753 * Matches channel, encoding and precision and find out 754 * the right alternate. Sets alternate interface and returns it. 755 */ 756static int 757usb_as_set_format(usb_as_state_t *uasp, usb_audio_formats_t *format) 758{ 759 int n; 760 usb_as_registration_t *reg; 761 int alt, rval; 762 uint_t interface; 763 764 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 765 766 if (uasp->usb_as_request_count) { 767 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 768 "usb_as_set_format: failing inst=%d, rq_cnt=%d", 769 ddi_get_instance(uasp->usb_as_dip), 770 uasp->usb_as_request_count); 771 772 return (USB_FAILURE); 773 } 774 775 ASSERT(uasp->usb_as_isoc_ph == NULL); 776 777 reg = &uasp->usb_as_reg; 778 interface = uasp->usb_as_ifno; 779 780 uasp->usb_as_curr_format = *format; 781 782 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 783 "usb_as_set_format: inst=%d, reg=0x%p, format=0x%p", 784 ddi_get_instance(uasp->usb_as_dip), (void *)reg, (void *)format); 785 786 for (n = 0; n < reg->reg_n_formats; n++) { 787 if ((format->fmt_chns == reg->reg_formats[n].fmt_chns) && 788 (format->fmt_precision == reg->reg_formats[n]. 789 fmt_precision) && (format->fmt_encoding == 790 reg->reg_formats[n].fmt_encoding)) { 791 /* 792 * Found the alternate 793 */ 794 uasp->usb_as_alternate = alt = 795 reg->reg_formats[n].fmt_alt; 796 break; 797 } 798 } 799 800 if (n >= reg->reg_n_formats) { 801 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 802 "usb_as_set_format: Didn't find a matching alt"); 803 804 return (USB_FAILURE); 805 } 806 807 ASSERT(uasp->usb_as_isoc_ph == NULL); 808 809 USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle, 810 "usb_as_set_format: interface=%d alternate=%d", 811 interface, alt); 812 813 mutex_exit(&uasp->usb_as_mutex); 814 815 rval = usb_as_send_ctrl_cmd(uasp, 816 /* bmRequestType */ 817 USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF, 818 USB_REQ_SET_IF, /* bRequest */ 819 alt, /* wValue */ 820 interface, /* wIndex */ 821 0, /* wLength */ 822 NULL, B_FALSE); 823 824 mutex_enter(&uasp->usb_as_mutex); 825 826 if (rval != USB_SUCCESS) { 827 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 828 "usb_as_set_format: set_alternate failed"); 829 } else { 830 format->fmt_alt = (uchar_t)alt; 831 } 832 833 return (rval); 834} 835 836 837/* 838 * usb_as_setup: 839 * Open isoc pipe. Will hang around till bandwidth 840 * is available. 841 */ 842static int 843usb_as_setup(usb_as_state_t *uasp) 844{ 845 int alt = uasp->usb_as_alternate; 846 usb_ep_descr_t *ep = (usb_ep_descr_t *)uasp->usb_as_alts[alt].alt_ep; 847 int rval; 848 849 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 850 851 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 852 "usb_as_setup: Begin usb_as_setup, inst=%d", 853 ddi_get_instance(uasp->usb_as_dip)); 854 855 ASSERT(uasp->usb_as_request_count == 0); 856 857 /* Set record packet size to max packet size */ 858 if (uasp->usb_as_alts[alt].alt_mode == AUDIO_RECORD) { 859 uasp->usb_as_record_pkt_size = ep->wMaxPacketSize; 860 } else { 861 uasp->usb_as_record_pkt_size = 0; 862 } 863 864 mutex_exit(&uasp->usb_as_mutex); 865 866 /* open isoc pipe, may fail if there is no bandwidth */ 867 rval = usb_pipe_open(uasp->usb_as_dip, ep, &uasp->usb_as_isoc_pp, 868 USB_FLAGS_SLEEP, &uasp->usb_as_isoc_ph); 869 870 if (rval != USB_SUCCESS) { 871 switch (rval) { 872 case USB_NO_BANDWIDTH: 873 USB_DPRINTF_L0(PRINT_MASK_ALL, uasp->usb_as_log_handle, 874 "no bandwidth available"); 875 break; 876 case USB_NOT_SUPPORTED: 877 USB_DPRINTF_L0(PRINT_MASK_ALL, uasp->usb_as_log_handle, 878 "Operating a full/high speed audio device on a " 879 "high speed port is not supported"); 880 break; 881 default: 882 USB_DPRINTF_L2(PRINT_MASK_ALL, 883 uasp->usb_as_log_handle, 884 "usb_as_setup: isoc pipe open failed (%d)", 885 rval); 886 } 887 888 mutex_enter(&uasp->usb_as_mutex); 889 890 return (USB_FAILURE); 891 } 892 893 (void) usb_pipe_set_private(uasp->usb_as_isoc_ph, (usb_opaque_t)uasp); 894 895 mutex_enter(&uasp->usb_as_mutex); 896 uasp->usb_as_audio_state = USB_AS_IDLE; 897 uasp->usb_as_setup_cnt++; 898 899 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 900 "usb_as_setup: End"); 901 902 return (USB_SUCCESS); 903} 904 905 906/* 907 * usb_as_teardown 908 * 909 */ 910static void 911usb_as_teardown(usb_as_state_t *uasp) 912{ 913 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 914 "usb_as_teardown: Begin inst=%d", 915 ddi_get_instance(uasp->usb_as_dip)); 916 917 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 918 919 uasp->usb_as_audio_state = USB_AS_IDLE; 920 921 if (uasp->usb_as_isoc_ph) { 922 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 923 "usb_as_teardown: closing isoc pipe, ph=0x%p", 924 (void *)uasp->usb_as_isoc_ph); 925 926 mutex_exit(&uasp->usb_as_mutex); 927 928 /* reply mp will be sent up in isoc close callback */ 929 usb_pipe_close(uasp->usb_as_dip, uasp->usb_as_isoc_ph, 930 USB_FLAGS_SLEEP, NULL, (usb_opaque_t)NULL); 931 932 mutex_enter(&uasp->usb_as_mutex); 933 uasp->usb_as_isoc_ph = NULL; 934 935 /* reset setup flag */ 936 uasp->usb_as_setup_cnt--; 937 938 } else { 939 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 940 "usb_as_teardown: Pipe already closed"); 941 } 942 943 ASSERT(uasp->usb_as_setup_cnt == 0); 944 945 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 946 "usb_as_teardown: End"); 947} 948 949 950/* 951 * usb_as_start_play 952 */ 953static int 954usb_as_start_play(usb_as_state_t *uasp, usb_audio_play_req_t *play_req) 955{ 956 int n_requests; 957 int rval = USB_FAILURE; 958 959 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 960 "usb_as_start_play: Begin inst=%d, req_cnt=%d", 961 ddi_get_instance(uasp->usb_as_dip), uasp->usb_as_request_count); 962 963 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 964 965 uasp->usb_as_request_samples = play_req->up_samples; 966 uasp->usb_as_ahdl = play_req->up_handle; 967 uasp->usb_as_audio_state = USB_AS_ACTIVE; 968 969 if ((uasp->usb_as_request_count >= USB_AS_MAX_REQUEST_COUNT) || 970 (uasp->usb_as_audio_state == USB_AS_IDLE) || 971 (uasp->usb_as_audio_state == USB_AS_PLAY_PAUSED)) { 972 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 973 "nothing to do or paused or idle (%d)", 974 uasp->usb_as_audio_state); 975 rval = USB_SUCCESS; 976 } else { 977 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 978 "usb_as_start_play: samples=%d requestcount=%d ", 979 uasp->usb_as_request_samples, uasp->usb_as_request_count); 980 981 /* queue up as many requests as allowed */ 982 for (n_requests = uasp->usb_as_request_count; 983 n_requests < USB_AS_MAX_REQUEST_COUNT; n_requests++) { 984 if ((rval = usb_as_play_isoc_data(uasp, play_req)) != 985 USB_SUCCESS) { 986 break; 987 } 988 } 989 } 990 991 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 992 "usb_as_start_play: End"); 993 994 return (rval); 995} 996 997 998/* 999 * usb_as_continue_play: 1000 * this function is called from the play callbacks 1001 */ 1002static void 1003usb_as_continue_play(usb_as_state_t *uasp) 1004{ 1005 int n_requests; 1006 1007 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1008 "usb_as_contine_play: Begin req_cnt=%d", 1009 uasp->usb_as_request_count); 1010 1011 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1012 1013 if (uasp->usb_as_dev_state == USB_DEV_DISCONNECTED) { 1014 usb_as_handle_shutdown(uasp); 1015 1016 return; 1017 } 1018 1019 if ((uasp->usb_as_request_count >= USB_AS_MAX_REQUEST_COUNT) || 1020 (uasp->usb_as_audio_state == USB_AS_IDLE) || 1021 (uasp->usb_as_audio_state == USB_AS_PLAY_PAUSED)) { 1022 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1023 "usb_as_continue_play: nothing to do (audio_state=%d)", 1024 uasp->usb_as_audio_state); 1025 } else { 1026 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1027 "usb_as_continue_play: samples=%d requestcount=%d ", 1028 uasp->usb_as_request_samples, uasp->usb_as_request_count); 1029 1030 /* queue up as many requests as allowed */ 1031 for (n_requests = uasp->usb_as_request_count; 1032 n_requests < USB_AS_MAX_REQUEST_COUNT; n_requests++) { 1033 if (usb_as_play_isoc_data(uasp, NULL) != 1034 USB_SUCCESS) { 1035 1036 break; 1037 } 1038 } 1039 } 1040 1041 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1042 "usb_as_continue_play: End"); 1043} 1044 1045 1046static void 1047usb_as_handle_shutdown(usb_as_state_t *uasp) 1048{ 1049 audiohdl_t ahdl; 1050 1051 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1052 "usb_as_handle_shutdown, inst=%d", 1053 ddi_get_instance(uasp->usb_as_dip)); 1054 1055 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1056 "usb_as_handle_shutdown: am_play_shutdown"); 1057 1058 uasp->usb_as_audio_state = USB_AS_IDLE; 1059 uasp->usb_as_pkt_count = 0; 1060 ahdl = uasp->usb_as_ahdl; 1061 1062 mutex_exit(&uasp->usb_as_mutex); 1063 am_play_shutdown(ahdl); 1064 mutex_enter(&uasp->usb_as_mutex); 1065} 1066 1067 1068static int 1069usb_as_play_isoc_data(usb_as_state_t *uasp, usb_audio_play_req_t *play_req) 1070{ 1071 int rval = USB_FAILURE; 1072 1073 usb_isoc_req_t *isoc_req = NULL; 1074 usb_audio_formats_t *format = &uasp->usb_as_curr_format; 1075 mblk_t *data = NULL; 1076 audiohdl_t ahdl = uasp->usb_as_ahdl; 1077 int precision; 1078 int pkt, frame, n, n_pkts, count; 1079 size_t bufsize; 1080 int pkt_len[USB_AS_N_FRAMES]; 1081 1082 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1083 1084 /* we only support two precisions */ 1085 if ((format->fmt_precision != AUDIO_PRECISION_8) && 1086 (format->fmt_precision != AUDIO_PRECISION_16)) { 1087 1088 rval = USB_FAILURE; 1089 1090 goto done; 1091 } 1092 1093 precision = (format->fmt_precision == AUDIO_PRECISION_8) ? 1 : 2; 1094 1095 frame = uasp->usb_as_pkt_count; 1096 1097 /* 1098 * calculate total bufsize by determining the pkt size for 1099 * each frame 1100 */ 1101 for (bufsize = pkt = 0; pkt < USB_AS_N_FRAMES; pkt++) { 1102 pkt_len[pkt] = usb_as_get_pktsize(uasp, format, frame++); 1103 bufsize += pkt_len[pkt]; 1104 } 1105 1106 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1107 "usb_as_play_isoc_data: Begin bufsize=0x%lx, inst=%d", bufsize, 1108 ddi_get_instance(uasp->usb_as_dip)); 1109 1110 mutex_exit(&uasp->usb_as_mutex); 1111 1112 if ((data = allocb(bufsize, BPRI_HI)) == NULL) { 1113 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1114 "usb_as_play_isoc_data: allocb failed"); 1115 mutex_enter(&uasp->usb_as_mutex); 1116 1117 goto done; 1118 } 1119 1120 /* 1121 * restriction of Boomer: cannot call am_get_audio() in the context 1122 * of start so we play a fragment of silence at first 1123 */ 1124 if (play_req != NULL) { 1125 bzero(data->b_wptr, bufsize); 1126 count = bufsize / precision; 1127 1128 } else if ((count = am_get_audio(ahdl, (void *)data->b_wptr, 1129 bufsize / precision)) == 0) { 1130 mutex_enter(&uasp->usb_as_mutex); 1131 if (uasp->usb_as_request_count == 0) { 1132 usb_as_handle_shutdown(uasp); 1133 1134 /* Don't return failure for 0 bytes of data sent */ 1135 if (play_req) { 1136 /* 1137 * Since we set rval to SUCCESS 1138 * we treat it as a special case 1139 * and free data here 1140 */ 1141 rval = USB_SUCCESS; 1142 freemsg(data); 1143 data = NULL; 1144 1145 goto done; 1146 } 1147 } else { 1148 USB_DPRINTF_L2(PRINT_MASK_ALL, 1149 uasp->usb_as_log_handle, 1150 "usb_as_play_isoc_data: no audio bytes, " 1151 "rcnt=0x%x ", uasp->usb_as_request_count); 1152 } 1153 rval = USB_FAILURE; 1154 1155 goto done; 1156 } 1157 1158 bufsize = n = count * precision; 1159 data->b_wptr += n; 1160 1161 /* calculate how many frames we can actually fill */ 1162 for (n_pkts = 0; (n_pkts < USB_AS_N_FRAMES) && (n > 0); n_pkts++) { 1163 if (n < pkt_len[n_pkts]) { 1164 pkt_len[n_pkts] = n; 1165 } 1166 n -= pkt_len[n_pkts]; 1167 } 1168 1169 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1170 "usb_as_play_isoc_data: n_pkts=%d, bufsize=%ld, n=%d", 1171 n_pkts, bufsize, count * precision); 1172 1173 /* allocate an isoc request packet */ 1174 if ((isoc_req = usb_alloc_isoc_req(uasp->usb_as_dip, 1175 n_pkts, 0, 0)) == NULL) { 1176 mutex_enter(&uasp->usb_as_mutex); 1177 1178 goto done; 1179 } 1180 1181 1182#if defined(_BIG_ENDIAN) 1183 /* byte swap if necessary */ 1184 if (format->fmt_precision == AUDIO_PRECISION_16) { 1185 int i; 1186 uchar_t tmp; 1187 uchar_t *p = data->b_rptr; 1188 1189 for (i = 0; i < bufsize; i += 2, p += 2) { 1190 tmp = *p; 1191 *p = *(p + 1); 1192 *(p + 1) = tmp; 1193 } 1194 } 1195#endif 1196 1197 /* initialize the packet descriptor */ 1198 for (pkt = 0; pkt < n_pkts; pkt++) { 1199 isoc_req->isoc_pkt_descr[pkt].isoc_pkt_length = 1200 pkt_len[pkt]; 1201 } 1202 1203 isoc_req->isoc_data = data; 1204 isoc_req->isoc_pkts_count = (ushort_t)n_pkts; 1205 isoc_req->isoc_attributes = USB_ATTRS_ISOC_XFER_ASAP | 1206 USB_ATTRS_AUTOCLEARING; 1207 isoc_req->isoc_cb = usb_as_play_cb; 1208 isoc_req->isoc_exc_cb = usb_as_play_exc_cb; 1209 isoc_req->isoc_client_private = (usb_opaque_t)uasp; 1210 1211 mutex_enter(&uasp->usb_as_mutex); 1212 1213 USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1214 "usb_as_play_isoc_data: rq=0x%p data=0x%p cnt=0x%x " 1215 "pkt=0x%p rqcnt=%d ", (void *)isoc_req, (void *)data, count, 1216 (void *)isoc_req->isoc_pkt_descr, uasp->usb_as_request_count); 1217 1218 ASSERT(isoc_req->isoc_data != NULL); 1219 1220 uasp->usb_as_send_debug_count++; 1221 uasp->usb_as_request_count++; 1222 uasp->usb_as_pkt_count += n_pkts; 1223 mutex_exit(&uasp->usb_as_mutex); 1224 1225 if ((rval = usb_pipe_isoc_xfer(uasp->usb_as_isoc_ph, 1226 isoc_req, 0)) != USB_SUCCESS) { 1227 1228 mutex_enter(&uasp->usb_as_mutex); 1229 uasp->usb_as_request_count--; 1230 uasp->usb_as_send_debug_count--; 1231 uasp->usb_as_pkt_count -= n_pkts; 1232 1233 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1234 "usb_as_play_isoc_data: rval=%d", rval); 1235 1236 rval = USB_FAILURE; 1237 1238 } else { 1239 mutex_enter(&uasp->usb_as_mutex); 1240 1241 data = NULL; 1242 isoc_req = NULL; 1243 } 1244 1245done: 1246 if (rval != USB_SUCCESS) { 1247 freemsg(data); 1248 if (isoc_req) { 1249 isoc_req->isoc_data = NULL; 1250 usb_free_isoc_req(isoc_req); 1251 } 1252 } 1253 1254 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1255 "usb_as_play_isoc_data: SEND CNT=%d, RCV COUNT=%d", 1256 uasp->usb_as_send_debug_count, uasp->usb_as_rcv_debug_count); 1257 1258 return (rval); 1259} 1260 1261 1262static void 1263usb_as_pause_play(usb_as_state_t *uasp) 1264{ 1265 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1266 1267 /* this will stop the isoc request in the play callback */ 1268 uasp->usb_as_audio_state = USB_AS_PLAY_PAUSED; 1269} 1270 1271 1272/*ARGSUSED*/ 1273static void 1274usb_as_play_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) 1275{ 1276 usb_as_state_t *uasp = (usb_as_state_t *) 1277 (isoc_req->isoc_client_private); 1278 int i; 1279 1280 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle, 1281 "usb_as_play_cb: Begin ph=0x%p, isoc_req=0x%p", 1282 (void *)ph, (void *)isoc_req); 1283 1284 ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) != 0); 1285 1286 for (i = 0; i < isoc_req->isoc_pkts_count; i++) { 1287 if (isoc_req->isoc_pkt_descr[i].isoc_pkt_status != 1288 USB_CR_OK) { 1289 USB_DPRINTF_L2(PRINT_MASK_CB, uasp->usb_as_log_handle, 1290 "usb_as_play_cb: \tpkt%d: len=%d status=%s", i, 1291 isoc_req->isoc_pkt_descr[i].isoc_pkt_length, 1292 usb_str_cr(isoc_req-> 1293 isoc_pkt_descr[i].isoc_pkt_status)); 1294 } 1295 } 1296 1297 mutex_enter(&uasp->usb_as_mutex); 1298 if (isoc_req->isoc_error_count) { 1299 USB_DPRINTF_L2(PRINT_MASK_CB, uasp->usb_as_log_handle, 1300 "usb_as_play_cb: error_count = %d", 1301 isoc_req->isoc_error_count); 1302 } 1303 1304 usb_free_isoc_req(isoc_req); 1305 uasp->usb_as_request_count--; 1306 uasp->usb_as_rcv_debug_count++; 1307 usb_as_continue_play(uasp); 1308 1309 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle, 1310 "usb_as_play_cb: SEND CNT=%d, RCV COUNT=%d", 1311 uasp->usb_as_send_debug_count, uasp->usb_as_rcv_debug_count); 1312 1313 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle, 1314 "usb_as_play_cb: End, req_cnt=%d", uasp->usb_as_request_count); 1315 1316 mutex_exit(&uasp->usb_as_mutex); 1317} 1318 1319 1320static void 1321usb_as_play_exc_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) 1322{ 1323 int i; 1324 usb_as_state_t *uasp = (usb_as_state_t *) 1325 (isoc_req->isoc_client_private); 1326 usb_cr_t cr = isoc_req->isoc_completion_reason; 1327 usb_cb_flags_t cb_flags = isoc_req->isoc_cb_flags; 1328 1329 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1330 "usb_as_play_exc_cb: ph=0x%p, rq=0x%p data=0x%p pkts=0x%x " 1331 "cr=%d, cb_flag=0x%x", (void *)ph, (void *)isoc_req, 1332 (void *)isoc_req->isoc_data, isoc_req->isoc_pkts_count, 1333 cr, cb_flags); 1334 1335 ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) == 0); 1336 1337 for (i = 0; i < isoc_req->isoc_pkts_count; i++) { 1338 if (isoc_req->isoc_pkt_descr[i].isoc_pkt_status == 1339 USB_CR_OK) { 1340 USB_DPRINTF_L2(PRINT_MASK_ALL, 1341 uasp->usb_as_log_handle, 1342 "usb_as_play_exc_cb: \tpkt%d: len=%d status=%d", 1343 i, 1344 isoc_req->isoc_pkt_descr[i].isoc_pkt_length, 1345 isoc_req->isoc_pkt_descr[i].isoc_pkt_status); 1346 } 1347 } 1348 1349 usb_free_isoc_req(isoc_req); 1350 1351 mutex_enter(&uasp->usb_as_mutex); 1352 uasp->usb_as_rcv_debug_count++; 1353 uasp->usb_as_request_count--; 1354 usb_as_handle_shutdown(uasp); 1355 1356 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1357 "usb_as_play_exc_cb: SEND CNT=%d, RCV COUNT=%d", 1358 uasp->usb_as_send_debug_count, uasp->usb_as_rcv_debug_count); 1359 1360 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1361 "usb_as_play_exc_cb: End request_count=%d", 1362 uasp->usb_as_request_count); 1363 1364 mutex_exit(&uasp->usb_as_mutex); 1365} 1366 1367 1368/* 1369 * usb_as_start_record 1370 */ 1371static int 1372usb_as_start_record(usb_as_state_t *uasp, audiohdl_t ahdl) 1373{ 1374 int rval = USB_FAILURE; 1375 usb_isoc_req_t *isoc_req; 1376 ushort_t record_pkt_size = uasp->usb_as_record_pkt_size; 1377 ushort_t n_pkt = 1, pkt; 1378 1379 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1380 "usb_as_start_record: inst=%d", 1381 ddi_get_instance(uasp->usb_as_dip)); 1382 1383 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1384 1385 /* 1386 * A start_record should not happen when stop polling is 1387 * happening 1388 */ 1389 ASSERT(uasp->usb_as_audio_state != USB_AS_STOP_POLLING_STARTED); 1390 1391 if (uasp->usb_as_audio_state == USB_AS_IDLE) { 1392 1393 uasp->usb_as_ahdl = ahdl; 1394 uasp->usb_as_audio_state = USB_AS_ACTIVE; 1395 mutex_exit(&uasp->usb_as_mutex); 1396 1397 if ((isoc_req = usb_alloc_isoc_req(uasp->usb_as_dip, n_pkt, 1398 n_pkt * record_pkt_size, 0)) != NULL) { 1399 /* Initialize the packet descriptor */ 1400 for (pkt = 0; pkt < n_pkt; pkt++) { 1401 isoc_req->isoc_pkt_descr[pkt]. 1402 isoc_pkt_length = record_pkt_size; 1403 } 1404 1405 isoc_req->isoc_pkts_count = n_pkt; 1406 isoc_req->isoc_pkts_length = record_pkt_size; 1407 isoc_req->isoc_attributes = USB_ATTRS_ISOC_XFER_ASAP | 1408 USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING; 1409 isoc_req->isoc_cb = usb_as_record_cb; 1410 isoc_req->isoc_exc_cb = usb_as_record_exc_cb; 1411 isoc_req->isoc_client_private = (usb_opaque_t)uasp; 1412 1413 rval = usb_pipe_isoc_xfer(uasp->usb_as_isoc_ph, 1414 isoc_req, 0); 1415 1416 } else { 1417 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1418 "usb_as_start_record: Isoc req allocation failed"); 1419 } 1420 1421 mutex_enter(&uasp->usb_as_mutex); 1422 1423 } else { 1424 1425 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1426 "usb_as_start_record: Record in progress"); 1427 1428 rval = USB_SUCCESS; 1429 } 1430 1431 if (rval != USB_SUCCESS) { 1432 uasp->usb_as_audio_state = USB_AS_IDLE; 1433 if (isoc_req) { 1434 usb_free_isoc_req(isoc_req); 1435 isoc_req = NULL; 1436 } 1437 } 1438 1439 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1440 "usb_as_start_record: rval=%d", rval); 1441 1442 return (rval); 1443} 1444 1445 1446static int 1447usb_as_stop_record(usb_as_state_t *uasp) 1448{ 1449 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1450 "usb_as_stop_record: "); 1451 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1452 1453 /* if we are disconnected, the pipe will be closed anyways */ 1454 if (uasp->usb_as_dev_state == USB_DEV_DISCONNECTED) 1455 return (USB_SUCCESS); 1456 1457 switch (uasp->usb_as_audio_state) { 1458 case USB_AS_ACTIVE: 1459 mutex_exit(&uasp->usb_as_mutex); 1460 1461 /* 1462 * Stop polling. When the completion reason indicate that 1463 * polling is over, return response message up. 1464 */ 1465 usb_pipe_stop_isoc_polling(uasp->usb_as_isoc_ph, 1466 USB_FLAGS_SLEEP); 1467 mutex_enter(&uasp->usb_as_mutex); 1468 1469 break; 1470 case USB_AS_STOP_POLLING_STARTED: 1471 /* A stop polling in progress, wait for completion and reply */ 1472 break; 1473 default: 1474 break; 1475 } 1476 1477 return (USB_SUCCESS); 1478} 1479 1480 1481static void 1482usb_as_record_exc_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) 1483{ 1484 usb_as_state_t *uasp = (usb_as_state_t *) 1485 (isoc_req->isoc_client_private); 1486 usb_cr_t completion_reason; 1487 int rval; 1488 1489 completion_reason = isoc_req->isoc_completion_reason; 1490 1491 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1492 "usb_as_record_exc_cb: ph=0x%p, isoc_req=0x%p, cr=%d", 1493 (void *)ph, (void *)isoc_req, completion_reason); 1494 1495 ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) == 0); 1496 1497 switch (completion_reason) { 1498 case USB_CR_STOPPED_POLLING: 1499 case USB_CR_PIPE_CLOSING: 1500 case USB_CR_PIPE_RESET: 1501 1502 break; 1503 case USB_CR_NO_RESOURCES: 1504 /* 1505 * keep the show going: Since we have the original 1506 * request, we just resubmit it 1507 */ 1508 rval = usb_pipe_isoc_xfer(uasp->usb_as_isoc_ph, isoc_req, 0); 1509 1510 USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1511 "usb_as_record_exc_cb: restart record rval=%d", rval); 1512 1513 return; 1514 default: 1515 1516 mutex_enter(&uasp->usb_as_mutex); 1517 1518 /* Do not start if one is already in progress */ 1519 if (uasp->usb_as_audio_state != USB_AS_STOP_POLLING_STARTED) { 1520 uasp->usb_as_audio_state = USB_AS_STOP_POLLING_STARTED; 1521 1522 mutex_exit(&uasp->usb_as_mutex); 1523 (void) usb_pipe_stop_isoc_polling(ph, 1524 USB_FLAGS_NOSLEEP); 1525 1526 return; 1527 } else { 1528 mutex_exit(&uasp->usb_as_mutex); 1529 } 1530 1531 break; 1532 } 1533 usb_free_isoc_req(isoc_req); 1534 1535 mutex_enter(&uasp->usb_as_mutex); 1536 USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1537 "usb_as_record_exc_cb: state=%d cr=0x%x", 1538 uasp->usb_as_audio_state, completion_reason); 1539 1540 uasp->usb_as_audio_state = USB_AS_IDLE; 1541 mutex_exit(&uasp->usb_as_mutex); 1542} 1543 1544 1545/*ARGSUSED*/ 1546static void 1547usb_as_record_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) 1548{ 1549 usb_as_state_t *uasp = (usb_as_state_t *)isoc_req->isoc_client_private; 1550 int i, offset, sz; 1551 audiohdl_t ahdl; 1552 usb_audio_formats_t *format = &uasp->usb_as_curr_format; 1553 int precision; 1554 1555 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle, 1556 "usb_as_record_cb: rq=0x%p data=0x%p pkts=0x%x", 1557 (void *)isoc_req, (void *)isoc_req->isoc_data, 1558 isoc_req->isoc_pkts_count); 1559 1560 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle, 1561 "\tfno=%" PRId64 ", n_pkts=%u, flag=0x%x, data=0x%p, cnt=%d", 1562 isoc_req->isoc_frame_no, isoc_req->isoc_pkts_count, 1563 isoc_req->isoc_attributes, (void *)isoc_req->isoc_data, 1564 isoc_req->isoc_error_count); 1565 1566 ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) != 0); 1567 1568 mutex_enter(&uasp->usb_as_mutex); 1569 ahdl = uasp->usb_as_ahdl; 1570 sz = uasp->usb_as_record_pkt_size; 1571 precision = (format->fmt_precision == AUDIO_PRECISION_8) ? 1 : 2; 1572 1573 if (uasp->usb_as_audio_state != USB_AS_IDLE) { 1574#if defined(_BIG_ENDIAN) 1575 unsigned char *ptr = isoc_req->isoc_data->b_rptr; 1576#endif 1577 for (offset = i = 0; i < isoc_req->isoc_pkts_count; i++) { 1578#if defined(_BIG_ENDIAN) 1579 int len = isoc_req->isoc_pkt_descr[i]. 1580 isoc_pkt_actual_length; 1581 /* do byte swap for precision 16 */ 1582 if (format->fmt_precision == AUDIO_PRECISION_16) { 1583 int j; 1584 for (j = 0; j < len; j += 2, ptr += 2) { 1585 char t = *ptr; 1586 *ptr = *(ptr + 1); 1587 *(ptr + 1) = t; 1588 } 1589 } 1590#endif 1591 USB_DPRINTF_L3(PRINT_MASK_CB, uasp->usb_as_log_handle, 1592 "\tpkt%d: " 1593 "offset=%d pktsize=%d len=%d status=%d resid=%d", 1594 i, offset, sz, 1595 isoc_req->isoc_pkt_descr[i].isoc_pkt_length, 1596 isoc_req->isoc_pkt_descr[i].isoc_pkt_status, 1597 isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length); 1598 1599 if (isoc_req->isoc_pkt_descr[i].isoc_pkt_status != 1600 USB_CR_OK) { 1601 USB_DPRINTF_L2(PRINT_MASK_CB, 1602 uasp->usb_as_log_handle, 1603 "record: pkt=%d offset=0x%x status=%s", 1604 i, offset, usb_str_cr(isoc_req-> 1605 isoc_pkt_descr[i].isoc_pkt_status)); 1606 } 1607 mutex_exit(&uasp->usb_as_mutex); 1608 1609 am_send_audio(ahdl, 1610 isoc_req->isoc_data->b_rptr + offset, 1611 isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length / 1612 precision); 1613 1614 mutex_enter(&uasp->usb_as_mutex); 1615 offset += isoc_req->isoc_pkt_descr[i].isoc_pkt_length; 1616 } 1617 } 1618 1619 mutex_exit(&uasp->usb_as_mutex); 1620 1621 usb_free_isoc_req(isoc_req); 1622} 1623 1624 1625/* 1626 * Support for sample rates that are not multiple of 1K. We have 3 such 1627 * sample rates: 11025, 22050 and 44100. 1628 */ 1629typedef struct usb_as_pktsize_table { 1630 uint_t sr; 1631 ushort_t pkt; 1632 ushort_t cycle; 1633 int extra; 1634} usb_as_pktsize_table_t; 1635 1636/* 1637 * usb_as_pktsize_info is the table that calculates the pktsize 1638 * corresponding to the current frame and the current format. 1639 * Since the int_rate is 1000, we have to do special arithmetic for 1640 * sample rates not multiple of 1K. For example, 1641 * if the sample rate is 48000(i.e multiple of 1K), we can send 48000/1000 1642 * = 48 samples every packet per channel. Since we have to support sample 1643 * rate like 11025, 22050 and 44100, we will have some extra samples 1644 * at the end that we need to spread among the 1000 cycles. So if we make 1645 * the pktsize as below for these sample rates, at the end of 1000 cycles, 1646 * we will be able to send all the data in the correct rate: 1647 * 1648 * 11025: 39 samples of 11, 1 of 12 1649 * 22050: 19 samples of 22, 1 of 23 1650 * 44100: 9 samples of 44, 1 of 45 1651 * 1652 * frameno is a simple counter maintained in the soft state structure. 1653 * So the pkt size is: 1654 * pkt_size = ((frameno % cycle) ? pkt : (pkt + extra)); 1655 * 1656 */ 1657static usb_as_pktsize_table_t usb_as_pktsize_info[] = { 1658 {8000, 8, 1000, 0}, 1659 {9600, 10, 5, -2}, 1660 {11025, 11, 40, 1}, 1661 {16000, 16, 1000, 0}, 1662 {18900, 19, 10, -1}, 1663 {22050, 22, 20, 1}, 1664 {32000, 32, 1000, 0}, 1665 {33075, 33, 12, 1}, 1666 {37800, 38, 5, -1}, 1667 {44100, 44, 10, 1}, 1668 {48000, 48, 1000, 0}, 1669 { 0 } 1670}; 1671 1672 1673static int 1674usb_as_get_pktsize(usb_as_state_t *uasp, usb_audio_formats_t *format, 1675 usb_frame_number_t frameno) 1676{ 1677 int n; 1678 int pkt_size = 0; 1679 ushort_t pkt, cycle; 1680 int extra; 1681 int n_srs = 1682 sizeof (usb_as_pktsize_info) / sizeof (usb_as_pktsize_table_t); 1683 1684 for (n = 0; n < n_srs; n++) { 1685 if (usb_as_pktsize_info[n].sr == format->fmt_sr) { 1686 cycle = usb_as_pktsize_info[n].cycle; 1687 pkt = usb_as_pktsize_info[n].pkt; 1688 extra = usb_as_pktsize_info[n].extra; 1689 pkt_size = (((frameno + 1) % cycle) ? 1690 pkt : (pkt + extra)); 1691 pkt_size *= ((format->fmt_precision == 1692 AUDIO_PRECISION_16) ? 2 : 1) 1693 * format->fmt_chns; 1694 break; 1695 } 1696 } 1697 1698 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1699 "usb_as_get_pktsize: %d", pkt_size); 1700 1701 return (pkt_size); 1702} 1703 1704 1705/* 1706 * usb_as_send_ctrl_cmd: 1707 * Opens the pipe; sends a control command down 1708 */ 1709static int 1710usb_as_send_ctrl_cmd(usb_as_state_t *uasp, 1711 uchar_t bmRequestType, uchar_t bRequest, 1712 ushort_t wValue, ushort_t wIndex, ushort_t wLength, 1713 mblk_t *data, boolean_t ignore_errors) 1714{ 1715 usb_ctrl_setup_t setup; 1716 usb_cr_t cr; 1717 usb_cb_flags_t cf; 1718 1719 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1720 "usb_as_send_ctrl_cmd: Begin bmRequestType=%d,\n\t" 1721 "bRequest=%d, wValue=%d, wIndex=%d, wLength=%d, data=0x%p", 1722 bmRequestType, bRequest, wValue, wIndex, wLength, (void *)data); 1723 1724 setup.bmRequestType = bmRequestType & ~USB_DEV_REQ_DEV_TO_HOST; 1725 setup.bRequest = bRequest; 1726 setup.wValue = wValue; 1727 setup.wIndex = wIndex; 1728 setup.wLength = wLength; 1729 setup.attrs = 0; 1730 1731 if (usb_pipe_ctrl_xfer_wait(uasp->usb_as_default_ph, &setup, &data, 1732 &cr, &cf, 0) != USB_SUCCESS) { 1733 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1734 "usb_as_send_ctrl_cmd: usba xfer failed (req=%d), " 1735 "completion reason: 0x%x, completion flags: 0x%x", 1736 bRequest, cr, cf); 1737 1738 return (ignore_errors ? USB_SUCCESS: USB_FAILURE); 1739 } 1740 1741 return (USB_SUCCESS); 1742} 1743 1744 1745/* 1746 * Power management 1747 */ 1748 1749/*ARGSUSED*/ 1750static void 1751usb_as_create_pm_components(dev_info_t *dip, usb_as_state_t *uasp) 1752{ 1753 usb_as_power_t *uaspm; 1754 uint_t pwr_states; 1755 1756 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle, 1757 "usb_as_create_pm_components: begin"); 1758 1759 /* Allocate the state structure */ 1760 uaspm = kmem_zalloc(sizeof (usb_as_power_t), KM_SLEEP); 1761 uasp->usb_as_pm = uaspm; 1762 uaspm->aspm_state = uasp; 1763 uaspm->aspm_capabilities = 0; 1764 uaspm->aspm_current_power = USB_DEV_OS_FULL_PWR; 1765 1766 USB_DPRINTF_L3(PRINT_MASK_PM, uasp->usb_as_log_handle, 1767 "usb_as_pm_components: remote Wakeup enabled"); 1768 if (usb_create_pm_components(dip, &pwr_states) == 1769 USB_SUCCESS) { 1770 if (usb_handle_remote_wakeup(dip, 1771 USB_REMOTE_WAKEUP_ENABLE) != USB_SUCCESS) { 1772 USB_DPRINTF_L2(PRINT_MASK_PM, 1773 uasp->usb_as_log_handle, 1774 "enable remote wakeup failed"); 1775 } else { 1776 uaspm->aspm_wakeup_enabled = 1; 1777 } 1778 uaspm->aspm_pwr_states = (uint8_t)pwr_states; 1779 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1780 } 1781 1782 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle, 1783 "usb_as_create_pm_components: end"); 1784} 1785 1786 1787/* 1788 * usb_as_power: 1789 * power entry point 1790 */ 1791static int 1792usb_as_power(dev_info_t *dip, int comp, int level) 1793{ 1794 int instance = ddi_get_instance(dip); 1795 usb_as_state_t *uasp; 1796 usb_as_power_t *uaspm; 1797 int retval = USB_FAILURE; 1798 1799 uasp = ddi_get_soft_state(usb_as_statep, instance); 1800 1801 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle, 1802 "usb_as_power: comp=%d level=%d", comp, level); 1803 1804 (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0); 1805 1806 mutex_enter(&uasp->usb_as_mutex); 1807 uaspm = uasp->usb_as_pm; 1808 1809 if (USB_DEV_PWRSTATE_OK(uaspm->aspm_pwr_states, level)) { 1810 USB_DPRINTF_L2(PRINT_MASK_PM, uasp->usb_as_log_handle, 1811 "usb_as_power: illegal level=%d pwr_states=%d", 1812 level, uaspm->aspm_pwr_states); 1813 1814 goto done; 1815 } 1816 1817 switch (level) { 1818 case USB_DEV_OS_PWR_OFF: 1819 retval = usb_as_pwrlvl0(uasp); 1820 break; 1821 case USB_DEV_OS_PWR_1: 1822 retval = usb_as_pwrlvl1(uasp); 1823 break; 1824 case USB_DEV_OS_PWR_2: 1825 retval = usb_as_pwrlvl2(uasp); 1826 break; 1827 case USB_DEV_OS_FULL_PWR: 1828 retval = usb_as_pwrlvl3(uasp); 1829 break; 1830 default: 1831 retval = USB_FAILURE; 1832 break; 1833 } 1834 1835done: 1836 1837 usb_release_access(uasp->usb_as_ser_acc); 1838 mutex_exit(&uasp->usb_as_mutex); 1839 1840 return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 1841} 1842 1843 1844/* 1845 * functions to handle power transition for various levels 1846 * These functions act as place holders to issue USB commands 1847 * to the devices to change their power levels 1848 * Level 0 = Device is powered off 1849 * Level 3 = Device if full powered 1850 * Level 1,2 = Intermediate power level of the device as implemented 1851 * by the hardware. 1852 * Note that Level 0 is OS power-off and Level 3 is OS full-power. 1853 */ 1854static int 1855usb_as_pwrlvl0(usb_as_state_t *uasp) 1856{ 1857 usb_as_power_t *uaspm; 1858 int rval; 1859 1860 uaspm = uasp->usb_as_pm; 1861 1862 switch (uasp->usb_as_dev_state) { 1863 case USB_DEV_ONLINE: 1864 /* Deny the powerdown request if the device is busy */ 1865 if (uaspm->aspm_pm_busy != 0) { 1866 1867 return (USB_FAILURE); 1868 } 1869 1870 if (uasp->usb_as_audio_state != USB_AS_IDLE) { 1871 1872 return (USB_FAILURE); 1873 } 1874 1875 /* Issue USB D3 command to the device here */ 1876 rval = usb_set_device_pwrlvl3(uasp->usb_as_dip); 1877 ASSERT(rval == USB_SUCCESS); 1878 1879 uasp->usb_as_dev_state = USB_DEV_PWRED_DOWN; 1880 uaspm->aspm_current_power = USB_DEV_OS_PWR_OFF; 1881 1882 /* FALLTHRU */ 1883 case USB_DEV_DISCONNECTED: 1884 case USB_DEV_SUSPENDED: 1885 /* allow a disconnected/cpr'ed device to go to low power */ 1886 1887 return (USB_SUCCESS); 1888 case USB_DEV_PWRED_DOWN: 1889 default: 1890 USB_DPRINTF_L2(PRINT_MASK_PM, uasp->usb_as_log_handle, 1891 "usb_as_pwrlvl0: Illegal dev_state"); 1892 1893 return (USB_FAILURE); 1894 } 1895} 1896 1897 1898/* ARGSUSED */ 1899static int 1900usb_as_pwrlvl1(usb_as_state_t *uasp) 1901{ 1902 int rval; 1903 1904 /* Issue USB D2 command to the device here */ 1905 rval = usb_set_device_pwrlvl2(uasp->usb_as_dip); 1906 ASSERT(rval == USB_SUCCESS); 1907 1908 return (USB_FAILURE); 1909} 1910 1911 1912/* ARGSUSED */ 1913static int 1914usb_as_pwrlvl2(usb_as_state_t *uasp) 1915{ 1916 int rval; 1917 1918 rval = usb_set_device_pwrlvl1(uasp->usb_as_dip); 1919 ASSERT(rval == USB_SUCCESS); 1920 1921 return (USB_FAILURE); 1922} 1923 1924 1925static int 1926usb_as_pwrlvl3(usb_as_state_t *uasp) 1927{ 1928 usb_as_power_t *uaspm; 1929 int rval; 1930 1931 uaspm = uasp->usb_as_pm; 1932 1933 switch (uasp->usb_as_dev_state) { 1934 case USB_DEV_PWRED_DOWN: 1935 1936 /* Issue USB D0 command to the device here */ 1937 rval = usb_set_device_pwrlvl0(uasp->usb_as_dip); 1938 ASSERT(rval == USB_SUCCESS); 1939 1940 uasp->usb_as_dev_state = USB_DEV_ONLINE; 1941 uaspm->aspm_current_power = USB_DEV_OS_FULL_PWR; 1942 1943 /* FALLTHRU */ 1944 case USB_DEV_ONLINE: 1945 /* we are already in full power */ 1946 1947 /* fall thru */ 1948 case USB_DEV_DISCONNECTED: 1949 case USB_DEV_SUSPENDED: 1950 /* allow power change on a disconnected/cpr'ed device */ 1951 1952 return (USB_SUCCESS); 1953 default: 1954 USB_DPRINTF_L2(PRINT_MASK_PM, uasp->usb_as_log_handle, 1955 "usb_as_pwrlvl3: Illegal dev_state"); 1956 1957 return (DDI_FAILURE); 1958 } 1959} 1960 1961 1962/* 1963 * Descriptor Management 1964 * 1965 * usb_as_handle_descriptors: 1966 * read and parse all descriptors and build up usb_as_alts list 1967 * 1968 * the order is as follows: 1969 * interface, general, format, endpoint, CV endpoint 1970 */ 1971static int 1972usb_as_handle_descriptors(usb_as_state_t *uasp) 1973{ 1974 usb_client_dev_data_t *dev_data = uasp->usb_as_dev_data; 1975 int interface = dev_data->dev_curr_if; 1976 uint_t alternate; 1977 uint_t n_alternates; 1978 int len, i, n, n_srs, sr, index; 1979 int rval = USB_SUCCESS; 1980 usb_if_descr_t *if_descr; 1981 usb_audio_as_if_descr_t *general; 1982 usb_audio_type1_format_descr_t *format; 1983 usb_ep_descr_t *ep; 1984 usb_audio_as_isoc_ep_descr_t *cs_ep; 1985 usb_if_data_t *if_data; 1986 usb_alt_if_data_t *altif_data; 1987 usb_ep_data_t *ep_data; 1988 1989 USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 1990 "usb_as_handle_descriptors: cfg=%ld interface=%d", 1991 (long)(dev_data->dev_curr_cfg - &dev_data->dev_cfg[0]), 1992 dev_data->dev_curr_if); 1993 1994 if_data = &dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if]; 1995 uasp->usb_as_ifno = interface; 1996 1997 /* 1998 * find the number of alternates for this interface 1999 * and allocate an array to store the descriptors for 2000 * each alternate 2001 */ 2002 uasp->usb_as_n_alternates = n_alternates = if_data->if_n_alt; 2003 uasp->usb_as_alts = kmem_zalloc((n_alternates) * 2004 sizeof (usb_as_alt_descr_t), KM_SLEEP); 2005 2006 /* 2007 * for each alternate read descriptors 2008 */ 2009 for (alternate = 0; alternate < n_alternates; alternate++) { 2010 altif_data = &if_data->if_alt[alternate]; 2011 2012 uasp->usb_as_alts[alternate].alt_if = 2013 kmem_zalloc(sizeof (usb_if_descr_t), KM_SLEEP); 2014 if_descr = &altif_data->altif_descr; 2015 2016 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2017 "interface (%d.%d):\n\t" 2018 "l = 0x%x type = 0x%x n = 0x%x alt = 0x%x #ep = 0x%x\n\t" 2019 "iclass = 0x%x subclass = 0x%x proto = 0x%x string = 0x%x", 2020 interface, alternate, 2021 if_descr->bLength, if_descr->bDescriptorType, 2022 if_descr->bInterfaceNumber, if_descr->bAlternateSetting, 2023 if_descr->bNumEndpoints, if_descr->bInterfaceClass, 2024 if_descr->bInterfaceSubClass, 2025 if_descr->bInterfaceProtocol, if_descr->iInterface); 2026 2027 *(uasp->usb_as_alts[alternate].alt_if) = *if_descr; 2028 2029 /* read the general descriptor */ 2030 index = 0; 2031 2032 if (altif_data->altif_cvs == NULL) { 2033 2034 continue; 2035 } 2036 2037 general = kmem_zalloc(sizeof (*general), KM_SLEEP); 2038 2039 len = usb_parse_data(AS_IF_DESCR_FORMAT, 2040 altif_data->altif_cvs[index].cvs_buf, 2041 altif_data->altif_cvs[index].cvs_buf_len, 2042 (void *)general, sizeof (*general)); 2043 2044 /* is this a sane header descriptor */ 2045 if (!((len >= AS_IF_DESCR_SIZE) && 2046 (general->bDescriptorType == USB_AUDIO_CS_INTERFACE) && 2047 (general->bDescriptorSubType == USB_AUDIO_AS_GENERAL))) { 2048 USB_DPRINTF_L2(PRINT_MASK_ATTA, 2049 uasp->usb_as_log_handle, 2050 "invalid general cs interface descr"); 2051 2052 kmem_free(general, sizeof (*general)); 2053 2054 continue; 2055 } 2056 2057 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2058 "general (%d.%d): type=0x%x subtype=0x%x termlink=0x%x\n\t" 2059 "delay=0x%x format=0x%x", 2060 interface, alternate, 2061 general->bDescriptorType, general->bDescriptorSubType, 2062 general->bTerminalLink, general->bDelay, 2063 general->wFormatTag); 2064 2065 uasp->usb_as_alts[alternate].alt_general = general; 2066 2067 /* 2068 * there should be one format descriptor of unknown size. 2069 * the format descriptor contains just bytes, no need to 2070 * parse 2071 */ 2072 index++; 2073 len = altif_data->altif_cvs[index].cvs_buf_len; 2074 format = kmem_zalloc(len, KM_SLEEP); 2075 bcopy(altif_data->altif_cvs[index].cvs_buf, format, len); 2076 2077 uasp->usb_as_alts[alternate].alt_format_len = (uchar_t)len; 2078 2079 /* is this a sane format descriptor */ 2080 if (!((format->blength >= AUDIO_TYPE1_FORMAT_SIZE) && 2081 format->bDescriptorSubType == USB_AUDIO_AS_FORMAT_TYPE)) { 2082 USB_DPRINTF_L2(PRINT_MASK_ATTA, 2083 uasp->usb_as_log_handle, 2084 "invalid format cs interface descr"); 2085 2086 kmem_free(format, len); 2087 2088 continue; 2089 } 2090 2091 uasp->usb_as_alts[alternate].alt_format = format; 2092 2093 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2094 "format (%d.%d): len = %d " 2095 "type = 0x%x subtype = 0x%x format = 0x%x\n\t" 2096 "#channels = 0x%x subframe = 0x%x resolution = 0x%x\n\t" 2097 "sample freq type = 0x%x", 2098 interface, alternate, len, 2099 format->bDescriptorType, 2100 format->bDescriptorSubType, 2101 format->bFormatType, 2102 format->bNrChannels, 2103 format->bSubFrameSize, 2104 format->bBitResolution, 2105 format->bSamFreqType); 2106 2107 if (format->bSamFreqType == 0) { 2108 /* continuous sample rate limits */ 2109 n_srs = 2; 2110 uasp->usb_as_alts[alternate].alt_continuous_sr++; 2111 } else { 2112 n_srs = format->bSamFreqType; 2113 } 2114 2115 uasp->usb_as_alts[alternate].alt_n_sample_rates = 2116 (uchar_t)n_srs; 2117 2118 uasp->usb_as_alts[alternate].alt_sample_rates = 2119 kmem_zalloc(n_srs * (sizeof (uint_t)), KM_SLEEP); 2120 2121 /* go thru all sample rates (3 bytes) each */ 2122 for (i = 0, n = 0; n < n_srs; i += 3, n++) { 2123 sr = ((format->bSamFreqs[i+2] << 16) & 0xff0000) | 2124 ((format->bSamFreqs[i+1] << 8) & 0xff00) | 2125 (format->bSamFreqs[i] & 0xff); 2126 2127 USB_DPRINTF_L3(PRINT_MASK_ATTA, 2128 uasp->usb_as_log_handle, 2129 "sr = %d", sr); 2130 2131 uasp->usb_as_alts[alternate]. 2132 alt_sample_rates[n] = sr; 2133 } 2134 2135 if ((ep_data = usb_lookup_ep_data(uasp->usb_as_dip, 2136 dev_data, interface, alternate, 0, 2137 USB_EP_ATTR_ISOCH, USB_EP_DIR_IN)) == NULL) { 2138 if ((ep_data = usb_lookup_ep_data(uasp->usb_as_dip, 2139 dev_data, interface, alternate, 0, 2140 USB_EP_ATTR_ISOCH, USB_EP_DIR_OUT)) == NULL) { 2141 2142 USB_DPRINTF_L2(PRINT_MASK_ATTA, 2143 uasp->usb_as_log_handle, 2144 "no endpoint descriptor found"); 2145 2146 continue; 2147 } 2148 } 2149 ep = &ep_data->ep_descr; 2150 2151 uasp->usb_as_alts[alternate].alt_ep = 2152 kmem_zalloc(sizeof (usb_ep_descr_t), KM_SLEEP); 2153 *(uasp->usb_as_alts[alternate].alt_ep) = *ep; 2154 2155 USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2156 "endpoint (%d.%d):\n\t" 2157 "len = 0x%x type = 0x%x add = 0x%x " 2158 "attr = 0x%x mps = 0x%x\n\t" 2159 "int = 0x%x", 2160 interface, alternate, 2161 ep->bLength, ep->bDescriptorType, ep->bEndpointAddress, 2162 ep->bmAttributes, ep->wMaxPacketSize, ep->bInterval); 2163 2164 uasp->usb_as_alts[alternate].alt_mode = 2165 (ep->bEndpointAddress & USB_EP_DIR_IN) ? 2166 AUDIO_RECORD : AUDIO_PLAY; 2167 2168 if (ep_data->ep_n_cvs == 0) { 2169 USB_DPRINTF_L2(PRINT_MASK_ATTA, 2170 uasp->usb_as_log_handle, 2171 "no cv ep descriptor"); 2172 2173 continue; 2174 } 2175 2176 cs_ep = kmem_zalloc(sizeof (*cs_ep), KM_SLEEP); 2177 len = usb_parse_data(AS_ISOC_EP_DESCR_FORMAT, 2178 ep_data->ep_cvs[0].cvs_buf, 2179 ep_data->ep_cvs[0].cvs_buf_len, 2180 (void *)cs_ep, sizeof (*cs_ep)); 2181 2182 if ((len < AS_ISOC_EP_DESCR_SIZE) || 2183 (cs_ep->bDescriptorType != USB_AUDIO_CS_ENDPOINT)) { 2184 USB_DPRINTF_L2(PRINT_MASK_ATTA, 2185 uasp->usb_as_log_handle, 2186 "cs endpoint descriptor invalid (%d)", len); 2187 kmem_free(cs_ep, sizeof (*cs_ep)); 2188 2189 continue; 2190 } 2191 2192 USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2193 "cs isoc endpoint (%d.%d):\n\t" 2194 "type=0x%x sub=0x%x attr=0x%x units=0x%x delay=%x", 2195 interface, alternate, 2196 cs_ep->bDescriptorType, 2197 cs_ep->bDescriptorSubType, 2198 cs_ep->bmAttributes, 2199 cs_ep->bLockDelayUnits, 2200 cs_ep->wLockDelay); 2201 2202 uasp->usb_as_alts[alternate].alt_cs_ep = cs_ep; 2203 2204 /* we are done */ 2205 uasp->usb_as_alts[alternate].alt_valid++; 2206 } 2207 2208done: 2209 usb_as_prepare_registration_data(uasp); 2210 2211 return (rval); 2212} 2213 2214 2215/* 2216 * usb_as_free_alts: 2217 * cleanup alternate list and deallocate all descriptors 2218 */ 2219static void 2220usb_as_free_alts(usb_as_state_t *uasp) 2221{ 2222 int alt; 2223 usb_as_alt_descr_t *altp; 2224 2225 if (uasp->usb_as_alts) { 2226 for (alt = 0; alt < uasp->usb_as_n_alternates; alt++) { 2227 altp = &uasp->usb_as_alts[alt]; 2228 if (altp) { 2229 if (altp->alt_sample_rates) { 2230 kmem_free(altp->alt_sample_rates, 2231 altp->alt_n_sample_rates * 2232 sizeof (uint_t)); 2233 } 2234 if (altp->alt_if) { 2235 kmem_free(altp->alt_if, 2236 sizeof (usb_if_descr_t)); 2237 } 2238 if (altp->alt_general) { 2239 kmem_free(altp->alt_general, 2240 sizeof (usb_audio_as_if_descr_t)); 2241 } 2242 if (altp->alt_format) { 2243 kmem_free(altp->alt_format, 2244 altp->alt_format_len); 2245 } 2246 if (altp->alt_ep) { 2247 kmem_free(altp->alt_ep, 2248 sizeof (usb_ep_descr_t)); 2249 } 2250 if (altp->alt_cs_ep) { 2251 kmem_free(altp->alt_cs_ep, 2252 sizeof (*altp->alt_cs_ep)); 2253 } 2254 } 2255 } 2256 kmem_free(uasp->usb_as_alts, (uasp->usb_as_n_alternates) * 2257 sizeof (usb_as_alt_descr_t)); 2258 } 2259} 2260 2261 2262/* 2263 * usb_as_prepare_registration_data 2264 */ 2265static void 2266usb_as_prepare_registration_data(usb_as_state_t *uasp) 2267{ 2268 usb_as_registration_t *reg = &uasp->usb_as_reg; 2269 usb_audio_type1_format_descr_t *format; 2270 uchar_t n_alternates = uasp->usb_as_n_alternates; 2271 uchar_t channels[3]; 2272 int alt, n, i, t; 2273 2274 USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2275 "usb_as_prepare_registration_data:"); 2276 2277 /* there has to be at least two alternates, ie 0 and 1 */ 2278 if (n_alternates < 2) { 2279 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2280 "not enough alternates %d", n_alternates); 2281 2282 return; 2283 } 2284 2285 reg->reg_ifno = uasp->usb_as_ifno; 2286 reg->reg_mode = uasp->usb_as_alts[1].alt_mode; 2287 2288 /* all endpoints need to have the same direction */ 2289 for (alt = 2; alt < n_alternates; alt++) { 2290 if (!uasp->usb_as_alts[alt].alt_valid) { 2291 continue; 2292 } 2293 if (uasp->usb_as_alts[alt].alt_mode != 2294 reg->reg_mode) { 2295 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2296 "alternates have different direction"); 2297 2298 return; 2299 } 2300 } 2301 2302 /* copy over sample rate table but zero it first */ 2303 bzero(reg->reg_srs, sizeof (reg->reg_srs)); 2304 bcopy(usb_as_default_srs, reg->reg_srs, sizeof (usb_as_default_srs)); 2305 2306 channels[1] = channels[2] = 0; 2307 2308 /* 2309 * we assume that alternate 0 is not interesting (no bandwidth), 2310 * we check all formats and use the formats that we can support 2311 */ 2312 for (alt = 1, n = 0; alt < n_alternates; alt++) { 2313 if (!uasp->usb_as_alts[alt].alt_valid) { 2314 continue; 2315 } 2316 2317 format = uasp->usb_as_alts[alt].alt_format; 2318 if (uasp->usb_as_alts[alt].alt_valid && 2319 (n < USB_AS_N_FORMATS) && 2320 (usb_as_valid_format(uasp, alt, 2321 reg->reg_srs, 2322 (sizeof (reg->reg_srs)/ 2323 sizeof (uint_t)) - 1)) == USB_SUCCESS) { 2324 reg->reg_formats[n].fmt_termlink = 2325 uasp->usb_as_alts[alt].alt_general-> 2326 bTerminalLink; 2327 reg->reg_formats[n].fmt_alt = (uchar_t)alt; 2328 reg->reg_formats[n].fmt_chns = 2329 format->bNrChannels; 2330 reg->reg_formats[n].fmt_precision = 2331 format->bBitResolution; 2332 reg->reg_formats[n++].fmt_encoding = 2333 usb_audio_fmt_convert(format->bFormatType); 2334 /* count how many mono and stereo we have */ 2335 channels[format->bNrChannels]++; 2336 } 2337 } 2338 2339 reg->reg_n_formats = (uchar_t)n; 2340 2341 if (n == 0) { 2342 /* no valid formats */ 2343 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2344 "zero valid formats"); 2345 2346 return; 2347 } 2348 2349 /* dump what we have so far */ 2350 for (n = 0; n < reg->reg_n_formats; n++) { 2351 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2352 "format%d: alt=%d chns=%d prec=%d enc=%d", n, 2353 reg->reg_formats[n].fmt_alt, 2354 reg->reg_formats[n].fmt_chns, 2355 reg->reg_formats[n].fmt_precision, 2356 reg->reg_formats[n].fmt_encoding); 2357 } 2358 2359 /* 2360 * Fill out channels 2361 * Note that we assumed all alternates have the same number 2362 * of channels. 2363 */ 2364 n = 0; 2365 if (channels[1]) { 2366 reg->reg_channels[n++] = AUDIO_CHANNELS_MONO; 2367 } 2368 if (channels[2]) { 2369 reg->reg_channels[n] = AUDIO_CHANNELS_STEREO; 2370 } 2371 2372 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2373 "channels %d %d", reg->reg_channels[0], reg->reg_channels[1]); 2374 2375 2376 /* fill out combinations */ 2377 for (i = n = 0; n < reg->reg_n_formats; n++) { 2378 uchar_t prec = reg->reg_formats[n].fmt_precision; 2379 uchar_t enc = reg->reg_formats[n].fmt_encoding; 2380 2381 /* check if already there */ 2382 for (t = 0; t < n; t++) { 2383 uchar_t ad_prec = reg->reg_combinations[t].ad_prec; 2384 uchar_t ad_enc = reg->reg_combinations[t].ad_enc; 2385 if ((prec == ad_prec) && (enc == ad_enc)) { 2386 break; 2387 } 2388 } 2389 2390 /* if not, add this combination */ 2391 if (t == n) { 2392 reg->reg_combinations[i].ad_prec = prec; 2393 reg->reg_combinations[i++].ad_enc = enc; 2394 } 2395 } 2396 2397 2398 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2399 "combinations: %d %d %d %d %d %d %d %d", 2400 reg->reg_combinations[0].ad_prec, reg->reg_combinations[0].ad_enc, 2401 reg->reg_combinations[1].ad_prec, reg->reg_combinations[1].ad_enc, 2402 reg->reg_combinations[2].ad_prec, reg->reg_combinations[2].ad_enc, 2403 reg->reg_combinations[3].ad_prec, reg->reg_combinations[3].ad_enc); 2404 2405 reg->reg_valid++; 2406} 2407 2408 2409/* 2410 * usb_as_valid_format: 2411 * check if this format can be supported 2412 */ 2413static int 2414usb_as_valid_format(usb_as_state_t *uasp, uint_t alternate, 2415 uint_t *srs, uint_t n_srs) 2416{ 2417 int n, i, j; 2418 usb_as_alt_descr_t *alt_descr = &uasp->usb_as_alts[alternate]; 2419 usb_audio_type1_format_descr_t *format = alt_descr->alt_format; 2420 2421 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle, 2422 "usb_as_valid_format: %d %d %d %d %d", 2423 format->bNrChannels, format->bSubFrameSize, 2424 format->bBitResolution, format->bSamFreqType, 2425 format->bFormatType); 2426 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle, 2427 "alt=%d n_srs=%d", alternate, n_srs); 2428 2429 switch (format->bNrChannels) { 2430 case 1: 2431 case 2: 2432 break; 2433 default: 2434 2435 return (USB_FAILURE); 2436 } 2437 2438 switch (format->bSubFrameSize) { 2439 case 1: 2440 case 2: 2441 break; 2442 default: 2443 2444 return (USB_FAILURE); 2445 } 2446 2447 switch (format->bBitResolution) { 2448 case 8: 2449 case 16: 2450 break; 2451 default: 2452 2453 return (USB_FAILURE); 2454 } 2455 2456 switch (format->bFormatType) { 2457 case USB_AUDIO_FORMAT_TYPE1_PCM: 2458 break; 2459 default: 2460 2461 return (USB_FAILURE); 2462 } 2463 2464 switch (format->bSamFreqType) { 2465 case 0: 2466 /* continuous */ 2467 2468 break; 2469 default: 2470 /* count the number of sample rates we still have */ 2471 for (j = n = 0; j < n_srs; n++) { 2472 if (srs[n] == 0) { 2473 2474 break; 2475 } else { 2476 j++; 2477 } 2478 } 2479 2480 /* check if our preferred sample rates are supported */ 2481 for (n = 0; n < n_srs; n++) { 2482 uint_t sr = srs[n]; 2483 2484 if (sr == 0) { 2485 break; 2486 } 2487 2488 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle, 2489 "checking sr=%d", sr); 2490 for (i = 0; i < alt_descr->alt_n_sample_rates; i++) { 2491 if (sr == alt_descr->alt_sample_rates[i]) { 2492 break; 2493 } 2494 } 2495 2496 if (i == alt_descr->alt_n_sample_rates) { 2497 /* 2498 * remove this sample rate except if it is 2499 * the last one 2500 */ 2501 if (j > 1) { 2502 srs[n] = 0; 2503 } else { 2504 2505 return (USB_FAILURE); 2506 } 2507 } 2508 } 2509 2510 USB_DPRINTF_L3(PRINT_MASK_PM, uasp->usb_as_log_handle, 2511 "before srs (%d): %d %d %d %d %d %d %d %d %d %d %d %d", 2512 n_srs, 2513 srs[0], srs[1], srs[2], srs[3], srs[4], srs[5], srs[6], 2514 srs[7], srs[8], srs[9], srs[10], srs[11]); 2515 2516 2517 /* now compact srs table, eliminating zero entries */ 2518 for (i = n = 0; n < n_srs; n++) { 2519 if (srs[n]) { 2520 /* move up & remove from the list */ 2521 srs[i] = srs[n]; 2522 if (i++ != n) { 2523 srs[n] = 0; 2524 } 2525 } 2526 } 2527 2528 /* last entry must always be zero */ 2529 srs[i] = 0; 2530 2531 USB_DPRINTF_L3(PRINT_MASK_PM, uasp->usb_as_log_handle, 2532 "before srs (%d): %d %d %d %d %d %d %d %d %d %d %d %d", 2533 n_srs, 2534 srs[0], srs[1], srs[2], srs[3], srs[4], srs[5], srs[6], 2535 srs[7], srs[8], srs[9], srs[10], srs[11]); 2536 2537 break; 2538 } 2539 return (USB_SUCCESS); 2540} 2541 2542 2543/* 2544 * convert usb audio format type to SADA type 2545 */ 2546static int 2547usb_audio_fmt_convert(int type) 2548{ 2549 switch (type) { 2550 case USB_AUDIO_FORMAT_TYPE1_PCM: 2551 return (AUDIO_ENCODING_LINEAR); 2552 2553 case USB_AUDIO_FORMAT_TYPE1_PCM8: 2554 return (AUDIO_ENCODING_LINEAR8); 2555 2556 case USB_AUDIO_FORMAT_TYPE1_ALAW: 2557 return (AUDIO_ENCODING_ALAW); 2558 2559 case USB_AUDIO_FORMAT_TYPE1_MULAW: 2560 return (AUDIO_ENCODING_ULAW); 2561 2562 case USB_AUDIO_FORMAT_TYPE1_IEEE_FLOAT: 2563 default: 2564 return (0); 2565 } 2566} 2567 2568 2569/* 2570 * Event Management 2571 * 2572 * usb_as_disconnect_event_cb: 2573 * The device has been disconnected. 2574 */ 2575static int 2576usb_as_disconnect_event_cb(dev_info_t *dip) 2577{ 2578 usb_as_state_t *uasp = (usb_as_state_t *)ddi_get_soft_state( 2579 usb_as_statep, ddi_get_instance(dip)); 2580 2581 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uasp->usb_as_log_handle, 2582 "usb_as_disconnect_event_cb: dip=0x%p", (void *)dip); 2583 2584 (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0); 2585 2586 mutex_enter(&uasp->usb_as_mutex); 2587 uasp->usb_as_dev_state = USB_DEV_DISCONNECTED; 2588 mutex_exit(&uasp->usb_as_mutex); 2589 2590 usb_release_access(uasp->usb_as_ser_acc); 2591 2592 return (USB_SUCCESS); 2593} 2594 2595 2596/* 2597 * usb_as_cpr_suspend: 2598 */ 2599static int 2600usb_as_cpr_suspend(dev_info_t *dip) 2601{ 2602 usb_as_state_t *uasp = (usb_as_state_t *)ddi_get_soft_state( 2603 usb_as_statep, ddi_get_instance(dip)); 2604 2605 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uasp->usb_as_log_handle, 2606 "usb_as_cpr_suspend: Begin"); 2607 2608 (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0); 2609 2610 mutex_enter(&uasp->usb_as_mutex); 2611 uasp->usb_as_dev_state = USB_DEV_SUSPENDED; 2612 mutex_exit(&uasp->usb_as_mutex); 2613 2614 usb_release_access(uasp->usb_as_ser_acc); 2615 2616 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 2617 "usb_as_cpr_suspend: End"); 2618 2619 return (USB_SUCCESS); 2620} 2621 2622 2623/* 2624 * usb_as_reconnect_event_cb: 2625 * The device was disconnected but this instance not detached, probably 2626 * because the device was busy. 2627 * if the same device, continue with restoring state 2628 */ 2629static int 2630usb_as_reconnect_event_cb(dev_info_t *dip) 2631{ 2632 usb_as_state_t *uasp = (usb_as_state_t *)ddi_get_soft_state( 2633 usb_as_statep, ddi_get_instance(dip)); 2634 2635 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uasp->usb_as_log_handle, 2636 "usb_as_reconnect_event_cb: dip=0x%p", (void *)dip); 2637 2638 (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0); 2639 2640 mutex_enter(&uasp->usb_as_mutex); 2641 usb_as_restore_device_state(dip, uasp); 2642 mutex_exit(&uasp->usb_as_mutex); 2643 2644 usb_release_access(uasp->usb_as_ser_acc); 2645 2646 return (USB_SUCCESS); 2647} 2648 2649 2650/* 2651 * usb_as_cpr_resume: 2652 * recover this device from suspended state 2653 */ 2654static void 2655usb_as_cpr_resume(dev_info_t *dip) 2656{ 2657 usb_as_state_t *uasp = (usb_as_state_t *)ddi_get_soft_state( 2658 usb_as_statep, ddi_get_instance(dip)); 2659 2660 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uasp->usb_as_log_handle, 2661 "usb_as_cpr_resume: dip=0x%p", (void *)dip); 2662 2663 (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0); 2664 2665 mutex_enter(&uasp->usb_as_mutex); 2666 usb_as_restore_device_state(dip, uasp); 2667 mutex_exit(&uasp->usb_as_mutex); 2668 2669 usb_release_access(uasp->usb_as_ser_acc); 2670} 2671 2672 2673/* 2674 * usb_as_restore_device_state: 2675 * Set original configuration of the device 2676 * enable wrq - this starts new transactions on the control pipe 2677 */ 2678static void 2679usb_as_restore_device_state(dev_info_t *dip, usb_as_state_t *uasp) 2680{ 2681 usb_as_power_t *uaspm; 2682 2683 USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2684 "usb_as_restore_device_state:"); 2685 2686 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 2687 2688 uaspm = uasp->usb_as_pm; 2689 2690 /* Check if we are talking to the same device */ 2691 mutex_exit(&uasp->usb_as_mutex); 2692 usb_as_pm_busy_component(uasp); 2693 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2694 2695 if (usb_check_same_device(dip, uasp->usb_as_log_handle, USB_LOG_L0, 2696 PRINT_MASK_ALL, USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) { 2697 usb_as_pm_idle_component(uasp); 2698 2699 /* change the device state from suspended to disconnected */ 2700 mutex_enter(&uasp->usb_as_mutex); 2701 uasp->usb_as_dev_state = USB_DEV_DISCONNECTED; 2702 2703 return; 2704 } 2705 mutex_enter(&uasp->usb_as_mutex); 2706 2707 if (uaspm) { 2708 if (uaspm->aspm_wakeup_enabled) { 2709 mutex_exit(&uasp->usb_as_mutex); 2710 if (usb_handle_remote_wakeup(uasp->usb_as_dip, 2711 USB_REMOTE_WAKEUP_ENABLE)) { 2712 USB_DPRINTF_L2(PRINT_MASK_ALL, 2713 uasp->usb_as_log_handle, 2714 "enable remote wake up failed"); 2715 } 2716 mutex_enter(&uasp->usb_as_mutex); 2717 } 2718 } 2719 uasp->usb_as_dev_state = USB_DEV_ONLINE; 2720 2721 mutex_exit(&uasp->usb_as_mutex); 2722 usb_as_pm_idle_component(uasp); 2723 mutex_enter(&uasp->usb_as_mutex); 2724} 2725 2726 2727static void 2728usb_as_pm_busy_component(usb_as_state_t *usb_as_statep) 2729{ 2730 ASSERT(!mutex_owned(&usb_as_statep->usb_as_mutex)); 2731 2732 if (usb_as_statep->usb_as_pm != NULL) { 2733 mutex_enter(&usb_as_statep->usb_as_mutex); 2734 usb_as_statep->usb_as_pm->aspm_pm_busy++; 2735 2736 USB_DPRINTF_L4(PRINT_MASK_PM, usb_as_statep->usb_as_log_handle, 2737 "usb_as_pm_busy_component: %d", 2738 usb_as_statep->usb_as_pm->aspm_pm_busy); 2739 2740 mutex_exit(&usb_as_statep->usb_as_mutex); 2741 2742 if (pm_busy_component(usb_as_statep->usb_as_dip, 0) != 2743 DDI_SUCCESS) { 2744 mutex_enter(&usb_as_statep->usb_as_mutex); 2745 usb_as_statep->usb_as_pm->aspm_pm_busy--; 2746 2747 USB_DPRINTF_L2(PRINT_MASK_PM, 2748 usb_as_statep->usb_as_log_handle, 2749 "usb_as_pm_busy_component failed: %d", 2750 usb_as_statep->usb_as_pm->aspm_pm_busy); 2751 2752 mutex_exit(&usb_as_statep->usb_as_mutex); 2753 } 2754 } 2755} 2756 2757 2758static void 2759usb_as_pm_idle_component(usb_as_state_t *usb_as_statep) 2760{ 2761 ASSERT(!mutex_owned(&usb_as_statep->usb_as_mutex)); 2762 2763 if (usb_as_statep->usb_as_pm != NULL) { 2764 if (pm_idle_component(usb_as_statep->usb_as_dip, 0) == 2765 DDI_SUCCESS) { 2766 mutex_enter(&usb_as_statep->usb_as_mutex); 2767 ASSERT(usb_as_statep->usb_as_pm->aspm_pm_busy > 0); 2768 usb_as_statep->usb_as_pm->aspm_pm_busy--; 2769 2770 USB_DPRINTF_L4(PRINT_MASK_PM, 2771 usb_as_statep->usb_as_log_handle, 2772 "usb_as_pm_idle_component: %d", 2773 usb_as_statep->usb_as_pm->aspm_pm_busy); 2774 2775 mutex_exit(&usb_as_statep->usb_as_mutex); 2776 } 2777 } 2778} 2779