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