17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5b0fe7b8fSlg * Common Development and Distribution License (the "License").
6b0fe7b8fSlg * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22be529ebcSRaymond Chen * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
2788447a05SGarrett D'Amore * Audio Streams Interface Driver:
2888447a05SGarrett D'Amore *
2988447a05SGarrett D'Amore * usb_as is responsible for (1) Processing audio data messages during
3088447a05SGarrett D'Amore * play and record and management of isoc pipe, (2) Selecting correct
3188447a05SGarrett D'Amore * alternate that matches a set of parameters and management of control pipe.
3288447a05SGarrett D'Amore * This driver is opened by usb_ac and interacts with usb_ac synchronously
3388447a05SGarrett D'Amore * using ioctls. If the processing involves an async USBA command, the ioctl
3488447a05SGarrett D'Amore * returns after completion of the command.
357c478bd9Sstevel@tonic-gate *
3688447a05SGarrett D'Amore * Note: When there is a play/record, usb_as calls framework routines
3788447a05SGarrett D'Amore * directly for data (play) or sends data to mixer (record).
387c478bd9Sstevel@tonic-gate *
3988447a05SGarrett D'Amore * Serialization: A competing thread can't be allowed to interfere with
4088447a05SGarrett D'Amore * (1) pipe, (2) streams state.
417c478bd9Sstevel@tonic-gate * So we need some kind of serialization among the asynchronous
427c478bd9Sstevel@tonic-gate * threads that can run in the driver. The serialization is mostly
437c478bd9Sstevel@tonic-gate * needed to avoid races among open/close/events/power entry points
447c478bd9Sstevel@tonic-gate * etc. Once a routine grabs access, if checks if the resource (pipe or
457c478bd9Sstevel@tonic-gate * stream or dev state) is still accessible. If so, it proceeds with
467c478bd9Sstevel@tonic-gate * its job and until it completes, no other thread requiring the same
477c478bd9Sstevel@tonic-gate * resource can run.
487c478bd9Sstevel@tonic-gate *
497c478bd9Sstevel@tonic-gate * PM Model in usb_as: Raise power during attach and lower power in detach.
507c478bd9Sstevel@tonic-gate * If device is not fully powered, synchronous raise power in wsrv entry points.
517c478bd9Sstevel@tonic-gate */
527c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
537c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h>
5488447a05SGarrett D'Amore #include <sys/ddi.h>
5588447a05SGarrett D'Amore #include <sys/sunddi.h>
567c478bd9Sstevel@tonic-gate
57e272e4c8SBinzi Cao - Sun Microsystems - Beijing China #include <sys/audio/audio_driver.h>
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate #include <sys/usb/clients/audio/usb_audio.h>
607c478bd9Sstevel@tonic-gate #include <sys/usb/clients/audio/usb_mixer.h>
617c478bd9Sstevel@tonic-gate #include <sys/usb/clients/audio/usb_as/usb_as.h>
62e272e4c8SBinzi Cao - Sun Microsystems - Beijing China #include <sys/usb/clients/audio/usb_ac/usb_ac.h>
637c478bd9Sstevel@tonic-gate
6488447a05SGarrett D'Amore
657c478bd9Sstevel@tonic-gate /* debug support */
664610e4a0Sfrits uint_t usb_as_errlevel = USB_LOG_L4;
674610e4a0Sfrits uint_t usb_as_errmask = (uint_t)-1;
684610e4a0Sfrits uint_t usb_as_instance_debug = (uint_t)-1;
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate * Module linkage routines for the kernel
727c478bd9Sstevel@tonic-gate */
737c478bd9Sstevel@tonic-gate static int usb_as_attach(dev_info_t *, ddi_attach_cmd_t);
747c478bd9Sstevel@tonic-gate static int usb_as_detach(dev_info_t *, ddi_detach_cmd_t);
757c478bd9Sstevel@tonic-gate static int usb_as_power(dev_info_t *, int, int);
767c478bd9Sstevel@tonic-gate static int usb_as_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
777c478bd9Sstevel@tonic-gate
7888447a05SGarrett D'Amore static int usb_as_open(dev_t *, int, int, cred_t *);
7988447a05SGarrett D'Amore static int usb_as_close(dev_t, int, int, cred_t *);
8088447a05SGarrett D'Amore
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate /* support functions */
837c478bd9Sstevel@tonic-gate static void usb_as_cleanup(dev_info_t *, usb_as_state_t *);
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate static int usb_as_handle_descriptors(usb_as_state_t *);
867c478bd9Sstevel@tonic-gate static void usb_as_prepare_registration_data(usb_as_state_t *);
87*64391892SAlbert Lee static int usb_as_valid_format(usb_as_state_t *, uint_t);
887c478bd9Sstevel@tonic-gate static void usb_as_free_alts(usb_as_state_t *);
897c478bd9Sstevel@tonic-gate
907c478bd9Sstevel@tonic-gate static void usb_as_create_pm_components(dev_info_t *, usb_as_state_t *);
917c478bd9Sstevel@tonic-gate static int usb_as_disconnect_event_cb(dev_info_t *);
927c478bd9Sstevel@tonic-gate static int usb_as_reconnect_event_cb(dev_info_t *);
937c478bd9Sstevel@tonic-gate static int usb_as_cpr_suspend(dev_info_t *);
947c478bd9Sstevel@tonic-gate static void usb_as_cpr_resume(dev_info_t *);
957c478bd9Sstevel@tonic-gate
9688447a05SGarrett D'Amore static int usb_as_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate static int usb_as_pwrlvl0(usb_as_state_t *);
997c478bd9Sstevel@tonic-gate static int usb_as_pwrlvl1(usb_as_state_t *);
1007c478bd9Sstevel@tonic-gate static int usb_as_pwrlvl2(usb_as_state_t *);
1017c478bd9Sstevel@tonic-gate static int usb_as_pwrlvl3(usb_as_state_t *);
1027c478bd9Sstevel@tonic-gate static void usb_as_pm_busy_component(usb_as_state_t *);
1037c478bd9Sstevel@tonic-gate static void usb_as_pm_idle_component(usb_as_state_t *);
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate static void usb_as_restore_device_state(dev_info_t *, usb_as_state_t *);
10688447a05SGarrett D'Amore static int usb_as_setup(usb_as_state_t *);
10788447a05SGarrett D'Amore static void usb_as_teardown(usb_as_state_t *);
10888447a05SGarrett D'Amore static int usb_as_start_play(usb_as_state_t *, usb_audio_play_req_t *);
1097c478bd9Sstevel@tonic-gate static void usb_as_continue_play(usb_as_state_t *);
11088447a05SGarrett D'Amore static void usb_as_pause_play(usb_as_state_t *);
1117c478bd9Sstevel@tonic-gate
11288447a05SGarrett D'Amore static int usb_as_set_format(usb_as_state_t *, usb_audio_formats_t *);
11388447a05SGarrett D'Amore static int usb_as_set_sample_freq(usb_as_state_t *, int);
1147c478bd9Sstevel@tonic-gate static int usb_as_send_ctrl_cmd(usb_as_state_t *, uchar_t, uchar_t,
1157c478bd9Sstevel@tonic-gate ushort_t, ushort_t, ushort_t, mblk_t *, boolean_t);
1167c478bd9Sstevel@tonic-gate
117e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int usb_as_start_record(usb_as_state_t *, void *);
11888447a05SGarrett D'Amore static int usb_as_stop_record(usb_as_state_t *);
1197c478bd9Sstevel@tonic-gate static void usb_as_play_cb(usb_pipe_handle_t, usb_isoc_req_t *);
1207c478bd9Sstevel@tonic-gate static void usb_as_record_cb(usb_pipe_handle_t, usb_isoc_req_t *);
1217c478bd9Sstevel@tonic-gate static void usb_as_play_exc_cb(usb_pipe_handle_t, usb_isoc_req_t *);
1227c478bd9Sstevel@tonic-gate static void usb_as_record_exc_cb(usb_pipe_handle_t, usb_isoc_req_t *);
123*64391892SAlbert Lee static int usb_as_get_pktsize(usb_as_state_t *, usb_frame_number_t);
12488447a05SGarrett D'Amore static void usb_as_handle_shutdown(usb_as_state_t *);
12588447a05SGarrett D'Amore static int usb_as_play_isoc_data(usb_as_state_t *,
12688447a05SGarrett D'Amore usb_audio_play_req_t *);
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate /* anchor for soft state structures */
1297c478bd9Sstevel@tonic-gate static void *usb_as_statep;
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate * DDI Structures
1347c478bd9Sstevel@tonic-gate */
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate /* Entry points structure */
1377c478bd9Sstevel@tonic-gate static struct cb_ops usb_as_cb_ops = {
13888447a05SGarrett D'Amore usb_as_open, /* cb_open */
13988447a05SGarrett D'Amore usb_as_close, /* cb_close */
1407c478bd9Sstevel@tonic-gate nodev, /* cb_strategy */
1417c478bd9Sstevel@tonic-gate nodev, /* cb_print */
1427c478bd9Sstevel@tonic-gate nodev, /* cb_dump */
1437c478bd9Sstevel@tonic-gate nodev, /* cb_read */
1447c478bd9Sstevel@tonic-gate nodev, /* cb_write */
14588447a05SGarrett D'Amore usb_as_ioctl, /* cb_ioctl */
1467c478bd9Sstevel@tonic-gate nodev, /* cb_devmap */
1477c478bd9Sstevel@tonic-gate nodev, /* cb_mmap */
1487c478bd9Sstevel@tonic-gate nodev, /* cb_segmap */
1497c478bd9Sstevel@tonic-gate nochpoll, /* cb_chpoll */
1507c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */
15188447a05SGarrett D'Amore NULL, /* cb_str */
15288447a05SGarrett D'Amore D_MP | D_64BIT, /* cb_flag */
1537c478bd9Sstevel@tonic-gate CB_REV, /* cb_rev */
1547c478bd9Sstevel@tonic-gate nodev, /* cb_aread */
1557c478bd9Sstevel@tonic-gate nodev, /* cb_arwite */
1567c478bd9Sstevel@tonic-gate };
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate /* Device operations structure */
1597c478bd9Sstevel@tonic-gate static struct dev_ops usb_as_dev_ops = {
1607c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev */
1617c478bd9Sstevel@tonic-gate 0, /* devo_refcnt */
1627c478bd9Sstevel@tonic-gate usb_as_getinfo, /* devo_getinfo */
1637c478bd9Sstevel@tonic-gate nulldev, /* devo_identify - obsolete */
1647c478bd9Sstevel@tonic-gate nulldev, /* devo_probe - not needed */
1657c478bd9Sstevel@tonic-gate usb_as_attach, /* devo_attach */
1667c478bd9Sstevel@tonic-gate usb_as_detach, /* devo_detach */
1677c478bd9Sstevel@tonic-gate nodev, /* devo_reset */
1687c478bd9Sstevel@tonic-gate &usb_as_cb_ops, /* devi_cb_ops */
1697c478bd9Sstevel@tonic-gate NULL, /* devo_busb_as_ops */
17019397407SSherry Moore usb_as_power, /* devo_power */
171be529ebcSRaymond Chen ddi_quiesce_not_needed, /* devo_quiesce */
1727c478bd9Sstevel@tonic-gate };
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate /* Linkage structure for loadable drivers */
1757c478bd9Sstevel@tonic-gate static struct modldrv usb_as_modldrv = {
1767c478bd9Sstevel@tonic-gate &mod_driverops, /* drv_modops */
17777e51571Sgongtian zhao - Sun Microsystems - Beijing China "USB Audio Streaming Driver", /* drv_linkinfo */
1787c478bd9Sstevel@tonic-gate &usb_as_dev_ops /* drv_dev_ops */
1797c478bd9Sstevel@tonic-gate };
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate /* Module linkage structure */
1827c478bd9Sstevel@tonic-gate static struct modlinkage usb_as_modlinkage = {
1837c478bd9Sstevel@tonic-gate MODREV_1, /* ml_rev */
1847c478bd9Sstevel@tonic-gate (void *)&usb_as_modldrv, /* ml_linkage */
1857c478bd9Sstevel@tonic-gate NULL /* NULL terminates the list */
1867c478bd9Sstevel@tonic-gate };
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate static usb_event_t usb_as_events = {
1907c478bd9Sstevel@tonic-gate usb_as_disconnect_event_cb,
1917c478bd9Sstevel@tonic-gate usb_as_reconnect_event_cb,
1927c478bd9Sstevel@tonic-gate NULL, NULL
1937c478bd9Sstevel@tonic-gate };
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate /*
1967c478bd9Sstevel@tonic-gate * Mixer registration Management
1977c478bd9Sstevel@tonic-gate * use defaults as much as possible
1987c478bd9Sstevel@tonic-gate */
1997c478bd9Sstevel@tonic-gate
200e272e4c8SBinzi Cao - Sun Microsystems - Beijing China _NOTE(SCHEME_PROTECTS_DATA("unique per call", mblk_t))
201e272e4c8SBinzi Cao - Sun Microsystems - Beijing China _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_isoc_req_t))
202e272e4c8SBinzi Cao - Sun Microsystems - Beijing China _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_isoc_pkt_descr))
2037c478bd9Sstevel@tonic-gate
2047c478bd9Sstevel@tonic-gate int
_init(void)2057c478bd9Sstevel@tonic-gate _init(void)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate int rval;
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate /* initialize the soft state */
2107c478bd9Sstevel@tonic-gate if ((rval = ddi_soft_state_init(&usb_as_statep,
2117c478bd9Sstevel@tonic-gate sizeof (usb_as_state_t), 1)) != DDI_SUCCESS) {
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate return (rval);
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate if ((rval = mod_install(&usb_as_modlinkage)) != 0) {
2177c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&usb_as_statep);
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate return (rval);
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate int
_fini(void)2257c478bd9Sstevel@tonic-gate _fini(void)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate int rval;
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate if ((rval = mod_remove(&usb_as_modlinkage)) == 0) {
2307c478bd9Sstevel@tonic-gate /* Free the soft state internal structures */
2317c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&usb_as_statep);
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate return (rval);
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2397c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate return (mod_info(&usb_as_modlinkage, modinfop));
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2467c478bd9Sstevel@tonic-gate static int
usb_as_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)2477c478bd9Sstevel@tonic-gate usb_as_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
2487c478bd9Sstevel@tonic-gate void *arg, void **result)
2497c478bd9Sstevel@tonic-gate {
2507c478bd9Sstevel@tonic-gate usb_as_state_t *uasp = NULL;
2517c478bd9Sstevel@tonic-gate int error = DDI_FAILURE;
2527c478bd9Sstevel@tonic-gate int instance = USB_AS_MINOR_TO_INSTANCE(
253112116d8Sfb getminor((dev_t)arg));
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate switch (infocmd) {
2567c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate if ((uasp = ddi_get_soft_state(usb_as_statep,
2597c478bd9Sstevel@tonic-gate instance)) != NULL) {
2607c478bd9Sstevel@tonic-gate *result = uasp->usb_as_dip;
2617c478bd9Sstevel@tonic-gate if (*result != NULL) {
2627c478bd9Sstevel@tonic-gate error = DDI_SUCCESS;
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate } else {
2657c478bd9Sstevel@tonic-gate *result = NULL;
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate break;
2687c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
2697c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)instance;
2707c478bd9Sstevel@tonic-gate error = DDI_SUCCESS;
2717c478bd9Sstevel@tonic-gate break;
2727c478bd9Sstevel@tonic-gate default:
2737c478bd9Sstevel@tonic-gate break;
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate return (error);
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate
2807c478bd9Sstevel@tonic-gate static int
usb_as_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2817c478bd9Sstevel@tonic-gate usb_as_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2827c478bd9Sstevel@tonic-gate {
2837c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip);
2847c478bd9Sstevel@tonic-gate usb_as_state_t *uasp;
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate switch (cmd) {
2877c478bd9Sstevel@tonic-gate case DDI_ATTACH:
2887c478bd9Sstevel@tonic-gate
2897c478bd9Sstevel@tonic-gate break;
2907c478bd9Sstevel@tonic-gate case DDI_RESUME:
2917c478bd9Sstevel@tonic-gate usb_as_cpr_resume(dip);
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
2947c478bd9Sstevel@tonic-gate default:
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate
2997c478bd9Sstevel@tonic-gate /*
3007c478bd9Sstevel@tonic-gate * Allocate soft state information.
3017c478bd9Sstevel@tonic-gate */
3027c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(usb_as_statep, instance) != DDI_SUCCESS) {
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gate /*
3087c478bd9Sstevel@tonic-gate * get soft state space and initialize
3097c478bd9Sstevel@tonic-gate */
3107c478bd9Sstevel@tonic-gate uasp = (usb_as_state_t *)ddi_get_soft_state(usb_as_statep, instance);
3117c478bd9Sstevel@tonic-gate if (uasp == NULL) {
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle = usb_alloc_log_hdl(dip, "as",
317112116d8Sfb &usb_as_errlevel,
318112116d8Sfb &usb_as_errmask, &usb_as_instance_debug, 0);
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate uasp->usb_as_instance = instance;
3217c478bd9Sstevel@tonic-gate uasp->usb_as_dip = dip;
3227c478bd9Sstevel@tonic-gate
32388447a05SGarrett D'Amore (void) snprintf(uasp->dstr, sizeof (uasp->dstr), "%s#%d",
32488447a05SGarrett D'Amore ddi_driver_name(dip), instance);
32588447a05SGarrett D'Amore
3267c478bd9Sstevel@tonic-gate if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
3277c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
3287c478bd9Sstevel@tonic-gate "usb_client_attach failed");
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate usb_free_log_hdl(uasp->usb_as_log_handle);
3317c478bd9Sstevel@tonic-gate ddi_soft_state_free(usb_as_statep, uasp->usb_as_instance);
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate if (usb_get_dev_data(dip, &uasp->usb_as_dev_data,
3377c478bd9Sstevel@tonic-gate USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
3387c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
3397c478bd9Sstevel@tonic-gate "usb_get_dev_data failed");
3407c478bd9Sstevel@tonic-gate usb_client_detach(dip, NULL);
3417c478bd9Sstevel@tonic-gate usb_free_log_hdl(uasp->usb_as_log_handle);
3427c478bd9Sstevel@tonic-gate ddi_soft_state_free(usb_as_statep, uasp->usb_as_instance);
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate /* initialize mutex */
3487c478bd9Sstevel@tonic-gate mutex_init(&uasp->usb_as_mutex, NULL, MUTEX_DRIVER,
349112116d8Sfb uasp->usb_as_dev_data->dev_iblock_cookie);
350e272e4c8SBinzi Cao - Sun Microsystems - Beijing China
351e272e4c8SBinzi Cao - Sun Microsystems - Beijing China cv_init(&uasp->usb_as_pipe_cv, NULL, CV_DRIVER, NULL);
352e272e4c8SBinzi Cao - Sun Microsystems - Beijing China
3537c478bd9Sstevel@tonic-gate uasp->usb_as_ser_acc = usb_init_serialization(dip,
3547c478bd9Sstevel@tonic-gate USB_INIT_SER_CHECK_SAME_THREAD);
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate uasp->usb_as_default_ph = uasp->usb_as_dev_data->dev_default_ph;
3577c478bd9Sstevel@tonic-gate uasp->usb_as_isoc_pp.pp_max_async_reqs = 1;
3587c478bd9Sstevel@tonic-gate
3597c478bd9Sstevel@tonic-gate /* parse all descriptors */
3607c478bd9Sstevel@tonic-gate if (usb_as_handle_descriptors(uasp) != USB_SUCCESS) {
3617c478bd9Sstevel@tonic-gate
3627c478bd9Sstevel@tonic-gate goto fail;
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate usb_free_descr_tree(dip, uasp->usb_as_dev_data);
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate if ((ddi_create_minor_node(dip, "usb_as", S_IFCHR,
3687c478bd9Sstevel@tonic-gate USB_AS_CONSTRUCT_MINOR(instance),
3697c478bd9Sstevel@tonic-gate NULL, 0)) != DDI_SUCCESS) {
370d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
3717c478bd9Sstevel@tonic-gate "usb_as_attach: couldn't create minor node");
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate goto fail;
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate
3767c478bd9Sstevel@tonic-gate /* we are online */
3777c478bd9Sstevel@tonic-gate uasp->usb_as_dev_state = USB_DEV_ONLINE;
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate /* create components to power manage this device */
3807c478bd9Sstevel@tonic-gate usb_as_create_pm_components(dip, uasp);
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate /* Register for events */
3837c478bd9Sstevel@tonic-gate if (usb_register_event_cbs(dip, &usb_as_events, 0) != USB_SUCCESS) {
384d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
3857c478bd9Sstevel@tonic-gate "usb_as_attach: couldn't register for events");
3867c478bd9Sstevel@tonic-gate
3877c478bd9Sstevel@tonic-gate goto fail;
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate /* report device */
3917c478bd9Sstevel@tonic-gate ddi_report_dev(dip);
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
3947c478bd9Sstevel@tonic-gate "usb_as_attach: End");
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
3977c478bd9Sstevel@tonic-gate
3987c478bd9Sstevel@tonic-gate fail:
3997c478bd9Sstevel@tonic-gate if (uasp) {
400d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
4017c478bd9Sstevel@tonic-gate "attach failed");
4027c478bd9Sstevel@tonic-gate usb_as_cleanup(dip, uasp);
4037c478bd9Sstevel@tonic-gate }
4047c478bd9Sstevel@tonic-gate
4057c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4107c478bd9Sstevel@tonic-gate static int
usb_as_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4117c478bd9Sstevel@tonic-gate usb_as_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip);
4147c478bd9Sstevel@tonic-gate usb_as_state_t *uasp;
4157c478bd9Sstevel@tonic-gate int rval;
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate uasp = ddi_get_soft_state(usb_as_statep, instance);
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate switch (cmd) {
4207c478bd9Sstevel@tonic-gate case DDI_DETACH:
4217c478bd9Sstevel@tonic-gate usb_as_cleanup(dip, uasp);
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
4247c478bd9Sstevel@tonic-gate case DDI_SUSPEND:
4257c478bd9Sstevel@tonic-gate rval = usb_as_cpr_suspend(dip);
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
4287c478bd9Sstevel@tonic-gate default:
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate static void
usb_as_cleanup(dev_info_t * dip,usb_as_state_t * uasp)4367c478bd9Sstevel@tonic-gate usb_as_cleanup(dev_info_t *dip, usb_as_state_t *uasp)
4377c478bd9Sstevel@tonic-gate {
4387c478bd9Sstevel@tonic-gate usb_as_power_t *uaspm;
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate if (uasp == NULL) {
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate return;
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate uaspm = uasp->usb_as_pm;
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
448112116d8Sfb "usb_as_cleanup: uaspm=0x%p", (void *)uaspm);
4497c478bd9Sstevel@tonic-gate
4506918308bSyz if (uasp->usb_as_isoc_ph) {
4516918308bSyz usb_pipe_close(dip, uasp->usb_as_isoc_ph,
4526918308bSyz USB_FLAGS_SLEEP, NULL, NULL);
4536918308bSyz }
4547c478bd9Sstevel@tonic-gate /*
4557c478bd9Sstevel@tonic-gate * Disable the event callbacks first, after this point, event
4567c478bd9Sstevel@tonic-gate * callbacks will never get called. Note we shouldn't hold
4577c478bd9Sstevel@tonic-gate * mutex while unregistering events because there may be a
4587c478bd9Sstevel@tonic-gate * competing event callback thread. Event callbacks are done
4597c478bd9Sstevel@tonic-gate * with ndi mutex held and this can cause a potential deadlock.
4607c478bd9Sstevel@tonic-gate */
4617c478bd9Sstevel@tonic-gate usb_unregister_event_cbs(dip, &usb_as_events);
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
4647c478bd9Sstevel@tonic-gate
4657c478bd9Sstevel@tonic-gate if (uaspm && (uasp->usb_as_dev_state != USB_DEV_DISCONNECTED)) {
4667c478bd9Sstevel@tonic-gate if (uaspm->aspm_wakeup_enabled) {
4677c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate /*
4707c478bd9Sstevel@tonic-gate * We need to raise power first because
4717c478bd9Sstevel@tonic-gate * we need to send down a command to disable
4727c478bd9Sstevel@tonic-gate * remote wakeup
4737c478bd9Sstevel@tonic-gate */
4747c478bd9Sstevel@tonic-gate usb_as_pm_busy_component(uasp);
4757c478bd9Sstevel@tonic-gate (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gate if (usb_handle_remote_wakeup(dip,
4787c478bd9Sstevel@tonic-gate USB_REMOTE_WAKEUP_DISABLE)) {
4797c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL,
4807c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle,
4817c478bd9Sstevel@tonic-gate "disable remote wake up failed");
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate usb_as_pm_idle_component(uasp);
4847c478bd9Sstevel@tonic-gate } else {
4857c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate if (uaspm) {
4947c478bd9Sstevel@tonic-gate kmem_free(uaspm, sizeof (usb_as_power_t));
4957c478bd9Sstevel@tonic-gate uasp->usb_as_pm = NULL;
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate usb_client_detach(dip, uasp->usb_as_dev_data);
4997c478bd9Sstevel@tonic-gate
5007c478bd9Sstevel@tonic-gate usb_as_free_alts(uasp);
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
5037c478bd9Sstevel@tonic-gate mutex_destroy(&uasp->usb_as_mutex);
5047c478bd9Sstevel@tonic-gate
5057c478bd9Sstevel@tonic-gate usb_fini_serialization(uasp->usb_as_ser_acc);
5067c478bd9Sstevel@tonic-gate
5077c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL);
5087c478bd9Sstevel@tonic-gate usb_free_log_hdl(uasp->usb_as_log_handle);
5097c478bd9Sstevel@tonic-gate ddi_soft_state_free(usb_as_statep, uasp->usb_as_instance);
5107c478bd9Sstevel@tonic-gate
5117c478bd9Sstevel@tonic-gate ddi_prop_remove_all(dip);
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gate
5157c478bd9Sstevel@tonic-gate /*
5167c478bd9Sstevel@tonic-gate * usb_as_open:
5177c478bd9Sstevel@tonic-gate * Open entry point for plumbing only
5187c478bd9Sstevel@tonic-gate */
5197c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5207c478bd9Sstevel@tonic-gate static int
usb_as_open(dev_t * devp,int flag,int otyp,cred_t * credp)52188447a05SGarrett D'Amore usb_as_open(dev_t *devp, int flag, int otyp, cred_t *credp)
5227c478bd9Sstevel@tonic-gate {
52388447a05SGarrett D'Amore int inst = USB_AS_MINOR_TO_INSTANCE(getminor(*devp));
52488447a05SGarrett D'Amore usb_as_state_t *uasp = ddi_get_soft_state(usb_as_statep, inst);
52588447a05SGarrett D'Amore
5267c478bd9Sstevel@tonic-gate if (uasp == NULL) {
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate return (ENXIO);
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate /* Do mux plumbing stuff */
5321cdd1aafSBinzi Cao - Sun Microsystems - Beijing China USB_DPRINTF_L4(PRINT_MASK_OPEN, uasp->usb_as_log_handle,
5331cdd1aafSBinzi Cao - Sun Microsystems - Beijing China "usb_as_open: start");
53488447a05SGarrett D'Amore
53588447a05SGarrett D'Amore mutex_enter(&uasp->usb_as_mutex);
5367c478bd9Sstevel@tonic-gate
53788447a05SGarrett D'Amore if (uasp->usb_as_flag == USB_AS_OPEN || credp != kcred) {
5381cdd1aafSBinzi Cao - Sun Microsystems - Beijing China USB_DPRINTF_L2(PRINT_MASK_OPEN, uasp->usb_as_log_handle,
5391cdd1aafSBinzi Cao - Sun Microsystems - Beijing China "usb_as_open:multiple opens or opens from userspace"
5401cdd1aafSBinzi Cao - Sun Microsystems - Beijing China " not supported");
5411cdd1aafSBinzi Cao - Sun Microsystems - Beijing China
54288447a05SGarrett D'Amore mutex_exit(&uasp->usb_as_mutex);
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate return (ENXIO);
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate /* fail open on a disconnected device */
5487c478bd9Sstevel@tonic-gate if (uasp->usb_as_dev_state == USB_DEV_DISCONNECTED) {
5491cdd1aafSBinzi Cao - Sun Microsystems - Beijing China USB_DPRINTF_L2(PRINT_MASK_OPEN, uasp->usb_as_log_handle,
5501cdd1aafSBinzi Cao - Sun Microsystems - Beijing China "usb_as_open: disconnected");
5517c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate return (ENODEV);
5547c478bd9Sstevel@tonic-gate }
5557c478bd9Sstevel@tonic-gate
55688447a05SGarrett D'Amore /* Initialize state */
55788447a05SGarrett D'Amore uasp->usb_as_flag = USB_AS_OPEN;
5587c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate /*
5617c478bd9Sstevel@tonic-gate * go to full power, and remain pm_busy till close
5627c478bd9Sstevel@tonic-gate */
5637c478bd9Sstevel@tonic-gate usb_as_pm_busy_component(uasp);
5647c478bd9Sstevel@tonic-gate (void) pm_raise_power(uasp->usb_as_dip, 0, USB_DEV_OS_FULL_PWR);
5657c478bd9Sstevel@tonic-gate
5661cdd1aafSBinzi Cao - Sun Microsystems - Beijing China USB_DPRINTF_L4(PRINT_MASK_OPEN, uasp->usb_as_log_handle,
5671cdd1aafSBinzi Cao - Sun Microsystems - Beijing China "usb_as_open:done");
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate return (0);
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate
5737c478bd9Sstevel@tonic-gate /*
5747c478bd9Sstevel@tonic-gate * usb_as_close:
5757c478bd9Sstevel@tonic-gate * Close entry point for plumbing
5767c478bd9Sstevel@tonic-gate */
5777c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5787c478bd9Sstevel@tonic-gate static int
usb_as_close(dev_t dev,int flag,int otyp,cred_t * credp)57988447a05SGarrett D'Amore usb_as_close(dev_t dev, int flag, int otyp, cred_t *credp)
5807c478bd9Sstevel@tonic-gate {
58188447a05SGarrett D'Amore int inst = USB_AS_MINOR_TO_INSTANCE(getminor(dev));
58288447a05SGarrett D'Amore usb_as_state_t *uasp = ddi_get_soft_state(usb_as_statep, inst);
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_CLOSE, uasp->usb_as_log_handle,
58588447a05SGarrett D'Amore "usb_as_close: inst=%d", inst);
5867c478bd9Sstevel@tonic-gate
5877c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
58888447a05SGarrett D'Amore uasp->usb_as_flag = USB_AS_DISMANTLING;
5897c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate /*
5927c478bd9Sstevel@tonic-gate * Avoid races with other routines.
5937c478bd9Sstevel@tonic-gate * For example, if a control transfer is going on, wait
5947c478bd9Sstevel@tonic-gate * for that to be completed
5957c478bd9Sstevel@tonic-gate * At this point default pipe cannot be open.
5967c478bd9Sstevel@tonic-gate */
5977c478bd9Sstevel@tonic-gate (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0);
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate usb_release_access(uasp->usb_as_ser_acc);
6007c478bd9Sstevel@tonic-gate
6017c478bd9Sstevel@tonic-gate /* we can now power down */
6027c478bd9Sstevel@tonic-gate usb_as_pm_idle_component(uasp);
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
60588447a05SGarrett D'Amore uasp->usb_as_flag = 0;
6067c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
6077c478bd9Sstevel@tonic-gate
60888447a05SGarrett D'Amore return (0);
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate /*
61388447a05SGarrett D'Amore *
6147c478bd9Sstevel@tonic-gate */
61588447a05SGarrett D'Amore /*ARGSUSED*/
6167c478bd9Sstevel@tonic-gate static int
usb_as_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)61788447a05SGarrett D'Amore usb_as_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
61888447a05SGarrett D'Amore int *rvalp)
6197c478bd9Sstevel@tonic-gate {
62088447a05SGarrett D'Amore int inst = USB_AS_MINOR_TO_INSTANCE(getminor(dev));
62188447a05SGarrett D'Amore usb_as_state_t *uasp = ddi_get_soft_state(usb_as_statep, inst);
62288447a05SGarrett D'Amore int rv = USB_SUCCESS;
6237c478bd9Sstevel@tonic-gate
6247c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
62588447a05SGarrett D'Amore "usb_as_ioctl: Begin inst=%d, cmd=0x%x, arg=0x%p",
62688447a05SGarrett D'Amore inst, cmd, (void *)arg);
6277c478bd9Sstevel@tonic-gate
62888447a05SGarrett D'Amore if (!(mode & FKIOCTL)) {
6297c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
63088447a05SGarrett D'Amore "usb_as_ioctl: inst=%d, user space not supported", inst);
63188447a05SGarrett D'Amore return (ENXIO);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate
63488447a05SGarrett D'Amore mutex_enter(&uasp->usb_as_mutex);
6357c478bd9Sstevel@tonic-gate
63688447a05SGarrett D'Amore switch (cmd) {
63788447a05SGarrett D'Amore case USB_AUDIO_MIXER_REGISTRATION:
63888447a05SGarrett D'Amore USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
63988447a05SGarrett D'Amore "usb_as_ioctl(mixer reg): inst=%d", inst);
6407c478bd9Sstevel@tonic-gate
64188447a05SGarrett D'Amore /*
64288447a05SGarrett D'Amore * Copy the usb_as_reg structure to the structure
64388447a05SGarrett D'Amore * that usb_ac passed. Note that this is a structure
64488447a05SGarrett D'Amore * assignment and not a pointer assignment!
64588447a05SGarrett D'Amore */
64688447a05SGarrett D'Amore *(usb_as_registration_t *)arg = uasp->usb_as_reg;
6477c478bd9Sstevel@tonic-gate
64888447a05SGarrett D'Amore break;
64988447a05SGarrett D'Amore case USB_AUDIO_SET_FORMAT:
65088447a05SGarrett D'Amore rv = usb_as_set_format(uasp, (usb_audio_formats_t *)arg);
65188447a05SGarrett D'Amore break;
65288447a05SGarrett D'Amore case USB_AUDIO_SET_SAMPLE_FREQ:
65388447a05SGarrett D'Amore rv = usb_as_set_sample_freq(uasp, *(int *)arg);
65488447a05SGarrett D'Amore break;
65588447a05SGarrett D'Amore case USB_AUDIO_SETUP:
65688447a05SGarrett D'Amore rv = usb_as_setup(uasp);
65788447a05SGarrett D'Amore break;
65888447a05SGarrett D'Amore case USB_AUDIO_TEARDOWN:
65988447a05SGarrett D'Amore usb_as_teardown(uasp);
66088447a05SGarrett D'Amore break;
66188447a05SGarrett D'Amore case USB_AUDIO_START_PLAY:
66288447a05SGarrett D'Amore rv = usb_as_start_play(uasp, (usb_audio_play_req_t *)arg);
66388447a05SGarrett D'Amore break;
66488447a05SGarrett D'Amore case USB_AUDIO_STOP_PLAY:
66588447a05SGarrett D'Amore case USB_AUDIO_PAUSE_PLAY:
66688447a05SGarrett D'Amore usb_as_pause_play(uasp);
66788447a05SGarrett D'Amore break;
66888447a05SGarrett D'Amore case USB_AUDIO_START_RECORD:
669e272e4c8SBinzi Cao - Sun Microsystems - Beijing China rv = usb_as_start_record(uasp, (void *)arg);
67088447a05SGarrett D'Amore break;
67188447a05SGarrett D'Amore case USB_AUDIO_STOP_RECORD:
67288447a05SGarrett D'Amore rv = usb_as_stop_record(uasp);
67388447a05SGarrett D'Amore break;
67488447a05SGarrett D'Amore default:
67588447a05SGarrett D'Amore USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
67688447a05SGarrett D'Amore "usb_as_ioctl: unknown IOCTL, cmd=%d", cmd);
67788447a05SGarrett D'Amore break;
6787c478bd9Sstevel@tonic-gate }
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
6817c478bd9Sstevel@tonic-gate
68288447a05SGarrett D'Amore return (rv == USB_SUCCESS ? 0 : ENXIO);
6837c478bd9Sstevel@tonic-gate }
6847c478bd9Sstevel@tonic-gate
6857c478bd9Sstevel@tonic-gate
6867c478bd9Sstevel@tonic-gate /*
6877c478bd9Sstevel@tonic-gate * usb_as_set_sample_freq:
6887c478bd9Sstevel@tonic-gate * Sets the sample freq by sending a control command to interface
6897c478bd9Sstevel@tonic-gate * Although not required for continuous sample rate devices, some
6907c478bd9Sstevel@tonic-gate * devices such as plantronics devices do need this.
6917c478bd9Sstevel@tonic-gate * On the other hand, the TI chip which does not support continuous
6927c478bd9Sstevel@tonic-gate * sample rate stalls on this request
6937c478bd9Sstevel@tonic-gate * Therefore, we ignore errors and carry on regardless
6947c478bd9Sstevel@tonic-gate */
6957c478bd9Sstevel@tonic-gate static int
usb_as_set_sample_freq(usb_as_state_t * uasp,int freq)69688447a05SGarrett D'Amore usb_as_set_sample_freq(usb_as_state_t *uasp, int freq)
6977c478bd9Sstevel@tonic-gate {
69888447a05SGarrett D'Amore int alt, ep;
6997c478bd9Sstevel@tonic-gate mblk_t *data;
7007c478bd9Sstevel@tonic-gate int rval = USB_FAILURE;
7017c478bd9Sstevel@tonic-gate boolean_t ignore_errors;
7027c478bd9Sstevel@tonic-gate
7037c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uasp->usb_as_mutex));
7047c478bd9Sstevel@tonic-gate
7057c478bd9Sstevel@tonic-gate alt = uasp->usb_as_alternate;
7067c478bd9Sstevel@tonic-gate
707*64391892SAlbert Lee uasp->usb_as_curr_sr = freq;
708*64391892SAlbert Lee
7097c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
71088447a05SGarrett D'Amore "usb_as_set_sample_freq: inst=%d cont_sr=%d freq=%d",
71188447a05SGarrett D'Amore ddi_get_instance(uasp->usb_as_dip),
71288447a05SGarrett D'Amore uasp->usb_as_alts[alt].alt_continuous_sr, freq);
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate ignore_errors = B_TRUE;
7157c478bd9Sstevel@tonic-gate
7167c478bd9Sstevel@tonic-gate ep = uasp->usb_as_alts[alt].alt_ep->bEndpointAddress;
7177c478bd9Sstevel@tonic-gate
7187c478bd9Sstevel@tonic-gate data = allocb(4, BPRI_HI);
7197c478bd9Sstevel@tonic-gate if (data) {
7207c478bd9Sstevel@tonic-gate *(data->b_wptr++) = (char)freq;
7217c478bd9Sstevel@tonic-gate *(data->b_wptr++) = (char)(freq >> 8);
7227c478bd9Sstevel@tonic-gate *(data->b_wptr++) = (char)(freq >> 16);
7237c478bd9Sstevel@tonic-gate
7247c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
7257c478bd9Sstevel@tonic-gate
7267c478bd9Sstevel@tonic-gate if ((rval = usb_as_send_ctrl_cmd(uasp,
7277c478bd9Sstevel@tonic-gate USB_DEV_REQ_HOST_TO_DEV |
7287c478bd9Sstevel@tonic-gate USB_DEV_REQ_TYPE_CLASS |
7297c478bd9Sstevel@tonic-gate USB_DEV_REQ_RCPT_EP, /* bmRequestType */
7307c478bd9Sstevel@tonic-gate USB_AUDIO_SET_CUR, /* bRequest */
7317c478bd9Sstevel@tonic-gate USB_AUDIO_SAMPLING_FREQ_CONTROL << 8, /* wValue */
7327c478bd9Sstevel@tonic-gate ep, /* wIndex */
7337c478bd9Sstevel@tonic-gate 3, /* wLength */
7347c478bd9Sstevel@tonic-gate data,
7357c478bd9Sstevel@tonic-gate ignore_errors)) != USB_SUCCESS) {
7367c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
7377c478bd9Sstevel@tonic-gate "usb_as_set_sample_freq: set sample freq failed");
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
7407c478bd9Sstevel@tonic-gate }
74188447a05SGarrett D'Amore freemsg(data);
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate return (rval);
7447c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate /*
7487c478bd9Sstevel@tonic-gate * usb_as_set_format:
7497c478bd9Sstevel@tonic-gate * Matches channel, encoding and precision and find out
75088447a05SGarrett D'Amore * the right alternate. Sets alternate interface and returns it.
7517c478bd9Sstevel@tonic-gate */
7527c478bd9Sstevel@tonic-gate static int
usb_as_set_format(usb_as_state_t * uasp,usb_audio_formats_t * format)75388447a05SGarrett D'Amore usb_as_set_format(usb_as_state_t *uasp, usb_audio_formats_t *format)
7547c478bd9Sstevel@tonic-gate {
7557c478bd9Sstevel@tonic-gate int n;
7567c478bd9Sstevel@tonic-gate usb_as_registration_t *reg;
7577c478bd9Sstevel@tonic-gate int alt, rval;
7587c478bd9Sstevel@tonic-gate uint_t interface;
7597c478bd9Sstevel@tonic-gate
7607c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uasp->usb_as_mutex));
7617c478bd9Sstevel@tonic-gate
7627c478bd9Sstevel@tonic-gate if (uasp->usb_as_request_count) {
7637c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
76488447a05SGarrett D'Amore "usb_as_set_format: failing inst=%d, rq_cnt=%d",
76588447a05SGarrett D'Amore ddi_get_instance(uasp->usb_as_dip),
76688447a05SGarrett D'Amore uasp->usb_as_request_count);
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate return (USB_FAILURE);
7697c478bd9Sstevel@tonic-gate }
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate reg = &uasp->usb_as_reg;
7727c478bd9Sstevel@tonic-gate interface = uasp->usb_as_ifno;
7737c478bd9Sstevel@tonic-gate
77488447a05SGarrett D'Amore uasp->usb_as_curr_format = *format;
7757c478bd9Sstevel@tonic-gate
7767c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
77788447a05SGarrett D'Amore "usb_as_set_format: inst=%d, reg=0x%p, format=0x%p",
77888447a05SGarrett D'Amore ddi_get_instance(uasp->usb_as_dip), (void *)reg, (void *)format);
7797c478bd9Sstevel@tonic-gate
7807c478bd9Sstevel@tonic-gate for (n = 0; n < reg->reg_n_formats; n++) {
7817c478bd9Sstevel@tonic-gate if ((format->fmt_chns == reg->reg_formats[n].fmt_chns) &&
7827c478bd9Sstevel@tonic-gate (format->fmt_precision == reg->reg_formats[n].
7837c478bd9Sstevel@tonic-gate fmt_precision) && (format->fmt_encoding ==
7847c478bd9Sstevel@tonic-gate reg->reg_formats[n].fmt_encoding)) {
785*64391892SAlbert Lee int i;
786*64391892SAlbert Lee int n_srs = reg->reg_formats[n].fmt_n_srs;
787*64391892SAlbert Lee uint_t *srs = reg->reg_formats[n].fmt_srs;
788*64391892SAlbert Lee
789*64391892SAlbert Lee /* match sample rate */
790*64391892SAlbert Lee for (i = 0; i < n_srs; i++) {
791*64391892SAlbert Lee if (format->fmt_srs[0] == srs[i]) {
792*64391892SAlbert Lee
793*64391892SAlbert Lee break;
794*64391892SAlbert Lee }
795*64391892SAlbert Lee }
796*64391892SAlbert Lee
797*64391892SAlbert Lee if (i == n_srs) {
798*64391892SAlbert Lee
799*64391892SAlbert Lee continue;
800*64391892SAlbert Lee }
801*64391892SAlbert Lee
8027c478bd9Sstevel@tonic-gate /*
8037c478bd9Sstevel@tonic-gate * Found the alternate
8047c478bd9Sstevel@tonic-gate */
8057c478bd9Sstevel@tonic-gate uasp->usb_as_alternate = alt =
806112116d8Sfb reg->reg_formats[n].fmt_alt;
8077c478bd9Sstevel@tonic-gate break;
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate }
8107c478bd9Sstevel@tonic-gate
81188447a05SGarrett D'Amore if (n >= reg->reg_n_formats) {
8127c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
8137c478bd9Sstevel@tonic-gate "usb_as_set_format: Didn't find a matching alt");
8147c478bd9Sstevel@tonic-gate
8157c478bd9Sstevel@tonic-gate return (USB_FAILURE);
8167c478bd9Sstevel@tonic-gate }
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle,
8207c478bd9Sstevel@tonic-gate "usb_as_set_format: interface=%d alternate=%d",
8217c478bd9Sstevel@tonic-gate interface, alt);
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
8247c478bd9Sstevel@tonic-gate
82588447a05SGarrett D'Amore rval = usb_as_send_ctrl_cmd(uasp,
8267c478bd9Sstevel@tonic-gate /* bmRequestType */
8277c478bd9Sstevel@tonic-gate USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF,
8287c478bd9Sstevel@tonic-gate USB_REQ_SET_IF, /* bRequest */
8297c478bd9Sstevel@tonic-gate alt, /* wValue */
8307c478bd9Sstevel@tonic-gate interface, /* wIndex */
8317c478bd9Sstevel@tonic-gate 0, /* wLength */
83288447a05SGarrett D'Amore NULL, B_FALSE);
83388447a05SGarrett D'Amore
83488447a05SGarrett D'Amore mutex_enter(&uasp->usb_as_mutex);
83588447a05SGarrett D'Amore
83688447a05SGarrett D'Amore if (rval != USB_SUCCESS) {
8377c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
8387c478bd9Sstevel@tonic-gate "usb_as_set_format: set_alternate failed");
83988447a05SGarrett D'Amore } else {
84088447a05SGarrett D'Amore format->fmt_alt = (uchar_t)alt;
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate return (rval);
8447c478bd9Sstevel@tonic-gate }
8457c478bd9Sstevel@tonic-gate
8467c478bd9Sstevel@tonic-gate
8477c478bd9Sstevel@tonic-gate /*
8487c478bd9Sstevel@tonic-gate * usb_as_setup:
8497c478bd9Sstevel@tonic-gate * Open isoc pipe. Will hang around till bandwidth
8507c478bd9Sstevel@tonic-gate * is available.
8517c478bd9Sstevel@tonic-gate */
8527c478bd9Sstevel@tonic-gate static int
usb_as_setup(usb_as_state_t * uasp)85388447a05SGarrett D'Amore usb_as_setup(usb_as_state_t *uasp)
8547c478bd9Sstevel@tonic-gate {
8557c478bd9Sstevel@tonic-gate int alt = uasp->usb_as_alternate;
8567c478bd9Sstevel@tonic-gate usb_ep_descr_t *ep = (usb_ep_descr_t *)uasp->usb_as_alts[alt].alt_ep;
8577c478bd9Sstevel@tonic-gate int rval;
8587c478bd9Sstevel@tonic-gate
859e272e4c8SBinzi Cao - Sun Microsystems - Beijing China
8607c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uasp->usb_as_mutex));
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
86388447a05SGarrett D'Amore "usb_as_setup: Begin usb_as_setup, inst=%d",
86488447a05SGarrett D'Amore ddi_get_instance(uasp->usb_as_dip));
8657c478bd9Sstevel@tonic-gate
8667c478bd9Sstevel@tonic-gate
8677c478bd9Sstevel@tonic-gate /* Set record packet size to max packet size */
868e272e4c8SBinzi Cao - Sun Microsystems - Beijing China if (uasp->usb_as_alts[alt].alt_mode == USB_AUDIO_RECORD) {
8697c478bd9Sstevel@tonic-gate uasp->usb_as_record_pkt_size = ep->wMaxPacketSize;
8707c478bd9Sstevel@tonic-gate } else {
8717c478bd9Sstevel@tonic-gate uasp->usb_as_record_pkt_size = 0;
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate
874e272e4c8SBinzi Cao - Sun Microsystems - Beijing China if (uasp->usb_as_isoc_ph != NULL) {
875e272e4c8SBinzi Cao - Sun Microsystems - Beijing China while (uasp->usb_as_request_count) {
876e272e4c8SBinzi Cao - Sun Microsystems - Beijing China cv_wait(&uasp->usb_as_pipe_cv,
877e272e4c8SBinzi Cao - Sun Microsystems - Beijing China &uasp->usb_as_mutex);
878e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
879e272e4c8SBinzi Cao - Sun Microsystems - Beijing China
880e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /* close the isoc pipe which is opened before */
881e272e4c8SBinzi Cao - Sun Microsystems - Beijing China mutex_exit(&uasp->usb_as_mutex);
882e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_pipe_close(uasp->usb_as_dip, uasp->usb_as_isoc_ph,
883e272e4c8SBinzi Cao - Sun Microsystems - Beijing China USB_FLAGS_SLEEP, NULL, (usb_opaque_t)NULL);
884e272e4c8SBinzi Cao - Sun Microsystems - Beijing China
885e272e4c8SBinzi Cao - Sun Microsystems - Beijing China mutex_enter(&uasp->usb_as_mutex);
886e272e4c8SBinzi Cao - Sun Microsystems - Beijing China uasp->usb_as_isoc_ph = NULL;
887e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
888e272e4c8SBinzi Cao - Sun Microsystems - Beijing China
889e272e4c8SBinzi Cao - Sun Microsystems - Beijing China ASSERT(uasp->usb_as_request_count == 0);
8907c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
8917c478bd9Sstevel@tonic-gate
8927c478bd9Sstevel@tonic-gate /* open isoc pipe, may fail if there is no bandwidth */
8937c478bd9Sstevel@tonic-gate rval = usb_pipe_open(uasp->usb_as_dip, ep, &uasp->usb_as_isoc_pp,
89488447a05SGarrett D'Amore USB_FLAGS_SLEEP, &uasp->usb_as_isoc_ph);
8957c478bd9Sstevel@tonic-gate
8967c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
8977c478bd9Sstevel@tonic-gate switch (rval) {
8987c478bd9Sstevel@tonic-gate case USB_NO_BANDWIDTH:
8997c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ALL, uasp->usb_as_log_handle,
9007c478bd9Sstevel@tonic-gate "no bandwidth available");
9017c478bd9Sstevel@tonic-gate break;
9027c478bd9Sstevel@tonic-gate case USB_NOT_SUPPORTED:
9037c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ALL, uasp->usb_as_log_handle,
9047c478bd9Sstevel@tonic-gate "Operating a full/high speed audio device on a "
9057c478bd9Sstevel@tonic-gate "high speed port is not supported");
9067c478bd9Sstevel@tonic-gate break;
9077c478bd9Sstevel@tonic-gate default:
9087c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL,
9097c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle,
9107c478bd9Sstevel@tonic-gate "usb_as_setup: isoc pipe open failed (%d)",
9117c478bd9Sstevel@tonic-gate rval);
9127c478bd9Sstevel@tonic-gate }
9137c478bd9Sstevel@tonic-gate
9147c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
9157c478bd9Sstevel@tonic-gate
9167c478bd9Sstevel@tonic-gate return (USB_FAILURE);
9177c478bd9Sstevel@tonic-gate }
9187c478bd9Sstevel@tonic-gate
9197c478bd9Sstevel@tonic-gate (void) usb_pipe_set_private(uasp->usb_as_isoc_ph, (usb_opaque_t)uasp);
9207c478bd9Sstevel@tonic-gate
9217c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
9227c478bd9Sstevel@tonic-gate uasp->usb_as_audio_state = USB_AS_IDLE;
9237c478bd9Sstevel@tonic-gate uasp->usb_as_setup_cnt++;
9247c478bd9Sstevel@tonic-gate
9257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
9267c478bd9Sstevel@tonic-gate "usb_as_setup: End");
9277c478bd9Sstevel@tonic-gate
9287c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
9297c478bd9Sstevel@tonic-gate }
9307c478bd9Sstevel@tonic-gate
9317c478bd9Sstevel@tonic-gate
9327c478bd9Sstevel@tonic-gate /*
9337c478bd9Sstevel@tonic-gate * usb_as_teardown
9347c478bd9Sstevel@tonic-gate *
9357c478bd9Sstevel@tonic-gate */
9367c478bd9Sstevel@tonic-gate static void
usb_as_teardown(usb_as_state_t * uasp)93788447a05SGarrett D'Amore usb_as_teardown(usb_as_state_t *uasp)
9387c478bd9Sstevel@tonic-gate {
9397c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
94088447a05SGarrett D'Amore "usb_as_teardown: Begin inst=%d",
94188447a05SGarrett D'Amore ddi_get_instance(uasp->usb_as_dip));
94288447a05SGarrett D'Amore
9437c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uasp->usb_as_mutex));
9447c478bd9Sstevel@tonic-gate
9457c478bd9Sstevel@tonic-gate uasp->usb_as_audio_state = USB_AS_IDLE;
9467c478bd9Sstevel@tonic-gate
947e272e4c8SBinzi Cao - Sun Microsystems - Beijing China ASSERT(uasp->usb_as_isoc_ph);
948e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /* reset setup flag */
949e272e4c8SBinzi Cao - Sun Microsystems - Beijing China uasp->usb_as_setup_cnt--;
9507c478bd9Sstevel@tonic-gate
9517c478bd9Sstevel@tonic-gate
9527c478bd9Sstevel@tonic-gate ASSERT(uasp->usb_as_setup_cnt == 0);
9537c478bd9Sstevel@tonic-gate
9547c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
9557c478bd9Sstevel@tonic-gate "usb_as_teardown: End");
9567c478bd9Sstevel@tonic-gate }
9577c478bd9Sstevel@tonic-gate
9587c478bd9Sstevel@tonic-gate
9597c478bd9Sstevel@tonic-gate /*
96088447a05SGarrett D'Amore * usb_as_start_play
9617c478bd9Sstevel@tonic-gate */
9627c478bd9Sstevel@tonic-gate static int
usb_as_start_play(usb_as_state_t * uasp,usb_audio_play_req_t * play_req)96388447a05SGarrett D'Amore usb_as_start_play(usb_as_state_t *uasp, usb_audio_play_req_t *play_req)
9647c478bd9Sstevel@tonic-gate {
9657c478bd9Sstevel@tonic-gate int n_requests;
9667c478bd9Sstevel@tonic-gate int rval = USB_FAILURE;
9677c478bd9Sstevel@tonic-gate
9687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
96988447a05SGarrett D'Amore "usb_as_start_play: Begin inst=%d, req_cnt=%d",
97088447a05SGarrett D'Amore ddi_get_instance(uasp->usb_as_dip), uasp->usb_as_request_count);
9717c478bd9Sstevel@tonic-gate
9727c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uasp->usb_as_mutex));
9737c478bd9Sstevel@tonic-gate
9747c478bd9Sstevel@tonic-gate uasp->usb_as_request_samples = play_req->up_samples;
9757c478bd9Sstevel@tonic-gate uasp->usb_as_ahdl = play_req->up_handle;
9767c478bd9Sstevel@tonic-gate uasp->usb_as_audio_state = USB_AS_ACTIVE;
9777c478bd9Sstevel@tonic-gate
9787c478bd9Sstevel@tonic-gate if ((uasp->usb_as_request_count >= USB_AS_MAX_REQUEST_COUNT) ||
9797c478bd9Sstevel@tonic-gate (uasp->usb_as_audio_state == USB_AS_IDLE) ||
9807c478bd9Sstevel@tonic-gate (uasp->usb_as_audio_state == USB_AS_PLAY_PAUSED)) {
9817c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
9827c478bd9Sstevel@tonic-gate "nothing to do or paused or idle (%d)",
9837c478bd9Sstevel@tonic-gate uasp->usb_as_audio_state);
9847c478bd9Sstevel@tonic-gate rval = USB_SUCCESS;
9857c478bd9Sstevel@tonic-gate } else {
9867c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
9877c478bd9Sstevel@tonic-gate "usb_as_start_play: samples=%d requestcount=%d ",
98888447a05SGarrett D'Amore uasp->usb_as_request_samples, uasp->usb_as_request_count);
9897c478bd9Sstevel@tonic-gate
9907c478bd9Sstevel@tonic-gate /* queue up as many requests as allowed */
9917c478bd9Sstevel@tonic-gate for (n_requests = uasp->usb_as_request_count;
9927c478bd9Sstevel@tonic-gate n_requests < USB_AS_MAX_REQUEST_COUNT; n_requests++) {
99388447a05SGarrett D'Amore if ((rval = usb_as_play_isoc_data(uasp, play_req)) !=
9947c478bd9Sstevel@tonic-gate USB_SUCCESS) {
9957c478bd9Sstevel@tonic-gate break;
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate }
9987c478bd9Sstevel@tonic-gate }
9997c478bd9Sstevel@tonic-gate
10007c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
10017c478bd9Sstevel@tonic-gate "usb_as_start_play: End");
10027c478bd9Sstevel@tonic-gate
10037c478bd9Sstevel@tonic-gate return (rval);
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate
10067c478bd9Sstevel@tonic-gate
10077c478bd9Sstevel@tonic-gate /*
10087c478bd9Sstevel@tonic-gate * usb_as_continue_play:
10097c478bd9Sstevel@tonic-gate * this function is called from the play callbacks
10107c478bd9Sstevel@tonic-gate */
10117c478bd9Sstevel@tonic-gate static void
usb_as_continue_play(usb_as_state_t * uasp)10127c478bd9Sstevel@tonic-gate usb_as_continue_play(usb_as_state_t *uasp)
10137c478bd9Sstevel@tonic-gate {
10147c478bd9Sstevel@tonic-gate int n_requests;
10157c478bd9Sstevel@tonic-gate
10167c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
10177c478bd9Sstevel@tonic-gate "usb_as_contine_play: Begin req_cnt=%d",
10187c478bd9Sstevel@tonic-gate uasp->usb_as_request_count);
10197c478bd9Sstevel@tonic-gate
10207c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uasp->usb_as_mutex));
10217c478bd9Sstevel@tonic-gate
10227c478bd9Sstevel@tonic-gate if (uasp->usb_as_dev_state == USB_DEV_DISCONNECTED) {
102388447a05SGarrett D'Amore usb_as_handle_shutdown(uasp);
10247c478bd9Sstevel@tonic-gate
10257c478bd9Sstevel@tonic-gate return;
10267c478bd9Sstevel@tonic-gate }
10277c478bd9Sstevel@tonic-gate
10287c478bd9Sstevel@tonic-gate if ((uasp->usb_as_request_count >= USB_AS_MAX_REQUEST_COUNT) ||
10297c478bd9Sstevel@tonic-gate (uasp->usb_as_audio_state == USB_AS_IDLE) ||
10307c478bd9Sstevel@tonic-gate (uasp->usb_as_audio_state == USB_AS_PLAY_PAUSED)) {
10317c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
10327c478bd9Sstevel@tonic-gate "usb_as_continue_play: nothing to do (audio_state=%d)",
10337c478bd9Sstevel@tonic-gate uasp->usb_as_audio_state);
10347c478bd9Sstevel@tonic-gate } else {
10357c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
10367c478bd9Sstevel@tonic-gate "usb_as_continue_play: samples=%d requestcount=%d ",
103788447a05SGarrett D'Amore uasp->usb_as_request_samples, uasp->usb_as_request_count);
10387c478bd9Sstevel@tonic-gate
10397c478bd9Sstevel@tonic-gate /* queue up as many requests as allowed */
10407c478bd9Sstevel@tonic-gate for (n_requests = uasp->usb_as_request_count;
10417c478bd9Sstevel@tonic-gate n_requests < USB_AS_MAX_REQUEST_COUNT; n_requests++) {
10427c478bd9Sstevel@tonic-gate if (usb_as_play_isoc_data(uasp, NULL) !=
10437c478bd9Sstevel@tonic-gate USB_SUCCESS) {
10447c478bd9Sstevel@tonic-gate
10457c478bd9Sstevel@tonic-gate break;
10467c478bd9Sstevel@tonic-gate }
10477c478bd9Sstevel@tonic-gate }
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate
10507c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
10517c478bd9Sstevel@tonic-gate "usb_as_continue_play: End");
10527c478bd9Sstevel@tonic-gate }
10537c478bd9Sstevel@tonic-gate
10547c478bd9Sstevel@tonic-gate
10557c478bd9Sstevel@tonic-gate static void
usb_as_handle_shutdown(usb_as_state_t * uasp)105688447a05SGarrett D'Amore usb_as_handle_shutdown(usb_as_state_t *uasp)
10577c478bd9Sstevel@tonic-gate {
1058e272e4c8SBinzi Cao - Sun Microsystems - Beijing China void *ahdl;
10597c478bd9Sstevel@tonic-gate
10607c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
106188447a05SGarrett D'Amore "usb_as_handle_shutdown, inst=%d",
106288447a05SGarrett D'Amore ddi_get_instance(uasp->usb_as_dip));
10637c478bd9Sstevel@tonic-gate
10647c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
10657c478bd9Sstevel@tonic-gate "usb_as_handle_shutdown: am_play_shutdown");
10667c478bd9Sstevel@tonic-gate
10677c478bd9Sstevel@tonic-gate uasp->usb_as_audio_state = USB_AS_IDLE;
10687c478bd9Sstevel@tonic-gate uasp->usb_as_pkt_count = 0;
10697c478bd9Sstevel@tonic-gate ahdl = uasp->usb_as_ahdl;
10707c478bd9Sstevel@tonic-gate
10717c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
1072e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_stop_play(ahdl, NULL);
10737c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
10747c478bd9Sstevel@tonic-gate }
10757c478bd9Sstevel@tonic-gate
10767c478bd9Sstevel@tonic-gate
10777c478bd9Sstevel@tonic-gate static int
usb_as_play_isoc_data(usb_as_state_t * uasp,usb_audio_play_req_t * play_req)107888447a05SGarrett D'Amore usb_as_play_isoc_data(usb_as_state_t *uasp, usb_audio_play_req_t *play_req)
10797c478bd9Sstevel@tonic-gate {
10807c478bd9Sstevel@tonic-gate int rval = USB_FAILURE;
10817c478bd9Sstevel@tonic-gate
10827c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_req = NULL;
10837c478bd9Sstevel@tonic-gate usb_audio_formats_t *format = &uasp->usb_as_curr_format;
10847c478bd9Sstevel@tonic-gate mblk_t *data = NULL;
1085e272e4c8SBinzi Cao - Sun Microsystems - Beijing China void * ahdl = uasp->usb_as_ahdl;
10867c478bd9Sstevel@tonic-gate int precision;
10877c478bd9Sstevel@tonic-gate int pkt, frame, n, n_pkts, count;
10887c478bd9Sstevel@tonic-gate size_t bufsize;
10897c478bd9Sstevel@tonic-gate int pkt_len[USB_AS_N_FRAMES];
10907c478bd9Sstevel@tonic-gate
10917c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uasp->usb_as_mutex));
10927c478bd9Sstevel@tonic-gate
1093*64391892SAlbert Lee precision = format->fmt_precision >> 3;
10947c478bd9Sstevel@tonic-gate
10957c478bd9Sstevel@tonic-gate frame = uasp->usb_as_pkt_count;
10967c478bd9Sstevel@tonic-gate
10977c478bd9Sstevel@tonic-gate /*
10987c478bd9Sstevel@tonic-gate * calculate total bufsize by determining the pkt size for
10997c478bd9Sstevel@tonic-gate * each frame
11007c478bd9Sstevel@tonic-gate */
11017c478bd9Sstevel@tonic-gate for (bufsize = pkt = 0; pkt < USB_AS_N_FRAMES; pkt++) {
1102*64391892SAlbert Lee pkt_len[pkt] = usb_as_get_pktsize(uasp, frame++);
11037c478bd9Sstevel@tonic-gate bufsize += pkt_len[pkt];
11047c478bd9Sstevel@tonic-gate }
11057c478bd9Sstevel@tonic-gate
11067c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
110788447a05SGarrett D'Amore "usb_as_play_isoc_data: Begin bufsize=0x%lx, inst=%d", bufsize,
110888447a05SGarrett D'Amore ddi_get_instance(uasp->usb_as_dip));
11097c478bd9Sstevel@tonic-gate
11107c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
11117c478bd9Sstevel@tonic-gate
11127c478bd9Sstevel@tonic-gate if ((data = allocb(bufsize, BPRI_HI)) == NULL) {
11137c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
11147c478bd9Sstevel@tonic-gate "usb_as_play_isoc_data: allocb failed");
11157c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate goto done;
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate
112088447a05SGarrett D'Amore /*
1121e272e4c8SBinzi Cao - Sun Microsystems - Beijing China * restriction of Boomer: cannot call usb_ac_get_audio() in the context
112288447a05SGarrett D'Amore * of start so we play a fragment of silence at first
112388447a05SGarrett D'Amore */
112488447a05SGarrett D'Amore if (play_req != NULL) {
112588447a05SGarrett D'Amore bzero(data->b_wptr, bufsize);
112688447a05SGarrett D'Amore count = bufsize / precision;
112788447a05SGarrett D'Amore
1128e272e4c8SBinzi Cao - Sun Microsystems - Beijing China } else if ((count = usb_ac_get_audio(ahdl, (void *)data->b_wptr,
112988447a05SGarrett D'Amore bufsize / precision)) == 0) {
11307c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
11317c478bd9Sstevel@tonic-gate if (uasp->usb_as_request_count == 0) {
113288447a05SGarrett D'Amore usb_as_handle_shutdown(uasp);
11337c478bd9Sstevel@tonic-gate
11347c478bd9Sstevel@tonic-gate /* Don't return failure for 0 bytes of data sent */
113588447a05SGarrett D'Amore if (play_req) {
11367c478bd9Sstevel@tonic-gate /*
11377c478bd9Sstevel@tonic-gate * Since we set rval to SUCCESS
11387c478bd9Sstevel@tonic-gate * we treat it as a special case
11397c478bd9Sstevel@tonic-gate * and free data here
11407c478bd9Sstevel@tonic-gate */
11417c478bd9Sstevel@tonic-gate rval = USB_SUCCESS;
11427c478bd9Sstevel@tonic-gate freemsg(data);
11437c478bd9Sstevel@tonic-gate data = NULL;
11447c478bd9Sstevel@tonic-gate
11457c478bd9Sstevel@tonic-gate goto done;
11467c478bd9Sstevel@tonic-gate }
11477c478bd9Sstevel@tonic-gate } else {
11487c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL,
11497c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle,
11507c478bd9Sstevel@tonic-gate "usb_as_play_isoc_data: no audio bytes, "
11517c478bd9Sstevel@tonic-gate "rcnt=0x%x ", uasp->usb_as_request_count);
11527c478bd9Sstevel@tonic-gate }
11537c478bd9Sstevel@tonic-gate rval = USB_FAILURE;
11547c478bd9Sstevel@tonic-gate
11557c478bd9Sstevel@tonic-gate goto done;
11567c478bd9Sstevel@tonic-gate }
11577c478bd9Sstevel@tonic-gate
11587c478bd9Sstevel@tonic-gate bufsize = n = count * precision;
11597c478bd9Sstevel@tonic-gate data->b_wptr += n;
11607c478bd9Sstevel@tonic-gate
11617c478bd9Sstevel@tonic-gate /* calculate how many frames we can actually fill */
11627c478bd9Sstevel@tonic-gate for (n_pkts = 0; (n_pkts < USB_AS_N_FRAMES) && (n > 0); n_pkts++) {
11637c478bd9Sstevel@tonic-gate if (n < pkt_len[n_pkts]) {
11647c478bd9Sstevel@tonic-gate pkt_len[n_pkts] = n;
11657c478bd9Sstevel@tonic-gate }
11667c478bd9Sstevel@tonic-gate n -= pkt_len[n_pkts];
11677c478bd9Sstevel@tonic-gate }
11687c478bd9Sstevel@tonic-gate
11697c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
11707c478bd9Sstevel@tonic-gate "usb_as_play_isoc_data: n_pkts=%d, bufsize=%ld, n=%d",
11717c478bd9Sstevel@tonic-gate n_pkts, bufsize, count * precision);
11727c478bd9Sstevel@tonic-gate
11737c478bd9Sstevel@tonic-gate /* allocate an isoc request packet */
11747c478bd9Sstevel@tonic-gate if ((isoc_req = usb_alloc_isoc_req(uasp->usb_as_dip,
11757c478bd9Sstevel@tonic-gate n_pkts, 0, 0)) == NULL) {
11767c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
11777c478bd9Sstevel@tonic-gate
11787c478bd9Sstevel@tonic-gate goto done;
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate
11817c478bd9Sstevel@tonic-gate
11827c478bd9Sstevel@tonic-gate
11837c478bd9Sstevel@tonic-gate /* initialize the packet descriptor */
11847c478bd9Sstevel@tonic-gate for (pkt = 0; pkt < n_pkts; pkt++) {
11857c478bd9Sstevel@tonic-gate isoc_req->isoc_pkt_descr[pkt].isoc_pkt_length =
1186112116d8Sfb pkt_len[pkt];
11877c478bd9Sstevel@tonic-gate }
11887c478bd9Sstevel@tonic-gate
11897c478bd9Sstevel@tonic-gate isoc_req->isoc_data = data;
11907c478bd9Sstevel@tonic-gate isoc_req->isoc_pkts_count = (ushort_t)n_pkts;
11917c478bd9Sstevel@tonic-gate isoc_req->isoc_attributes = USB_ATTRS_ISOC_XFER_ASAP |
1192112116d8Sfb USB_ATTRS_AUTOCLEARING;
11937c478bd9Sstevel@tonic-gate isoc_req->isoc_cb = usb_as_play_cb;
11947c478bd9Sstevel@tonic-gate isoc_req->isoc_exc_cb = usb_as_play_exc_cb;
11957c478bd9Sstevel@tonic-gate isoc_req->isoc_client_private = (usb_opaque_t)uasp;
11967c478bd9Sstevel@tonic-gate
11977c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
11987c478bd9Sstevel@tonic-gate
11997c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle,
12007c478bd9Sstevel@tonic-gate "usb_as_play_isoc_data: rq=0x%p data=0x%p cnt=0x%x "
1201112116d8Sfb "pkt=0x%p rqcnt=%d ", (void *)isoc_req, (void *)data, count,
1202112116d8Sfb (void *)isoc_req->isoc_pkt_descr, uasp->usb_as_request_count);
12037c478bd9Sstevel@tonic-gate
12047c478bd9Sstevel@tonic-gate ASSERT(isoc_req->isoc_data != NULL);
12057c478bd9Sstevel@tonic-gate
12067c478bd9Sstevel@tonic-gate uasp->usb_as_send_debug_count++;
12077c478bd9Sstevel@tonic-gate uasp->usb_as_request_count++;
12087c478bd9Sstevel@tonic-gate uasp->usb_as_pkt_count += n_pkts;
12097c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
12107c478bd9Sstevel@tonic-gate
12117c478bd9Sstevel@tonic-gate if ((rval = usb_pipe_isoc_xfer(uasp->usb_as_isoc_ph,
12127c478bd9Sstevel@tonic-gate isoc_req, 0)) != USB_SUCCESS) {
12137c478bd9Sstevel@tonic-gate
12147c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
12157c478bd9Sstevel@tonic-gate uasp->usb_as_request_count--;
1216e272e4c8SBinzi Cao - Sun Microsystems - Beijing China cv_signal(&uasp->usb_as_pipe_cv);
12177c478bd9Sstevel@tonic-gate uasp->usb_as_send_debug_count--;
12187c478bd9Sstevel@tonic-gate uasp->usb_as_pkt_count -= n_pkts;
12197c478bd9Sstevel@tonic-gate
12207c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
12217c478bd9Sstevel@tonic-gate "usb_as_play_isoc_data: rval=%d", rval);
12227c478bd9Sstevel@tonic-gate
12237c478bd9Sstevel@tonic-gate rval = USB_FAILURE;
12247c478bd9Sstevel@tonic-gate
12257c478bd9Sstevel@tonic-gate } else {
12267c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
12277c478bd9Sstevel@tonic-gate
12287c478bd9Sstevel@tonic-gate data = NULL;
12297c478bd9Sstevel@tonic-gate isoc_req = NULL;
12307c478bd9Sstevel@tonic-gate }
12317c478bd9Sstevel@tonic-gate
12327c478bd9Sstevel@tonic-gate done:
12337c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
12347c478bd9Sstevel@tonic-gate freemsg(data);
12357c478bd9Sstevel@tonic-gate if (isoc_req) {
12367c478bd9Sstevel@tonic-gate isoc_req->isoc_data = NULL;
12377c478bd9Sstevel@tonic-gate usb_free_isoc_req(isoc_req);
12387c478bd9Sstevel@tonic-gate }
12397c478bd9Sstevel@tonic-gate }
12407c478bd9Sstevel@tonic-gate
12414610e4a0Sfrits USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
12427c478bd9Sstevel@tonic-gate "usb_as_play_isoc_data: SEND CNT=%d, RCV COUNT=%d",
12437c478bd9Sstevel@tonic-gate uasp->usb_as_send_debug_count, uasp->usb_as_rcv_debug_count);
12447c478bd9Sstevel@tonic-gate
12457c478bd9Sstevel@tonic-gate return (rval);
12467c478bd9Sstevel@tonic-gate }
12477c478bd9Sstevel@tonic-gate
12487c478bd9Sstevel@tonic-gate
12497c478bd9Sstevel@tonic-gate static void
usb_as_pause_play(usb_as_state_t * uasp)125088447a05SGarrett D'Amore usb_as_pause_play(usb_as_state_t *uasp)
12517c478bd9Sstevel@tonic-gate {
12527c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uasp->usb_as_mutex));
125388447a05SGarrett D'Amore
125488447a05SGarrett D'Amore /* this will stop the isoc request in the play callback */
12557c478bd9Sstevel@tonic-gate uasp->usb_as_audio_state = USB_AS_PLAY_PAUSED;
12567c478bd9Sstevel@tonic-gate }
12577c478bd9Sstevel@tonic-gate
12587c478bd9Sstevel@tonic-gate
12597c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12607c478bd9Sstevel@tonic-gate static void
usb_as_play_cb(usb_pipe_handle_t ph,usb_isoc_req_t * isoc_req)12617c478bd9Sstevel@tonic-gate usb_as_play_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req)
12627c478bd9Sstevel@tonic-gate {
12637c478bd9Sstevel@tonic-gate usb_as_state_t *uasp = (usb_as_state_t *)
1264112116d8Sfb (isoc_req->isoc_client_private);
12657c478bd9Sstevel@tonic-gate int i;
12667c478bd9Sstevel@tonic-gate
12677c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle,
12687c478bd9Sstevel@tonic-gate "usb_as_play_cb: Begin ph=0x%p, isoc_req=0x%p",
1269112116d8Sfb (void *)ph, (void *)isoc_req);
12707c478bd9Sstevel@tonic-gate
12717c478bd9Sstevel@tonic-gate ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) != 0);
12727c478bd9Sstevel@tonic-gate
12737c478bd9Sstevel@tonic-gate for (i = 0; i < isoc_req->isoc_pkts_count; i++) {
12747c478bd9Sstevel@tonic-gate if (isoc_req->isoc_pkt_descr[i].isoc_pkt_status !=
12757c478bd9Sstevel@tonic-gate USB_CR_OK) {
12767c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_CB, uasp->usb_as_log_handle,
12777c478bd9Sstevel@tonic-gate "usb_as_play_cb: \tpkt%d: len=%d status=%s", i,
12787c478bd9Sstevel@tonic-gate isoc_req->isoc_pkt_descr[i].isoc_pkt_length,
12797c478bd9Sstevel@tonic-gate usb_str_cr(isoc_req->
12807c478bd9Sstevel@tonic-gate isoc_pkt_descr[i].isoc_pkt_status));
12817c478bd9Sstevel@tonic-gate }
12827c478bd9Sstevel@tonic-gate }
12837c478bd9Sstevel@tonic-gate
12847c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
12857c478bd9Sstevel@tonic-gate if (isoc_req->isoc_error_count) {
12867c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_CB, uasp->usb_as_log_handle,
12877c478bd9Sstevel@tonic-gate "usb_as_play_cb: error_count = %d",
12887c478bd9Sstevel@tonic-gate isoc_req->isoc_error_count);
12897c478bd9Sstevel@tonic-gate }
12907c478bd9Sstevel@tonic-gate
12917c478bd9Sstevel@tonic-gate usb_free_isoc_req(isoc_req);
12927c478bd9Sstevel@tonic-gate uasp->usb_as_request_count--;
1293e272e4c8SBinzi Cao - Sun Microsystems - Beijing China cv_signal(&uasp->usb_as_pipe_cv);
12947c478bd9Sstevel@tonic-gate uasp->usb_as_rcv_debug_count++;
12957c478bd9Sstevel@tonic-gate usb_as_continue_play(uasp);
12967c478bd9Sstevel@tonic-gate
12974610e4a0Sfrits USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle,
12987c478bd9Sstevel@tonic-gate "usb_as_play_cb: SEND CNT=%d, RCV COUNT=%d",
12997c478bd9Sstevel@tonic-gate uasp->usb_as_send_debug_count, uasp->usb_as_rcv_debug_count);
13007c478bd9Sstevel@tonic-gate
13017c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle,
13027c478bd9Sstevel@tonic-gate "usb_as_play_cb: End, req_cnt=%d", uasp->usb_as_request_count);
13037c478bd9Sstevel@tonic-gate
13047c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
13057c478bd9Sstevel@tonic-gate }
13067c478bd9Sstevel@tonic-gate
13077c478bd9Sstevel@tonic-gate
13087c478bd9Sstevel@tonic-gate static void
usb_as_play_exc_cb(usb_pipe_handle_t ph,usb_isoc_req_t * isoc_req)13097c478bd9Sstevel@tonic-gate usb_as_play_exc_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req)
13107c478bd9Sstevel@tonic-gate {
13117c478bd9Sstevel@tonic-gate int i;
13127c478bd9Sstevel@tonic-gate usb_as_state_t *uasp = (usb_as_state_t *)
1313112116d8Sfb (isoc_req->isoc_client_private);
13147c478bd9Sstevel@tonic-gate usb_cr_t cr = isoc_req->isoc_completion_reason;
13157c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags = isoc_req->isoc_cb_flags;
13167c478bd9Sstevel@tonic-gate
13177c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
13187c478bd9Sstevel@tonic-gate "usb_as_play_exc_cb: ph=0x%p, rq=0x%p data=0x%p pkts=0x%x "
1319112116d8Sfb "cr=%d, cb_flag=0x%x", (void *)ph, (void *)isoc_req,
1320112116d8Sfb (void *)isoc_req->isoc_data, isoc_req->isoc_pkts_count,
1321112116d8Sfb cr, cb_flags);
13227c478bd9Sstevel@tonic-gate
13237c478bd9Sstevel@tonic-gate ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) == 0);
13247c478bd9Sstevel@tonic-gate
13257c478bd9Sstevel@tonic-gate for (i = 0; i < isoc_req->isoc_pkts_count; i++) {
13267c478bd9Sstevel@tonic-gate if (isoc_req->isoc_pkt_descr[i].isoc_pkt_status ==
13277c478bd9Sstevel@tonic-gate USB_CR_OK) {
13287c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL,
13297c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle,
13307c478bd9Sstevel@tonic-gate "usb_as_play_exc_cb: \tpkt%d: len=%d status=%d",
13317c478bd9Sstevel@tonic-gate i,
13327c478bd9Sstevel@tonic-gate isoc_req->isoc_pkt_descr[i].isoc_pkt_length,
13337c478bd9Sstevel@tonic-gate isoc_req->isoc_pkt_descr[i].isoc_pkt_status);
13347c478bd9Sstevel@tonic-gate }
13357c478bd9Sstevel@tonic-gate }
13367c478bd9Sstevel@tonic-gate
13377c478bd9Sstevel@tonic-gate usb_free_isoc_req(isoc_req);
13387c478bd9Sstevel@tonic-gate
13397c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
13407c478bd9Sstevel@tonic-gate uasp->usb_as_rcv_debug_count++;
13417c478bd9Sstevel@tonic-gate uasp->usb_as_request_count--;
1342e272e4c8SBinzi Cao - Sun Microsystems - Beijing China cv_signal(&uasp->usb_as_pipe_cv);
134388447a05SGarrett D'Amore usb_as_handle_shutdown(uasp);
13447c478bd9Sstevel@tonic-gate
13457c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
13467c478bd9Sstevel@tonic-gate "usb_as_play_exc_cb: SEND CNT=%d, RCV COUNT=%d",
13477c478bd9Sstevel@tonic-gate uasp->usb_as_send_debug_count, uasp->usb_as_rcv_debug_count);
13487c478bd9Sstevel@tonic-gate
13497c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
13507c478bd9Sstevel@tonic-gate "usb_as_play_exc_cb: End request_count=%d",
13517c478bd9Sstevel@tonic-gate uasp->usb_as_request_count);
13527c478bd9Sstevel@tonic-gate
13537c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
13547c478bd9Sstevel@tonic-gate }
13557c478bd9Sstevel@tonic-gate
13567c478bd9Sstevel@tonic-gate
13577c478bd9Sstevel@tonic-gate /*
13587c478bd9Sstevel@tonic-gate * usb_as_start_record
13597c478bd9Sstevel@tonic-gate */
13607c478bd9Sstevel@tonic-gate static int
usb_as_start_record(usb_as_state_t * uasp,void * ahdl)1361e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_as_start_record(usb_as_state_t *uasp, void * ahdl)
13627c478bd9Sstevel@tonic-gate {
13637c478bd9Sstevel@tonic-gate int rval = USB_FAILURE;
13647c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_req;
13657c478bd9Sstevel@tonic-gate ushort_t record_pkt_size = uasp->usb_as_record_pkt_size;
13667c478bd9Sstevel@tonic-gate ushort_t n_pkt = 1, pkt;
13677c478bd9Sstevel@tonic-gate
13687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
136988447a05SGarrett D'Amore "usb_as_start_record: inst=%d",
137088447a05SGarrett D'Amore ddi_get_instance(uasp->usb_as_dip));
13717c478bd9Sstevel@tonic-gate
13727c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uasp->usb_as_mutex));
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate /*
13757c478bd9Sstevel@tonic-gate * A start_record should not happen when stop polling is
13767c478bd9Sstevel@tonic-gate * happening
13777c478bd9Sstevel@tonic-gate */
13787c478bd9Sstevel@tonic-gate ASSERT(uasp->usb_as_audio_state != USB_AS_STOP_POLLING_STARTED);
13797c478bd9Sstevel@tonic-gate
13807c478bd9Sstevel@tonic-gate if (uasp->usb_as_audio_state == USB_AS_IDLE) {
13817c478bd9Sstevel@tonic-gate
138288447a05SGarrett D'Amore uasp->usb_as_ahdl = ahdl;
13837c478bd9Sstevel@tonic-gate uasp->usb_as_audio_state = USB_AS_ACTIVE;
13847c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
13857c478bd9Sstevel@tonic-gate
13867c478bd9Sstevel@tonic-gate if ((isoc_req = usb_alloc_isoc_req(uasp->usb_as_dip, n_pkt,
13877c478bd9Sstevel@tonic-gate n_pkt * record_pkt_size, 0)) != NULL) {
13887c478bd9Sstevel@tonic-gate /* Initialize the packet descriptor */
13897c478bd9Sstevel@tonic-gate for (pkt = 0; pkt < n_pkt; pkt++) {
13907c478bd9Sstevel@tonic-gate isoc_req->isoc_pkt_descr[pkt].
13917c478bd9Sstevel@tonic-gate isoc_pkt_length = record_pkt_size;
13927c478bd9Sstevel@tonic-gate }
13937c478bd9Sstevel@tonic-gate
13947c478bd9Sstevel@tonic-gate isoc_req->isoc_pkts_count = n_pkt;
13957c478bd9Sstevel@tonic-gate isoc_req->isoc_pkts_length = record_pkt_size;
13967c478bd9Sstevel@tonic-gate isoc_req->isoc_attributes = USB_ATTRS_ISOC_XFER_ASAP |
13977c478bd9Sstevel@tonic-gate USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
13987c478bd9Sstevel@tonic-gate isoc_req->isoc_cb = usb_as_record_cb;
13997c478bd9Sstevel@tonic-gate isoc_req->isoc_exc_cb = usb_as_record_exc_cb;
14007c478bd9Sstevel@tonic-gate isoc_req->isoc_client_private = (usb_opaque_t)uasp;
14017c478bd9Sstevel@tonic-gate
14027c478bd9Sstevel@tonic-gate rval = usb_pipe_isoc_xfer(uasp->usb_as_isoc_ph,
14037c478bd9Sstevel@tonic-gate isoc_req, 0);
14047c478bd9Sstevel@tonic-gate
14057c478bd9Sstevel@tonic-gate } else {
14067c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
14077c478bd9Sstevel@tonic-gate "usb_as_start_record: Isoc req allocation failed");
14087c478bd9Sstevel@tonic-gate }
14097c478bd9Sstevel@tonic-gate
14107c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
14117c478bd9Sstevel@tonic-gate
14127c478bd9Sstevel@tonic-gate } else {
14137c478bd9Sstevel@tonic-gate
14147c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
14157c478bd9Sstevel@tonic-gate "usb_as_start_record: Record in progress");
14167c478bd9Sstevel@tonic-gate
14177c478bd9Sstevel@tonic-gate rval = USB_SUCCESS;
14187c478bd9Sstevel@tonic-gate }
14197c478bd9Sstevel@tonic-gate
14207c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
14217c478bd9Sstevel@tonic-gate uasp->usb_as_audio_state = USB_AS_IDLE;
14227c478bd9Sstevel@tonic-gate if (isoc_req) {
14237c478bd9Sstevel@tonic-gate usb_free_isoc_req(isoc_req);
14247c478bd9Sstevel@tonic-gate isoc_req = NULL;
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate }
14277c478bd9Sstevel@tonic-gate
14287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
14297c478bd9Sstevel@tonic-gate "usb_as_start_record: rval=%d", rval);
14307c478bd9Sstevel@tonic-gate
14317c478bd9Sstevel@tonic-gate return (rval);
14327c478bd9Sstevel@tonic-gate }
14337c478bd9Sstevel@tonic-gate
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate static int
usb_as_stop_record(usb_as_state_t * uasp)143688447a05SGarrett D'Amore usb_as_stop_record(usb_as_state_t *uasp)
14377c478bd9Sstevel@tonic-gate {
14387c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
14397c478bd9Sstevel@tonic-gate "usb_as_stop_record: ");
14407c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uasp->usb_as_mutex));
14417c478bd9Sstevel@tonic-gate
14427c478bd9Sstevel@tonic-gate /* if we are disconnected, the pipe will be closed anyways */
144388447a05SGarrett D'Amore if (uasp->usb_as_dev_state == USB_DEV_DISCONNECTED)
14447c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
14457c478bd9Sstevel@tonic-gate
14467c478bd9Sstevel@tonic-gate switch (uasp->usb_as_audio_state) {
14477c478bd9Sstevel@tonic-gate case USB_AS_ACTIVE:
14487c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
14497c478bd9Sstevel@tonic-gate
14507c478bd9Sstevel@tonic-gate /*
14517c478bd9Sstevel@tonic-gate * Stop polling. When the completion reason indicate that
14527c478bd9Sstevel@tonic-gate * polling is over, return response message up.
14537c478bd9Sstevel@tonic-gate */
14547c478bd9Sstevel@tonic-gate usb_pipe_stop_isoc_polling(uasp->usb_as_isoc_ph,
14557c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP);
14567c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
14577c478bd9Sstevel@tonic-gate
14587c478bd9Sstevel@tonic-gate break;
14597c478bd9Sstevel@tonic-gate case USB_AS_STOP_POLLING_STARTED:
14607c478bd9Sstevel@tonic-gate /* A stop polling in progress, wait for completion and reply */
14617c478bd9Sstevel@tonic-gate break;
14627c478bd9Sstevel@tonic-gate default:
146388447a05SGarrett D'Amore break;
14647c478bd9Sstevel@tonic-gate }
14657c478bd9Sstevel@tonic-gate
14667c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
14677c478bd9Sstevel@tonic-gate }
14687c478bd9Sstevel@tonic-gate
14697c478bd9Sstevel@tonic-gate
14707c478bd9Sstevel@tonic-gate static void
usb_as_record_exc_cb(usb_pipe_handle_t ph,usb_isoc_req_t * isoc_req)14717c478bd9Sstevel@tonic-gate usb_as_record_exc_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req)
14727c478bd9Sstevel@tonic-gate {
14737c478bd9Sstevel@tonic-gate usb_as_state_t *uasp = (usb_as_state_t *)
1474112116d8Sfb (isoc_req->isoc_client_private);
14757c478bd9Sstevel@tonic-gate usb_cr_t completion_reason;
14767c478bd9Sstevel@tonic-gate int rval;
14777c478bd9Sstevel@tonic-gate
14787c478bd9Sstevel@tonic-gate completion_reason = isoc_req->isoc_completion_reason;
14797c478bd9Sstevel@tonic-gate
14807c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
14817c478bd9Sstevel@tonic-gate "usb_as_record_exc_cb: ph=0x%p, isoc_req=0x%p, cr=%d",
1482112116d8Sfb (void *)ph, (void *)isoc_req, completion_reason);
14837c478bd9Sstevel@tonic-gate
14847c478bd9Sstevel@tonic-gate ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) == 0);
14857c478bd9Sstevel@tonic-gate
14867c478bd9Sstevel@tonic-gate switch (completion_reason) {
14877c478bd9Sstevel@tonic-gate case USB_CR_STOPPED_POLLING:
14887c478bd9Sstevel@tonic-gate case USB_CR_PIPE_CLOSING:
14897c478bd9Sstevel@tonic-gate case USB_CR_PIPE_RESET:
14907c478bd9Sstevel@tonic-gate
14917c478bd9Sstevel@tonic-gate break;
14927c478bd9Sstevel@tonic-gate case USB_CR_NO_RESOURCES:
14937c478bd9Sstevel@tonic-gate /*
14947c478bd9Sstevel@tonic-gate * keep the show going: Since we have the original
14957c478bd9Sstevel@tonic-gate * request, we just resubmit it
14967c478bd9Sstevel@tonic-gate */
14977c478bd9Sstevel@tonic-gate rval = usb_pipe_isoc_xfer(uasp->usb_as_isoc_ph, isoc_req, 0);
14987c478bd9Sstevel@tonic-gate
14997c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle,
15007c478bd9Sstevel@tonic-gate "usb_as_record_exc_cb: restart record rval=%d", rval);
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate return;
15037c478bd9Sstevel@tonic-gate default:
15047c478bd9Sstevel@tonic-gate
15057c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
15067c478bd9Sstevel@tonic-gate
15077c478bd9Sstevel@tonic-gate /* Do not start if one is already in progress */
15087c478bd9Sstevel@tonic-gate if (uasp->usb_as_audio_state != USB_AS_STOP_POLLING_STARTED) {
15097c478bd9Sstevel@tonic-gate uasp->usb_as_audio_state = USB_AS_STOP_POLLING_STARTED;
15107c478bd9Sstevel@tonic-gate
15117c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
15127c478bd9Sstevel@tonic-gate (void) usb_pipe_stop_isoc_polling(ph,
15137c478bd9Sstevel@tonic-gate USB_FLAGS_NOSLEEP);
15147c478bd9Sstevel@tonic-gate
15157c478bd9Sstevel@tonic-gate return;
15167c478bd9Sstevel@tonic-gate } else {
15177c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
15187c478bd9Sstevel@tonic-gate }
15197c478bd9Sstevel@tonic-gate
15207c478bd9Sstevel@tonic-gate break;
15217c478bd9Sstevel@tonic-gate }
15227c478bd9Sstevel@tonic-gate usb_free_isoc_req(isoc_req);
15237c478bd9Sstevel@tonic-gate
15247c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
15257c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle,
15267c478bd9Sstevel@tonic-gate "usb_as_record_exc_cb: state=%d cr=0x%x",
15277c478bd9Sstevel@tonic-gate uasp->usb_as_audio_state, completion_reason);
15287c478bd9Sstevel@tonic-gate
15297c478bd9Sstevel@tonic-gate uasp->usb_as_audio_state = USB_AS_IDLE;
15307c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
15317c478bd9Sstevel@tonic-gate }
15327c478bd9Sstevel@tonic-gate
15337c478bd9Sstevel@tonic-gate
15347c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15357c478bd9Sstevel@tonic-gate static void
usb_as_record_cb(usb_pipe_handle_t ph,usb_isoc_req_t * isoc_req)15367c478bd9Sstevel@tonic-gate usb_as_record_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req)
15377c478bd9Sstevel@tonic-gate {
15387c478bd9Sstevel@tonic-gate usb_as_state_t *uasp = (usb_as_state_t *)isoc_req->isoc_client_private;
15397c478bd9Sstevel@tonic-gate int i, offset, sz;
1540e272e4c8SBinzi Cao - Sun Microsystems - Beijing China void * ahdl;
15417c478bd9Sstevel@tonic-gate usb_audio_formats_t *format = &uasp->usb_as_curr_format;
15427c478bd9Sstevel@tonic-gate int precision;
15437c478bd9Sstevel@tonic-gate
15447c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle,
15457c478bd9Sstevel@tonic-gate "usb_as_record_cb: rq=0x%p data=0x%p pkts=0x%x",
1546112116d8Sfb (void *)isoc_req, (void *)isoc_req->isoc_data,
1547112116d8Sfb isoc_req->isoc_pkts_count);
15487c478bd9Sstevel@tonic-gate
15497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle,
15507c478bd9Sstevel@tonic-gate "\tfno=%" PRId64 ", n_pkts=%u, flag=0x%x, data=0x%p, cnt=%d",
15517c478bd9Sstevel@tonic-gate isoc_req->isoc_frame_no, isoc_req->isoc_pkts_count,
1552112116d8Sfb isoc_req->isoc_attributes, (void *)isoc_req->isoc_data,
15537c478bd9Sstevel@tonic-gate isoc_req->isoc_error_count);
15547c478bd9Sstevel@tonic-gate
15557c478bd9Sstevel@tonic-gate ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) != 0);
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
15587c478bd9Sstevel@tonic-gate ahdl = uasp->usb_as_ahdl;
15597c478bd9Sstevel@tonic-gate sz = uasp->usb_as_record_pkt_size;
1560*64391892SAlbert Lee precision = format->fmt_precision >> 3;
15617c478bd9Sstevel@tonic-gate
15627c478bd9Sstevel@tonic-gate if (uasp->usb_as_audio_state != USB_AS_IDLE) {
15637c478bd9Sstevel@tonic-gate for (offset = i = 0; i < isoc_req->isoc_pkts_count; i++) {
15647c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_CB, uasp->usb_as_log_handle,
15657c478bd9Sstevel@tonic-gate "\tpkt%d: "
15667c478bd9Sstevel@tonic-gate "offset=%d pktsize=%d len=%d status=%d resid=%d",
15677c478bd9Sstevel@tonic-gate i, offset, sz,
15687c478bd9Sstevel@tonic-gate isoc_req->isoc_pkt_descr[i].isoc_pkt_length,
15697c478bd9Sstevel@tonic-gate isoc_req->isoc_pkt_descr[i].isoc_pkt_status,
15707c478bd9Sstevel@tonic-gate isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length);
15717c478bd9Sstevel@tonic-gate
15727c478bd9Sstevel@tonic-gate if (isoc_req->isoc_pkt_descr[i].isoc_pkt_status !=
15737c478bd9Sstevel@tonic-gate USB_CR_OK) {
15747c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_CB,
15757c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle,
15767c478bd9Sstevel@tonic-gate "record: pkt=%d offset=0x%x status=%s",
15777c478bd9Sstevel@tonic-gate i, offset, usb_str_cr(isoc_req->
15787c478bd9Sstevel@tonic-gate isoc_pkt_descr[i].isoc_pkt_status));
15797c478bd9Sstevel@tonic-gate }
15807c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
15817c478bd9Sstevel@tonic-gate
1582e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_send_audio(ahdl,
15837c478bd9Sstevel@tonic-gate isoc_req->isoc_data->b_rptr + offset,
158488447a05SGarrett D'Amore isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length /
15857c478bd9Sstevel@tonic-gate precision);
15867c478bd9Sstevel@tonic-gate
15877c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
15887c478bd9Sstevel@tonic-gate offset += isoc_req->isoc_pkt_descr[i].isoc_pkt_length;
15897c478bd9Sstevel@tonic-gate }
15907c478bd9Sstevel@tonic-gate }
15917c478bd9Sstevel@tonic-gate
15927c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
15937c478bd9Sstevel@tonic-gate
15947c478bd9Sstevel@tonic-gate usb_free_isoc_req(isoc_req);
15957c478bd9Sstevel@tonic-gate }
15967c478bd9Sstevel@tonic-gate
15977c478bd9Sstevel@tonic-gate /*
15987c478bd9Sstevel@tonic-gate * Since the int_rate is 1000, we have to do special arithmetic for
15997c478bd9Sstevel@tonic-gate * sample rates not multiple of 1K. For example,
16007c478bd9Sstevel@tonic-gate * if the sample rate is 48000(i.e multiple of 1K), we can send 48000/1000
16017c478bd9Sstevel@tonic-gate * = 48 samples every packet per channel. Since we have to support sample
16027c478bd9Sstevel@tonic-gate * rate like 11025, 22050 and 44100, we will have some extra samples
16037c478bd9Sstevel@tonic-gate * at the end that we need to spread among the 1000 cycles. So if we make
16047c478bd9Sstevel@tonic-gate * the pktsize as below for these sample rates, at the end of 1000 cycles,
16057c478bd9Sstevel@tonic-gate * we will be able to send all the data in the correct rate:
16067c478bd9Sstevel@tonic-gate *
16077c478bd9Sstevel@tonic-gate * 11025: 39 samples of 11, 1 of 12
16087c478bd9Sstevel@tonic-gate * 22050: 19 samples of 22, 1 of 23
16097c478bd9Sstevel@tonic-gate * 44100: 9 samples of 44, 1 of 45
16107c478bd9Sstevel@tonic-gate *
16117c478bd9Sstevel@tonic-gate * frameno is a simple counter maintained in the soft state structure.
16127c478bd9Sstevel@tonic-gate * So the pkt size is:
16137c478bd9Sstevel@tonic-gate * pkt_size = ((frameno % cycle) ? pkt : (pkt + extra));
16147c478bd9Sstevel@tonic-gate *
16157c478bd9Sstevel@tonic-gate */
16167c478bd9Sstevel@tonic-gate
16177c478bd9Sstevel@tonic-gate static int
usb_as_get_pktsize(usb_as_state_t * uasp,usb_frame_number_t frameno)1618*64391892SAlbert Lee usb_as_get_pktsize(usb_as_state_t *uasp, usb_frame_number_t frameno)
16197c478bd9Sstevel@tonic-gate {
1620*64391892SAlbert Lee static uint_t sr = 0;
1621*64391892SAlbert Lee static ushort_t pkt, cycle;
1622*64391892SAlbert Lee static int extra;
16237c478bd9Sstevel@tonic-gate int pkt_size = 0;
1624*64391892SAlbert Lee usb_audio_formats_t *format = &uasp->usb_as_curr_format;
1625*64391892SAlbert Lee
1626*64391892SAlbert Lee if (sr != uasp->usb_as_curr_sr) {
1627*64391892SAlbert Lee /* calculate once */
1628*64391892SAlbert Lee sr = uasp->usb_as_curr_sr;
1629*64391892SAlbert Lee pkt = (sr + 500) / 1000;
1630*64391892SAlbert Lee extra = sr % 1000;
1631*64391892SAlbert Lee
1632*64391892SAlbert Lee if (extra == 0) {
1633*64391892SAlbert Lee /* sample rate is a multiple of 1000 */
1634*64391892SAlbert Lee cycle = 1000;
1635*64391892SAlbert Lee } else {
1636*64391892SAlbert Lee /* find a common divisor of 1000 and extra */
1637*64391892SAlbert Lee int m = 1000;
1638*64391892SAlbert Lee int n = extra;
1639*64391892SAlbert Lee
1640*64391892SAlbert Lee while (m != n) {
1641*64391892SAlbert Lee if (m > n) {
1642*64391892SAlbert Lee m = m - n;
1643*64391892SAlbert Lee } else {
1644*64391892SAlbert Lee n = n - m;
1645*64391892SAlbert Lee }
1646*64391892SAlbert Lee }
1647*64391892SAlbert Lee cycle = (1000 / n);
1648*64391892SAlbert Lee extra = ((extra >= 500) ? (extra - 1000) : extra) / n;
16497c478bd9Sstevel@tonic-gate }
16507c478bd9Sstevel@tonic-gate }
1651*64391892SAlbert Lee pkt_size = (((frameno + 1) % cycle) ?
1652*64391892SAlbert Lee pkt : (pkt + extra));
1653*64391892SAlbert Lee pkt_size *= (format->fmt_precision >> 3)
1654*64391892SAlbert Lee * format->fmt_chns;
16557c478bd9Sstevel@tonic-gate
16567c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
16577c478bd9Sstevel@tonic-gate "usb_as_get_pktsize: %d", pkt_size);
16587c478bd9Sstevel@tonic-gate
16597c478bd9Sstevel@tonic-gate return (pkt_size);
16607c478bd9Sstevel@tonic-gate }
16617c478bd9Sstevel@tonic-gate
16627c478bd9Sstevel@tonic-gate
16637c478bd9Sstevel@tonic-gate /*
16647c478bd9Sstevel@tonic-gate * usb_as_send_ctrl_cmd:
16657c478bd9Sstevel@tonic-gate * Opens the pipe; sends a control command down
16667c478bd9Sstevel@tonic-gate */
16677c478bd9Sstevel@tonic-gate static int
usb_as_send_ctrl_cmd(usb_as_state_t * uasp,uchar_t bmRequestType,uchar_t bRequest,ushort_t wValue,ushort_t wIndex,ushort_t wLength,mblk_t * data,boolean_t ignore_errors)16687c478bd9Sstevel@tonic-gate usb_as_send_ctrl_cmd(usb_as_state_t *uasp,
16697c478bd9Sstevel@tonic-gate uchar_t bmRequestType, uchar_t bRequest,
16707c478bd9Sstevel@tonic-gate ushort_t wValue, ushort_t wIndex, ushort_t wLength,
16717c478bd9Sstevel@tonic-gate mblk_t *data, boolean_t ignore_errors)
16727c478bd9Sstevel@tonic-gate {
167388447a05SGarrett D'Amore usb_ctrl_setup_t setup;
167488447a05SGarrett D'Amore usb_cr_t cr;
167588447a05SGarrett D'Amore usb_cb_flags_t cf;
16767c478bd9Sstevel@tonic-gate
16777c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
16787c478bd9Sstevel@tonic-gate "usb_as_send_ctrl_cmd: Begin bmRequestType=%d,\n\t"
16797c478bd9Sstevel@tonic-gate "bRequest=%d, wValue=%d, wIndex=%d, wLength=%d, data=0x%p",
1680112116d8Sfb bmRequestType, bRequest, wValue, wIndex, wLength, (void *)data);
16817c478bd9Sstevel@tonic-gate
168288447a05SGarrett D'Amore setup.bmRequestType = bmRequestType & ~USB_DEV_REQ_DEV_TO_HOST;
168388447a05SGarrett D'Amore setup.bRequest = bRequest;
168488447a05SGarrett D'Amore setup.wValue = wValue;
168588447a05SGarrett D'Amore setup.wIndex = wIndex;
168688447a05SGarrett D'Amore setup.wLength = wLength;
168788447a05SGarrett D'Amore setup.attrs = 0;
16887c478bd9Sstevel@tonic-gate
168988447a05SGarrett D'Amore if (usb_pipe_ctrl_xfer_wait(uasp->usb_as_default_ph, &setup, &data,
169088447a05SGarrett D'Amore &cr, &cf, 0) != USB_SUCCESS) {
16917c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
169288447a05SGarrett D'Amore "usb_as_send_ctrl_cmd: usba xfer failed (req=%d), "
169388447a05SGarrett D'Amore "completion reason: 0x%x, completion flags: 0x%x",
169488447a05SGarrett D'Amore bRequest, cr, cf);
16957c478bd9Sstevel@tonic-gate
169688447a05SGarrett D'Amore return (ignore_errors ? USB_SUCCESS: USB_FAILURE);
16977c478bd9Sstevel@tonic-gate }
16987c478bd9Sstevel@tonic-gate
16997c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
17007c478bd9Sstevel@tonic-gate }
17017c478bd9Sstevel@tonic-gate
17027c478bd9Sstevel@tonic-gate
17037c478bd9Sstevel@tonic-gate /*
17047c478bd9Sstevel@tonic-gate * Power management
17057c478bd9Sstevel@tonic-gate */
17067c478bd9Sstevel@tonic-gate
17077c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17087c478bd9Sstevel@tonic-gate static void
usb_as_create_pm_components(dev_info_t * dip,usb_as_state_t * uasp)17097c478bd9Sstevel@tonic-gate usb_as_create_pm_components(dev_info_t *dip, usb_as_state_t *uasp)
17107c478bd9Sstevel@tonic-gate {
17117c478bd9Sstevel@tonic-gate usb_as_power_t *uaspm;
17127c478bd9Sstevel@tonic-gate uint_t pwr_states;
17137c478bd9Sstevel@tonic-gate
17147c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle,
17157c478bd9Sstevel@tonic-gate "usb_as_create_pm_components: begin");
17167c478bd9Sstevel@tonic-gate
17177c478bd9Sstevel@tonic-gate /* Allocate the state structure */
17187c478bd9Sstevel@tonic-gate uaspm = kmem_zalloc(sizeof (usb_as_power_t), KM_SLEEP);
17197c478bd9Sstevel@tonic-gate uasp->usb_as_pm = uaspm;
17207c478bd9Sstevel@tonic-gate uaspm->aspm_state = uasp;
17217c478bd9Sstevel@tonic-gate uaspm->aspm_capabilities = 0;
17227c478bd9Sstevel@tonic-gate uaspm->aspm_current_power = USB_DEV_OS_FULL_PWR;
17237c478bd9Sstevel@tonic-gate
17247c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_PM, uasp->usb_as_log_handle,
17257c478bd9Sstevel@tonic-gate "usb_as_pm_components: remote Wakeup enabled");
17267c478bd9Sstevel@tonic-gate if (usb_create_pm_components(dip, &pwr_states) ==
17277c478bd9Sstevel@tonic-gate USB_SUCCESS) {
17287c478bd9Sstevel@tonic-gate if (usb_handle_remote_wakeup(dip,
17297c478bd9Sstevel@tonic-gate USB_REMOTE_WAKEUP_ENABLE) != USB_SUCCESS) {
17307c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_PM,
17317c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle,
17327c478bd9Sstevel@tonic-gate "enable remote wakeup failed");
17337c478bd9Sstevel@tonic-gate } else {
17347c478bd9Sstevel@tonic-gate uaspm->aspm_wakeup_enabled = 1;
17357c478bd9Sstevel@tonic-gate }
17367c478bd9Sstevel@tonic-gate uaspm->aspm_pwr_states = (uint8_t)pwr_states;
17377c478bd9Sstevel@tonic-gate (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
17387c478bd9Sstevel@tonic-gate }
17397c478bd9Sstevel@tonic-gate
17407c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle,
17417c478bd9Sstevel@tonic-gate "usb_as_create_pm_components: end");
17427c478bd9Sstevel@tonic-gate }
17437c478bd9Sstevel@tonic-gate
17447c478bd9Sstevel@tonic-gate
17457c478bd9Sstevel@tonic-gate /*
17467c478bd9Sstevel@tonic-gate * usb_as_power:
17477c478bd9Sstevel@tonic-gate * power entry point
17487c478bd9Sstevel@tonic-gate */
17497c478bd9Sstevel@tonic-gate static int
usb_as_power(dev_info_t * dip,int comp,int level)17507c478bd9Sstevel@tonic-gate usb_as_power(dev_info_t *dip, int comp, int level)
17517c478bd9Sstevel@tonic-gate {
17527c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip);
17537c478bd9Sstevel@tonic-gate usb_as_state_t *uasp;
17547c478bd9Sstevel@tonic-gate usb_as_power_t *uaspm;
17557c478bd9Sstevel@tonic-gate int retval = USB_FAILURE;
17567c478bd9Sstevel@tonic-gate
17577c478bd9Sstevel@tonic-gate uasp = ddi_get_soft_state(usb_as_statep, instance);
17587c478bd9Sstevel@tonic-gate
17597c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle,
17607c478bd9Sstevel@tonic-gate "usb_as_power: comp=%d level=%d", comp, level);
17617c478bd9Sstevel@tonic-gate
17627c478bd9Sstevel@tonic-gate (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0);
17637c478bd9Sstevel@tonic-gate
17647c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
17657c478bd9Sstevel@tonic-gate uaspm = uasp->usb_as_pm;
17667c478bd9Sstevel@tonic-gate
17677c478bd9Sstevel@tonic-gate if (USB_DEV_PWRSTATE_OK(uaspm->aspm_pwr_states, level)) {
17687c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_PM, uasp->usb_as_log_handle,
17697c478bd9Sstevel@tonic-gate "usb_as_power: illegal level=%d pwr_states=%d",
1770112116d8Sfb level, uaspm->aspm_pwr_states);
17717c478bd9Sstevel@tonic-gate
17727c478bd9Sstevel@tonic-gate goto done;
17737c478bd9Sstevel@tonic-gate }
17747c478bd9Sstevel@tonic-gate
17757c478bd9Sstevel@tonic-gate switch (level) {
17767c478bd9Sstevel@tonic-gate case USB_DEV_OS_PWR_OFF:
17777c478bd9Sstevel@tonic-gate retval = usb_as_pwrlvl0(uasp);
17787c478bd9Sstevel@tonic-gate break;
17797c478bd9Sstevel@tonic-gate case USB_DEV_OS_PWR_1:
17807c478bd9Sstevel@tonic-gate retval = usb_as_pwrlvl1(uasp);
17817c478bd9Sstevel@tonic-gate break;
17827c478bd9Sstevel@tonic-gate case USB_DEV_OS_PWR_2:
17837c478bd9Sstevel@tonic-gate retval = usb_as_pwrlvl2(uasp);
17847c478bd9Sstevel@tonic-gate break;
17857c478bd9Sstevel@tonic-gate case USB_DEV_OS_FULL_PWR:
17867c478bd9Sstevel@tonic-gate retval = usb_as_pwrlvl3(uasp);
17877c478bd9Sstevel@tonic-gate break;
17887c478bd9Sstevel@tonic-gate default:
17897c478bd9Sstevel@tonic-gate retval = USB_FAILURE;
17907c478bd9Sstevel@tonic-gate break;
17917c478bd9Sstevel@tonic-gate }
17927c478bd9Sstevel@tonic-gate
17937c478bd9Sstevel@tonic-gate done:
17947c478bd9Sstevel@tonic-gate
17957c478bd9Sstevel@tonic-gate usb_release_access(uasp->usb_as_ser_acc);
17967c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
17977c478bd9Sstevel@tonic-gate
17987c478bd9Sstevel@tonic-gate return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
17997c478bd9Sstevel@tonic-gate }
18007c478bd9Sstevel@tonic-gate
18017c478bd9Sstevel@tonic-gate
18027c478bd9Sstevel@tonic-gate /*
18037c478bd9Sstevel@tonic-gate * functions to handle power transition for various levels
18047c478bd9Sstevel@tonic-gate * These functions act as place holders to issue USB commands
18057c478bd9Sstevel@tonic-gate * to the devices to change their power levels
18067c478bd9Sstevel@tonic-gate * Level 0 = Device is powered off
18077c478bd9Sstevel@tonic-gate * Level 3 = Device if full powered
18087c478bd9Sstevel@tonic-gate * Level 1,2 = Intermediate power level of the device as implemented
18097c478bd9Sstevel@tonic-gate * by the hardware.
18107c478bd9Sstevel@tonic-gate * Note that Level 0 is OS power-off and Level 3 is OS full-power.
18117c478bd9Sstevel@tonic-gate */
18127c478bd9Sstevel@tonic-gate static int
usb_as_pwrlvl0(usb_as_state_t * uasp)18137c478bd9Sstevel@tonic-gate usb_as_pwrlvl0(usb_as_state_t *uasp)
18147c478bd9Sstevel@tonic-gate {
18157c478bd9Sstevel@tonic-gate usb_as_power_t *uaspm;
18167c478bd9Sstevel@tonic-gate int rval;
18177c478bd9Sstevel@tonic-gate
18187c478bd9Sstevel@tonic-gate uaspm = uasp->usb_as_pm;
18197c478bd9Sstevel@tonic-gate
18207c478bd9Sstevel@tonic-gate switch (uasp->usb_as_dev_state) {
18217c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE:
18227c478bd9Sstevel@tonic-gate /* Deny the powerdown request if the device is busy */
18237c478bd9Sstevel@tonic-gate if (uaspm->aspm_pm_busy != 0) {
18247c478bd9Sstevel@tonic-gate
18257c478bd9Sstevel@tonic-gate return (USB_FAILURE);
18267c478bd9Sstevel@tonic-gate }
18277c478bd9Sstevel@tonic-gate
18287c478bd9Sstevel@tonic-gate if (uasp->usb_as_audio_state != USB_AS_IDLE) {
18297c478bd9Sstevel@tonic-gate
18307c478bd9Sstevel@tonic-gate return (USB_FAILURE);
18317c478bd9Sstevel@tonic-gate }
18327c478bd9Sstevel@tonic-gate
18337c478bd9Sstevel@tonic-gate /* Issue USB D3 command to the device here */
18347c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl3(uasp->usb_as_dip);
18357c478bd9Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
18367c478bd9Sstevel@tonic-gate
18377c478bd9Sstevel@tonic-gate uasp->usb_as_dev_state = USB_DEV_PWRED_DOWN;
18387c478bd9Sstevel@tonic-gate uaspm->aspm_current_power = USB_DEV_OS_PWR_OFF;
18397c478bd9Sstevel@tonic-gate
18407c478bd9Sstevel@tonic-gate /* FALLTHRU */
18417c478bd9Sstevel@tonic-gate case USB_DEV_DISCONNECTED:
18427c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED:
18437c478bd9Sstevel@tonic-gate /* allow a disconnected/cpr'ed device to go to low power */
18447c478bd9Sstevel@tonic-gate
18457c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
18467c478bd9Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
18477c478bd9Sstevel@tonic-gate default:
18487c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_PM, uasp->usb_as_log_handle,
18497c478bd9Sstevel@tonic-gate "usb_as_pwrlvl0: Illegal dev_state");
18507c478bd9Sstevel@tonic-gate
18517c478bd9Sstevel@tonic-gate return (USB_FAILURE);
18527c478bd9Sstevel@tonic-gate }
18537c478bd9Sstevel@tonic-gate }
18547c478bd9Sstevel@tonic-gate
18557c478bd9Sstevel@tonic-gate
18567c478bd9Sstevel@tonic-gate /* ARGSUSED */
18577c478bd9Sstevel@tonic-gate static int
usb_as_pwrlvl1(usb_as_state_t * uasp)18587c478bd9Sstevel@tonic-gate usb_as_pwrlvl1(usb_as_state_t *uasp)
18597c478bd9Sstevel@tonic-gate {
18607c478bd9Sstevel@tonic-gate int rval;
18617c478bd9Sstevel@tonic-gate
18627c478bd9Sstevel@tonic-gate /* Issue USB D2 command to the device here */
18637c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl2(uasp->usb_as_dip);
18647c478bd9Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
18657c478bd9Sstevel@tonic-gate
18667c478bd9Sstevel@tonic-gate return (USB_FAILURE);
18677c478bd9Sstevel@tonic-gate }
18687c478bd9Sstevel@tonic-gate
18697c478bd9Sstevel@tonic-gate
18707c478bd9Sstevel@tonic-gate /* ARGSUSED */
18717c478bd9Sstevel@tonic-gate static int
usb_as_pwrlvl2(usb_as_state_t * uasp)18727c478bd9Sstevel@tonic-gate usb_as_pwrlvl2(usb_as_state_t *uasp)
18737c478bd9Sstevel@tonic-gate {
18747c478bd9Sstevel@tonic-gate int rval;
18757c478bd9Sstevel@tonic-gate
18767c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl1(uasp->usb_as_dip);
18777c478bd9Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
18787c478bd9Sstevel@tonic-gate
18797c478bd9Sstevel@tonic-gate return (USB_FAILURE);
18807c478bd9Sstevel@tonic-gate }
18817c478bd9Sstevel@tonic-gate
18827c478bd9Sstevel@tonic-gate
18837c478bd9Sstevel@tonic-gate static int
usb_as_pwrlvl3(usb_as_state_t * uasp)18847c478bd9Sstevel@tonic-gate usb_as_pwrlvl3(usb_as_state_t *uasp)
18857c478bd9Sstevel@tonic-gate {
18867c478bd9Sstevel@tonic-gate usb_as_power_t *uaspm;
18877c478bd9Sstevel@tonic-gate int rval;
18887c478bd9Sstevel@tonic-gate
18897c478bd9Sstevel@tonic-gate uaspm = uasp->usb_as_pm;
18907c478bd9Sstevel@tonic-gate
18917c478bd9Sstevel@tonic-gate switch (uasp->usb_as_dev_state) {
18927c478bd9Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
18937c478bd9Sstevel@tonic-gate
18947c478bd9Sstevel@tonic-gate /* Issue USB D0 command to the device here */
18957c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl0(uasp->usb_as_dip);
18967c478bd9Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
18977c478bd9Sstevel@tonic-gate
18987c478bd9Sstevel@tonic-gate uasp->usb_as_dev_state = USB_DEV_ONLINE;
18997c478bd9Sstevel@tonic-gate uaspm->aspm_current_power = USB_DEV_OS_FULL_PWR;
19007c478bd9Sstevel@tonic-gate
19017c478bd9Sstevel@tonic-gate /* FALLTHRU */
19027c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE:
19037c478bd9Sstevel@tonic-gate /* we are already in full power */
19047c478bd9Sstevel@tonic-gate
19057c478bd9Sstevel@tonic-gate /* fall thru */
19067c478bd9Sstevel@tonic-gate case USB_DEV_DISCONNECTED:
19077c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED:
19087c478bd9Sstevel@tonic-gate /* allow power change on a disconnected/cpr'ed device */
19097c478bd9Sstevel@tonic-gate
19107c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
19117c478bd9Sstevel@tonic-gate default:
19127c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_PM, uasp->usb_as_log_handle,
19137c478bd9Sstevel@tonic-gate "usb_as_pwrlvl3: Illegal dev_state");
19147c478bd9Sstevel@tonic-gate
19157c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
19167c478bd9Sstevel@tonic-gate }
19177c478bd9Sstevel@tonic-gate }
19187c478bd9Sstevel@tonic-gate
19197c478bd9Sstevel@tonic-gate
19207c478bd9Sstevel@tonic-gate /*
19217c478bd9Sstevel@tonic-gate * Descriptor Management
19227c478bd9Sstevel@tonic-gate *
19237c478bd9Sstevel@tonic-gate * usb_as_handle_descriptors:
19247c478bd9Sstevel@tonic-gate * read and parse all descriptors and build up usb_as_alts list
19257c478bd9Sstevel@tonic-gate *
19267c478bd9Sstevel@tonic-gate * the order is as follows:
19277c478bd9Sstevel@tonic-gate * interface, general, format, endpoint, CV endpoint
19287c478bd9Sstevel@tonic-gate */
19297c478bd9Sstevel@tonic-gate static int
usb_as_handle_descriptors(usb_as_state_t * uasp)19307c478bd9Sstevel@tonic-gate usb_as_handle_descriptors(usb_as_state_t *uasp)
19317c478bd9Sstevel@tonic-gate {
19327c478bd9Sstevel@tonic-gate usb_client_dev_data_t *dev_data = uasp->usb_as_dev_data;
19337c478bd9Sstevel@tonic-gate int interface = dev_data->dev_curr_if;
19347c478bd9Sstevel@tonic-gate uint_t alternate;
19357c478bd9Sstevel@tonic-gate uint_t n_alternates;
1936*64391892SAlbert Lee int len, i, j, n, n_srs, sr, index;
19377c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS;
19387c478bd9Sstevel@tonic-gate usb_if_descr_t *if_descr;
19397c478bd9Sstevel@tonic-gate usb_audio_as_if_descr_t *general;
19407c478bd9Sstevel@tonic-gate usb_audio_type1_format_descr_t *format;
1941*64391892SAlbert Lee uint_t *sample_rates;
19427c478bd9Sstevel@tonic-gate usb_ep_descr_t *ep;
19437c478bd9Sstevel@tonic-gate usb_audio_as_isoc_ep_descr_t *cs_ep;
19447c478bd9Sstevel@tonic-gate usb_if_data_t *if_data;
19457c478bd9Sstevel@tonic-gate usb_alt_if_data_t *altif_data;
19467c478bd9Sstevel@tonic-gate usb_ep_data_t *ep_data;
19477c478bd9Sstevel@tonic-gate
19487c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
1949112116d8Sfb "usb_as_handle_descriptors: cfg=%ld interface=%d",
1950112116d8Sfb (long)(dev_data->dev_curr_cfg - &dev_data->dev_cfg[0]),
19517c478bd9Sstevel@tonic-gate dev_data->dev_curr_if);
19527c478bd9Sstevel@tonic-gate
19537c478bd9Sstevel@tonic-gate if_data = &dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if];
19547c478bd9Sstevel@tonic-gate uasp->usb_as_ifno = interface;
19557c478bd9Sstevel@tonic-gate
19567c478bd9Sstevel@tonic-gate /*
19577c478bd9Sstevel@tonic-gate * find the number of alternates for this interface
19587c478bd9Sstevel@tonic-gate * and allocate an array to store the descriptors for
19597c478bd9Sstevel@tonic-gate * each alternate
19607c478bd9Sstevel@tonic-gate */
19617c478bd9Sstevel@tonic-gate uasp->usb_as_n_alternates = n_alternates = if_data->if_n_alt;
19627c478bd9Sstevel@tonic-gate uasp->usb_as_alts = kmem_zalloc((n_alternates) *
1963112116d8Sfb sizeof (usb_as_alt_descr_t), KM_SLEEP);
19647c478bd9Sstevel@tonic-gate
19657c478bd9Sstevel@tonic-gate /*
19667c478bd9Sstevel@tonic-gate * for each alternate read descriptors
19677c478bd9Sstevel@tonic-gate */
19687c478bd9Sstevel@tonic-gate for (alternate = 0; alternate < n_alternates; alternate++) {
19697c478bd9Sstevel@tonic-gate altif_data = &if_data->if_alt[alternate];
19707c478bd9Sstevel@tonic-gate
19717c478bd9Sstevel@tonic-gate uasp->usb_as_alts[alternate].alt_if =
1972112116d8Sfb kmem_zalloc(sizeof (usb_if_descr_t), KM_SLEEP);
19737c478bd9Sstevel@tonic-gate if_descr = &altif_data->altif_descr;
19747c478bd9Sstevel@tonic-gate
19757c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
19767c478bd9Sstevel@tonic-gate "interface (%d.%d):\n\t"
19777c478bd9Sstevel@tonic-gate "l = 0x%x type = 0x%x n = 0x%x alt = 0x%x #ep = 0x%x\n\t"
19787c478bd9Sstevel@tonic-gate "iclass = 0x%x subclass = 0x%x proto = 0x%x string = 0x%x",
19797c478bd9Sstevel@tonic-gate interface, alternate,
19807c478bd9Sstevel@tonic-gate if_descr->bLength, if_descr->bDescriptorType,
19817c478bd9Sstevel@tonic-gate if_descr->bInterfaceNumber, if_descr->bAlternateSetting,
19827c478bd9Sstevel@tonic-gate if_descr->bNumEndpoints, if_descr->bInterfaceClass,
19837c478bd9Sstevel@tonic-gate if_descr->bInterfaceSubClass,
19847c478bd9Sstevel@tonic-gate if_descr->bInterfaceProtocol, if_descr->iInterface);
19857c478bd9Sstevel@tonic-gate
19867c478bd9Sstevel@tonic-gate *(uasp->usb_as_alts[alternate].alt_if) = *if_descr;
19877c478bd9Sstevel@tonic-gate
19887c478bd9Sstevel@tonic-gate /* read the general descriptor */
19897c478bd9Sstevel@tonic-gate index = 0;
19907c478bd9Sstevel@tonic-gate
19917c478bd9Sstevel@tonic-gate if (altif_data->altif_cvs == NULL) {
19927c478bd9Sstevel@tonic-gate
19937c478bd9Sstevel@tonic-gate continue;
19947c478bd9Sstevel@tonic-gate }
19957c478bd9Sstevel@tonic-gate
19967c478bd9Sstevel@tonic-gate general = kmem_zalloc(sizeof (*general), KM_SLEEP);
19977c478bd9Sstevel@tonic-gate
19987c478bd9Sstevel@tonic-gate len = usb_parse_data(AS_IF_DESCR_FORMAT,
1999112116d8Sfb altif_data->altif_cvs[index].cvs_buf,
2000112116d8Sfb altif_data->altif_cvs[index].cvs_buf_len,
2001112116d8Sfb (void *)general, sizeof (*general));
20027c478bd9Sstevel@tonic-gate
20037c478bd9Sstevel@tonic-gate /* is this a sane header descriptor */
20047c478bd9Sstevel@tonic-gate if (!((len >= AS_IF_DESCR_SIZE) &&
20057c478bd9Sstevel@tonic-gate (general->bDescriptorType == USB_AUDIO_CS_INTERFACE) &&
20067c478bd9Sstevel@tonic-gate (general->bDescriptorSubType == USB_AUDIO_AS_GENERAL))) {
20077c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA,
20087c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle,
20097c478bd9Sstevel@tonic-gate "invalid general cs interface descr");
20107c478bd9Sstevel@tonic-gate
20117c478bd9Sstevel@tonic-gate kmem_free(general, sizeof (*general));
20127c478bd9Sstevel@tonic-gate
20137c478bd9Sstevel@tonic-gate continue;
20147c478bd9Sstevel@tonic-gate }
20157c478bd9Sstevel@tonic-gate
20167c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
20177c478bd9Sstevel@tonic-gate "general (%d.%d): type=0x%x subtype=0x%x termlink=0x%x\n\t"
20187c478bd9Sstevel@tonic-gate "delay=0x%x format=0x%x",
20197c478bd9Sstevel@tonic-gate interface, alternate,
20207c478bd9Sstevel@tonic-gate general->bDescriptorType, general->bDescriptorSubType,
20217c478bd9Sstevel@tonic-gate general->bTerminalLink, general->bDelay,
20227c478bd9Sstevel@tonic-gate general->wFormatTag);
20237c478bd9Sstevel@tonic-gate
20247c478bd9Sstevel@tonic-gate uasp->usb_as_alts[alternate].alt_general = general;
20257c478bd9Sstevel@tonic-gate
20267c478bd9Sstevel@tonic-gate /*
20277c478bd9Sstevel@tonic-gate * there should be one format descriptor of unknown size.
20287c478bd9Sstevel@tonic-gate * the format descriptor contains just bytes, no need to
20297c478bd9Sstevel@tonic-gate * parse
20307c478bd9Sstevel@tonic-gate */
20317c478bd9Sstevel@tonic-gate index++;
20327c478bd9Sstevel@tonic-gate len = altif_data->altif_cvs[index].cvs_buf_len;
20337c478bd9Sstevel@tonic-gate format = kmem_zalloc(len, KM_SLEEP);
20347c478bd9Sstevel@tonic-gate bcopy(altif_data->altif_cvs[index].cvs_buf, format, len);
20357c478bd9Sstevel@tonic-gate
20367c478bd9Sstevel@tonic-gate /* is this a sane format descriptor */
20377c478bd9Sstevel@tonic-gate if (!((format->blength >= AUDIO_TYPE1_FORMAT_SIZE) &&
20387c478bd9Sstevel@tonic-gate format->bDescriptorSubType == USB_AUDIO_AS_FORMAT_TYPE)) {
20397c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA,
20407c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle,
20417c478bd9Sstevel@tonic-gate "invalid format cs interface descr");
20427c478bd9Sstevel@tonic-gate
20437c478bd9Sstevel@tonic-gate kmem_free(format, len);
20447c478bd9Sstevel@tonic-gate
20457c478bd9Sstevel@tonic-gate continue;
20467c478bd9Sstevel@tonic-gate }
20477c478bd9Sstevel@tonic-gate
20487c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
20497c478bd9Sstevel@tonic-gate "format (%d.%d): len = %d "
20507c478bd9Sstevel@tonic-gate "type = 0x%x subtype = 0x%x format = 0x%x\n\t"
20517c478bd9Sstevel@tonic-gate "#channels = 0x%x subframe = 0x%x resolution = 0x%x\n\t"
20527c478bd9Sstevel@tonic-gate "sample freq type = 0x%x",
20537c478bd9Sstevel@tonic-gate interface, alternate, len,
20547c478bd9Sstevel@tonic-gate format->bDescriptorType,
20557c478bd9Sstevel@tonic-gate format->bDescriptorSubType,
20567c478bd9Sstevel@tonic-gate format->bFormatType,
20577c478bd9Sstevel@tonic-gate format->bNrChannels,
20587c478bd9Sstevel@tonic-gate format->bSubFrameSize,
20597c478bd9Sstevel@tonic-gate format->bBitResolution,
20607c478bd9Sstevel@tonic-gate format->bSamFreqType);
20617c478bd9Sstevel@tonic-gate
20627c478bd9Sstevel@tonic-gate if (format->bSamFreqType == 0) {
20637c478bd9Sstevel@tonic-gate /* continuous sample rate limits */
20647c478bd9Sstevel@tonic-gate n_srs = 2;
20657c478bd9Sstevel@tonic-gate uasp->usb_as_alts[alternate].alt_continuous_sr++;
20667c478bd9Sstevel@tonic-gate } else {
20677c478bd9Sstevel@tonic-gate n_srs = format->bSamFreqType;
20687c478bd9Sstevel@tonic-gate }
20697c478bd9Sstevel@tonic-gate
2070*64391892SAlbert Lee sample_rates =
2071112116d8Sfb kmem_zalloc(n_srs * (sizeof (uint_t)), KM_SLEEP);
20727c478bd9Sstevel@tonic-gate
20737c478bd9Sstevel@tonic-gate /* go thru all sample rates (3 bytes) each */
2074*64391892SAlbert Lee for (i = 0, j = 0, n = 0; n < n_srs; i += 3, n++) {
2075*64391892SAlbert Lee sr = (format->bSamFreqs[i+2] << 16) |
2076*64391892SAlbert Lee (format->bSamFreqs[i+1] << 8) |
2077*64391892SAlbert Lee format->bSamFreqs[i];
20787c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA,
20797c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle,
20807c478bd9Sstevel@tonic-gate "sr = %d", sr);
2081*64391892SAlbert Lee sample_rates[n] = sr;
2082*64391892SAlbert Lee if (sr != 0) {
2083*64391892SAlbert Lee j++;
2084*64391892SAlbert Lee }
2085*64391892SAlbert Lee }
2086*64391892SAlbert Lee
2087*64391892SAlbert Lee if (j == 0) {
2088*64391892SAlbert Lee USB_DPRINTF_L2(PRINT_MASK_ATTA,
2089*64391892SAlbert Lee uasp->usb_as_log_handle,
2090*64391892SAlbert Lee "format cs interface descr has no valid rates");
2091*64391892SAlbert Lee
2092*64391892SAlbert Lee kmem_free(format, len);
2093*64391892SAlbert Lee kmem_free(sample_rates, n_srs * (sizeof (uint_t)));
20947c478bd9Sstevel@tonic-gate
2095*64391892SAlbert Lee continue;
20967c478bd9Sstevel@tonic-gate }
20977c478bd9Sstevel@tonic-gate
2098*64391892SAlbert Lee uasp->usb_as_alts[alternate].alt_format_len = (uchar_t)len;
2099*64391892SAlbert Lee
2100*64391892SAlbert Lee uasp->usb_as_alts[alternate].alt_format = format;
2101*64391892SAlbert Lee
2102*64391892SAlbert Lee uasp->usb_as_alts[alternate].alt_n_sample_rates =
2103*64391892SAlbert Lee (uchar_t)n_srs;
2104*64391892SAlbert Lee
2105*64391892SAlbert Lee uasp->usb_as_alts[alternate].alt_sample_rates =
2106*64391892SAlbert Lee sample_rates;
2107*64391892SAlbert Lee
21087c478bd9Sstevel@tonic-gate if ((ep_data = usb_lookup_ep_data(uasp->usb_as_dip,
21097c478bd9Sstevel@tonic-gate dev_data, interface, alternate, 0,
21107c478bd9Sstevel@tonic-gate USB_EP_ATTR_ISOCH, USB_EP_DIR_IN)) == NULL) {
21117c478bd9Sstevel@tonic-gate if ((ep_data = usb_lookup_ep_data(uasp->usb_as_dip,
21127c478bd9Sstevel@tonic-gate dev_data, interface, alternate, 0,
21137c478bd9Sstevel@tonic-gate USB_EP_ATTR_ISOCH, USB_EP_DIR_OUT)) == NULL) {
21147c478bd9Sstevel@tonic-gate
21157c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA,
21167c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle,
21177c478bd9Sstevel@tonic-gate "no endpoint descriptor found");
21187c478bd9Sstevel@tonic-gate
21197c478bd9Sstevel@tonic-gate continue;
21207c478bd9Sstevel@tonic-gate }
21217c478bd9Sstevel@tonic-gate }
21227c478bd9Sstevel@tonic-gate ep = &ep_data->ep_descr;
21237c478bd9Sstevel@tonic-gate
21247c478bd9Sstevel@tonic-gate uasp->usb_as_alts[alternate].alt_ep =
21257c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (usb_ep_descr_t), KM_SLEEP);
21267c478bd9Sstevel@tonic-gate *(uasp->usb_as_alts[alternate].alt_ep) = *ep;
21277c478bd9Sstevel@tonic-gate
21287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
21297c478bd9Sstevel@tonic-gate "endpoint (%d.%d):\n\t"
21307c478bd9Sstevel@tonic-gate "len = 0x%x type = 0x%x add = 0x%x "
21317c478bd9Sstevel@tonic-gate "attr = 0x%x mps = 0x%x\n\t"
21327c478bd9Sstevel@tonic-gate "int = 0x%x",
21337c478bd9Sstevel@tonic-gate interface, alternate,
21347c478bd9Sstevel@tonic-gate ep->bLength, ep->bDescriptorType, ep->bEndpointAddress,
21357c478bd9Sstevel@tonic-gate ep->bmAttributes, ep->wMaxPacketSize, ep->bInterval);
21367c478bd9Sstevel@tonic-gate
21377c478bd9Sstevel@tonic-gate uasp->usb_as_alts[alternate].alt_mode =
21387c478bd9Sstevel@tonic-gate (ep->bEndpointAddress & USB_EP_DIR_IN) ?
2139e272e4c8SBinzi Cao - Sun Microsystems - Beijing China USB_AUDIO_RECORD : USB_AUDIO_PLAY;
21407c478bd9Sstevel@tonic-gate
21417c478bd9Sstevel@tonic-gate if (ep_data->ep_n_cvs == 0) {
21427c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA,
21437c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle,
21447c478bd9Sstevel@tonic-gate "no cv ep descriptor");
21457c478bd9Sstevel@tonic-gate
21467c478bd9Sstevel@tonic-gate continue;
21477c478bd9Sstevel@tonic-gate }
21487c478bd9Sstevel@tonic-gate
21497c478bd9Sstevel@tonic-gate cs_ep = kmem_zalloc(sizeof (*cs_ep), KM_SLEEP);
21507c478bd9Sstevel@tonic-gate len = usb_parse_data(AS_ISOC_EP_DESCR_FORMAT,
2151112116d8Sfb ep_data->ep_cvs[0].cvs_buf,
2152112116d8Sfb ep_data->ep_cvs[0].cvs_buf_len,
2153112116d8Sfb (void *)cs_ep, sizeof (*cs_ep));
21547c478bd9Sstevel@tonic-gate
21557c478bd9Sstevel@tonic-gate if ((len < AS_ISOC_EP_DESCR_SIZE) ||
21567c478bd9Sstevel@tonic-gate (cs_ep->bDescriptorType != USB_AUDIO_CS_ENDPOINT)) {
21577c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA,
21587c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle,
21597c478bd9Sstevel@tonic-gate "cs endpoint descriptor invalid (%d)", len);
21607c478bd9Sstevel@tonic-gate kmem_free(cs_ep, sizeof (*cs_ep));
21617c478bd9Sstevel@tonic-gate
21627c478bd9Sstevel@tonic-gate continue;
21637c478bd9Sstevel@tonic-gate }
21647c478bd9Sstevel@tonic-gate
21657c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
21667c478bd9Sstevel@tonic-gate "cs isoc endpoint (%d.%d):\n\t"
21677c478bd9Sstevel@tonic-gate "type=0x%x sub=0x%x attr=0x%x units=0x%x delay=%x",
21687c478bd9Sstevel@tonic-gate interface, alternate,
21697c478bd9Sstevel@tonic-gate cs_ep->bDescriptorType,
21707c478bd9Sstevel@tonic-gate cs_ep->bDescriptorSubType,
21717c478bd9Sstevel@tonic-gate cs_ep->bmAttributes,
21727c478bd9Sstevel@tonic-gate cs_ep->bLockDelayUnits,
21734610e4a0Sfrits cs_ep->wLockDelay);
21747c478bd9Sstevel@tonic-gate
21757c478bd9Sstevel@tonic-gate uasp->usb_as_alts[alternate].alt_cs_ep = cs_ep;
21767c478bd9Sstevel@tonic-gate
21777c478bd9Sstevel@tonic-gate /* we are done */
21787c478bd9Sstevel@tonic-gate uasp->usb_as_alts[alternate].alt_valid++;
21797c478bd9Sstevel@tonic-gate }
21807c478bd9Sstevel@tonic-gate
21817c478bd9Sstevel@tonic-gate done:
21827c478bd9Sstevel@tonic-gate usb_as_prepare_registration_data(uasp);
21837c478bd9Sstevel@tonic-gate
21847c478bd9Sstevel@tonic-gate return (rval);
21857c478bd9Sstevel@tonic-gate }
21867c478bd9Sstevel@tonic-gate
21877c478bd9Sstevel@tonic-gate
21887c478bd9Sstevel@tonic-gate /*
21897c478bd9Sstevel@tonic-gate * usb_as_free_alts:
21907c478bd9Sstevel@tonic-gate * cleanup alternate list and deallocate all descriptors
21917c478bd9Sstevel@tonic-gate */
21927c478bd9Sstevel@tonic-gate static void
usb_as_free_alts(usb_as_state_t * uasp)21937c478bd9Sstevel@tonic-gate usb_as_free_alts(usb_as_state_t *uasp)
21947c478bd9Sstevel@tonic-gate {
21957c478bd9Sstevel@tonic-gate int alt;
21967c478bd9Sstevel@tonic-gate usb_as_alt_descr_t *altp;
21977c478bd9Sstevel@tonic-gate
21987c478bd9Sstevel@tonic-gate if (uasp->usb_as_alts) {
21997c478bd9Sstevel@tonic-gate for (alt = 0; alt < uasp->usb_as_n_alternates; alt++) {
22007c478bd9Sstevel@tonic-gate altp = &uasp->usb_as_alts[alt];
22017c478bd9Sstevel@tonic-gate if (altp) {
22027c478bd9Sstevel@tonic-gate if (altp->alt_sample_rates) {
22037c478bd9Sstevel@tonic-gate kmem_free(altp->alt_sample_rates,
22047c478bd9Sstevel@tonic-gate altp->alt_n_sample_rates *
22057c478bd9Sstevel@tonic-gate sizeof (uint_t));
22067c478bd9Sstevel@tonic-gate }
22077c478bd9Sstevel@tonic-gate if (altp->alt_if) {
22087c478bd9Sstevel@tonic-gate kmem_free(altp->alt_if,
22097c478bd9Sstevel@tonic-gate sizeof (usb_if_descr_t));
22107c478bd9Sstevel@tonic-gate }
22117c478bd9Sstevel@tonic-gate if (altp->alt_general) {
22127c478bd9Sstevel@tonic-gate kmem_free(altp->alt_general,
22137c478bd9Sstevel@tonic-gate sizeof (usb_audio_as_if_descr_t));
22147c478bd9Sstevel@tonic-gate }
22157c478bd9Sstevel@tonic-gate if (altp->alt_format) {
22167c478bd9Sstevel@tonic-gate kmem_free(altp->alt_format,
22177c478bd9Sstevel@tonic-gate altp->alt_format_len);
22187c478bd9Sstevel@tonic-gate }
22197c478bd9Sstevel@tonic-gate if (altp->alt_ep) {
22207c478bd9Sstevel@tonic-gate kmem_free(altp->alt_ep,
22217c478bd9Sstevel@tonic-gate sizeof (usb_ep_descr_t));
22227c478bd9Sstevel@tonic-gate }
22237c478bd9Sstevel@tonic-gate if (altp->alt_cs_ep) {
22247c478bd9Sstevel@tonic-gate kmem_free(altp->alt_cs_ep,
22257c478bd9Sstevel@tonic-gate sizeof (*altp->alt_cs_ep));
22267c478bd9Sstevel@tonic-gate }
22277c478bd9Sstevel@tonic-gate }
22287c478bd9Sstevel@tonic-gate }
22297c478bd9Sstevel@tonic-gate kmem_free(uasp->usb_as_alts, (uasp->usb_as_n_alternates) *
22307c478bd9Sstevel@tonic-gate sizeof (usb_as_alt_descr_t));
22317c478bd9Sstevel@tonic-gate }
22327c478bd9Sstevel@tonic-gate }
22337c478bd9Sstevel@tonic-gate
22347c478bd9Sstevel@tonic-gate
22357c478bd9Sstevel@tonic-gate /*
22367c478bd9Sstevel@tonic-gate * usb_as_prepare_registration_data
22377c478bd9Sstevel@tonic-gate */
22387c478bd9Sstevel@tonic-gate static void
usb_as_prepare_registration_data(usb_as_state_t * uasp)22397c478bd9Sstevel@tonic-gate usb_as_prepare_registration_data(usb_as_state_t *uasp)
22407c478bd9Sstevel@tonic-gate {
22417c478bd9Sstevel@tonic-gate usb_as_registration_t *reg = &uasp->usb_as_reg;
22427c478bd9Sstevel@tonic-gate usb_audio_type1_format_descr_t *format;
22437c478bd9Sstevel@tonic-gate uchar_t n_alternates = uasp->usb_as_n_alternates;
2244e272e4c8SBinzi Cao - Sun Microsystems - Beijing China int alt, n;
22457c478bd9Sstevel@tonic-gate
22467c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
22477c478bd9Sstevel@tonic-gate "usb_as_prepare_registration_data:");
22487c478bd9Sstevel@tonic-gate
22497c478bd9Sstevel@tonic-gate /* there has to be at least two alternates, ie 0 and 1 */
22507c478bd9Sstevel@tonic-gate if (n_alternates < 2) {
22517c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
22527c478bd9Sstevel@tonic-gate "not enough alternates %d", n_alternates);
22537c478bd9Sstevel@tonic-gate
22547c478bd9Sstevel@tonic-gate return;
22557c478bd9Sstevel@tonic-gate }
22567c478bd9Sstevel@tonic-gate
22577c478bd9Sstevel@tonic-gate reg->reg_ifno = uasp->usb_as_ifno;
22587c478bd9Sstevel@tonic-gate
22597c478bd9Sstevel@tonic-gate /* all endpoints need to have the same direction */
2260*64391892SAlbert Lee for (alt = 1; alt < n_alternates; alt++) {
22617c478bd9Sstevel@tonic-gate if (!uasp->usb_as_alts[alt].alt_valid) {
22627c478bd9Sstevel@tonic-gate continue;
22637c478bd9Sstevel@tonic-gate }
2264*64391892SAlbert Lee if (reg->reg_mode && uasp->usb_as_alts[alt].alt_mode !=
22657c478bd9Sstevel@tonic-gate reg->reg_mode) {
22667c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
22677c478bd9Sstevel@tonic-gate "alternates have different direction");
22687c478bd9Sstevel@tonic-gate
22697c478bd9Sstevel@tonic-gate return;
22707c478bd9Sstevel@tonic-gate }
2271*64391892SAlbert Lee reg->reg_mode = uasp->usb_as_alts[alt].alt_mode;
22727c478bd9Sstevel@tonic-gate }
22737c478bd9Sstevel@tonic-gate
22747c478bd9Sstevel@tonic-gate /*
22757c478bd9Sstevel@tonic-gate * we assume that alternate 0 is not interesting (no bandwidth),
22767c478bd9Sstevel@tonic-gate * we check all formats and use the formats that we can support
22777c478bd9Sstevel@tonic-gate */
22787c478bd9Sstevel@tonic-gate for (alt = 1, n = 0; alt < n_alternates; alt++) {
22797c478bd9Sstevel@tonic-gate if (!uasp->usb_as_alts[alt].alt_valid) {
22807c478bd9Sstevel@tonic-gate continue;
22817c478bd9Sstevel@tonic-gate }
22827c478bd9Sstevel@tonic-gate
22837c478bd9Sstevel@tonic-gate format = uasp->usb_as_alts[alt].alt_format;
22847c478bd9Sstevel@tonic-gate if (uasp->usb_as_alts[alt].alt_valid &&
22857c478bd9Sstevel@tonic-gate (n < USB_AS_N_FORMATS) &&
2286*64391892SAlbert Lee (usb_as_valid_format(uasp, alt) == USB_SUCCESS)) {
22877c478bd9Sstevel@tonic-gate reg->reg_formats[n].fmt_termlink =
22887c478bd9Sstevel@tonic-gate uasp->usb_as_alts[alt].alt_general->
22897c478bd9Sstevel@tonic-gate bTerminalLink;
22907c478bd9Sstevel@tonic-gate reg->reg_formats[n].fmt_alt = (uchar_t)alt;
22917c478bd9Sstevel@tonic-gate reg->reg_formats[n].fmt_chns =
2292112116d8Sfb format->bNrChannels;
22937c478bd9Sstevel@tonic-gate reg->reg_formats[n].fmt_precision =
2294112116d8Sfb format->bBitResolution;
2295*64391892SAlbert Lee reg->reg_formats[n].fmt_encoding =
2296e272e4c8SBinzi Cao - Sun Microsystems - Beijing China format->bFormatType;
2297*64391892SAlbert Lee reg->reg_formats[n].fmt_n_srs =
2298*64391892SAlbert Lee uasp->usb_as_alts[alt].alt_n_sample_rates;
2299*64391892SAlbert Lee reg->reg_formats[n++].fmt_srs =
2300*64391892SAlbert Lee uasp->usb_as_alts[alt].alt_sample_rates;
23017c478bd9Sstevel@tonic-gate }
23027c478bd9Sstevel@tonic-gate }
23037c478bd9Sstevel@tonic-gate
23047c478bd9Sstevel@tonic-gate reg->reg_n_formats = (uchar_t)n;
23057c478bd9Sstevel@tonic-gate
23067c478bd9Sstevel@tonic-gate if (n == 0) {
23077c478bd9Sstevel@tonic-gate /* no valid formats */
23087c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
23097c478bd9Sstevel@tonic-gate "zero valid formats");
23107c478bd9Sstevel@tonic-gate
23117c478bd9Sstevel@tonic-gate return;
23127c478bd9Sstevel@tonic-gate }
23137c478bd9Sstevel@tonic-gate
23147c478bd9Sstevel@tonic-gate /* dump what we have so far */
23157c478bd9Sstevel@tonic-gate for (n = 0; n < reg->reg_n_formats; n++) {
23167c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
2317e272e4c8SBinzi Cao - Sun Microsystems - Beijing China "regformats[%d]: termlink = %d, alt=%d chns=%d"
2318e272e4c8SBinzi Cao - Sun Microsystems - Beijing China " prec=%d enc=%d", n,
2319e272e4c8SBinzi Cao - Sun Microsystems - Beijing China reg->reg_formats[n].fmt_termlink,
23207c478bd9Sstevel@tonic-gate reg->reg_formats[n].fmt_alt,
23217c478bd9Sstevel@tonic-gate reg->reg_formats[n].fmt_chns,
23227c478bd9Sstevel@tonic-gate reg->reg_formats[n].fmt_precision,
23237c478bd9Sstevel@tonic-gate reg->reg_formats[n].fmt_encoding);
23247c478bd9Sstevel@tonic-gate }
23257c478bd9Sstevel@tonic-gate
23267c478bd9Sstevel@tonic-gate reg->reg_valid++;
23277c478bd9Sstevel@tonic-gate }
23287c478bd9Sstevel@tonic-gate
23297c478bd9Sstevel@tonic-gate
23307c478bd9Sstevel@tonic-gate /*
23317c478bd9Sstevel@tonic-gate * usb_as_valid_format:
23327c478bd9Sstevel@tonic-gate * check if this format can be supported
23337c478bd9Sstevel@tonic-gate */
23347c478bd9Sstevel@tonic-gate static int
usb_as_valid_format(usb_as_state_t * uasp,uint_t alternate)2335*64391892SAlbert Lee usb_as_valid_format(usb_as_state_t *uasp, uint_t alternate)
23367c478bd9Sstevel@tonic-gate {
23377c478bd9Sstevel@tonic-gate usb_as_alt_descr_t *alt_descr = &uasp->usb_as_alts[alternate];
23387c478bd9Sstevel@tonic-gate usb_audio_type1_format_descr_t *format = alt_descr->alt_format;
23397c478bd9Sstevel@tonic-gate
23407c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle,
23417c478bd9Sstevel@tonic-gate "usb_as_valid_format: %d %d %d %d %d",
23427c478bd9Sstevel@tonic-gate format->bNrChannels, format->bSubFrameSize,
23437c478bd9Sstevel@tonic-gate format->bBitResolution, format->bSamFreqType,
23447c478bd9Sstevel@tonic-gate format->bFormatType);
23457c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle,
2346*64391892SAlbert Lee "alt=%d", alternate);
23477c478bd9Sstevel@tonic-gate
23487c478bd9Sstevel@tonic-gate switch (format->bNrChannels) {
2349*64391892SAlbert Lee case 0:
23507c478bd9Sstevel@tonic-gate
23517c478bd9Sstevel@tonic-gate return (USB_FAILURE);
2352*64391892SAlbert Lee default:
2353*64391892SAlbert Lee
2354*64391892SAlbert Lee break;
23557c478bd9Sstevel@tonic-gate }
23567c478bd9Sstevel@tonic-gate
23577c478bd9Sstevel@tonic-gate switch (format->bSubFrameSize) {
23587c478bd9Sstevel@tonic-gate case 1:
23597c478bd9Sstevel@tonic-gate case 2:
23607c478bd9Sstevel@tonic-gate break;
23617c478bd9Sstevel@tonic-gate default:
23627c478bd9Sstevel@tonic-gate
23637c478bd9Sstevel@tonic-gate return (USB_FAILURE);
23647c478bd9Sstevel@tonic-gate }
23657c478bd9Sstevel@tonic-gate
23667c478bd9Sstevel@tonic-gate switch (format->bBitResolution) {
2367*64391892SAlbert Lee case USB_AUDIO_PRECISION_8:
2368*64391892SAlbert Lee case USB_AUDIO_PRECISION_16:
2369*64391892SAlbert Lee case USB_AUDIO_PRECISION_24:
2370*64391892SAlbert Lee case USB_AUDIO_PRECISION_32:
23717c478bd9Sstevel@tonic-gate break;
23727c478bd9Sstevel@tonic-gate default:
23737c478bd9Sstevel@tonic-gate
23747c478bd9Sstevel@tonic-gate return (USB_FAILURE);
23757c478bd9Sstevel@tonic-gate }
23767c478bd9Sstevel@tonic-gate
23777c478bd9Sstevel@tonic-gate switch (format->bFormatType) {
23787c478bd9Sstevel@tonic-gate case USB_AUDIO_FORMAT_TYPE1_PCM:
23797c478bd9Sstevel@tonic-gate break;
23807c478bd9Sstevel@tonic-gate default:
23817c478bd9Sstevel@tonic-gate
23827c478bd9Sstevel@tonic-gate return (USB_FAILURE);
23837c478bd9Sstevel@tonic-gate }
23847c478bd9Sstevel@tonic-gate
23857c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
23867c478bd9Sstevel@tonic-gate }
23877c478bd9Sstevel@tonic-gate
23887c478bd9Sstevel@tonic-gate
23897c478bd9Sstevel@tonic-gate
23907c478bd9Sstevel@tonic-gate
23917c478bd9Sstevel@tonic-gate /*
23927c478bd9Sstevel@tonic-gate * Event Management
23937c478bd9Sstevel@tonic-gate *
23947c478bd9Sstevel@tonic-gate * usb_as_disconnect_event_cb:
23957c478bd9Sstevel@tonic-gate * The device has been disconnected.
23967c478bd9Sstevel@tonic-gate */
23977c478bd9Sstevel@tonic-gate static int
usb_as_disconnect_event_cb(dev_info_t * dip)23987c478bd9Sstevel@tonic-gate usb_as_disconnect_event_cb(dev_info_t *dip)
23997c478bd9Sstevel@tonic-gate {
24007c478bd9Sstevel@tonic-gate usb_as_state_t *uasp = (usb_as_state_t *)ddi_get_soft_state(
24017c478bd9Sstevel@tonic-gate usb_as_statep, ddi_get_instance(dip));
24027c478bd9Sstevel@tonic-gate
24037c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_EVENTS, uasp->usb_as_log_handle,
2404112116d8Sfb "usb_as_disconnect_event_cb: dip=0x%p", (void *)dip);
24057c478bd9Sstevel@tonic-gate
24067c478bd9Sstevel@tonic-gate (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0);
24077c478bd9Sstevel@tonic-gate
24087c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
24097c478bd9Sstevel@tonic-gate uasp->usb_as_dev_state = USB_DEV_DISCONNECTED;
24107c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
24117c478bd9Sstevel@tonic-gate
24127c478bd9Sstevel@tonic-gate usb_release_access(uasp->usb_as_ser_acc);
24137c478bd9Sstevel@tonic-gate
24147c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
24157c478bd9Sstevel@tonic-gate }
24167c478bd9Sstevel@tonic-gate
24177c478bd9Sstevel@tonic-gate
24187c478bd9Sstevel@tonic-gate /*
24197c478bd9Sstevel@tonic-gate * usb_as_cpr_suspend:
24207c478bd9Sstevel@tonic-gate */
24217c478bd9Sstevel@tonic-gate static int
usb_as_cpr_suspend(dev_info_t * dip)24227c478bd9Sstevel@tonic-gate usb_as_cpr_suspend(dev_info_t *dip)
24237c478bd9Sstevel@tonic-gate {
24247c478bd9Sstevel@tonic-gate usb_as_state_t *uasp = (usb_as_state_t *)ddi_get_soft_state(
24257c478bd9Sstevel@tonic-gate usb_as_statep, ddi_get_instance(dip));
24267c478bd9Sstevel@tonic-gate
24277c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_EVENTS, uasp->usb_as_log_handle,
24287c478bd9Sstevel@tonic-gate "usb_as_cpr_suspend: Begin");
24297c478bd9Sstevel@tonic-gate
24307c478bd9Sstevel@tonic-gate (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0);
24317c478bd9Sstevel@tonic-gate
24327c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
24337c478bd9Sstevel@tonic-gate uasp->usb_as_dev_state = USB_DEV_SUSPENDED;
24347c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
24357c478bd9Sstevel@tonic-gate
24367c478bd9Sstevel@tonic-gate usb_release_access(uasp->usb_as_ser_acc);
24377c478bd9Sstevel@tonic-gate
24387c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
24397c478bd9Sstevel@tonic-gate "usb_as_cpr_suspend: End");
24407c478bd9Sstevel@tonic-gate
24417c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
24427c478bd9Sstevel@tonic-gate }
24437c478bd9Sstevel@tonic-gate
24447c478bd9Sstevel@tonic-gate
24457c478bd9Sstevel@tonic-gate /*
24467c478bd9Sstevel@tonic-gate * usb_as_reconnect_event_cb:
24477c478bd9Sstevel@tonic-gate * The device was disconnected but this instance not detached, probably
24487c478bd9Sstevel@tonic-gate * because the device was busy.
24497c478bd9Sstevel@tonic-gate * if the same device, continue with restoring state
24507c478bd9Sstevel@tonic-gate */
24517c478bd9Sstevel@tonic-gate static int
usb_as_reconnect_event_cb(dev_info_t * dip)24527c478bd9Sstevel@tonic-gate usb_as_reconnect_event_cb(dev_info_t *dip)
24537c478bd9Sstevel@tonic-gate {
24547c478bd9Sstevel@tonic-gate usb_as_state_t *uasp = (usb_as_state_t *)ddi_get_soft_state(
24557c478bd9Sstevel@tonic-gate usb_as_statep, ddi_get_instance(dip));
24567c478bd9Sstevel@tonic-gate
24577c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_EVENTS, uasp->usb_as_log_handle,
2458112116d8Sfb "usb_as_reconnect_event_cb: dip=0x%p", (void *)dip);
24597c478bd9Sstevel@tonic-gate
24607c478bd9Sstevel@tonic-gate (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0);
24617c478bd9Sstevel@tonic-gate
24627c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
24637c478bd9Sstevel@tonic-gate usb_as_restore_device_state(dip, uasp);
24647c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
24657c478bd9Sstevel@tonic-gate
24667c478bd9Sstevel@tonic-gate usb_release_access(uasp->usb_as_ser_acc);
24677c478bd9Sstevel@tonic-gate
24687c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
24697c478bd9Sstevel@tonic-gate }
24707c478bd9Sstevel@tonic-gate
24717c478bd9Sstevel@tonic-gate
24727c478bd9Sstevel@tonic-gate /*
24737c478bd9Sstevel@tonic-gate * usb_as_cpr_resume:
24747c478bd9Sstevel@tonic-gate * recover this device from suspended state
24757c478bd9Sstevel@tonic-gate */
24767c478bd9Sstevel@tonic-gate static void
usb_as_cpr_resume(dev_info_t * dip)24777c478bd9Sstevel@tonic-gate usb_as_cpr_resume(dev_info_t *dip)
24787c478bd9Sstevel@tonic-gate {
24797c478bd9Sstevel@tonic-gate usb_as_state_t *uasp = (usb_as_state_t *)ddi_get_soft_state(
24807c478bd9Sstevel@tonic-gate usb_as_statep, ddi_get_instance(dip));
24817c478bd9Sstevel@tonic-gate
24827c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_EVENTS, uasp->usb_as_log_handle,
2483112116d8Sfb "usb_as_cpr_resume: dip=0x%p", (void *)dip);
24847c478bd9Sstevel@tonic-gate
24857c478bd9Sstevel@tonic-gate (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0);
24867c478bd9Sstevel@tonic-gate
24877c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
24887c478bd9Sstevel@tonic-gate usb_as_restore_device_state(dip, uasp);
24897c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
24907c478bd9Sstevel@tonic-gate
24917c478bd9Sstevel@tonic-gate usb_release_access(uasp->usb_as_ser_acc);
24927c478bd9Sstevel@tonic-gate }
24937c478bd9Sstevel@tonic-gate
24947c478bd9Sstevel@tonic-gate
24957c478bd9Sstevel@tonic-gate /*
24967c478bd9Sstevel@tonic-gate * usb_as_restore_device_state:
24977c478bd9Sstevel@tonic-gate * Set original configuration of the device
24987c478bd9Sstevel@tonic-gate * enable wrq - this starts new transactions on the control pipe
24997c478bd9Sstevel@tonic-gate */
25007c478bd9Sstevel@tonic-gate static void
usb_as_restore_device_state(dev_info_t * dip,usb_as_state_t * uasp)25017c478bd9Sstevel@tonic-gate usb_as_restore_device_state(dev_info_t *dip, usb_as_state_t *uasp)
25027c478bd9Sstevel@tonic-gate {
25037c478bd9Sstevel@tonic-gate usb_as_power_t *uaspm;
25047c478bd9Sstevel@tonic-gate
25057c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
25067c478bd9Sstevel@tonic-gate "usb_as_restore_device_state:");
25077c478bd9Sstevel@tonic-gate
25087c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uasp->usb_as_mutex));
25097c478bd9Sstevel@tonic-gate
25107c478bd9Sstevel@tonic-gate uaspm = uasp->usb_as_pm;
25117c478bd9Sstevel@tonic-gate
25127c478bd9Sstevel@tonic-gate /* Check if we are talking to the same device */
25137c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
25147c478bd9Sstevel@tonic-gate usb_as_pm_busy_component(uasp);
25157c478bd9Sstevel@tonic-gate (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
25167c478bd9Sstevel@tonic-gate
25177c478bd9Sstevel@tonic-gate if (usb_check_same_device(dip, uasp->usb_as_log_handle, USB_LOG_L0,
25187c478bd9Sstevel@tonic-gate PRINT_MASK_ALL, USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) {
25197c478bd9Sstevel@tonic-gate usb_as_pm_idle_component(uasp);
25207c478bd9Sstevel@tonic-gate
25217c478bd9Sstevel@tonic-gate /* change the device state from suspended to disconnected */
25227c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
25237c478bd9Sstevel@tonic-gate uasp->usb_as_dev_state = USB_DEV_DISCONNECTED;
25247c478bd9Sstevel@tonic-gate
25257c478bd9Sstevel@tonic-gate return;
25267c478bd9Sstevel@tonic-gate }
25277c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
25287c478bd9Sstevel@tonic-gate
25297c478bd9Sstevel@tonic-gate if (uaspm) {
25307c478bd9Sstevel@tonic-gate if (uaspm->aspm_wakeup_enabled) {
25317c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
25327c478bd9Sstevel@tonic-gate if (usb_handle_remote_wakeup(uasp->usb_as_dip,
25337c478bd9Sstevel@tonic-gate USB_REMOTE_WAKEUP_ENABLE)) {
25347c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL,
25357c478bd9Sstevel@tonic-gate uasp->usb_as_log_handle,
25367c478bd9Sstevel@tonic-gate "enable remote wake up failed");
25377c478bd9Sstevel@tonic-gate }
25387c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
25397c478bd9Sstevel@tonic-gate }
25407c478bd9Sstevel@tonic-gate }
25417c478bd9Sstevel@tonic-gate uasp->usb_as_dev_state = USB_DEV_ONLINE;
25427c478bd9Sstevel@tonic-gate
25437c478bd9Sstevel@tonic-gate mutex_exit(&uasp->usb_as_mutex);
25447c478bd9Sstevel@tonic-gate usb_as_pm_idle_component(uasp);
25457c478bd9Sstevel@tonic-gate mutex_enter(&uasp->usb_as_mutex);
25467c478bd9Sstevel@tonic-gate }
25477c478bd9Sstevel@tonic-gate
25487c478bd9Sstevel@tonic-gate
25497c478bd9Sstevel@tonic-gate static void
usb_as_pm_busy_component(usb_as_state_t * usb_as_statep)25507c478bd9Sstevel@tonic-gate usb_as_pm_busy_component(usb_as_state_t *usb_as_statep)
25517c478bd9Sstevel@tonic-gate {
25527c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&usb_as_statep->usb_as_mutex));
25537c478bd9Sstevel@tonic-gate
25547c478bd9Sstevel@tonic-gate if (usb_as_statep->usb_as_pm != NULL) {
25557c478bd9Sstevel@tonic-gate mutex_enter(&usb_as_statep->usb_as_mutex);
25567c478bd9Sstevel@tonic-gate usb_as_statep->usb_as_pm->aspm_pm_busy++;
25577c478bd9Sstevel@tonic-gate
25587c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM, usb_as_statep->usb_as_log_handle,
25597c478bd9Sstevel@tonic-gate "usb_as_pm_busy_component: %d",
25607c478bd9Sstevel@tonic-gate usb_as_statep->usb_as_pm->aspm_pm_busy);
25617c478bd9Sstevel@tonic-gate
25627c478bd9Sstevel@tonic-gate mutex_exit(&usb_as_statep->usb_as_mutex);
25637c478bd9Sstevel@tonic-gate
25647c478bd9Sstevel@tonic-gate if (pm_busy_component(usb_as_statep->usb_as_dip, 0) !=
25657c478bd9Sstevel@tonic-gate DDI_SUCCESS) {
25667c478bd9Sstevel@tonic-gate mutex_enter(&usb_as_statep->usb_as_mutex);
25677c478bd9Sstevel@tonic-gate usb_as_statep->usb_as_pm->aspm_pm_busy--;
25687c478bd9Sstevel@tonic-gate
25697c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_PM,
25707c478bd9Sstevel@tonic-gate usb_as_statep->usb_as_log_handle,
25717c478bd9Sstevel@tonic-gate "usb_as_pm_busy_component failed: %d",
25727c478bd9Sstevel@tonic-gate usb_as_statep->usb_as_pm->aspm_pm_busy);
25737c478bd9Sstevel@tonic-gate
25747c478bd9Sstevel@tonic-gate mutex_exit(&usb_as_statep->usb_as_mutex);
25757c478bd9Sstevel@tonic-gate }
25767c478bd9Sstevel@tonic-gate }
25777c478bd9Sstevel@tonic-gate }
25787c478bd9Sstevel@tonic-gate
25797c478bd9Sstevel@tonic-gate
25807c478bd9Sstevel@tonic-gate static void
usb_as_pm_idle_component(usb_as_state_t * usb_as_statep)25817c478bd9Sstevel@tonic-gate usb_as_pm_idle_component(usb_as_state_t *usb_as_statep)
25827c478bd9Sstevel@tonic-gate {
25837c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&usb_as_statep->usb_as_mutex));
25847c478bd9Sstevel@tonic-gate
25857c478bd9Sstevel@tonic-gate if (usb_as_statep->usb_as_pm != NULL) {
25867c478bd9Sstevel@tonic-gate if (pm_idle_component(usb_as_statep->usb_as_dip, 0) ==
25877c478bd9Sstevel@tonic-gate DDI_SUCCESS) {
25887c478bd9Sstevel@tonic-gate mutex_enter(&usb_as_statep->usb_as_mutex);
25897c478bd9Sstevel@tonic-gate ASSERT(usb_as_statep->usb_as_pm->aspm_pm_busy > 0);
25907c478bd9Sstevel@tonic-gate usb_as_statep->usb_as_pm->aspm_pm_busy--;
25917c478bd9Sstevel@tonic-gate
25927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_PM,
25937c478bd9Sstevel@tonic-gate usb_as_statep->usb_as_log_handle,
25947c478bd9Sstevel@tonic-gate "usb_as_pm_idle_component: %d",
25957c478bd9Sstevel@tonic-gate usb_as_statep->usb_as_pm->aspm_pm_busy);
25967c478bd9Sstevel@tonic-gate
25977c478bd9Sstevel@tonic-gate mutex_exit(&usb_as_statep->usb_as_mutex);
25987c478bd9Sstevel@tonic-gate }
25997c478bd9Sstevel@tonic-gate }
26007c478bd9Sstevel@tonic-gate }
2601