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