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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Audio Streams Driver: This driver is responsible for 31 * (1) Processing audio data messages during play and record and 32 * management of isoc pipe, (2) Selecting correct alternate that matches 33 * a set of parameters and management of control pipe. This streams driver 34 * is pushed under usb_ac and interacts with usb_ac using streams messages. 35 * When a streams message has been received from usb_ac, it is immediately 36 * put on WQ. The write side service routine loops thru all the queued 37 * messages, processes them and sends up a reply. If the processing involves 38 * an async USBA command, the reqly is sent up after completion of the 39 * command. 40 * 41 * Note: (1) All streams messages from usb_ac are M_CTL messages. 42 * (2) When there is a play/record, usb_as calls mixer routines directly for 43 * data (play) or sends data to mixer (record). 44 * 45 * Serialization: usb_as being a streams driver and having the requirement 46 * making non-blockings calls (USBA or streams or mixer) needs to drop 47 * mutexes over such calls. But at the same time, a competing thread 48 * can't be allowed to interfere with (1) pipe, (2) streams state. 49 * So we need some kind of serialization among the asynchronous 50 * threads that can run in the driver. The serialization is mostly 51 * needed to avoid races among open/close/events/power entry points 52 * etc. Once a routine grabs access, if checks if the resource (pipe or 53 * stream or dev state) is still accessible. If so, it proceeds with 54 * its job and until it completes, no other thread requiring the same 55 * resource can run. 56 * 57 * PM Model in usb_as: Raise power during attach and lower power in detach. 58 * If device is not fully powered, synchronous raise power in wsrv entry points. 59 * 60 * locking: Warlock is not aware of the automatic locking mechanisms for 61 * streams drivers. This driver is single threaded per queue instance. 62 * 63 * TODO: 64 * - mdb dcmds 65 * - dump 66 * - kstat 67 */ 68 #include <sys/usb/usba/usbai_version.h> 69 #include <sys/usb/usba.h> 70 #include <sys/stropts.h> 71 #include <sys/strsun.h> 72 #include <sys/strsubr.h> 73 74 #include <sys/audio.h> 75 #include <sys/audiovar.h> 76 #include <sys/audio/audio_support.h> 77 #include <sys/audio/audio_src.h> 78 #include <sys/mixer.h> 79 #include <sys/audio/audio_mixer.h> 80 #include <sys/audio/am_src2.h> 81 82 #include <sys/usb/clients/audio/usb_audio.h> 83 #include <sys/usb/clients/audio/usb_mixer.h> 84 #include <sys/usb/clients/audio/usb_as/usb_as.h> 85 86 /* debug support */ 87 uint_t usb_as_errlevel = USB_LOG_L4; 88 uint_t usb_as_errmask = (uint_t)-1; 89 uint_t usb_as_instance_debug = (uint_t)-1; 90 91 /* 92 * Module linkage routines for the kernel 93 */ 94 static int usb_as_attach(dev_info_t *, ddi_attach_cmd_t); 95 static int usb_as_detach(dev_info_t *, ddi_detach_cmd_t); 96 static int usb_as_power(dev_info_t *, int, int); 97 static int usb_as_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 98 99 /* 100 * STREAMS module entry points 101 */ 102 static int usb_as_open(); 103 static int usb_as_close(); 104 static int usb_as_wsrv(); 105 106 /* support functions */ 107 static void usb_as_cleanup(dev_info_t *, usb_as_state_t *); 108 109 static int usb_as_handle_descriptors(usb_as_state_t *); 110 static void usb_as_prepare_registration_data(usb_as_state_t *); 111 static int usb_as_valid_format(usb_as_state_t *, uint_t, 112 uint_t *, uint_t); 113 static void usb_as_free_alts(usb_as_state_t *); 114 static int usb_audio_fmt_convert(int); 115 116 static void usb_as_create_pm_components(dev_info_t *, usb_as_state_t *); 117 static int usb_as_disconnect_event_cb(dev_info_t *); 118 static int usb_as_reconnect_event_cb(dev_info_t *); 119 static int usb_as_cpr_suspend(dev_info_t *); 120 static void usb_as_cpr_resume(dev_info_t *); 121 122 static int usb_as_ioctl(queue_t *, mblk_t *); 123 static int usb_as_mctl_rcv(queue_t *, mblk_t *); 124 125 static void usb_as_default_xfer_cb(usb_pipe_handle_t, usb_ctrl_req_t *); 126 static void usb_as_default_xfer_exc_cb(usb_pipe_handle_t, usb_ctrl_req_t *); 127 128 static int usb_as_pwrlvl0(usb_as_state_t *); 129 static int usb_as_pwrlvl1(usb_as_state_t *); 130 static int usb_as_pwrlvl2(usb_as_state_t *); 131 static int usb_as_pwrlvl3(usb_as_state_t *); 132 static void usb_as_pm_busy_component(usb_as_state_t *); 133 static void usb_as_pm_idle_component(usb_as_state_t *); 134 135 static void usb_as_restore_device_state(dev_info_t *, usb_as_state_t *); 136 static int usb_as_setup(usb_as_state_t *, mblk_t *); 137 static void usb_as_teardown(usb_as_state_t *, mblk_t *); 138 static int usb_as_start_play(usb_as_state_t *, mblk_t *); 139 static void usb_as_continue_play(usb_as_state_t *); 140 static void usb_as_pause_play(usb_as_state_t *, mblk_t *); 141 142 static void usb_as_qreply_error(usb_as_state_t *, queue_t *, mblk_t *); 143 static void usb_as_send_merr_up(usb_as_state_t *, mblk_t *); 144 static void usb_as_send_mctl_up(usb_as_state_t *, mblk_t *); 145 static int usb_as_set_format(usb_as_state_t *, mblk_t *); 146 static int usb_as_set_sample_freq(usb_as_state_t *, mblk_t *); 147 static int usb_as_send_ctrl_cmd(usb_as_state_t *, uchar_t, uchar_t, 148 ushort_t, ushort_t, ushort_t, mblk_t *, boolean_t); 149 150 static void usb_as_isoc_close_cb(usb_pipe_handle_t ph, 151 usb_opaque_t arg, int, usb_cb_flags_t); 152 static int usb_as_start_record(usb_as_state_t *, mblk_t *); 153 static int usb_as_stop_record(usb_as_state_t *, mblk_t *); 154 static void usb_as_play_cb(usb_pipe_handle_t, usb_isoc_req_t *); 155 static void usb_as_record_cb(usb_pipe_handle_t, usb_isoc_req_t *); 156 static void usb_as_play_exc_cb(usb_pipe_handle_t, usb_isoc_req_t *); 157 static void usb_as_record_exc_cb(usb_pipe_handle_t, usb_isoc_req_t *); 158 static int usb_as_get_pktsize(usb_as_state_t *, usb_audio_formats_t *, 159 usb_frame_number_t); 160 static void usb_as_handle_shutdown(usb_as_state_t *, mblk_t *); 161 static int usb_as_play_isoc_data(usb_as_state_t *, mblk_t *); 162 163 /* anchor for soft state structures */ 164 static void *usb_as_statep; 165 166 /* 167 * STREAMS Structures 168 */ 169 170 /* STREAMS driver id and limit value structure */ 171 static struct module_info usb_as_modinfo = { 172 0xffff, /* module ID number */ 173 "usb_as", /* module name */ 174 USB_AUDIO_MIN_PKTSZ, /* minimum packet size */ 175 USB_AUDIO_MAX_PKTSZ, /* maximum packet size */ 176 USB_AS_HIWATER, /* high water mark */ 177 USB_AS_LOWATER /* low water mark */ 178 }; 179 180 /* STREAMS queue processing procedures structures */ 181 /* read queue */ 182 static struct qinit usb_as_rqueue = { 183 NULL, /* put procedure */ 184 NULL, /* service procedure */ 185 usb_as_open, /* open procedure */ 186 usb_as_close, /* close procedure */ 187 NULL, /* unused */ 188 &usb_as_modinfo, /* module parameters */ 189 NULL /* module statistics */ 190 }; 191 192 /* write queue */ 193 static struct qinit usb_as_wqueue = { 194 putq, /* put procedure */ 195 usb_as_wsrv, /* service procedure */ 196 NULL, /* open procedure */ 197 NULL, /* close procedure */ 198 NULL, /* unused */ 199 &usb_as_modinfo, /* module parameters */ 200 NULL /* module statistics */ 201 }; 202 203 /* STREAMS entity declaration structure */ 204 static struct streamtab usb_as_str_info = { 205 &usb_as_rqueue, /* read queue */ 206 &usb_as_wqueue, /* write queue */ 207 NULL, /* mux lower read queue */ 208 NULL, /* mux lower write queue */ 209 }; 210 211 /* 212 * DDI Structures 213 */ 214 215 /* Entry points structure */ 216 static struct cb_ops usb_as_cb_ops = { 217 nulldev, /* cb_open */ 218 nulldev, /* cb_close */ 219 nodev, /* cb_strategy */ 220 nodev, /* cb_print */ 221 nodev, /* cb_dump */ 222 nodev, /* cb_read */ 223 nodev, /* cb_write */ 224 nodev, /* cb_ioctl */ 225 nodev, /* cb_devmap */ 226 nodev, /* cb_mmap */ 227 nodev, /* cb_segmap */ 228 nochpoll, /* cb_chpoll */ 229 ddi_prop_op, /* cb_prop_op */ 230 &usb_as_str_info, /* cb_str */ 231 D_MP | D_MTPERQ, /* cb_flag */ 232 CB_REV, /* cb_rev */ 233 nodev, /* cb_aread */ 234 nodev, /* cb_arwite */ 235 }; 236 237 /* Device operations structure */ 238 static struct dev_ops usb_as_dev_ops = { 239 DEVO_REV, /* devo_rev */ 240 0, /* devo_refcnt */ 241 usb_as_getinfo, /* devo_getinfo */ 242 nulldev, /* devo_identify - obsolete */ 243 nulldev, /* devo_probe - not needed */ 244 usb_as_attach, /* devo_attach */ 245 usb_as_detach, /* devo_detach */ 246 nodev, /* devo_reset */ 247 &usb_as_cb_ops, /* devi_cb_ops */ 248 NULL, /* devo_busb_as_ops */ 249 usb_as_power /* devo_power */ 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 %I%", /* 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", 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", 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", 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", 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", q, mp); 722 } 723 724 725 /* 726 * usb_as_wsrv 727 * write service routine, processes all the queued mblks. 728 * returns DDI_SUCCESS or DDI_FAILURE 729 */ 730 static int 731 usb_as_wsrv(queue_t *q) 732 { 733 int error; 734 usb_as_state_t *uasp = q->q_ptr; 735 mblk_t *mp = NULL; 736 737 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 738 "usb_as_wsrv: Begin q=0x%p", q); 739 740 /* process all message blocks on the queue */ 741 while ((mp = getq(q)) != NULL) { 742 ASSERT(mp->b_datap != NULL); 743 744 switch (mp->b_datap->db_type) { 745 case M_FLUSH: 746 /* 747 * Canonical flush handling : 748 * mp will be freed by usb_ac since it passes 749 * the same mp 750 */ 751 if (*mp->b_rptr & FLUSHW) { 752 flushq(q, FLUSHDATA); 753 } 754 /* read queue not used so just send up */ 755 if (*mp->b_rptr & FLUSHR) { 756 *mp->b_rptr &= ~FLUSHW; 757 qreply(q, mp); 758 } else { 759 freemsg(mp); 760 } 761 762 break; 763 case M_IOCTL: 764 /* only ioctl is mixer registration data */ 765 error = usb_as_ioctl(q, mp); 766 767 break; 768 case M_CTL: 769 /* process the message */ 770 mutex_enter(&uasp->usb_as_mutex); 771 ASSERT(uasp->usb_as_def_mblk == NULL); 772 uasp->usb_as_def_mblk = mp; 773 mutex_exit(&uasp->usb_as_mutex); 774 775 error = usb_as_mctl_rcv(q, mp); 776 if (error != USB_SUCCESS) { 777 usb_as_qreply_error(uasp, q, mp); 778 } 779 780 break; 781 default: 782 usb_as_qreply_error(uasp, q, mp); 783 784 break; 785 } 786 } 787 788 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 789 "usb_as_wsrv: End q=0x%p", q); 790 791 return (DDI_SUCCESS); 792 } 793 794 795 /* 796 * usb_as_ioctl: 797 * usb_as handles only USB_AUDIO_MIXER_REGISTRATION ioctl 798 * NACK all other ioctl requests 799 * Returns USB_SUCCESS or USB_FAILURE 800 */ 801 static int 802 usb_as_ioctl(queue_t *q, mblk_t *mp) 803 { 804 int error = USB_FAILURE; 805 usb_as_state_t *uasp = q->q_ptr; 806 register struct iocblk *iocp; 807 808 iocp = (struct iocblk *)mp->b_rptr; 809 810 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 811 "usb_as_ioctl: Begin q=0x%p, mp=0x%p", q, mp); 812 813 if (mp->b_cont == NULL) { 814 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 815 "usb_as_ioctl: no data block, q=0x%p, mp=0x%p", q, mp); 816 } else { 817 switch (iocp->ioc_cmd) { 818 case USB_AUDIO_MIXER_REGISTRATION: 819 USB_DPRINTF_L4(PRINT_MASK_ALL, 820 uasp->usb_as_log_handle, 821 "usb_as_ioctl(mixer reg): q=0x%p, " 822 "mp=0x%p, b_cont_rptr=0x%p, b_cont_wptr=0x%p", 823 q, mp, mp->b_cont->b_rptr, mp->b_cont->b_wptr); 824 825 mutex_enter(&uasp->usb_as_mutex); 826 827 /* 828 * Copy the usb_as_reg structure to the structure 829 * that usb_ac passed. Note that this is a structure 830 * assignment and not a pointer assignment! 831 */ 832 *((usb_as_registration_t *)(*(( 833 usb_as_registration_t **)mp-> 834 b_cont->b_rptr))) = uasp->usb_as_reg; 835 836 mp->b_cont->b_wptr = mp->b_cont->b_rptr + 837 sizeof (usb_as_registration_t *); 838 839 mutex_exit(&uasp->usb_as_mutex); 840 error = USB_SUCCESS; 841 break; 842 default: 843 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 844 "usb_as_ioctl: unknown IOCTL, cmd=%d", 845 iocp->ioc_cmd); 846 break; 847 } 848 } 849 850 iocp->ioc_rval = 0; 851 if (error == USB_FAILURE) { 852 iocp->ioc_error = ENOTTY; 853 mp->b_datap->db_type = M_IOCNAK; 854 } else { 855 iocp->ioc_error = 0; 856 mp->b_datap->db_type = M_IOCACK; 857 } 858 859 /* 860 * Send the response up 861 */ 862 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 863 "usb_as_ioctl: error=%d, q=0x%p, mp=0x%p", error, q, mp); 864 865 qreply(q, mp); 866 867 return (error); 868 } 869 870 871 /* 872 * usb_as_mctl_rcv: 873 * Handle M_CTL requests from usb_ac. 874 * Returns USB_SUCCESS/FAILURE 875 */ 876 static int 877 usb_as_mctl_rcv(queue_t *q, mblk_t *mp) 878 { 879 int error = USB_FAILURE; 880 usb_as_state_t *uasp = q->q_ptr; 881 struct iocblk *iocp; 882 883 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 884 "usb_as_mctl_rcv: Begin q=0x%p mp=0x%p", q, mp); 885 886 ASSERT(mp != NULL); 887 888 /* 889 * Uopn success, each function sends up a reply either immediately, 890 * or on callback. On failure, reply is send up in the wsrv. 891 */ 892 iocp = (struct iocblk *)mp->b_rptr; 893 mutex_enter(&uasp->usb_as_mutex); 894 switch (iocp->ioc_cmd) { 895 case USB_AUDIO_SET_FORMAT: 896 error = usb_as_set_format(uasp, mp); 897 break; 898 case USB_AUDIO_SET_SAMPLE_FREQ: 899 error = usb_as_set_sample_freq(uasp, mp); 900 break; 901 case USB_AUDIO_SETUP: 902 error = usb_as_setup(uasp, mp); 903 break; 904 case USB_AUDIO_TEARDOWN: 905 usb_as_teardown(uasp, mp); 906 error = USB_SUCCESS; 907 break; 908 case USB_AUDIO_START_PLAY: 909 error = usb_as_start_play(uasp, mp); 910 break; 911 case USB_AUDIO_STOP_PLAY: 912 case USB_AUDIO_PAUSE_PLAY: 913 usb_as_pause_play(uasp, mp); 914 error = USB_SUCCESS; 915 break; 916 case USB_AUDIO_START_RECORD: 917 error = usb_as_start_record(uasp, mp); 918 break; 919 case USB_AUDIO_STOP_RECORD: 920 error = usb_as_stop_record(uasp, mp); 921 break; 922 default: 923 break; 924 } 925 926 mutex_exit(&uasp->usb_as_mutex); 927 928 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 929 "usb_as_mctl_rcv: End q=0x%p mp=0x%p error=%d", q, mp, error); 930 931 return (error); 932 } 933 934 935 /* 936 * usb_as_set_sample_freq: 937 * Sets the sample freq by sending a control command to interface 938 * Although not required for continuous sample rate devices, some 939 * devices such as plantronics devices do need this. 940 * On the other hand, the TI chip which does not support continuous 941 * sample rate stalls on this request 942 * Therefore, we ignore errors and carry on regardless 943 */ 944 static int 945 usb_as_set_sample_freq(usb_as_state_t *uasp, mblk_t *mp) 946 { 947 int freq, alt, ep; 948 mblk_t *data; 949 int rval = USB_FAILURE; 950 boolean_t ignore_errors; 951 952 ASSERT(mp != NULL); 953 ASSERT(mp->b_cont != NULL); 954 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 955 956 alt = uasp->usb_as_alternate; 957 958 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 959 "usb_as_set_sample_freq: mp=0x%p cont_sr=%d", mp, 960 uasp->usb_as_alts[alt].alt_continuous_sr); 961 962 ignore_errors = B_TRUE; 963 964 ep = uasp->usb_as_alts[alt].alt_ep->bEndpointAddress; 965 freq = *((int *)mp->b_cont->b_rptr); 966 967 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 968 "usb_as_set_sample_freq: freq = %d", freq); 969 970 if (mp->b_cont) { 971 freemsg(mp->b_cont); 972 mp->b_cont = NULL; 973 } 974 975 data = allocb(4, BPRI_HI); 976 if (data) { 977 *(data->b_wptr++) = (char)freq; 978 *(data->b_wptr++) = (char)(freq >> 8); 979 *(data->b_wptr++) = (char)(freq >> 16); 980 981 mutex_exit(&uasp->usb_as_mutex); 982 983 if ((rval = usb_as_send_ctrl_cmd(uasp, 984 USB_DEV_REQ_HOST_TO_DEV | 985 USB_DEV_REQ_TYPE_CLASS | 986 USB_DEV_REQ_RCPT_EP, /* bmRequestType */ 987 USB_AUDIO_SET_CUR, /* bRequest */ 988 USB_AUDIO_SAMPLING_FREQ_CONTROL << 8, /* wValue */ 989 ep, /* wIndex */ 990 3, /* wLength */ 991 data, 992 ignore_errors)) != USB_SUCCESS) { 993 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 994 "usb_as_set_sample_freq: set sample freq failed"); 995 996 freemsg(data); 997 } 998 mutex_enter(&uasp->usb_as_mutex); 999 } 1000 1001 return (rval); 1002 } 1003 1004 1005 /* 1006 * usb_as_set_format: 1007 * Matches channel, encoding and precision and find out 1008 * the right alternate. Sets alternate interface. 1009 */ 1010 static int 1011 usb_as_set_format(usb_as_state_t *uasp, mblk_t *mp) 1012 { 1013 int n; 1014 usb_as_registration_t *reg; 1015 usb_audio_formats_t *format; 1016 int alt, rval; 1017 uint_t interface; 1018 1019 ASSERT(mp != NULL); 1020 ASSERT(mp->b_cont != NULL); 1021 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1022 1023 if (uasp->usb_as_request_count) { 1024 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1025 "usb_as_set_format: failing mp=0x%p, rq_cnt=%d", 1026 mp, uasp->usb_as_request_count); 1027 1028 return (USB_FAILURE); 1029 } 1030 1031 ASSERT(uasp->usb_as_isoc_ph == NULL); 1032 1033 reg = &uasp->usb_as_reg; 1034 interface = uasp->usb_as_ifno; 1035 format = (usb_audio_formats_t *)mp->b_cont->b_rptr; 1036 1037 bcopy(format, &uasp->usb_as_curr_format, sizeof (usb_audio_formats_t)); 1038 1039 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1040 "usb_as_set_format: mp=0x%p, reg=0x%p, format=0x%p", 1041 mp, reg, format); 1042 1043 for (n = 0; n < reg->reg_n_formats; n++) { 1044 if ((format->fmt_chns == reg->reg_formats[n].fmt_chns) && 1045 (format->fmt_precision == reg->reg_formats[n]. 1046 fmt_precision) && (format->fmt_encoding == 1047 reg->reg_formats[n].fmt_encoding)) { 1048 /* 1049 * Found the alternate 1050 */ 1051 uasp->usb_as_alternate = alt = 1052 reg->reg_formats[n].fmt_alt; 1053 break; 1054 } 1055 } 1056 1057 if (n > reg->reg_n_formats) { 1058 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1059 "usb_as_set_format: Didn't find a matching alt"); 1060 1061 return (USB_FAILURE); 1062 } 1063 1064 ASSERT(uasp->usb_as_isoc_ph == NULL); 1065 1066 USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1067 "usb_as_set_format: interface=%d alternate=%d", 1068 interface, alt); 1069 1070 mutex_exit(&uasp->usb_as_mutex); 1071 1072 if ((rval = usb_as_send_ctrl_cmd(uasp, 1073 /* bmRequestType */ 1074 USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF, 1075 USB_REQ_SET_IF, /* bRequest */ 1076 alt, /* wValue */ 1077 interface, /* wIndex */ 1078 0, /* wLength */ 1079 NULL, B_FALSE)) != USB_SUCCESS) { 1080 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1081 "usb_as_set_format: set_alternate failed"); 1082 1083 } 1084 mutex_enter(&uasp->usb_as_mutex); 1085 1086 return (rval); 1087 } 1088 1089 1090 /* 1091 * usb_as_setup: 1092 * Open isoc pipe. Will hang around till bandwidth 1093 * is available. 1094 */ 1095 static int 1096 usb_as_setup(usb_as_state_t *uasp, mblk_t *mp) 1097 { 1098 int alt = uasp->usb_as_alternate; 1099 usb_ep_descr_t *ep = (usb_ep_descr_t *)uasp->usb_as_alts[alt].alt_ep; 1100 int rval; 1101 1102 ASSERT(mp != NULL); 1103 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1104 1105 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1106 "usb_as_setup: Begin usb_as_setup, mp=0x%p", mp); 1107 1108 ASSERT(uasp->usb_as_request_count == 0); 1109 1110 /* Set record packet size to max packet size */ 1111 if (uasp->usb_as_alts[alt].alt_mode == AUDIO_RECORD) { 1112 uasp->usb_as_record_pkt_size = ep->wMaxPacketSize; 1113 } else { 1114 uasp->usb_as_record_pkt_size = 0; 1115 } 1116 1117 mutex_exit(&uasp->usb_as_mutex); 1118 1119 /* open isoc pipe, may fail if there is no bandwidth */ 1120 rval = usb_pipe_open(uasp->usb_as_dip, ep, &uasp->usb_as_isoc_pp, 1121 0, &uasp->usb_as_isoc_ph); 1122 1123 if (rval != USB_SUCCESS) { 1124 switch (rval) { 1125 case USB_NO_BANDWIDTH: 1126 USB_DPRINTF_L0(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1127 "no bandwidth available"); 1128 break; 1129 case USB_NOT_SUPPORTED: 1130 USB_DPRINTF_L0(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1131 "Operating a full/high speed audio device on a " 1132 "high speed port is not supported"); 1133 break; 1134 default: 1135 USB_DPRINTF_L2(PRINT_MASK_ALL, 1136 uasp->usb_as_log_handle, 1137 "usb_as_setup: isoc pipe open failed (%d)", 1138 rval); 1139 } 1140 1141 mutex_enter(&uasp->usb_as_mutex); 1142 1143 return (USB_FAILURE); 1144 } 1145 1146 (void) usb_pipe_set_private(uasp->usb_as_isoc_ph, (usb_opaque_t)uasp); 1147 1148 /* return reply up */ 1149 mutex_enter(&uasp->usb_as_mutex); 1150 uasp->usb_as_audio_state = USB_AS_IDLE; 1151 uasp->usb_as_setup_cnt++; 1152 usb_as_send_mctl_up(uasp, NULL); 1153 1154 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1155 "usb_as_setup: End"); 1156 1157 return (USB_SUCCESS); 1158 } 1159 1160 1161 /* 1162 * usb_as_teardown 1163 * 1164 */ 1165 static void 1166 usb_as_teardown(usb_as_state_t *uasp, mblk_t *mp) 1167 { 1168 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1169 "usb_as_teardown: Begin mp=0x%p", mp); 1170 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1171 1172 uasp->usb_as_audio_state = USB_AS_IDLE; 1173 1174 if (uasp->usb_as_isoc_ph) { 1175 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1176 "usb_as_teardown: closing isoc pipe, ph=0x%p", 1177 uasp->usb_as_isoc_ph); 1178 1179 mutex_exit(&uasp->usb_as_mutex); 1180 1181 /* reply mp will be sent up in isoc close callback */ 1182 usb_pipe_close(uasp->usb_as_dip, uasp->usb_as_isoc_ph, 0, 1183 usb_as_isoc_close_cb, (usb_opaque_t)uasp); 1184 1185 /* wait for callback to send up a reply */ 1186 mutex_enter(&uasp->usb_as_mutex); 1187 uasp->usb_as_isoc_ph = NULL; 1188 1189 /* reset setup flag */ 1190 uasp->usb_as_setup_cnt--; 1191 1192 } else { 1193 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1194 "usb_as_teardown: Pipe already closed"); 1195 1196 usb_as_send_mctl_up(uasp, NULL); 1197 } 1198 1199 ASSERT(uasp->usb_as_setup_cnt == 0); 1200 1201 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1202 "usb_as_teardown: End"); 1203 } 1204 1205 1206 /* 1207 * usb_as_start_play: 1208 * this function is called from usb_as_mctl_rcv 1209 */ 1210 static int 1211 usb_as_start_play(usb_as_state_t *uasp, mblk_t *mp) 1212 { 1213 usb_audio_play_req_t *play_req; 1214 int samples; 1215 int n_requests; 1216 int rval = USB_FAILURE; 1217 1218 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1219 "usb_as_start_play: Begin mp=0x%p, req_cnt=%d", 1220 mp, uasp->usb_as_request_count); 1221 1222 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1223 1224 ASSERT(mp && mp->b_cont); 1225 1226 play_req = (usb_audio_play_req_t *)mp->b_cont->b_rptr; 1227 uasp->usb_as_request_samples = play_req->up_samples; 1228 uasp->usb_as_ahdl = play_req->up_handle; 1229 uasp->usb_as_audio_state = USB_AS_ACTIVE; 1230 1231 samples = uasp->usb_as_request_samples; 1232 1233 if ((uasp->usb_as_request_count >= USB_AS_MAX_REQUEST_COUNT) || 1234 (uasp->usb_as_audio_state == USB_AS_IDLE) || 1235 (uasp->usb_as_audio_state == USB_AS_PLAY_PAUSED)) { 1236 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1237 "nothing to do or paused or idle (%d)", 1238 uasp->usb_as_audio_state); 1239 rval = USB_SUCCESS; 1240 } else { 1241 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1242 "usb_as_start_play: samples=%d requestcount=%d ", 1243 samples, uasp->usb_as_request_count); 1244 1245 /* queue up as many requests as allowed */ 1246 for (n_requests = uasp->usb_as_request_count; 1247 n_requests < USB_AS_MAX_REQUEST_COUNT; n_requests++) { 1248 if ((rval = usb_as_play_isoc_data(uasp, mp)) != 1249 USB_SUCCESS) { 1250 break; 1251 } 1252 } 1253 } 1254 1255 /* 1256 * send mctl up for success. For failure, usb_as_wsrv 1257 * will send an merr up. 1258 */ 1259 if (rval == USB_SUCCESS) { 1260 usb_as_send_mctl_up(uasp, NULL); 1261 } 1262 1263 1264 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1265 "usb_as_start_play: End"); 1266 1267 return (rval); 1268 } 1269 1270 1271 /* 1272 * usb_as_continue_play: 1273 * this function is called from the play callbacks 1274 */ 1275 static void 1276 usb_as_continue_play(usb_as_state_t *uasp) 1277 { 1278 int samples; 1279 int n_requests; 1280 1281 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1282 "usb_as_contine_play: Begin req_cnt=%d", 1283 uasp->usb_as_request_count); 1284 1285 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1286 1287 if (uasp->usb_as_dev_state == USB_DEV_DISCONNECTED) { 1288 usb_as_handle_shutdown(uasp, NULL); 1289 1290 return; 1291 } 1292 1293 samples = uasp->usb_as_request_samples; 1294 1295 if ((uasp->usb_as_request_count >= USB_AS_MAX_REQUEST_COUNT) || 1296 (uasp->usb_as_audio_state == USB_AS_IDLE) || 1297 (uasp->usb_as_audio_state == USB_AS_PLAY_PAUSED)) { 1298 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1299 "usb_as_continue_play: nothing to do (audio_state=%d)", 1300 uasp->usb_as_audio_state); 1301 } else { 1302 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1303 "usb_as_continue_play: samples=%d requestcount=%d ", 1304 samples, uasp->usb_as_request_count); 1305 1306 /* queue up as many requests as allowed */ 1307 for (n_requests = uasp->usb_as_request_count; 1308 n_requests < USB_AS_MAX_REQUEST_COUNT; n_requests++) { 1309 if (usb_as_play_isoc_data(uasp, NULL) != 1310 USB_SUCCESS) { 1311 1312 break; 1313 } 1314 } 1315 } 1316 1317 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1318 "usb_as_continue_play: End"); 1319 } 1320 1321 1322 static void 1323 usb_as_handle_shutdown(usb_as_state_t *uasp, mblk_t *mp) 1324 { 1325 audiohdl_t ahdl; 1326 1327 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1328 "usb_as_handl_shutdown, mp=0x%p", mp); 1329 1330 if (mp != NULL) { 1331 usb_as_send_mctl_up(uasp, NULL); 1332 } 1333 1334 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1335 "usb_as_handle_shutdown: am_play_shutdown"); 1336 1337 uasp->usb_as_audio_state = USB_AS_IDLE; 1338 uasp->usb_as_pkt_count = 0; 1339 ahdl = uasp->usb_as_ahdl; 1340 1341 mutex_exit(&uasp->usb_as_mutex); 1342 am_play_shutdown(ahdl, AUDIO_NO_CHANNEL); 1343 mutex_enter(&uasp->usb_as_mutex); 1344 } 1345 1346 1347 static int 1348 usb_as_play_isoc_data(usb_as_state_t *uasp, mblk_t *mp) 1349 { 1350 int rval = USB_FAILURE; 1351 1352 usb_isoc_req_t *isoc_req = NULL; 1353 usb_audio_formats_t *format = &uasp->usb_as_curr_format; 1354 mblk_t *data = NULL; 1355 audiohdl_t ahdl = uasp->usb_as_ahdl; 1356 int precision; 1357 int pkt, frame, n, n_pkts, count; 1358 size_t bufsize; 1359 int pkt_len[USB_AS_N_FRAMES]; 1360 1361 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1362 1363 /* we only support two precisions */ 1364 if ((format->fmt_precision != AUDIO_PRECISION_8) && 1365 (format->fmt_precision != AUDIO_PRECISION_16)) { 1366 1367 rval = USB_FAILURE; 1368 1369 goto done; 1370 } 1371 1372 precision = (format->fmt_precision == AUDIO_PRECISION_8) ? 1 : 2; 1373 1374 frame = uasp->usb_as_pkt_count; 1375 1376 /* 1377 * calculate total bufsize by determining the pkt size for 1378 * each frame 1379 */ 1380 for (bufsize = pkt = 0; pkt < USB_AS_N_FRAMES; pkt++) { 1381 pkt_len[pkt] = usb_as_get_pktsize(uasp, format, frame++); 1382 bufsize += pkt_len[pkt]; 1383 } 1384 1385 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1386 "usb_as_play_isoc_data: Begin bufsize=0x%lx, mp=0x%p", bufsize, mp); 1387 1388 mutex_exit(&uasp->usb_as_mutex); 1389 1390 if ((data = allocb(bufsize, BPRI_HI)) == NULL) { 1391 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1392 "usb_as_play_isoc_data: allocb failed"); 1393 mutex_enter(&uasp->usb_as_mutex); 1394 1395 goto done; 1396 } 1397 1398 if ((count = am_get_audio(ahdl, (void *)data->b_wptr, 1399 AUDIO_NO_CHANNEL, bufsize / precision)) == 0) { 1400 mutex_enter(&uasp->usb_as_mutex); 1401 if (uasp->usb_as_request_count == 0) { 1402 usb_as_handle_shutdown(uasp, NULL); 1403 1404 /* Don't return failure for 0 bytes of data sent */ 1405 if (mp) { 1406 /* 1407 * Since we set rval to SUCCESS 1408 * we treat it as a special case 1409 * and free data here 1410 */ 1411 rval = USB_SUCCESS; 1412 freemsg(data); 1413 data = NULL; 1414 1415 goto done; 1416 } 1417 } else { 1418 USB_DPRINTF_L2(PRINT_MASK_ALL, 1419 uasp->usb_as_log_handle, 1420 "usb_as_play_isoc_data: no audio bytes, " 1421 "rcnt=0x%x ", uasp->usb_as_request_count); 1422 } 1423 rval = USB_FAILURE; 1424 1425 goto done; 1426 } 1427 1428 bufsize = n = count * precision; 1429 data->b_wptr += n; 1430 1431 /* calculate how many frames we can actually fill */ 1432 for (n_pkts = 0; (n_pkts < USB_AS_N_FRAMES) && (n > 0); n_pkts++) { 1433 if (n < pkt_len[n_pkts]) { 1434 pkt_len[n_pkts] = n; 1435 } 1436 n -= pkt_len[n_pkts]; 1437 } 1438 1439 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1440 "usb_as_play_isoc_data: n_pkts=%d, bufsize=%ld, n=%d", 1441 n_pkts, bufsize, count * precision); 1442 1443 /* allocate an isoc request packet */ 1444 if ((isoc_req = usb_alloc_isoc_req(uasp->usb_as_dip, 1445 n_pkts, 0, 0)) == NULL) { 1446 mutex_enter(&uasp->usb_as_mutex); 1447 1448 goto done; 1449 } 1450 1451 1452 #if defined(_BIG_ENDIAN) 1453 /* byte swap if necessary */ 1454 if (format->fmt_precision == AUDIO_PRECISION_16) { 1455 int i; 1456 uchar_t tmp; 1457 uchar_t *p = data->b_rptr; 1458 1459 for (i = 0; i < bufsize; i += 2, p += 2) { 1460 tmp = *p; 1461 *p = *(p + 1); 1462 *(p + 1) = tmp; 1463 } 1464 } 1465 #endif 1466 1467 /* initialize the packet descriptor */ 1468 for (pkt = 0; pkt < n_pkts; pkt++) { 1469 isoc_req->isoc_pkt_descr[pkt].isoc_pkt_length = 1470 pkt_len[pkt]; 1471 } 1472 1473 isoc_req->isoc_data = data; 1474 isoc_req->isoc_pkts_count = (ushort_t)n_pkts; 1475 isoc_req->isoc_attributes = USB_ATTRS_ISOC_XFER_ASAP | 1476 USB_ATTRS_AUTOCLEARING; 1477 isoc_req->isoc_cb = usb_as_play_cb; 1478 isoc_req->isoc_exc_cb = usb_as_play_exc_cb; 1479 isoc_req->isoc_client_private = (usb_opaque_t)uasp; 1480 1481 mutex_enter(&uasp->usb_as_mutex); 1482 1483 USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1484 "usb_as_play_isoc_data: rq=0x%p data=0x%p cnt=0x%x " 1485 "pkt=0x%p rqcnt=%d ", isoc_req, data, count, 1486 isoc_req->isoc_pkt_descr, uasp->usb_as_request_count); 1487 1488 ASSERT(isoc_req->isoc_data != NULL); 1489 1490 uasp->usb_as_send_debug_count++; 1491 uasp->usb_as_request_count++; 1492 uasp->usb_as_pkt_count += n_pkts; 1493 mutex_exit(&uasp->usb_as_mutex); 1494 1495 if ((rval = usb_pipe_isoc_xfer(uasp->usb_as_isoc_ph, 1496 isoc_req, 0)) != USB_SUCCESS) { 1497 1498 mutex_enter(&uasp->usb_as_mutex); 1499 uasp->usb_as_request_count--; 1500 uasp->usb_as_send_debug_count--; 1501 uasp->usb_as_pkt_count -= n_pkts; 1502 1503 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1504 "usb_as_play_isoc_data: rval=%d", rval); 1505 1506 rval = USB_FAILURE; 1507 1508 } else { 1509 mutex_enter(&uasp->usb_as_mutex); 1510 1511 data = NULL; 1512 isoc_req = NULL; 1513 } 1514 1515 done: 1516 if (rval != USB_SUCCESS) { 1517 freemsg(data); 1518 if (isoc_req) { 1519 isoc_req->isoc_data = NULL; 1520 usb_free_isoc_req(isoc_req); 1521 } 1522 } 1523 1524 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1525 "usb_as_play_isoc_data: SEND CNT=%d, RCV COUNT=%d", 1526 uasp->usb_as_send_debug_count, uasp->usb_as_rcv_debug_count); 1527 1528 return (rval); 1529 } 1530 1531 1532 /*ARGSUSED*/ 1533 static void 1534 usb_as_pause_play(usb_as_state_t *uasp, mblk_t *mp) 1535 { 1536 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1537 uasp->usb_as_audio_state = USB_AS_PLAY_PAUSED; 1538 usb_as_send_mctl_up(uasp, NULL); 1539 } 1540 1541 1542 /*ARGSUSED*/ 1543 static void 1544 usb_as_play_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) 1545 { 1546 usb_as_state_t *uasp = (usb_as_state_t *) 1547 (isoc_req->isoc_client_private); 1548 int i; 1549 1550 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle, 1551 "usb_as_play_cb: Begin ph=0x%p, isoc_req=0x%p", 1552 ph, isoc_req); 1553 1554 ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) != 0); 1555 1556 for (i = 0; i < isoc_req->isoc_pkts_count; i++) { 1557 if (isoc_req->isoc_pkt_descr[i].isoc_pkt_status != 1558 USB_CR_OK) { 1559 USB_DPRINTF_L2(PRINT_MASK_CB, uasp->usb_as_log_handle, 1560 "usb_as_play_cb: \tpkt%d: len=%d status=%s", i, 1561 isoc_req->isoc_pkt_descr[i].isoc_pkt_length, 1562 usb_str_cr(isoc_req-> 1563 isoc_pkt_descr[i].isoc_pkt_status)); 1564 } 1565 } 1566 1567 mutex_enter(&uasp->usb_as_mutex); 1568 if (isoc_req->isoc_error_count) { 1569 USB_DPRINTF_L2(PRINT_MASK_CB, uasp->usb_as_log_handle, 1570 "usb_as_play_cb: error_count = %d", 1571 isoc_req->isoc_error_count); 1572 } 1573 1574 usb_free_isoc_req(isoc_req); 1575 uasp->usb_as_request_count--; 1576 uasp->usb_as_rcv_debug_count++; 1577 usb_as_continue_play(uasp); 1578 1579 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle, 1580 "usb_as_play_cb: SEND CNT=%d, RCV COUNT=%d", 1581 uasp->usb_as_send_debug_count, uasp->usb_as_rcv_debug_count); 1582 1583 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle, 1584 "usb_as_play_cb: End, req_cnt=%d", uasp->usb_as_request_count); 1585 1586 mutex_exit(&uasp->usb_as_mutex); 1587 } 1588 1589 1590 static void 1591 usb_as_play_exc_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) 1592 { 1593 int i; 1594 usb_as_state_t *uasp = (usb_as_state_t *) 1595 (isoc_req->isoc_client_private); 1596 usb_cr_t cr = isoc_req->isoc_completion_reason; 1597 usb_cb_flags_t cb_flags = isoc_req->isoc_cb_flags; 1598 1599 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1600 "usb_as_play_exc_cb: ph=0x%p, rq=0x%p data=0x%p pkts=0x%x " 1601 "cr=%d, cb_flag=0x%x", ph, isoc_req, isoc_req->isoc_data, 1602 isoc_req->isoc_pkts_count, cr, cb_flags); 1603 1604 ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) == 0); 1605 1606 for (i = 0; i < isoc_req->isoc_pkts_count; i++) { 1607 if (isoc_req->isoc_pkt_descr[i].isoc_pkt_status == 1608 USB_CR_OK) { 1609 USB_DPRINTF_L2(PRINT_MASK_ALL, 1610 uasp->usb_as_log_handle, 1611 "usb_as_play_exc_cb: \tpkt%d: len=%d status=%d", 1612 i, 1613 isoc_req->isoc_pkt_descr[i].isoc_pkt_length, 1614 isoc_req->isoc_pkt_descr[i].isoc_pkt_status); 1615 } 1616 } 1617 1618 usb_free_isoc_req(isoc_req); 1619 1620 mutex_enter(&uasp->usb_as_mutex); 1621 uasp->usb_as_rcv_debug_count++; 1622 uasp->usb_as_request_count--; 1623 usb_as_handle_shutdown(uasp, NULL); 1624 1625 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1626 "usb_as_play_exc_cb: SEND CNT=%d, RCV COUNT=%d", 1627 uasp->usb_as_send_debug_count, uasp->usb_as_rcv_debug_count); 1628 1629 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1630 "usb_as_play_exc_cb: End request_count=%d", 1631 uasp->usb_as_request_count); 1632 1633 mutex_exit(&uasp->usb_as_mutex); 1634 } 1635 1636 1637 /* 1638 * usb_as_start_record 1639 */ 1640 static int 1641 usb_as_start_record(usb_as_state_t *uasp, mblk_t *mp) 1642 { 1643 int rval = USB_FAILURE; 1644 usb_isoc_req_t *isoc_req; 1645 ushort_t record_pkt_size = uasp->usb_as_record_pkt_size; 1646 ushort_t n_pkt = 1, pkt; 1647 1648 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1649 "usb_as_start_record: mp=0x%p", mp); 1650 1651 ASSERT(mp != NULL); 1652 ASSERT(mp->b_cont != NULL); 1653 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1654 1655 /* 1656 * A start_record should not happen when stop polling is 1657 * happening 1658 */ 1659 ASSERT(uasp->usb_as_audio_state != USB_AS_STOP_POLLING_STARTED); 1660 1661 if (uasp->usb_as_audio_state == USB_AS_IDLE) { 1662 1663 uasp->usb_as_ahdl = *((audiohdl_t *)mp->b_cont->b_rptr); 1664 uasp->usb_as_audio_state = USB_AS_ACTIVE; 1665 mutex_exit(&uasp->usb_as_mutex); 1666 1667 if ((isoc_req = usb_alloc_isoc_req(uasp->usb_as_dip, n_pkt, 1668 n_pkt * record_pkt_size, 0)) != NULL) { 1669 /* Initialize the packet descriptor */ 1670 for (pkt = 0; pkt < n_pkt; pkt++) { 1671 isoc_req->isoc_pkt_descr[pkt]. 1672 isoc_pkt_length = record_pkt_size; 1673 } 1674 1675 isoc_req->isoc_pkts_count = n_pkt; 1676 isoc_req->isoc_pkts_length = record_pkt_size; 1677 isoc_req->isoc_attributes = USB_ATTRS_ISOC_XFER_ASAP | 1678 USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING; 1679 isoc_req->isoc_cb = usb_as_record_cb; 1680 isoc_req->isoc_exc_cb = usb_as_record_exc_cb; 1681 isoc_req->isoc_client_private = (usb_opaque_t)uasp; 1682 1683 rval = usb_pipe_isoc_xfer(uasp->usb_as_isoc_ph, 1684 isoc_req, 0); 1685 1686 } else { 1687 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1688 "usb_as_start_record: Isoc req allocation failed"); 1689 } 1690 1691 mutex_enter(&uasp->usb_as_mutex); 1692 1693 } else { 1694 1695 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1696 "usb_as_start_record: Record in progress"); 1697 1698 rval = USB_SUCCESS; 1699 } 1700 1701 if (rval != USB_SUCCESS) { 1702 uasp->usb_as_audio_state = USB_AS_IDLE; 1703 if (isoc_req) { 1704 usb_free_isoc_req(isoc_req); 1705 isoc_req = NULL; 1706 } 1707 } else { 1708 usb_as_send_mctl_up(uasp, NULL); 1709 } 1710 1711 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1712 "usb_as_start_record: rval=%d", rval); 1713 1714 return (rval); 1715 } 1716 1717 1718 /*ARGSUSED*/ 1719 static int 1720 usb_as_stop_record(usb_as_state_t *uasp, mblk_t *mp) 1721 { 1722 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1723 "usb_as_stop_record: "); 1724 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 1725 1726 /* if we are disconnected, the pipe will be closed anyways */ 1727 if (uasp->usb_as_dev_state == USB_DEV_DISCONNECTED) { 1728 usb_as_send_mctl_up(uasp, NULL); 1729 1730 return (USB_SUCCESS); 1731 } 1732 1733 switch (uasp->usb_as_audio_state) { 1734 case USB_AS_ACTIVE: 1735 mutex_exit(&uasp->usb_as_mutex); 1736 1737 /* 1738 * Stop polling. When the completion reason indicate that 1739 * polling is over, return response message up. 1740 */ 1741 usb_pipe_stop_isoc_polling(uasp->usb_as_isoc_ph, 1742 USB_FLAGS_SLEEP); 1743 mutex_enter(&uasp->usb_as_mutex); 1744 1745 usb_as_send_mctl_up(uasp, NULL); 1746 1747 break; 1748 case USB_AS_STOP_POLLING_STARTED: 1749 /* A stop polling in progress, wait for completion and reply */ 1750 break; 1751 default: 1752 usb_as_send_mctl_up(uasp, NULL); 1753 } 1754 1755 1756 return (USB_SUCCESS); 1757 } 1758 1759 1760 static void 1761 usb_as_record_exc_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) 1762 { 1763 usb_as_state_t *uasp = (usb_as_state_t *) 1764 (isoc_req->isoc_client_private); 1765 usb_cr_t completion_reason; 1766 int rval; 1767 1768 completion_reason = isoc_req->isoc_completion_reason; 1769 1770 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1771 "usb_as_record_exc_cb: ph=0x%p, isoc_req=0x%p, cr=%d", 1772 ph, isoc_req, completion_reason); 1773 1774 ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) == 0); 1775 1776 switch (completion_reason) { 1777 case USB_CR_STOPPED_POLLING: 1778 case USB_CR_PIPE_CLOSING: 1779 case USB_CR_PIPE_RESET: 1780 1781 break; 1782 case USB_CR_NO_RESOURCES: 1783 /* 1784 * keep the show going: Since we have the original 1785 * request, we just resubmit it 1786 */ 1787 rval = usb_pipe_isoc_xfer(uasp->usb_as_isoc_ph, isoc_req, 0); 1788 1789 USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1790 "usb_as_record_exc_cb: restart record rval=%d", rval); 1791 1792 return; 1793 default: 1794 1795 mutex_enter(&uasp->usb_as_mutex); 1796 1797 /* Do not start if one is already in progress */ 1798 if (uasp->usb_as_audio_state != USB_AS_STOP_POLLING_STARTED) { 1799 uasp->usb_as_audio_state = USB_AS_STOP_POLLING_STARTED; 1800 1801 mutex_exit(&uasp->usb_as_mutex); 1802 (void) usb_pipe_stop_isoc_polling(ph, 1803 USB_FLAGS_NOSLEEP); 1804 1805 return; 1806 } else { 1807 mutex_exit(&uasp->usb_as_mutex); 1808 } 1809 1810 break; 1811 } 1812 usb_free_isoc_req(isoc_req); 1813 1814 mutex_enter(&uasp->usb_as_mutex); 1815 USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1816 "usb_as_record_exc_cb: state=%d cr=0x%x", 1817 uasp->usb_as_audio_state, completion_reason); 1818 1819 uasp->usb_as_audio_state = USB_AS_IDLE; 1820 mutex_exit(&uasp->usb_as_mutex); 1821 } 1822 1823 1824 /*ARGSUSED*/ 1825 static void 1826 usb_as_record_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) 1827 { 1828 usb_as_state_t *uasp = (usb_as_state_t *)isoc_req->isoc_client_private; 1829 int i, offset, sz; 1830 audiohdl_t ahdl; 1831 usb_audio_formats_t *format = &uasp->usb_as_curr_format; 1832 int precision; 1833 1834 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle, 1835 "usb_as_record_cb: rq=0x%p data=0x%p pkts=0x%x", 1836 isoc_req, isoc_req->isoc_data, isoc_req->isoc_pkts_count); 1837 1838 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle, 1839 "\tfno=%" PRId64 ", n_pkts=%u, flag=0x%x, data=0x%p, cnt=%d", 1840 isoc_req->isoc_frame_no, isoc_req->isoc_pkts_count, 1841 isoc_req->isoc_attributes, isoc_req->isoc_data, 1842 isoc_req->isoc_error_count); 1843 1844 ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) != 0); 1845 1846 mutex_enter(&uasp->usb_as_mutex); 1847 ahdl = uasp->usb_as_ahdl; 1848 sz = uasp->usb_as_record_pkt_size; 1849 precision = (format->fmt_precision == AUDIO_PRECISION_8) ? 1 : 2; 1850 1851 if (uasp->usb_as_audio_state != USB_AS_IDLE) { 1852 #if defined(_BIG_ENDIAN) 1853 unsigned char *ptr = isoc_req->isoc_data->b_rptr; 1854 #endif 1855 for (offset = i = 0; i < isoc_req->isoc_pkts_count; i++) { 1856 #if defined(_BIG_ENDIAN) 1857 int len = isoc_req->isoc_pkt_descr[i]. 1858 isoc_pkt_actual_length; 1859 /* do byte swap for precision 16 */ 1860 if (format->fmt_precision == AUDIO_PRECISION_16) { 1861 int j; 1862 for (j = 0; j < len; j += 2, ptr += 2) { 1863 char t = *ptr; 1864 *ptr = *(ptr + 1); 1865 *(ptr + 1) = t; 1866 } 1867 } 1868 #endif 1869 USB_DPRINTF_L3(PRINT_MASK_CB, uasp->usb_as_log_handle, 1870 "\tpkt%d: " 1871 "offset=%d pktsize=%d len=%d status=%d resid=%d", 1872 i, offset, sz, 1873 isoc_req->isoc_pkt_descr[i].isoc_pkt_length, 1874 isoc_req->isoc_pkt_descr[i].isoc_pkt_status, 1875 isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length); 1876 1877 if (isoc_req->isoc_pkt_descr[i].isoc_pkt_status != 1878 USB_CR_OK) { 1879 USB_DPRINTF_L2(PRINT_MASK_CB, 1880 uasp->usb_as_log_handle, 1881 "record: pkt=%d offset=0x%x status=%s", 1882 i, offset, usb_str_cr(isoc_req-> 1883 isoc_pkt_descr[i].isoc_pkt_status)); 1884 } 1885 mutex_exit(&uasp->usb_as_mutex); 1886 1887 am_send_audio(ahdl, 1888 isoc_req->isoc_data->b_rptr + offset, 1889 AUDIO_NO_CHANNEL, isoc_req-> 1890 isoc_pkt_descr[i].isoc_pkt_actual_length / 1891 precision); 1892 1893 mutex_enter(&uasp->usb_as_mutex); 1894 offset += isoc_req->isoc_pkt_descr[i].isoc_pkt_length; 1895 } 1896 } 1897 1898 mutex_exit(&uasp->usb_as_mutex); 1899 1900 usb_free_isoc_req(isoc_req); 1901 } 1902 1903 1904 /* 1905 * Support for sample rates that are not multiple of 1K. We have 3 such 1906 * sample rates: 11025, 22050 and 44100. 1907 */ 1908 typedef struct usb_as_pktsize_table { 1909 uint_t sr; 1910 ushort_t pkt; 1911 ushort_t cycle; 1912 int extra; 1913 } usb_as_pktsize_table_t; 1914 1915 /* 1916 * usb_as_pktsize_info is the table that calculates the pktsize 1917 * corresponding to the current frame and the current format. 1918 * Since the int_rate is 1000, we have to do special arithmetic for 1919 * sample rates not multiple of 1K. For example, 1920 * if the sample rate is 48000(i.e multiple of 1K), we can send 48000/1000 1921 * = 48 samples every packet per channel. Since we have to support sample 1922 * rate like 11025, 22050 and 44100, we will have some extra samples 1923 * at the end that we need to spread among the 1000 cycles. So if we make 1924 * the pktsize as below for these sample rates, at the end of 1000 cycles, 1925 * we will be able to send all the data in the correct rate: 1926 * 1927 * 11025: 39 samples of 11, 1 of 12 1928 * 22050: 19 samples of 22, 1 of 23 1929 * 44100: 9 samples of 44, 1 of 45 1930 * 1931 * frameno is a simple counter maintained in the soft state structure. 1932 * So the pkt size is: 1933 * pkt_size = ((frameno % cycle) ? pkt : (pkt + extra)); 1934 * 1935 */ 1936 static usb_as_pktsize_table_t usb_as_pktsize_info[] = { 1937 {8000, 8, 1000, 0}, 1938 {9600, 10, 5, -2}, 1939 {11025, 11, 40, 1}, 1940 {16000, 16, 1000, 0}, 1941 {18900, 19, 10, -1}, 1942 {22050, 22, 20, 1}, 1943 {32000, 32, 1000, 0}, 1944 {33075, 33, 12, 1}, 1945 {37800, 38, 5, -1}, 1946 {44100, 44, 10, 1}, 1947 {48000, 48, 1000, 0}, 1948 { 0 } 1949 }; 1950 1951 1952 static int 1953 usb_as_get_pktsize(usb_as_state_t *uasp, usb_audio_formats_t *format, 1954 usb_frame_number_t frameno) 1955 { 1956 int n; 1957 int pkt_size = 0; 1958 ushort_t pkt, cycle; 1959 int extra; 1960 int n_srs = 1961 sizeof (usb_as_pktsize_info) / sizeof (usb_as_pktsize_table_t); 1962 1963 for (n = 0; n < n_srs; n++) { 1964 if (usb_as_pktsize_info[n].sr == format->fmt_sr) { 1965 cycle = usb_as_pktsize_info[n].cycle; 1966 pkt = usb_as_pktsize_info[n].pkt; 1967 extra = usb_as_pktsize_info[n].extra; 1968 pkt_size = (((frameno + 1) % cycle) ? 1969 pkt : (pkt + extra)); 1970 pkt_size *= ((format->fmt_precision == 1971 AUDIO_PRECISION_16) ? 2 : 1) 1972 * format->fmt_chns; 1973 break; 1974 } 1975 } 1976 1977 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1978 "usb_as_get_pktsize: %d", pkt_size); 1979 1980 return (pkt_size); 1981 } 1982 1983 1984 /* 1985 * usb_as_send_ctrl_cmd: 1986 * Opens the pipe; sends a control command down 1987 */ 1988 static int 1989 usb_as_send_ctrl_cmd(usb_as_state_t *uasp, 1990 uchar_t bmRequestType, uchar_t bRequest, 1991 ushort_t wValue, ushort_t wIndex, ushort_t wLength, 1992 mblk_t *data, boolean_t ignore_errors) 1993 { 1994 usb_ctrl_req_t *reqp; 1995 1996 1997 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 1998 "usb_as_send_ctrl_cmd: Begin bmRequestType=%d,\n\t" 1999 "bRequest=%d, wValue=%d, wIndex=%d, wLength=%d, data=0x%p", 2000 bmRequestType, bRequest, wValue, wIndex, wLength, data); 2001 2002 if ((reqp = usb_alloc_ctrl_req(uasp->usb_as_dip, 0, 0)) == NULL) { 2003 2004 mutex_enter(&uasp->usb_as_mutex); 2005 uasp->usb_as_xfer_cr = USB_AS_SEND_MERR; 2006 mutex_exit(&uasp->usb_as_mutex); 2007 2008 return (USB_FAILURE); 2009 } 2010 2011 reqp->ctrl_bmRequestType = bmRequestType; 2012 reqp->ctrl_bRequest = bRequest; 2013 reqp->ctrl_wValue = wValue; 2014 reqp->ctrl_wIndex = wIndex; 2015 reqp->ctrl_wLength = wLength; 2016 reqp->ctrl_data = data; 2017 reqp->ctrl_attributes = 0; 2018 reqp->ctrl_client_private = (usb_opaque_t)uasp; 2019 reqp->ctrl_cb = usb_as_default_xfer_cb; 2020 reqp->ctrl_exc_cb = ignore_errors ? 2021 usb_as_default_xfer_cb : 2022 usb_as_default_xfer_exc_cb; 2023 2024 /* Send async command down */ 2025 if (usb_pipe_ctrl_xfer(uasp->usb_as_default_ph, reqp, 0) != 2026 USB_SUCCESS) { 2027 2028 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 2029 "usb_as_send_ctrl_cmd: usba xfer failed (req=%d)", 2030 bRequest); 2031 2032 mutex_enter(&uasp->usb_as_mutex); 2033 uasp->usb_as_xfer_cr = USB_AS_SEND_MERR; 2034 mutex_exit(&uasp->usb_as_mutex); 2035 usb_free_ctrl_req(reqp); 2036 2037 return (USB_FAILURE); 2038 } 2039 2040 return (USB_SUCCESS); 2041 } 2042 2043 2044 static void 2045 usb_as_send_merr_up(usb_as_state_t *uasp, mblk_t *mp) 2046 { 2047 queue_t *q; 2048 2049 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 2050 "usb_as_send_merr_up: data=0x%p", mp); 2051 2052 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 2053 q = uasp->usb_as_rq; 2054 2055 mp->b_datap->db_type = M_ERROR; 2056 2057 if (mp->b_cont) { 2058 freemsg(mp->b_cont); 2059 mp->b_cont = NULL; 2060 } 2061 2062 mp->b_rptr = mp->b_datap->db_base; 2063 mp->b_wptr = mp->b_rptr + sizeof (char); 2064 *mp->b_rptr = EINVAL; 2065 2066 mutex_exit(&uasp->usb_as_mutex); 2067 if (!canputnext(RD(q))) { 2068 freemsg(mp); 2069 mp = NULL; 2070 } else { 2071 putnext(RD(q), mp); 2072 } 2073 mutex_enter(&uasp->usb_as_mutex); 2074 } 2075 2076 2077 static void 2078 usb_as_send_mctl_up(usb_as_state_t *uasp, mblk_t *data) 2079 { 2080 mblk_t *tmp, *mp; 2081 queue_t *q; 2082 struct iocblk *iocp; 2083 2084 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 2085 "usb_as_send_mctl_up: data=0x%p", data); 2086 ASSERT(mutex_owned(&uasp->usb_as_mutex)); 2087 2088 q = uasp->usb_as_rq; 2089 mp = uasp->usb_as_def_mblk; 2090 ASSERT(mp != NULL); 2091 2092 /* Free the b_cont of the original mblk_t, if any */ 2093 if (mp->b_cont) { 2094 freemsg(mp->b_cont); 2095 mp->b_cont = NULL; 2096 } 2097 2098 /* 2099 * If we have response to send up, attach it at the b_cont 2100 * of the mctl message. Otherwise just send the mctl message 2101 * up and the module above will decode the command 2102 */ 2103 iocp = (struct iocblk *)mp->b_rptr; 2104 iocp->ioc_error = 0; 2105 2106 switch (iocp->ioc_cmd) { 2107 case USB_AUDIO_SET_FORMAT: 2108 freemsg(data); 2109 2110 /* 2111 * we cannot easily recover if we can't get an mblk 2112 * so we have to sleep here 2113 */ 2114 tmp = allocb_wait(sizeof (int), BPRI_HI, 2115 STR_NOSIG, NULL); 2116 iocp->ioc_count = sizeof (int); 2117 *(int *)tmp->b_wptr = uasp->usb_as_alternate; 2118 tmp->b_wptr += sizeof (int); 2119 mp->b_cont = tmp; 2120 2121 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 2122 "usb_as_send_mctl_up: set_format returning,alt=%d", 2123 uasp->usb_as_alternate); 2124 2125 break; 2126 default: 2127 if (data != NULL) { 2128 /* 2129 * Use the original mp to send the message up 2130 * This should already have the right ioc_cmd in. 2131 */ 2132 iocp->ioc_count = data->b_wptr - data->b_rptr; 2133 mp->b_cont = data; 2134 } else { 2135 iocp->ioc_count = 0; 2136 } 2137 break; 2138 } 2139 uasp->usb_as_def_mblk = NULL; 2140 mutex_exit(&uasp->usb_as_mutex); 2141 if (!canputnext(q)) { 2142 freemsg(mp); 2143 mp = NULL; 2144 } else { 2145 putnext(q, mp); 2146 } 2147 mutex_enter(&uasp->usb_as_mutex); 2148 } 2149 2150 2151 /* 2152 * usb_as_default_xfer_cb: 2153 * Callback routine for the async control xfer. Reply mctl here. 2154 */ 2155 /*ARGSUSED*/ 2156 static void 2157 usb_as_default_xfer_cb(usb_pipe_handle_t def, usb_ctrl_req_t *reqp) 2158 { 2159 usb_as_state_t *uasp = (usb_as_state_t *)reqp->ctrl_client_private; 2160 2161 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 2162 "usb_as_default_xfer_cb: ph=0x%p, reqp=0x%p", 2163 def, reqp); 2164 2165 ASSERT((reqp->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0); 2166 2167 mutex_enter(&uasp->usb_as_mutex); 2168 uasp->usb_as_xfer_cr = USB_AS_SEND_MCTL; 2169 usb_as_send_mctl_up(uasp, NULL); 2170 mutex_exit(&uasp->usb_as_mutex); 2171 2172 usb_free_ctrl_req(reqp); 2173 2174 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 2175 "usb_as_default_xfer_cb: End"); 2176 } 2177 2178 2179 /* 2180 * usb_as_isoc_close_cb() 2181 * called from teardown usb_pipe_close 2182 */ 2183 static void 2184 usb_as_isoc_close_cb(usb_pipe_handle_t ph, usb_opaque_t arg, 2185 int rval, usb_cb_flags_t cb_flags) 2186 { 2187 usb_as_state_t *uasp = (usb_as_state_t *)arg; 2188 2189 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 2190 "usb_as_isoc_close_cb: ph=0x%p arg=0x%p cb_flags=0x%x", 2191 ph, arg, cb_flags); 2192 2193 /* pipe close cannot fail */ 2194 ASSERT(rval == USB_SUCCESS); 2195 2196 mutex_enter(&uasp->usb_as_mutex); 2197 usb_as_send_mctl_up(uasp, NULL); 2198 mutex_exit(&uasp->usb_as_mutex); 2199 2200 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 2201 "usb_as_isoc_close_cb: End"); 2202 } 2203 2204 2205 /* 2206 * usb_as_default_exc_cb: 2207 * Exception callback for the default pipe. Autoclearing took care 2208 * of the recovery 2209 */ 2210 /*ARGSUSED*/ 2211 static void 2212 usb_as_default_xfer_exc_cb(usb_pipe_handle_t def, usb_ctrl_req_t *reqp) 2213 { 2214 usb_as_state_t *uasp = (usb_as_state_t *)reqp->ctrl_client_private; 2215 mblk_t *mp; 2216 2217 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, 2218 "usb_as_default_xfer_exc_cb: ph=0x%p, reqp=0x%p", def, reqp); 2219 2220 ASSERT((reqp->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0); 2221 2222 mutex_enter(&uasp->usb_as_mutex); 2223 uasp->usb_as_xfer_cr = USB_AS_SEND_MERR; 2224 mp = uasp->usb_as_def_mblk; 2225 uasp->usb_as_def_mblk = NULL; 2226 2227 usb_as_send_merr_up(uasp, mp); 2228 2229 mutex_exit(&uasp->usb_as_mutex); 2230 2231 usb_free_ctrl_req(reqp); 2232 2233 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, 2234 "usb_as_default_xfer_exc_cb: End"); 2235 } 2236 2237 2238 /* 2239 * Power management 2240 */ 2241 2242 /*ARGSUSED*/ 2243 static void 2244 usb_as_create_pm_components(dev_info_t *dip, usb_as_state_t *uasp) 2245 { 2246 usb_as_power_t *uaspm; 2247 uint_t pwr_states; 2248 2249 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle, 2250 "usb_as_create_pm_components: begin"); 2251 2252 /* Allocate the state structure */ 2253 uaspm = kmem_zalloc(sizeof (usb_as_power_t), KM_SLEEP); 2254 uasp->usb_as_pm = uaspm; 2255 uaspm->aspm_state = uasp; 2256 uaspm->aspm_capabilities = 0; 2257 uaspm->aspm_current_power = USB_DEV_OS_FULL_PWR; 2258 2259 USB_DPRINTF_L3(PRINT_MASK_PM, uasp->usb_as_log_handle, 2260 "usb_as_pm_components: remote Wakeup enabled"); 2261 if (usb_create_pm_components(dip, &pwr_states) == 2262 USB_SUCCESS) { 2263 if (usb_handle_remote_wakeup(dip, 2264 USB_REMOTE_WAKEUP_ENABLE) != USB_SUCCESS) { 2265 USB_DPRINTF_L2(PRINT_MASK_PM, 2266 uasp->usb_as_log_handle, 2267 "enable remote wakeup failed"); 2268 } else { 2269 uaspm->aspm_wakeup_enabled = 1; 2270 } 2271 uaspm->aspm_pwr_states = (uint8_t)pwr_states; 2272 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2273 } 2274 2275 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle, 2276 "usb_as_create_pm_components: end"); 2277 } 2278 2279 2280 /* 2281 * usb_as_power: 2282 * power entry point 2283 */ 2284 static int 2285 usb_as_power(dev_info_t *dip, int comp, int level) 2286 { 2287 int instance = ddi_get_instance(dip); 2288 usb_as_state_t *uasp; 2289 usb_as_power_t *uaspm; 2290 int retval = USB_FAILURE; 2291 2292 uasp = ddi_get_soft_state(usb_as_statep, instance); 2293 2294 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle, 2295 "usb_as_power: comp=%d level=%d", comp, level); 2296 2297 (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0); 2298 2299 mutex_enter(&uasp->usb_as_mutex); 2300 uaspm = uasp->usb_as_pm; 2301 2302 if (USB_DEV_PWRSTATE_OK(uaspm->aspm_pwr_states, level)) { 2303 USB_DPRINTF_L2(PRINT_MASK_PM, uasp->usb_as_log_handle, 2304 "usb_as_power: illegal level=%d pwr_states=%d", 2305 level, uaspm->aspm_pwr_states); 2306 2307 goto done; 2308 } 2309 2310 switch (level) { 2311 case USB_DEV_OS_PWR_OFF: 2312 retval = usb_as_pwrlvl0(uasp); 2313 break; 2314 case USB_DEV_OS_PWR_1: 2315 retval = usb_as_pwrlvl1(uasp); 2316 break; 2317 case USB_DEV_OS_PWR_2: 2318 retval = usb_as_pwrlvl2(uasp); 2319 break; 2320 case USB_DEV_OS_FULL_PWR: 2321 retval = usb_as_pwrlvl3(uasp); 2322 break; 2323 default: 2324 retval = USB_FAILURE; 2325 break; 2326 } 2327 2328 done: 2329 2330 usb_release_access(uasp->usb_as_ser_acc); 2331 mutex_exit(&uasp->usb_as_mutex); 2332 2333 return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 2334 } 2335 2336 2337 /* 2338 * functions to handle power transition for various levels 2339 * These functions act as place holders to issue USB commands 2340 * to the devices to change their power levels 2341 * Level 0 = Device is powered off 2342 * Level 3 = Device if full powered 2343 * Level 1,2 = Intermediate power level of the device as implemented 2344 * by the hardware. 2345 * Note that Level 0 is OS power-off and Level 3 is OS full-power. 2346 */ 2347 static int 2348 usb_as_pwrlvl0(usb_as_state_t *uasp) 2349 { 2350 usb_as_power_t *uaspm; 2351 int rval; 2352 2353 uaspm = uasp->usb_as_pm; 2354 2355 switch (uasp->usb_as_dev_state) { 2356 case USB_DEV_ONLINE: 2357 /* Deny the powerdown request if the device is busy */ 2358 if (uaspm->aspm_pm_busy != 0) { 2359 2360 return (USB_FAILURE); 2361 } 2362 2363 if (uasp->usb_as_audio_state != USB_AS_IDLE) { 2364 2365 return (USB_FAILURE); 2366 } 2367 2368 /* Issue USB D3 command to the device here */ 2369 rval = usb_set_device_pwrlvl3(uasp->usb_as_dip); 2370 ASSERT(rval == USB_SUCCESS); 2371 2372 uasp->usb_as_dev_state = USB_DEV_PWRED_DOWN; 2373 uaspm->aspm_current_power = USB_DEV_OS_PWR_OFF; 2374 2375 /* FALLTHRU */ 2376 case USB_DEV_DISCONNECTED: 2377 case USB_DEV_SUSPENDED: 2378 /* allow a disconnected/cpr'ed device to go to low power */ 2379 2380 return (USB_SUCCESS); 2381 case USB_DEV_PWRED_DOWN: 2382 default: 2383 USB_DPRINTF_L2(PRINT_MASK_PM, uasp->usb_as_log_handle, 2384 "usb_as_pwrlvl0: Illegal dev_state"); 2385 2386 return (USB_FAILURE); 2387 } 2388 } 2389 2390 2391 /* ARGSUSED */ 2392 static int 2393 usb_as_pwrlvl1(usb_as_state_t *uasp) 2394 { 2395 int rval; 2396 2397 /* Issue USB D2 command to the device here */ 2398 rval = usb_set_device_pwrlvl2(uasp->usb_as_dip); 2399 ASSERT(rval == USB_SUCCESS); 2400 2401 return (USB_FAILURE); 2402 } 2403 2404 2405 /* ARGSUSED */ 2406 static int 2407 usb_as_pwrlvl2(usb_as_state_t *uasp) 2408 { 2409 int rval; 2410 2411 rval = usb_set_device_pwrlvl1(uasp->usb_as_dip); 2412 ASSERT(rval == USB_SUCCESS); 2413 2414 return (USB_FAILURE); 2415 } 2416 2417 2418 static int 2419 usb_as_pwrlvl3(usb_as_state_t *uasp) 2420 { 2421 usb_as_power_t *uaspm; 2422 int rval; 2423 2424 uaspm = uasp->usb_as_pm; 2425 2426 switch (uasp->usb_as_dev_state) { 2427 case USB_DEV_PWRED_DOWN: 2428 2429 /* Issue USB D0 command to the device here */ 2430 rval = usb_set_device_pwrlvl0(uasp->usb_as_dip); 2431 ASSERT(rval == USB_SUCCESS); 2432 2433 uasp->usb_as_dev_state = USB_DEV_ONLINE; 2434 uaspm->aspm_current_power = USB_DEV_OS_FULL_PWR; 2435 2436 /* FALLTHRU */ 2437 case USB_DEV_ONLINE: 2438 /* we are already in full power */ 2439 2440 /* fall thru */ 2441 case USB_DEV_DISCONNECTED: 2442 case USB_DEV_SUSPENDED: 2443 /* allow power change on a disconnected/cpr'ed device */ 2444 2445 return (USB_SUCCESS); 2446 default: 2447 USB_DPRINTF_L2(PRINT_MASK_PM, uasp->usb_as_log_handle, 2448 "usb_as_pwrlvl3: Illegal dev_state"); 2449 2450 return (DDI_FAILURE); 2451 } 2452 } 2453 2454 2455 /* 2456 * Descriptor Management 2457 * 2458 * usb_as_handle_descriptors: 2459 * read and parse all descriptors and build up usb_as_alts list 2460 * 2461 * the order is as follows: 2462 * interface, general, format, endpoint, CV endpoint 2463 */ 2464 static int 2465 usb_as_handle_descriptors(usb_as_state_t *uasp) 2466 { 2467 usb_client_dev_data_t *dev_data = uasp->usb_as_dev_data; 2468 int interface = dev_data->dev_curr_if; 2469 uint_t alternate; 2470 uint_t n_alternates; 2471 int len, i, n, n_srs, sr, index; 2472 int rval = USB_SUCCESS; 2473 usb_if_descr_t *if_descr; 2474 usb_audio_as_if_descr_t *general; 2475 usb_audio_type1_format_descr_t *format; 2476 usb_ep_descr_t *ep; 2477 usb_audio_as_isoc_ep_descr_t *cs_ep; 2478 usb_if_data_t *if_data; 2479 usb_alt_if_data_t *altif_data; 2480 usb_ep_data_t *ep_data; 2481 2482 USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2483 "usb_as_handle_descriptors: cfg=%d interface=%d", 2484 dev_data->dev_curr_cfg - &dev_data->dev_cfg[0], 2485 dev_data->dev_curr_if); 2486 2487 if_data = &dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if]; 2488 uasp->usb_as_ifno = interface; 2489 2490 /* 2491 * find the number of alternates for this interface 2492 * and allocate an array to store the descriptors for 2493 * each alternate 2494 */ 2495 uasp->usb_as_n_alternates = n_alternates = if_data->if_n_alt; 2496 uasp->usb_as_alts = kmem_zalloc((n_alternates) * 2497 sizeof (usb_as_alt_descr_t), KM_SLEEP); 2498 2499 /* 2500 * for each alternate read descriptors 2501 */ 2502 for (alternate = 0; alternate < n_alternates; alternate++) { 2503 altif_data = &if_data->if_alt[alternate]; 2504 2505 uasp->usb_as_alts[alternate].alt_if = 2506 kmem_zalloc(sizeof (usb_if_descr_t), KM_SLEEP); 2507 if_descr = &altif_data->altif_descr; 2508 2509 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2510 "interface (%d.%d):\n\t" 2511 "l = 0x%x type = 0x%x n = 0x%x alt = 0x%x #ep = 0x%x\n\t" 2512 "iclass = 0x%x subclass = 0x%x proto = 0x%x string = 0x%x", 2513 interface, alternate, 2514 if_descr->bLength, if_descr->bDescriptorType, 2515 if_descr->bInterfaceNumber, if_descr->bAlternateSetting, 2516 if_descr->bNumEndpoints, if_descr->bInterfaceClass, 2517 if_descr->bInterfaceSubClass, 2518 if_descr->bInterfaceProtocol, if_descr->iInterface); 2519 2520 *(uasp->usb_as_alts[alternate].alt_if) = *if_descr; 2521 2522 /* read the general descriptor */ 2523 index = 0; 2524 2525 if (altif_data->altif_cvs == NULL) { 2526 2527 continue; 2528 } 2529 2530 general = kmem_zalloc(sizeof (*general), KM_SLEEP); 2531 2532 len = usb_parse_data(AS_IF_DESCR_FORMAT, 2533 altif_data->altif_cvs[index].cvs_buf, 2534 altif_data->altif_cvs[index].cvs_buf_len, 2535 (void *)general, sizeof (*general)); 2536 2537 /* is this a sane header descriptor */ 2538 if (!((len >= AS_IF_DESCR_SIZE) && 2539 (general->bDescriptorType == USB_AUDIO_CS_INTERFACE) && 2540 (general->bDescriptorSubType == USB_AUDIO_AS_GENERAL))) { 2541 USB_DPRINTF_L2(PRINT_MASK_ATTA, 2542 uasp->usb_as_log_handle, 2543 "invalid general cs interface descr"); 2544 2545 kmem_free(general, sizeof (*general)); 2546 2547 continue; 2548 } 2549 2550 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2551 "general (%d.%d): type=0x%x subtype=0x%x termlink=0x%x\n\t" 2552 "delay=0x%x format=0x%x", 2553 interface, alternate, 2554 general->bDescriptorType, general->bDescriptorSubType, 2555 general->bTerminalLink, general->bDelay, 2556 general->wFormatTag); 2557 2558 uasp->usb_as_alts[alternate].alt_general = general; 2559 2560 /* 2561 * there should be one format descriptor of unknown size. 2562 * the format descriptor contains just bytes, no need to 2563 * parse 2564 */ 2565 index++; 2566 len = altif_data->altif_cvs[index].cvs_buf_len; 2567 format = kmem_zalloc(len, KM_SLEEP); 2568 bcopy(altif_data->altif_cvs[index].cvs_buf, format, len); 2569 2570 uasp->usb_as_alts[alternate].alt_format_len = (uchar_t)len; 2571 2572 /* is this a sane format descriptor */ 2573 if (!((format->blength >= AUDIO_TYPE1_FORMAT_SIZE) && 2574 format->bDescriptorSubType == USB_AUDIO_AS_FORMAT_TYPE)) { 2575 USB_DPRINTF_L2(PRINT_MASK_ATTA, 2576 uasp->usb_as_log_handle, 2577 "invalid format cs interface descr"); 2578 2579 kmem_free(format, len); 2580 2581 continue; 2582 } 2583 2584 uasp->usb_as_alts[alternate].alt_format = format; 2585 2586 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2587 "format (%d.%d): len = %d " 2588 "type = 0x%x subtype = 0x%x format = 0x%x\n\t" 2589 "#channels = 0x%x subframe = 0x%x resolution = 0x%x\n\t" 2590 "sample freq type = 0x%x", 2591 interface, alternate, len, 2592 format->bDescriptorType, 2593 format->bDescriptorSubType, 2594 format->bFormatType, 2595 format->bNrChannels, 2596 format->bSubFrameSize, 2597 format->bBitResolution, 2598 format->bSamFreqType); 2599 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle, 2600 "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x " 2601 "0x%x 0x%x 0x%x 0x%x", 2602 format->bSamFreqs[0], format->bSamFreqs[1], 2603 format->bSamFreqs[2], format->bSamFreqs[3], 2604 format->bSamFreqs[4], format->bSamFreqs[5], 2605 format->bSamFreqs[6], format->bSamFreqs[7], 2606 format->bSamFreqs[8], format->bSamFreqs[9], 2607 format->bSamFreqs[10], format->bSamFreqs[11]); 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", 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", 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", 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