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