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