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