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