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