diff options
author | Binzi Cao - Sun Microsystems - Beijing China <Binzi.Cao@Sun.COM> | 2009-08-28 10:14:12 +0800 |
---|---|---|
committer | Binzi Cao - Sun Microsystems - Beijing China <Binzi.Cao@Sun.COM> | 2009-08-28 10:14:12 +0800 |
commit | e272e4c8df90e762ecb6a6564503bb2cb1e2027d (patch) | |
tree | 063487b7cea8764dec3ab3501a813ade7c9c66bf | |
parent | 0ff3af34972e8504d3d8bc351d12371be6a60abf (diff) | |
download | illumos-joyent-e272e4c8df90e762ecb6a6564503bb2cb1e2027d.tar.gz |
6842045 usb audio driver should be updated to OSS framework
6855250 "audioplay" may cause system hang when play audio files to USB headset on snv_117
6852046 MPlayer have problems playing on Sun OSS implementation using OSS driver
6854227 considerable usb audio distortion on build 116
6837267 warlock is not clean for usb audio
20 files changed, 1849 insertions, 3775 deletions
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 11161e87f9..bb8498a58f 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -708,7 +708,7 @@ USBVC_OBJS += usbvc.o usbvc_v4l2.o HIDPARSER_OBJS += hidparser.o -USB_AC_OBJS += usb_ac.o audio_shim.o +USB_AC_OBJS += usb_ac.o USB_AS_OBJS += usb_as.o diff --git a/usr/src/uts/common/io/usb/clients/audio/usb_ac/audio_shim.c b/usr/src/uts/common/io/usb/clients/audio/usb_ac/audio_shim.c deleted file mode 100644 index 123a07e050..0000000000 --- a/usr/src/uts/common/io/usb/clients/audio/usb_ac/audio_shim.c +++ /dev/null @@ -1,1948 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include <sys/note.h> -#include <sys/varargs.h> -#include <sys/stream.h> -#include <sys/modctl.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/strsun.h> -#include <sys/strsubr.h> -#include <sys/taskq.h> - -#include <sys/audio.h> -#include <sys/audio/audio_support.h> -#include <sys/mixer.h> -#include <sys/audio/audio_mixer.h> - -#include <sys/usb/usba/usbai_version.h> -#include <sys/usb/usba.h> -#include <sys/usb/clients/audio/usb_audio.h> -#include <sys/usb/clients/audio/usb_mixer.h> -#include <sys/usb/clients/audio/usb_ac/usb_ac.h> - -#include "audio_shim.h" - - - - -/* - * The code here is a "shim" connecting legacy SADA USB drivers with the - * Boomer audio framework, translating interfaces between the two. - * This is an interim measure until new Boomer-native USB drivers are in place. - */ - -extern void audio_dump_bytes(const uint8_t *, int); -extern void audio_dump_words(const uint16_t *, int); -extern void audio_dump_dwords(const uint32_t *, int); - - -#define ASHIM_ENG_PLAY 0 -#define ASHIM_ENG_REC 1 - -#define ASHIM_GET_ENG(statep, which) (&(statep)->engines[(which)]) -#define ASHIM_ENG_DIR(engp) \ - (((engp)->af_eflags & ENGINE_OUTPUT_CAP) ? AUDIO_PLAY : AUDIO_RECORD) - -static int ashim_eng_start(ashim_eng_t *); -static void ashim_eng_stop(ashim_eng_t *); - -static int ashim_af_open(void *arg, int flag, - unsigned *fragszp, unsigned *nfragsp, caddr_t *bufp); -static void ashim_af_close(void *arg); -static uint64_t ashim_af_count(void *arg); -static int ashim_af_start(void *arg); -static void ashim_af_stop(void *arg); -static int ashim_af_format(void *arg); -static int ashim_af_channels(void *arg); -static int ashim_af_rate(void *arg); -static void ashim_af_sync(void *arg, unsigned nframes); -static size_t ashim_af_qlen(void *arg); - -audio_engine_ops_t ashim_engine_ops = { - AUDIO_ENGINE_VERSION, - ashim_af_open, - ashim_af_close, - ashim_af_start, - ashim_af_stop, - ashim_af_count, - ashim_af_format, - ashim_af_channels, - ashim_af_rate, - ashim_af_sync, - ashim_af_qlen, -}; - - -#define ASHIM_BUFSCALE_MIN 1 -#define ASHIM_BUFSCALE_MAX 2000 -#define ASHIM_BUFSCALE_DEF 10 - -/* engine buffer size in terms of fragments */ -int ashim_bufscale = ASHIM_BUFSCALE_DEF; - -/* use driver specified buffer size instead */ -int ashim_use_drvbuf = 0; - -/* format override */ -uint_t ashim_fmt_sr = 0; -uint_t ashim_fmt_ch = 0; -uint_t ashim_fmt_prec = 0; -uint_t ashim_fmt_enc = 0; /* use SADA values e.g. AUDIO_ENCODING_LINEAR = 3 */ - -/* open without starting engine */ -int ashim_eng_disable = 0; - -/* dump audio data */ -uint64_t ashim_dump_audio_start = 0; -uint64_t ashim_dump_audio_len = 0; -int ashim_dump_audio_bufsel = 0; /* 0 = shim buf; 1 = drv/dma buf */ - -/* dump i/o related counters */ -uint64_t ashim_dump_counters_start = 0; -uint64_t ashim_dump_counters_len = 0; - -/* ignore errors when setting control values */ -int ashim_ctrl_ignore_errors = 0; - -/* - * ************************************************************************* - * audio controls - * - * Note: we cannot determine if a SADA device truly supports play or record - * gain adjustment until we actually try the command. Messages showing - * failed control updates will be printed at the DINFO ashim_debug level. - */ - -#define AUDIO_CTRL_STEREO_LEFT(v) ((uint8_t)((v) & 0xff)) -#define AUDIO_CTRL_STEREO_RIGHT(v) ((uint8_t)(((v) >> 8) & 0xff)) -#define AUDIO_CTRL_STEREO_VAL(l, r) (((l) & 0xff) | (((r) & 0xff) << 8)) - -/* - * framework gain range - */ -#define AF_MAX_GAIN 100 -#define AF_MIN_GAIN 0 - -#define AF_MAX_GAIN_ST AUDIO_CTRL_STEREO_VAL(AF_MAX_GAIN, AF_MAX_GAIN) -#define AF_MIN_GAIN_ST AUDIO_CTRL_STEREO_VAL(AF_MIN_GAIN, AF_MIN_GAIN) - -/* - * convert between framework and driver gain values - * must multiply (n) before dividing else D2F_GAIN result will be 0 - */ -#define F2D_GAIN(n) (((n) * AUDIO_MAX_GAIN) / AF_MAX_GAIN) -#define D2F_GAIN(n) (((n) * AF_MAX_GAIN) / AUDIO_MAX_GAIN) - -typedef struct ashim_ctrl_map ashim_ctrl_map_t; - -static uint64_t ashim_ctrl_defval(ashim_state_t *statep, - ashim_ctrl_map_t *mapp); -static int ashim_ctrl_set_defaults(ashim_state_t *statep); -static int ashim_ctrl_restore(ashim_state_t *statep); - -static int ashim_ctrl_rd(void *, uint64_t *); -static int ashim_ctrl_wr_st(void *, uint64_t); -static int ashim_ctrl_wr_mn(void *, uint64_t); -static int ashim_ctrl_wr_bool(void *, uint64_t); -static int ashim_ctrl_wr_ports(void *, uint64_t); - -static void ashim_rem_controls(ashim_state_t *statep); -static int ashim_add_controls(ashim_state_t *statep); - - -/* - * map framework port definitions to SADA ports - */ - -typedef struct { - int dport; - const char *pname; -} ashim_port_map_t; - - -static ashim_port_map_t ashim_play_pmap[] = { - {AUDIO_SPEAKER, AUDIO_PORT_SPEAKER}, - {AUDIO_HEADPHONE, AUDIO_PORT_HEADPHONES}, - {AUDIO_LINE_OUT, AUDIO_PORT_LINEOUT}, - {AUDIO_SPDIF_OUT, AUDIO_PORT_SPDIFOUT}, - {AUDIO_AUX1_OUT, AUDIO_PORT_AUX1OUT}, - {AUDIO_AUX2_OUT, AUDIO_PORT_AUX2OUT} -}; -static int ashim_play_pmap_len = - sizeof (ashim_play_pmap) / sizeof (ashim_port_map_t); - - -static ashim_port_map_t ashim_rec_pmap[] = { - {AUDIO_MICROPHONE, AUDIO_PORT_MIC}, - {AUDIO_LINE_IN, AUDIO_PORT_LINEIN}, - {AUDIO_CD, AUDIO_PORT_CD}, - {AUDIO_SPDIF_IN, AUDIO_PORT_SPDIFIN}, - {AUDIO_AUX1_IN, AUDIO_PORT_AUX1IN}, - {AUDIO_AUX2_IN, AUDIO_PORT_AUX2IN}, - {AUDIO_CODEC_LOOPB_IN, AUDIO_PORT_STEREOMIX} -}; -static int ashim_rec_pmap_len = - sizeof (ashim_rec_pmap) / sizeof (ashim_port_map_t); - - -/* - * map frameowork controls to SADA controls - */ -struct ashim_ctrl_map { - int dcmd; - int dir; - audio_ctrl_desc_t acd; - audio_ctrl_wr_t af_wr; - audio_ctrl_rd_t af_rd; -}; - -#define DESC_ST(n, f) { \ - .acd_name = (n), \ - .acd_type = AUDIO_CTRL_TYPE_STEREO, \ - .acd_flags = (f) | \ - AUDIO_CTRL_FLAG_READABLE | AUDIO_CTRL_FLAG_WRITEABLE, \ - .acd_maxvalue = AF_MAX_GAIN, \ - .acd_minvalue = AF_MIN_GAIN, \ -} -#define FUNC_ST \ - &ashim_ctrl_wr_st, &ashim_ctrl_rd - - -#define DESC_MN(n, f) { \ - .acd_name = (n), \ - .acd_type = AUDIO_CTRL_TYPE_MONO, \ - .acd_flags = (f) | \ - AUDIO_CTRL_FLAG_READABLE | AUDIO_CTRL_FLAG_WRITEABLE, \ - .acd_maxvalue = AF_MAX_GAIN, \ - .acd_minvalue = AF_MIN_GAIN, \ -} -#define FUNC_MN \ - &ashim_ctrl_wr_mn, &ashim_ctrl_rd - - -#define DESC_BOOL(n, f) { \ - .acd_name = (n), \ - .acd_type = AUDIO_CTRL_TYPE_BOOLEAN, \ - .acd_flags = (f) | \ - AUDIO_CTRL_FLAG_READABLE | AUDIO_CTRL_FLAG_WRITEABLE, \ - .acd_maxvalue = 1, \ - .acd_minvalue = 0, \ -} -#define FUNC_BOOL \ - &ashim_ctrl_wr_bool, &ashim_ctrl_rd - - -#define DESC_OUTS(n, f) { \ - .acd_name = AUDIO_CTRL_ID_OUTPUTS, \ - .acd_type = AUDIO_CTRL_TYPE_ENUM, \ - .acd_flags = (f) | \ - AUDIO_CTRL_FLAG_READABLE | AUDIO_CTRL_FLAG_WRITEABLE | \ - AUDIO_CTRL_FLAG_MULTI, \ - .acd_maxvalue = (n), \ - .acd_minvalue = (n), \ -} - -#define DESC_INS(n, f) { \ - .acd_name = AUDIO_CTRL_ID_INPUTS, \ - .acd_type = AUDIO_CTRL_TYPE_ENUM, \ - .acd_flags = (f) | \ - AUDIO_CTRL_FLAG_READABLE | AUDIO_CTRL_FLAG_WRITEABLE, \ - .acd_maxvalue = (n), \ - .acd_minvalue = (n), \ -} -#define FUNC_PORTS \ - &ashim_ctrl_wr_ports, &ashim_ctrl_rd - - -/* - * sada <-> framework translation table - * a DESC_NULL() for audio_ctrl_desc_t is used to indicate a - * non-registered sada control that needs some initialization or be used - * internally by the shim - * - * Note: currently, usb_ac only notifies the framework of play volume changes - * from HID so the volume control the only one using AUDIO_CTRL_FLAG_POLL - */ -static ashim_ctrl_map_t ashim_ctrl_map[] = { - {AM_SET_GAIN, AUDIO_PLAY, - DESC_ST(AUDIO_CTRL_ID_VOLUME, AUDIO_CTRL_FLAG_MAINVOL | - AUDIO_CTRL_FLAG_PLAY | AUDIO_CTRL_FLAG_POLL), - FUNC_ST}, - - {AM_SET_GAIN, AUDIO_PLAY, - DESC_MN(AUDIO_CTRL_ID_VOLUME, AUDIO_CTRL_FLAG_MAINVOL | - AUDIO_CTRL_FLAG_PLAY | AUDIO_CTRL_FLAG_POLL), - FUNC_MN}, - - {AM_SET_GAIN, AUDIO_RECORD, - DESC_ST(AUDIO_CTRL_ID_RECGAIN, AUDIO_CTRL_FLAG_RECVOL | - AUDIO_CTRL_FLAG_REC), - FUNC_ST}, - - {AM_SET_GAIN, AUDIO_RECORD, - DESC_MN(AUDIO_CTRL_ID_RECGAIN, AUDIO_CTRL_FLAG_RECVOL | - AUDIO_CTRL_FLAG_REC), - FUNC_MN}, - - {AM_SET_MONITOR_GAIN, AUDIO_RECORD, - DESC_MN(AUDIO_CTRL_ID_MONGAIN, AUDIO_CTRL_FLAG_MONVOL | - AUDIO_CTRL_FLAG_MONITOR), - FUNC_MN}, - - {AM_MIC_BOOST, AUDIO_RECORD, - DESC_BOOL(AUDIO_CTRL_ID_MICBOOST, 0), - FUNC_BOOL}, - - {AM_SET_PORT, AUDIO_PLAY, - DESC_OUTS(0, 0), - FUNC_PORTS}, - - {AM_SET_PORT, AUDIO_RECORD, - DESC_INS(0, 0), - FUNC_PORTS}, -}; -static int ashim_ctrl_map_len = - sizeof (ashim_ctrl_map) / sizeof (ashim_ctrl_map_t); - - -/* - * ************************************************************************* - * shim support routines - */ - -int ashim_debug = DBG_WARN; - -static void -vdprint(debug_level_t lvl, const char *fmt, va_list adx) -{ - if (ashim_debug < lvl) - return; - - vcmn_err(CE_CONT, fmt, adx); -} - -static void -dwarn(const char *fmt, ...) -{ - va_list adx; - - va_start(adx, fmt); - vdprint(DBG_WARN, fmt, adx); - va_end(adx); -} - -static void -dinfo(const char *fmt, ...) -{ - va_list adx; - - va_start(adx, fmt); - vdprint(DBG_INFO, fmt, adx); - va_end(adx); -} - -static void -ddtl(const char *fmt, ...) -{ - va_list adx; - - va_start(adx, fmt); - vdprint(DBG_DETAIL, fmt, adx); - va_end(adx); -} - - -/* - * get the maximum format specification the device supports - */ -static void -ashim_max_fmt(ashim_state_t *statep, int dir, ashim_fmt_t *fmtp) -{ - am_ad_ch_cap_t *capp = &statep->ad_infop->ad_play; - am_ad_cap_comb_t *combp = statep->ad_infop->ad_play_comb; - - uint_t *srs, *chs; - uint_t sr, ch, prec, enc, val; - int i; - - if (dir == AUDIO_RECORD) { - capp = &statep->ad_infop->ad_record; - combp = statep->ad_infop->ad_rec_comb; - } - srs = capp->ad_mixer_srs.ad_srs; - chs = capp->ad_chs; - - for (i = 0, sr = 0; srs[i]; i++) { - val = srs[i]; - if (val > sr) - sr = val; - } - - for (i = 0, ch = 0; chs[i]; i++) { - val = chs[i]; - if (val > ch) - ch = val; - } - - for (i = 0, prec = 0, enc = 0; combp[i].ad_prec; i++) { - val = combp[i].ad_prec; - if (val > prec) - prec = val; - - val = combp[i].ad_enc; - if (val > enc) - enc = val; - } - - fmtp->sr = ashim_fmt_sr ? ashim_fmt_sr : sr; - fmtp->ch = ashim_fmt_ch ? ashim_fmt_ch : ch; - fmtp->prec = ashim_fmt_prec ? ashim_fmt_prec : prec; - fmtp->enc = ashim_fmt_enc ? ashim_fmt_enc : enc; -} - - -/* - * calls the driver's setup routine if present - * For USB audio, this opens a pipe to the endpoint usb_as - * returns AUDIO_SUCCESS or AUDIO_FAILURE - */ -static int -ashim_ad_setup(ashim_state_t *statep, int dir) -{ - am_ad_entry_t *ad_entry = statep->ad_infop->ad_entry; - - if (ad_entry->ad_setup == NULL) - return (AUDIO_SUCCESS); - - return (ad_entry->ad_setup(AUDIO_SHIMST2HDL(statep), dir)); -} - - -/* - * calls the driver's teardown routine if present. - * Note that the amount of teardowns must match the amount of setups used - * in each direction. - * returns AUDIO_SUCCESS or AUDIO_FAILURE - */ -static void -ashim_ad_teardown(ashim_state_t *statep, int dir) -{ - am_ad_entry_t *ad_entry = statep->ad_infop->ad_entry; - - if (ad_entry->ad_teardown != NULL) - ad_entry->ad_teardown(AUDIO_SHIMST2HDL(statep), dir); -} - - -/* - * sets the audio format (sample rate, channels, precision, encoding) - * returns AUDIO_SUCCESS or AUDIO_FAILURE - */ -static int -ashim_set_fmt(ashim_state_t *statep, int dir, ashim_fmt_t *fmtp) -{ - am_ad_entry_t *ad_entry = statep->ad_infop->ad_entry; - - return (ad_entry->ad_set_format(AUDIO_SHIMST2HDL(statep), dir, - fmtp->sr, fmtp->ch, fmtp->prec, fmtp->enc)); -} - - -static int -ashim_af_fmt(ashim_fmt_t *fmtp) -{ - switch (fmtp->enc) { - case AUDIO_ENCODING_ULAW: - return (AUDIO_FORMAT_ULAW); - case AUDIO_ENCODING_ALAW: - return (AUDIO_FORMAT_ALAW); - case AUDIO_ENCODING_DVI: - return (AUDIO_FORMAT_NONE); - case AUDIO_ENCODING_LINEAR8: - return (AUDIO_FORMAT_U8); - case AUDIO_ENCODING_LINEAR: - break; - default: - return (AUDIO_FORMAT_NONE); - } - - switch (fmtp->prec) { - case 8: - return (AUDIO_FORMAT_S8); - case 16: - return (AUDIO_FORMAT_S16_NE); - case 24: - return (AUDIO_FORMAT_S24_NE); - case 32: - return (AUDIO_FORMAT_S32_NE); - default: - break; - } - return (AUDIO_FORMAT_NONE); -} - - -static void -ashim_rem_eng(ashim_state_t *statep, ashim_eng_t *engp) -{ - if (statep->af_devp == NULL || engp->af_engp == NULL) - return; - - audio_dev_remove_engine(statep->af_devp, engp->af_engp); - audio_engine_free(engp->af_engp); - engp->af_engp = NULL; - -} - - -static int -ashim_add_eng(ashim_state_t *statep, int dir) -{ - audio_dev_t *af_devp = statep->af_devp; - ashim_eng_t *engp; - audio_engine_t *af_engp; - int rv = AUDIO_FAILURE; - int which; - - if (dir == AUDIO_PLAY) { - which = ASHIM_ENG_PLAY; - engp = ASHIM_GET_ENG(statep, which); - engp->af_eflags = ENGINE_OUTPUT_CAP; - engp->prinfop = &statep->ad_infop->ad_defaults->play; - engp->name = "PLAY"; - } else { - which = ASHIM_ENG_REC; - engp = ASHIM_GET_ENG(statep, which); - engp->af_eflags = ENGINE_INPUT_CAP; - engp->prinfop = &statep->ad_infop->ad_defaults->record; - engp->name = "RECORD"; - } - - mutex_init(&engp->lock, NULL, MUTEX_DRIVER, NULL); - - engp->statep = statep; - - ashim_max_fmt(statep, dir, &engp->fmt); - engp->af_fmt = ashim_af_fmt(&engp->fmt); - - af_engp = audio_engine_alloc(&ashim_engine_ops, engp->af_eflags); - if (af_engp == NULL) { - audio_dev_warn(af_devp, "audio_engine_alloc failed"); - goto OUT; - } - - engp->af_engp = af_engp; - audio_engine_set_private(af_engp, engp); - audio_dev_add_engine(af_devp, af_engp); - - engp->flags = ENG_ENABLED; - - /* - * Set the format for this engine - */ - if (ashim_set_fmt(statep, dir, &engp->fmt) != AUDIO_SUCCESS) { - audio_dev_warn(af_devp, "set format failed, dir = %d\n", dir); - goto OUT; - } - rv = AUDIO_SUCCESS; - -OUT: - if (rv != AUDIO_SUCCESS) - ashim_rem_eng(statep, engp); - - return (rv); -} - - -static int -ashim_set_config(ashim_state_t *statep, ashim_ctrl_t *ctrlp, int cmd, int dir, - int arg1, int arg2) -{ - int (*fn)(audiohdl_t, int, int, int, int) = - statep->ad_infop->ad_entry->ad_set_config; - - ddtl("%s - ashim_set_config: cmd 0x%x, dir %d, arg1 0x%x, arg2 0x%x\n", - statep->dstr, cmd, dir, arg1, arg2); - - if (fn(AUDIO_SHIMST2HDL(statep), cmd, dir, arg1, arg2) != - AUDIO_SUCCESS) { - dinfo("%s: failed update control %s " - "with cmd 0x%x, dir %d, arg1 0x%x, arg2 0x%x", - statep->dstr, ctrlp->acd.acd_name, cmd, dir, arg1, arg2); - return (EIO); - } - - return (0); -} - - -static int -ashim_ctrl_set_defaults(ashim_state_t *statep) -{ - ashim_ctrl_t *ctrlp; - int rv = AUDIO_SUCCESS; - - for (ctrlp = statep->controls; ctrlp; ctrlp = ctrlp->nextp) { - if (audio_control_write(ctrlp->af_ctrlp, ctrlp->defval)) { - dinfo("%s: setting control %s to default value " - "0x%llx failed\n", - statep->dstr, ctrlp->acd.acd_name, - (long long unsigned)ctrlp->defval); - rv = AUDIO_FAILURE; - } - } - return (rv); -} - - -static int -ashim_ctrl_restore(ashim_state_t *statep) -{ - ashim_ctrl_t *ctrlp; - int rv = AUDIO_SUCCESS; - - for (ctrlp = statep->controls; ctrlp; ctrlp = ctrlp->nextp) { - if (ctrlp->af_wr((void *)ctrlp, ctrlp->cval) != 0) { - dinfo("%s: restoring " - "control %s to value 0x%llx failed", - statep->dstr, ctrlp->acd.acd_name, - (long long unsigned)ctrlp->cval); - rv = AUDIO_FAILURE; - } - } - return (rv); -} - - -static inline void -ashim_dump_audio(ashim_eng_t *engp, void *buf, int sz) -{ - if (engp->io_count >= ashim_dump_audio_start && - engp->io_count - ashim_dump_audio_start < ashim_dump_audio_len) { - int samples = sz >> engp->smszshift; - int frames = samples >> engp->frsmshift; - - cmn_err(CE_NOTE, "\n\n======= %s - %s: REQUEST #%llu, " - "BUF I/O #%llu, SAMPLES %d (%d frames, %d bytes), " - "BUF ADDR 0x%p =======\n", - engp->statep->dstr, engp->name, - (unsigned long long)engp->io_count, - (unsigned long long)engp->bufio_count, - samples, frames, sz, buf); - - if (sz <= 0) - return; - - switch (engp->fmt.prec) { - case 8: - case 24: - audio_dump_bytes((uint8_t *)buf, sz); - break; - case 16: - audio_dump_words((uint16_t *)buf, sz >> 1); - break; - case 32: - audio_dump_dwords((uint32_t *)buf, sz >> 2); - break; - } - } -} - - -static inline void -ashim_dump_counters(ashim_eng_t *engp, unsigned frames, int bufcnt) -{ - if (engp->io_count >= ashim_dump_counters_start && - engp->io_count - ashim_dump_counters_start < - ashim_dump_counters_len) { - int samples = frames << engp->frsmshift; - int sz = samples << engp->smszshift; - - if (bufcnt >= 0) { - cmn_err(CE_CONT, "======= %s - %s: buf i/o %d of " - "REQUEST #%llu, SAMPLES %d " - "(%d frames, %d bytes)\n", - engp->statep->dstr, engp->name, bufcnt, - (unsigned long long)engp->io_count, samples, - frames, sz); - } else { - cmn_err(CE_CONT, "======= %s - %s: REQUEST #%llu, " - "SAMPLES %d (%d frames, %d bytes)\n", - engp->statep->dstr, engp->name, - (unsigned long long)engp->io_count, - samples, frames, sz); - } - } -} - - -/* - * moves data between driver buffer and framework/shim buffer - */ -static void -ashim_eng_bufio(ashim_eng_t *engp, void *buf, size_t sz) -{ - size_t cpsz = sz; - caddr_t *src, *dst, *dp; - - if (engp->af_eflags & ENGINE_OUTPUT_CAP) { - src = &engp->bufpos; - dst = (caddr_t *)&buf; - } else { - src = (caddr_t *)&buf; - dst = &engp->bufpos; - } - dp = ashim_dump_audio_bufsel ? (caddr_t *)&buf : &engp->bufpos; - - /* - * Wrap. If sz is exactly the remainder of the buffer - * (bufpos + sz == bufendp) then the second cpsz should be 0 and so - * the second memcpy() should have no effect, with bufpos updated - * to the head of the buffer. - */ - if (engp->bufpos + sz >= engp->bufendp) { - cpsz = (size_t)engp->bufendp - (size_t)engp->bufpos; - (void) memcpy(*dst, *src, cpsz); - - if (ashim_dump_audio_len) - ashim_dump_audio(engp, *dp, cpsz); - - buf = (caddr_t)buf + cpsz; - engp->bufpos = engp->bufp; - cpsz = sz - cpsz; - } - - if (cpsz) { - (void) memcpy(*dst, *src, cpsz); - - if (ashim_dump_audio_len) - ashim_dump_audio(engp, *dp, cpsz); - - engp->bufpos += cpsz; - } - engp->bufio_count++; -} - - -static void -ashim_prtstats(ashim_eng_t *engp) -{ - ashim_state_t *statep = engp->statep; - - dinfo("%s - %s: driver i/o: %llu, framework i/o: %llu, " - "frames: %llu\n", statep->dstr, engp->name, - (long long unsigned)engp->io_count, - (long long unsigned)engp->bufio_count, - (long long unsigned)engp->frames); -} - - -/* - * ************************************************************************* - * audio control routines - */ - -static uint64_t -ashim_ctrl_defval(ashim_state_t *statep, ashim_ctrl_map_t *mapp) -{ - audio_prinfo_t *play_prp = &statep->ad_infop->ad_defaults->play; - audio_prinfo_t *rec_prp = &statep->ad_infop->ad_defaults->record; - const char *cname = mapp->acd.acd_name; - uint64_t cval = 0; - uint64_t gain; - ashim_fmt_t fmt; - - if (strcmp(cname, AUDIO_CTRL_ID_VOLUME) == 0) { - ashim_max_fmt(statep, AUDIO_PLAY, &fmt); - if (fmt.ch == 0) - return (0); - - gain = D2F_GAIN(play_prp->gain); - if (fmt.ch == 1) - cval = gain; - else - cval = AUDIO_CTRL_STEREO_VAL(gain, gain); - - } else if (strcmp(cname, AUDIO_CTRL_ID_RECGAIN) == 0) { - ashim_max_fmt(statep, AUDIO_RECORD, &fmt); - if (fmt.ch == 0) - return (0); - - gain = D2F_GAIN(rec_prp->gain); - if (fmt.ch == 1) - cval = gain; - else - cval = AUDIO_CTRL_STEREO_VAL(gain, gain); - - } else if (strcmp(cname, AUDIO_CTRL_ID_MONGAIN) == 0) { - cval = D2F_GAIN(statep->ad_infop->ad_defaults->monitor_gain); - - } else if (strcmp(cname, AUDIO_CTRL_ID_MICBOOST) == 0) { - cval = 0; - - } else if (strcmp(cname, AUDIO_CTRL_ID_OUTPUTS) == 0) { - cval = play_prp->port; - - } else if (strcmp(cname, AUDIO_CTRL_ID_INPUTS) == 0) { - cval = rec_prp->port; - } - - return (cval); -} - - -static ashim_ctrl_t * -ashim_find_ctrl_dcmd(ashim_state_t *statep, int dcmd, int dir) -{ - ashim_ctrl_t *ctrlp; - - for (ctrlp = statep->controls; ctrlp != NULL; ctrlp = ctrlp->nextp) { - if (ctrlp->dcmd == dcmd && ctrlp->dir == dir) - break; - } - return (ctrlp); -} - - -/* - * control callback and related routines - */ - -static int -ashim_ctrl_gain_mutable(ashim_ctrl_t *ctrlp, int left, int right) -{ - ashim_state_t *statep = ctrlp->statep; - int gain; - - if (left == 0 && right == 0) - gain = 0; - else if (left != 0) - gain = left; - else - gain = right; - - if (ctrlp->dcmd == AM_SET_GAIN && ctrlp->dir == AUDIO_PLAY) { - /* - * mute when gain = 0, and on the transition when gain != 0 - * but do not set unmute cmds during non-zero changes - */ - if (gain == 0) { - ctrlp->flags |= CTRL_MUTED; - - if (ashim_set_config(statep, ctrlp, AM_OUTPUT_MUTE, - AUDIO_PLAY, 1, 0) != AUDIO_SUCCESS) - return (EIO); - - } else if (ctrlp->flags & CTRL_MUTED) { - ctrlp->flags &= ~CTRL_MUTED; - - if (ashim_set_config(statep, ctrlp, AM_OUTPUT_MUTE, - AUDIO_PLAY, 0, 0) != AUDIO_SUCCESS) - return (EIO); - } - } - - return (0); -} - - -/* - * control read callback - */ -static int -ashim_ctrl_rd(void *arg, uint64_t *cvalp) -{ - ashim_ctrl_t *ctrlp = arg; - - mutex_enter(&ctrlp->lock); - *cvalp = ctrlp->cval; - mutex_exit(&ctrlp->lock); - - return (0); -} - - -/* - * stereo level control callback - */ -static int -ashim_ctrl_wr_st(void *arg, uint64_t cval) -{ - ashim_ctrl_t *ctrlp = arg; - ashim_state_t *statep = ctrlp->statep; - int rv = EIO; - int left, right; - - ddtl("%s - control %s WRITE: 0x%llx\n", statep->dstr, - ctrlp->acd.acd_name, (long long unsigned)cval); - - left = AUDIO_CTRL_STEREO_LEFT(cval); - right = AUDIO_CTRL_STEREO_RIGHT(cval); - - if (left < AF_MIN_GAIN || left > AF_MAX_GAIN || - right < AF_MIN_GAIN || right > AF_MAX_GAIN) { - dinfo("%s - control %s invalid value: 0x%llx\n", statep->dstr, - ctrlp->acd.acd_name, (long long unsigned)cval); - return (EINVAL); - } - - mutex_enter(&ctrlp->lock); - ctrlp->cval = cval; - - left = F2D_GAIN(left); - right = F2D_GAIN(right); - - if (ashim_set_config(statep, ctrlp, ctrlp->dcmd, ctrlp->dir, left, - 0) != AUDIO_SUCCESS) - goto OUT; - - if (ashim_set_config(statep, ctrlp, ctrlp->dcmd, ctrlp->dir, right, - 1) != AUDIO_SUCCESS) { - /* restore previous left gain value */ - (void) ashim_set_config(statep, ctrlp, ctrlp->dcmd, ctrlp->dir, - left, 0); - goto OUT; - } - - rv = ashim_ctrl_gain_mutable(ctrlp, left, right); - -OUT: - mutex_exit(&ctrlp->lock); - return (ashim_ctrl_ignore_errors ? 0 : rv); -} - - -/* - * mono level control callback - */ -static int -ashim_ctrl_wr_mn(void *arg, uint64_t cval) -{ - ashim_ctrl_t *ctrlp = arg; - ashim_state_t *statep = ctrlp->statep; - int rv = EIO; - int gain; - - ddtl("%s - control %s WRITE: 0x%llx\n", statep->dstr, - ctrlp->acd.acd_name, (long long unsigned)cval); - - if (cval < (uint64_t)AF_MIN_GAIN || cval > (uint64_t)AF_MAX_GAIN) { - dinfo("%s - control %s invalid value: 0x%llx\n", statep->dstr, - ctrlp->acd.acd_name, (long long unsigned)cval); - return (EINVAL); - } - - mutex_enter(&ctrlp->lock); - ctrlp->cval = cval; - - gain = (int)F2D_GAIN(cval); - - if (ashim_set_config(statep, ctrlp, ctrlp->dcmd, ctrlp->dir, - gain, 0) != AUDIO_SUCCESS) - goto OUT; - - rv = ashim_ctrl_gain_mutable(ctrlp, gain, 0); - -OUT: - mutex_exit(&ctrlp->lock); - return (ashim_ctrl_ignore_errors ? 0 : rv); -} - - -/* - * boolean control callback - */ -/*ARGSUSED*/ -static int -ashim_ctrl_wr_bool(void *arg, uint64_t cval) -{ - ashim_ctrl_t *ctrlp = arg; - ashim_state_t *statep = ctrlp->statep; - int rv = EIO; - - ddtl("%s - control %s WRITE: 0x%llx\n", statep->dstr, - ctrlp->acd.acd_name, (long long unsigned)cval); - - mutex_enter(&ctrlp->lock); - ctrlp->cval = cval; - - if (ashim_set_config(statep, ctrlp, ctrlp->dcmd, ctrlp->dir, - (int)cval, 0) != AUDIO_SUCCESS) - goto OUT; - - rv = 0; - -OUT: - mutex_exit(&ctrlp->lock); - return (ashim_ctrl_ignore_errors ? 0 : rv); -} - - -/* - * port selection control callback - */ -static int -ashim_ctrl_wr_ports(void *arg, uint64_t cval) -{ - ashim_ctrl_t *ctrlp = arg; - ashim_state_t *statep = ctrlp->statep; - int rv = EIO; - int dports = cval & 0xff; - - ddtl("%s - control %s WRITE: 0x%llx\n", statep->dstr, - ctrlp->acd.acd_name, (long long unsigned)cval); - - if ((cval & ~ctrlp->acd.acd_minvalue) != - (ctrlp->acd.acd_maxvalue & ~ctrlp->acd.acd_minvalue)) { - dinfo("%s - control %s invalid value: 0x%llx\n", statep->dstr, - ctrlp->acd.acd_name, (long long unsigned)cval); - return (EINVAL); - } - - mutex_enter(&ctrlp->lock); - ctrlp->cval = cval; - - if (ashim_set_config(statep, ctrlp, ctrlp->dcmd, ctrlp->dir, dports, - 0) != AUDIO_SUCCESS) - goto OUT; - - rv = 0; - -OUT: - mutex_exit(&ctrlp->lock); - return (ashim_ctrl_ignore_errors ? 0 : rv); -} - - -/* - * audio control registration related routines - */ - -static ashim_ctrl_t * -ashim_ctrl_alloc(void) -{ - return (kmem_zalloc(sizeof (ashim_ctrl_t), KM_SLEEP)); -} - - -static void -ashim_ctrl_free(ashim_ctrl_t *ctrlp) -{ - kmem_free(ctrlp, sizeof (ashim_ctrl_t)); -} - - -static void -ashim_ctrl_insert(ashim_state_t *statep, ashim_ctrl_t *ctrlp) -{ - ctrlp->nextp = statep->controls; - statep->controls = ctrlp; -} - - -/* - * returns the amount of modifiable ports - */ -static int -ashim_ctrl_init_ports(ashim_state_t *statep, ashim_ctrl_t *ctrlp) -{ - audio_prinfo_t *prp; - ashim_port_map_t *pmap; - int pmaplen; - int i; - int count = 0; - - if (ctrlp->dir == AUDIO_PLAY) { - prp = &statep->ad_infop->ad_defaults->play; - pmap = ashim_play_pmap; - pmaplen = ashim_play_pmap_len; - } else { - prp = &statep->ad_infop->ad_defaults->record; - pmap = ashim_rec_pmap; - pmaplen = ashim_rec_pmap_len; - } - - /* - * look at all SADA supported ports then set the corresponding - * framework defined bits in the control description if the driver - * informs us that it is present (avail_ports) and if it can be - * toggled on/off (mod_ports) - */ - for (i = 0; i < pmaplen; i++) { - ctrlp->acd.acd_enum[i] = pmap[i].pname; - - if (pmap[i].dport & prp->avail_ports) { - ctrlp->acd.acd_maxvalue |= pmap[i].dport; - - dinfo("%s: available port: " - "driver 0x%x, framework 0x%s\n", - statep->dstr, pmap[i].dport, pmap[i].pname); - } - if (pmap[i].dport & prp->mod_ports) { - ctrlp->acd.acd_minvalue |= pmap[i].dport; - - dinfo("%s: modifiable port: " - "(driver 0x%x, framework %s)\n", - statep->dstr, pmap[i].dport, pmap[i].pname); - - count++; - } - } - - return (count); -} - - -static void -ashim_ctrl_fini(ashim_ctrl_t *ctrlp) -{ - mutex_destroy(&ctrlp->lock); -} - - -/* - * returns 0 if initialization is successful; failure to initialize is - * not fatal so caller should deallocate and continue on to the next control - */ -static int -ashim_ctrl_init(ashim_state_t *statep, ashim_ctrl_t *ctrlp, - ashim_ctrl_map_t *mapp) -{ - ctrlp->dcmd = mapp->dcmd; - ctrlp->dir = mapp->dir; - ctrlp->acd = mapp->acd; - ctrlp->af_ctrlp = NULL; - ctrlp->defval = ashim_ctrl_defval(statep, mapp); - ctrlp->cval = ctrlp->defval; - ctrlp->af_wr = mapp->af_wr; - ctrlp->statep = statep; - - if (mapp->acd.acd_type == AUDIO_CTRL_TYPE_ENUM && - ashim_ctrl_init_ports(statep, ctrlp) <= 1) { - dinfo("%s: no more than one modifiable port detected for " - "control %s, enabling and skipping\n", - statep->dstr, ctrlp->acd.acd_name); - - (void) ctrlp->af_wr((void *)ctrlp, ctrlp->defval); - return (1); - } - - mutex_init(&ctrlp->lock, NULL, MUTEX_DRIVER, NULL); - return (0); -} - - -/* - * heuristic to determine if a control is actually present by writing the - * default value and checking if the operation succeeds - */ -/*ARGSUSED*/ -static int -ashim_ctrl_test(ashim_state_t *statep, ashim_ctrl_t *ctrlp) -{ - return (ctrlp->af_wr((void *)ctrlp, ctrlp->defval)); -} - - -static void -ashim_rem_controls(ashim_state_t *statep) -{ - ashim_ctrl_t *ctrlp = statep->controls; - ashim_ctrl_t *nextp; - - while (ctrlp != NULL) { - if (ctrlp->af_ctrlp != NULL) - audio_dev_del_control(ctrlp->af_ctrlp); - - nextp = ctrlp->nextp; - ashim_ctrl_fini(ctrlp); - ashim_ctrl_free(ctrlp); - ctrlp = nextp; - } - - /* required */ - statep->controls = NULL; -} - - -static int -ashim_add_controls(ashim_state_t *statep) -{ - int rv = AUDIO_FAILURE; - int i; - ashim_ctrl_map_t *mapp; - ashim_ctrl_t *ctrlp; - audio_ctrl_t *af_ctrlp; - ashim_fmt_t playfmt = {0}; - ashim_fmt_t recfmt = {0}; - ashim_fmt_t *fmtp; - int ad_feat = statep->ad_infop->ad_defaults->hw_features; - - if (ad_feat & AUDIO_HWFEATURE_PLAY) - ashim_max_fmt(statep, AUDIO_PLAY, &playfmt); - - if (ad_feat & AUDIO_HWFEATURE_RECORD) - ashim_max_fmt(statep, AUDIO_RECORD, &recfmt); - - for (i = 0; i < ashim_ctrl_map_len; i++) { - mapp = &ashim_ctrl_map[i]; - fmtp = NULL; - - if (mapp->dir == AUDIO_PLAY) { - if (!(ad_feat & AUDIO_HWFEATURE_PLAY)) - continue; - - fmtp = &playfmt; - } - if (mapp->dir == AUDIO_RECORD) { - if (!(ad_feat & AUDIO_HWFEATURE_RECORD)) - continue; - - fmtp = &recfmt; - } - - if (mapp->dcmd == AM_SET_GAIN) { - if (fmtp->ch == 0) - continue; - - if (mapp->acd.acd_type == AUDIO_CTRL_TYPE_MONO && - fmtp->ch != 1) - continue; - - if (mapp->acd.acd_type == AUDIO_CTRL_TYPE_STEREO && - fmtp->ch != 2) - continue; - } - - ctrlp = ashim_ctrl_alloc(); - - if (ashim_ctrl_init(statep, ctrlp, mapp)) { - ashim_ctrl_free(ctrlp); - continue; - } - - if (ashim_ctrl_test(statep, ctrlp)) { - dwarn("%s: i= %d, control %s tested invalid\n", - statep->dstr, i, ctrlp->acd.acd_name); - - ashim_ctrl_fini(ctrlp); - ashim_ctrl_free(ctrlp); - continue; - } - - af_ctrlp = audio_dev_add_control(statep->af_devp, &ctrlp->acd, - mapp->af_rd, mapp->af_wr, (void *)ctrlp); - - if (af_ctrlp == NULL) { - audio_dev_warn(statep->af_devp, "failed to add " - "control %s", ctrlp->acd.acd_name); - ashim_ctrl_fini(ctrlp); - ashim_ctrl_free(ctrlp); - goto OUT; - } - - dinfo("%s: added control %s, type: %d, " - "flags: 0x%x, min: 0x%llx, max: 0x%llx, default: 0x%llx\n", - statep->dstr, ctrlp->acd.acd_name, ctrlp->acd.acd_type, - ctrlp->acd.acd_flags, - ctrlp->acd.acd_minvalue, ctrlp->acd.acd_maxvalue, - ctrlp->defval); - - ctrlp->af_ctrlp = af_ctrlp; - ashim_ctrl_insert(statep, ctrlp); - } - - rv = AUDIO_SUCCESS; - -OUT: - if (rv != AUDIO_SUCCESS) - ashim_rem_controls(statep); - return (rv); -} - - -/* - * ************************************************************************** - * replacements for SADA framework interfaces - */ - -void * -audio_sup_get_private(audiohdl_t handle) -{ - return (AUDIO_HDL2SHIMST(handle)->private); -} - - -void -audio_sup_set_private(audiohdl_t handle, void *private) -{ - AUDIO_HDL2SHIMST(handle)->private = private; -} - - -int -audio_sup_unregister(audiohdl_t handle) -{ - ashim_state_t *statep; - - if (handle == NULL) - return (AUDIO_SUCCESS); - - statep = AUDIO_HDL2SHIMST(handle); - - kmem_free(statep, sizeof (*statep)); - return (AUDIO_SUCCESS); -} - - -audiohdl_t -audio_sup_register(dev_info_t *dip) -{ - ashim_state_t *statep = NULL; - int inst; - const char *nm; - - statep = kmem_zalloc(sizeof (*statep), KM_SLEEP); - statep->dip = dip; - - inst = ddi_get_instance(dip); - nm = ddi_driver_name(dip); - - (void) snprintf(statep->dstr, sizeof (statep->dstr), - "%s#%d", nm, inst); - - return (AUDIO_SHIMST2HDL(statep)); -} - - -int -am_unregister(audiohdl_t handle) -{ - ashim_state_t *statep = AUDIO_HDL2SHIMST(handle); - - if (statep->af_devp == NULL) - return (AUDIO_SUCCESS); - - if (statep->flags & AF_REGISTERED) { - if (audio_dev_unregister(statep->af_devp) != DDI_SUCCESS) { - dwarn("%s: am_unregister: audio_dev_unregister() " - "failed\n", statep->dstr); - - return (AUDIO_FAILURE); - } - statep->flags &= ~AF_REGISTERED; - } - - return (AUDIO_SUCCESS); -} - - -/*ARGSUSED*/ -int -am_detach(audiohdl_t handle, ddi_detach_cmd_t cmd) -{ - ashim_state_t *statep = AUDIO_HDL2SHIMST(handle); - int i; - - if (statep == NULL) - return (AUDIO_SUCCESS); - - if (statep->af_devp == NULL) - return (AUDIO_SUCCESS); - - if ((statep->flags & AF_REGISTERED) && - audio_dev_unregister(statep->af_devp) != DDI_SUCCESS) { - dwarn("%s: am_detach: audio_dev_unregister() failed\n", - statep->dstr); - return (AUDIO_FAILURE); - } - statep->flags &= ~AF_REGISTERED; - - for (i = 0; i < ASHIM_ENG_MAX; i++) - ashim_rem_eng(statep, &statep->engines[i]); - - if (statep->controls != NULL) - ashim_rem_controls(statep); - - audio_dev_free(statep->af_devp); - statep->af_devp = NULL; - - return (AUDIO_SUCCESS); -} - - -int -am_attach(audiohdl_t handle, ddi_attach_cmd_t cmd, - am_ad_info_t *ad_infop) -{ - ashim_state_t *statep = AUDIO_HDL2SHIMST(handle); - audio_dev_t *af_devp; - int ad_feat = ad_infop->ad_defaults->hw_features; - int rv = AUDIO_FAILURE; - - if (cmd != DDI_ATTACH) - return (AUDIO_FAILURE); - - af_devp = audio_dev_alloc(statep->dip, 0); - audio_dev_set_description(af_devp, ad_infop->ad_dev_info->name); - audio_dev_set_version(af_devp, ad_infop->ad_dev_info->version); - - statep->af_devp = af_devp; - statep->ad_infop = ad_infop; - - - /* - * If the device supports both play and record we require duplex - * functionality. However, there are no known simplex SADA devices. - * In this case we limit the device to play only. - */ - if ((ad_feat & AUDIO_HWFEATURE_PLAY) && - (ad_feat & AUDIO_HWFEATURE_RECORD) && - !(ad_feat & AUDIO_HWFEATURE_DUPLEX)) { - audio_dev_warn(af_devp, "missing duplex feature " - "required for record"); - - ad_feat &= ~AUDIO_HWFEATURE_RECORD; - ad_infop->ad_defaults->hw_features = ad_feat; - } - - if (ad_feat & AUDIO_HWFEATURE_PLAY) { - if (ashim_add_eng(statep, AUDIO_PLAY) != AUDIO_SUCCESS) - goto OUT; - } - if (ad_feat & AUDIO_HWFEATURE_RECORD) { - if (ashim_add_eng(statep, AUDIO_RECORD) != AUDIO_SUCCESS) - goto OUT; - } - - if (ashim_add_controls(statep) != AUDIO_SUCCESS) - goto OUT; - - if (ashim_ctrl_set_defaults(statep) != AUDIO_SUCCESS) - goto OUT; - - if (audio_dev_register(af_devp) != DDI_SUCCESS) { - audio_dev_warn(af_devp, "audio_dev_register() failed"); - goto OUT; - } - statep->flags |= AF_REGISTERED; - - rv = AUDIO_SUCCESS; - -OUT: - if (rv != AUDIO_SUCCESS) - (void) am_detach(handle, DDI_DETACH); - return (rv); -} - - -int -am_get_audio(audiohdl_t handle, void *buf, int samples) -{ - ashim_state_t *statep = AUDIO_HDL2SHIMST(handle); - ashim_eng_t *engp = ASHIM_GET_ENG(statep, ASHIM_ENG_PLAY); - unsigned reqframes = samples >> engp->frsmshift; - unsigned frames; - unsigned i; - size_t sz; - int bufcnt = 0; - caddr_t bp = buf; - - mutex_enter(&engp->lock); - if (ashim_dump_counters_len) - ashim_dump_counters(engp, reqframes, -1); - - if (!(engp->flags & ENG_STARTED)) { - ddtl("%s - am_get_audio: stop in progress, ignoring\n", - statep->dstr); - mutex_exit(&engp->lock); - return (0); - } - mutex_exit(&engp->lock); - - /* break requests from the driver into fragment sized chunks */ - for (i = 0; i < reqframes; i += frames) { - mutex_enter(&engp->lock); - - frames = reqframes - i; - if (frames > engp->fragfr) - frames = engp->fragfr; - - sz = (frames << engp->frsmshift) << engp->smszshift; - - if (ashim_dump_counters_len) { - ashim_dump_counters(engp, frames, bufcnt); - } - bufcnt++; - - /* must move data before updating framework */ - ashim_eng_bufio(engp, bp, sz); - engp->frames += frames; - bp += sz; - - mutex_exit(&engp->lock); - audio_engine_consume(engp->af_engp); - } - - mutex_enter(&engp->lock); - engp->io_count++; - mutex_exit(&engp->lock); - - return (samples); -} - - -void -am_play_shutdown(audiohdl_t handle) -{ - - ashim_state_t *statep = AUDIO_HDL2SHIMST(handle); - am_ad_entry_t *ad_entry = statep->ad_infop->ad_entry; - - ad_entry->ad_stop_play(handle); - - /* - * XXX - * used to notify framework that device's engine has stopped - */ -} - - -void -am_send_audio(audiohdl_t handle, void *buf, int samples) -{ - ashim_state_t *statep = AUDIO_HDL2SHIMST(handle); - ashim_eng_t *engp = ASHIM_GET_ENG(statep, ASHIM_ENG_REC); - unsigned reqframes = samples >> engp->frsmshift; - unsigned frames; - unsigned i; - size_t sz; - int bufcnt = 0; - caddr_t bp = buf; - - mutex_enter(&engp->lock); - if (ashim_dump_counters_len) - ashim_dump_counters(engp, reqframes, -1); - - if (!(engp->flags & ENG_STARTED)) { - ddtl("%s - am_send_audio: stop in progress, ignoring\n", - statep->dstr); - - mutex_exit(&engp->lock); - return; - } - mutex_exit(&engp->lock); - - /* break requests from the driver into fragment sized chunks */ - for (i = 0; i < reqframes; i += frames) { - mutex_enter(&engp->lock); - - frames = reqframes - i; - if (frames > engp->fragfr) - frames = engp->fragfr; - - sz = (frames << engp->frsmshift) << engp->smszshift; - - if (ashim_dump_counters_len) - ashim_dump_counters(engp, frames, bufcnt); - bufcnt++; - - /* must move data before updating framework */ - ashim_eng_bufio(engp, bp, sz); - engp->frames += frames; - bp += sz; - - mutex_exit(&engp->lock); - audio_engine_produce(engp->af_engp); - } - - mutex_enter(&engp->lock); - engp->io_count++; - mutex_exit(&engp->lock); -} - -void -audio_sup_restore_state(audiohdl_t handle) -{ - ashim_state_t *statep = AUDIO_HDL2SHIMST(handle); - ashim_eng_t *engp; - int i; - int start = 0; - - (void) ashim_ctrl_restore(statep); - - for (i = 0; i < ASHIM_ENG_MAX; i++) { - engp = &statep->engines[i]; - if (engp->af_engp == NULL) - continue; - start = (engp->flags & ENG_STARTED); - - if (start) - (void) ashim_eng_start(engp); - } -} - - -/* - * ************************************************************************** - * audio framework engine callbacks - */ - -/*ARGSUSED*/ -static int -ashim_af_open(void *arg, int flag, - unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp) -{ - ashim_eng_t *engp = (ashim_eng_t *)arg; - ashim_state_t *statep = engp->statep; - int rv = EIO; - int dir = ASHIM_ENG_DIR(engp); - - - if (usb_ac_open(statep->dip) != AUDIO_SUCCESS) { - audio_dev_warn(statep->af_devp, "usb_ac_open failed"); - return (EIO); - } - - mutex_enter(&engp->lock); - - - engp->intrate = (engp->af_eflags & ENGINE_OUTPUT_CAP) ? - statep->ad_infop->ad_play.ad_int_rate : - statep->ad_infop->ad_record.ad_int_rate; - - engp->sampsz = engp->fmt.prec / 8; - engp->framesz = engp->sampsz * engp->fmt.ch; - - if (engp->fmt.ch > 2) { - audio_dev_warn(statep->af_devp, "unsupported ", - "channel count: %u", engp->fmt.ch); - goto OUT; - } - if (engp->fmt.prec > 16) { - audio_dev_warn(statep->af_devp, "unsupported ", - "precision: %u", engp->fmt.prec); - goto OUT; - } - - engp->frsmshift = engp->fmt.ch / 2; - engp->smszshift = engp->sampsz / 2; - - /* - * In order to match the requested number of samples per interrupt - * from SADA drivers when computing the fragment size, - * we need to first truncate the floating point result from - * sample rate * channels / intr rate - * then adjust up to an even number, before multiplying it - * with the sample size - */ - engp->fragsz = engp->fmt.sr * engp->fmt.ch / engp->intrate; - if (engp->fragsz & 1) - engp->fragsz++; - engp->fragsz *= engp->sampsz; - engp->fragfr = engp->fragsz / engp->framesz; - - if (ashim_use_drvbuf) { - engp->bufsz = ((engp)->af_eflags & ENGINE_OUTPUT_CAP) ? - statep->ad_infop->ad_play.ad_bsize : - statep->ad_infop->ad_record.ad_bsize; - - engp->nfrags = engp->bufsz / engp->fragsz; - - /* adjust buf size to frag boundary */ - if (engp->nfrags * engp->fragsz < engp->bufsz) - engp->nfrags++; - - engp->bufsz = engp->nfrags * engp->fragsz; - } else { - if (ashim_bufscale < ASHIM_BUFSCALE_MIN || - ashim_bufscale > ASHIM_BUFSCALE_MAX) - engp->nfrags = ASHIM_BUFSCALE_DEF; - else - engp->nfrags = ashim_bufscale; - engp->bufsz = engp->fragsz * engp->nfrags; - } - - engp->bufp = kmem_zalloc(engp->bufsz, KM_SLEEP); - engp->bufpos = engp->bufp; - engp->bufendp = engp->bufp + engp->bufsz; - engp->frames = 0; - engp->io_count = 0; - engp->bufio_count = 0; - - *fragfrp = engp->fragfr; - *nfragsp = engp->nfrags; - *bufp = engp->bufp; - - if (ashim_ad_setup(statep, dir) != AUDIO_SUCCESS) { - audio_dev_warn(statep->af_devp, "device setup failed"); - goto OUT; - } - statep->flags |= AD_SETUP; - - rv = 0; - - dinfo("%s - %s: " - "frames per frag: %u, frags in buffer: %u, frag size: %u, " - "intr rate: %u, buffer size: %u, buffer: 0x%p - 0x%p\n", - statep->dstr, engp->name, - *fragfrp, *nfragsp, engp->fragsz, - engp->intrate, engp->bufsz, *bufp, engp->bufendp); - -OUT: - mutex_exit(&engp->lock); - if (rv != 0) - ashim_af_close(arg); - - return (rv); -} - - -static void -ashim_af_close(void *arg) -{ - ashim_eng_t *engp = (ashim_eng_t *)arg; - ashim_state_t *statep = engp->statep; - - mutex_enter(&engp->lock); - - if (statep->flags & AD_SETUP) { - ashim_ad_teardown(statep, ASHIM_ENG_DIR(engp)); - statep->flags &= ~AD_SETUP; - } - - if (engp->bufp != NULL) { - kmem_free(engp->bufp, engp->bufsz); - engp->bufp = NULL; - engp->bufpos = NULL; - engp->bufendp = NULL; - } - - ashim_prtstats(engp); - mutex_exit(&engp->lock); - - usb_ac_close(statep->dip); -} - - -static int -ashim_eng_start(ashim_eng_t *engp) -{ - ashim_state_t *statep = engp->statep; - am_ad_entry_t *ad_entry = statep->ad_infop->ad_entry; - int (*start)(audiohdl_t); - int rv = 0; - - start = ((engp)->af_eflags & ENGINE_OUTPUT_CAP) ? - ad_entry->ad_start_play : ad_entry->ad_start_record; - - dinfo("%s: starting device %s engine\n", statep->dstr, engp->name); - - if ((*start)(AUDIO_SHIMST2HDL(statep)) != AUDIO_SUCCESS) { - audio_dev_warn(statep->af_devp, "failed to start %s engine", - engp->name); - rv = EIO; - } - - return (rv); -} - - -static void -ashim_eng_stop(ashim_eng_t *engp) -{ - ashim_state_t *statep = engp->statep; - am_ad_entry_t *ad_entry = statep->ad_infop->ad_entry; - void (*stop)(audiohdl_t); - - stop = ((engp)->af_eflags & ENGINE_OUTPUT_CAP) ? - ad_entry->ad_stop_play : ad_entry->ad_stop_record; - - dinfo("%s: stopping device %s engine\n", statep->dstr, engp->name); - - (*stop)(AUDIO_SHIMST2HDL(statep)); -} - - -static int -ashim_af_start(void *arg) -{ - ashim_eng_t *engp = (ashim_eng_t *)arg; - int rv = EIO; - - if (ashim_eng_disable) - return (rv); - - mutex_enter(&engp->lock); - engp->flags |= ENG_STARTED; - mutex_exit(&engp->lock); - - rv = ashim_eng_start(engp); - - return (rv); -} - - -static void -ashim_af_stop(void *arg) -{ - ashim_eng_t *engp = (ashim_eng_t *)arg; - - mutex_enter(&engp->lock); - engp->flags &= ~ENG_STARTED; - mutex_exit(&engp->lock); - - ashim_eng_stop(engp); -} - - -static uint64_t -ashim_af_count(void *arg) -{ - ashim_eng_t *engp = arg; - uint64_t val; - - mutex_enter(&engp->lock); - val = engp->frames; - mutex_exit(&engp->lock); - - return (val); -} - - -static int -ashim_af_format(void *arg) -{ - ashim_eng_t *engp = arg; - - return (engp->af_fmt); -} - -static int -ashim_af_channels(void *arg) -{ - ashim_eng_t *engp = arg; - - return (engp->fmt.ch); -} - - -static int -ashim_af_rate(void *arg) -{ - ashim_eng_t *engp = arg; - - return (engp->fmt.sr); -} - - -/*ARGSUSED*/ -static void -ashim_af_sync(void *arg, unsigned nframes) -{ - /* - * drivers will call ddi_dma_sync() themselves after requesting data - * on playback and before sending data on record through the shim - */ -} - - -static size_t -ashim_af_qlen(void *arg) -{ - ashim_eng_t *engp = (ashim_eng_t *)arg; - - return (engp->fragfr); -} - - -/* - * ************************************************************************** - * interfaces used by USB audio - */ - -/*ARGSUSED*/ -int -am_hw_state_change(audiohdl_t handle, int cmd, int dir, int value, - int sleep) -{ - ashim_state_t *statep = AUDIO_HDL2SHIMST(handle); - ashim_ctrl_t *ctrlp; - uint64_t cval = 0; - int64_t left, right, delta = 0; - int dcmd = AM_SET_GAIN; - - /* only known HWSC command used */ - if (cmd != AM_HWSC_SET_GAIN_DELTA) { - audio_dev_warn(statep->af_devp, "invalid HW state change " - "command recieved"); - return (AUDIO_FAILURE); - } - - ctrlp = ashim_find_ctrl_dcmd(statep, dcmd, dir); - if (ctrlp == NULL) { - audio_dev_warn(statep->af_devp, "driver control command %d " - "not found for HW state change command %d", dcmd, cmd); - return (AUDIO_FAILURE); - } - ASSERT(value != 0); - - mutex_enter(&ctrlp->lock); - - delta = D2F_GAIN(value); - - /* - * Value got from device can be scaled to 0, - * set the delta to -1 or 1. - */ - if (delta == 0) { - delta = (value < 0)?-1:1; - } - left = AUDIO_CTRL_STEREO_LEFT(ctrlp->cval) + delta; - right = AUDIO_CTRL_STEREO_RIGHT(ctrlp->cval) + delta; - - if (left > AF_MAX_GAIN) - left = AF_MAX_GAIN; - if (right > AF_MAX_GAIN) - right = AF_MAX_GAIN; - - if (left < AF_MIN_GAIN) - left = AF_MIN_GAIN; - if (right < AF_MIN_GAIN) - right = AF_MIN_GAIN; - - cval = AUDIO_CTRL_STEREO_VAL(left, right); - mutex_exit(&ctrlp->lock); - - if (audio_control_write(ctrlp->af_ctrlp, cval)) { - audio_dev_warn(statep->af_devp, "updating " - "control %s to value 0x%llx by driver failed", - ctrlp->acd.acd_name, (long long unsigned)cval); - return (AUDIO_FAILURE); - } - return (AUDIO_SUCCESS); -} diff --git a/usr/src/uts/common/io/usb/clients/audio/usb_ac/audio_shim.h b/usr/src/uts/common/io/usb/clients/audio/usb_ac/audio_shim.h deleted file mode 100644 index 6f73d61091..0000000000 --- a/usr/src/uts/common/io/usb/clients/audio/usb_ac/audio_shim.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - - -#ifndef _AUDIO_SHIM_H -#define _AUDIO_SHIM_H - -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/audio.h> -#include <sys/audio/audio_support.h> -#include <sys/mixer.h> -#include <sys/audio/audio_mixer.h> - -#include <sys/audio/audio_driver.h> - -#ifdef __cplusplus -extern "C" { -#endif - - -typedef enum {DBG_WARN = 1, DBG_INFO, DBG_DETAIL} debug_level_t; - -int am_unregister(audiohdl_t handle); - -#define CTRL_MUTED 0x1 /* muted output gain */ - -#define TQ_NM_MAX 64 -#define DSTR_MAX 64 - -typedef struct ashim_config_arg ashim_config_arg_t; -typedef struct ashim_ctrl ashim_ctrl_t; -typedef struct ashim_fmt ashim_fmt_t; -typedef struct ashim_eng ashim_eng_t; -typedef struct ashim_state ashim_state_t; - -struct ashim_config_arg { - int cmd; - int dir; - int arg1; - int arg2; -}; - -struct ashim_ctrl { - int dcmd; /* SADA command */ - int dir; /* play or record */ - audio_ctrl_desc_t acd; /* description */ - audio_ctrl_t *af_ctrlp; /* framework handle */ - uint64_t cval; /* current control value */ - uint64_t defval; /* default control value */ - audio_ctrl_wr_t af_wr; /* write callback */ - - int flags; /* CTRL_XXX flags */ - kmutex_t lock; - - ashim_state_t *statep; - ashim_ctrl_t *nextp; -}; - -struct ashim_fmt { - int sr; /* sample rate */ - uint_t ch; /* channels */ - uint_t prec; /* precision */ - uint_t enc; /* encoding */ -}; - -struct ashim_eng { - ashim_state_t *statep; - audio_engine_t *af_engp; - int af_eflags; /* ENGINE_* flags */ - int af_fmt; /* AUDIO_FORMAT_* flags */ - ashim_fmt_t fmt; - - unsigned intrate; /* interrupt rate */ - unsigned sampsz; /* sample size */ - unsigned framesz; /* frame size */ - unsigned fragsz; /* fragment size */ - unsigned nfrags; /* number of fragments in buffer */ - unsigned fragfr; /* number of frames per fragment */ - unsigned frsmshift; /* right shift: frames in sample cnt */ - unsigned smszshift; /* left shift: sample cnt * sampsz */ - - caddr_t bufp; /* I/O buf; framework to/from drv */ - unsigned bufsz; /* buffer size */ - caddr_t bufpos; /* buffer position */ - caddr_t bufendp; /* end of buffer */ - - audio_prinfo_t *prinfop; /* SADA ad_defaults play/record */ - - uint64_t frames; /* total frames processed since open */ - uint64_t io_count; /* i/o requests from the driver */ - uint64_t bufio_count; /* i/o requests to the framework */ - char *name; - -#define ENG_STARTED 0x1 -#define ENG_ENABLED 0x10 - int flags; - - kmutex_t lock; -}; - -struct ashim_state { - dev_info_t *dip; - void *private; /* private audio driver data */ - audio_dev_t *af_devp; - am_ad_info_t *ad_infop; - -#define ASHIM_ENG_MAX 2 - ashim_eng_t engines[ASHIM_ENG_MAX]; - - ashim_ctrl_t *controls; - - char *devnm; - char dstr[DSTR_MAX]; - -#define AF_REGISTERED 0x1 -#define AD_SETUP 0x10 - int flags; -}; - -/* - * Macros used to convert between audio handles and the shim state structure. - */ -#define AUDIO_HDL2SHIMST(hdl) ((ashim_state_t *)(hdl)) -#define AUDIO_SHIMST2HDL(statep) ((audiohdl_t)(statep)) - - -#ifdef __cplusplus -} -#endif - -#endif /* _AUDIO_SHIM_H */ diff --git a/usr/src/uts/common/io/usb/clients/audio/usb_ac/usb_ac.c b/usr/src/uts/common/io/usb/clients/audio/usb_ac/usb_ac.c index 05b29cffb9..be6d8d1b28 100644 --- a/usr/src/uts/common/io/usb/clients/audio/usb_ac/usb_ac.c +++ b/usr/src/uts/common/io/usb/clients/audio/usb_ac/usb_ac.c @@ -25,12 +25,6 @@ /* * AUDIO CONTROL Driver: - * This driver is derived from the legacy SADA streams-based usb_ac driver - * and serves as an intermediate measure before the full conversion to the - * to the Boomer framework in a follow-on phase of the Boomer project, which - * will utilize more comprehensive USB audio features as well. Multiplexor - * plumbing functionality that used to be in the usb_ac_dacf DACF module is - * now located here. * * usb_ac is a multiplexor that sits on top of usb_as and hid and is * responsible for (1) providing the entry points to audio mixer framework, @@ -65,19 +59,14 @@ */ #include <sys/usb/usba/usbai_version.h> #include <sys/usb/usba.h> -#include <sys/stropts.h> #include <sys/sunndi.h> -#include <sys/ndi_impldefs.h> #include <sys/strsubr.h> #include <sys/strsun.h> #include <sys/ddi.h> #include <sys/sunddi.h> #include <sys/sunldi.h> -#include <sys/audio.h> -#include <sys/audio/audio_support.h> -#include <sys/mixer.h> -#include <sys/audio/audio_mixer.h> +#include <sys/audio/audio_driver.h> #include <sys/usb/clients/audio/usb_audio.h> #include <sys/usb/clients/audio/usb_mixer.h> @@ -87,7 +76,6 @@ #include <sys/usb/clients/hid/hidminor.h> #include <sys/usb/clients/audio/usb_as/usb_as.h> -#include "audio_shim.h" /* debug support */ uint_t usb_ac_errlevel = USB_LOG_L4; @@ -102,46 +90,68 @@ uint_t usb_ac_wait_hid = 1; /* * table for converting term types of input and output terminals - * to SADA port types (pretty rough mapping) + * to OSS port types (pretty rough mapping) */ +static const char *usb_audio_dtypes[] = { + AUDIO_PORT_LINEIN, + AUDIO_PORT_LINEOUT, + AUDIO_PORT_SPEAKER, + AUDIO_PORT_HEADPHONES, + AUDIO_PORT_HANDSET, + AUDIO_PORT_CD, + AUDIO_PORT_MIC, + AUDIO_PORT_PHONE, + AUDIO_PORT_SPDIFIN, + AUDIO_PORT_OTHER, + NULL, +}; +enum { + USB_PORT_LINEIN = 0, + USB_PORT_LINEOUT, + USB_PORT_SPEAKER, + USB_PORT_HEADPHONES, + USB_PORT_HANDSET, + USB_PORT_CD, + USB_PORT_MIC, + USB_PORT_PHONE, + USB_PORT_SPDIFIN, + USB_PORT_UNKNOWN +}; + static struct { ushort_t term_type; - ushort_t port_type; + uint_t port_type; } usb_ac_term_type_map[] = { -{ USB_AUDIO_TERM_TYPE_STREAMING, AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_MICROPHONE, AUDIO_MICROPHONE }, -{ USB_AUDIO_TERM_TYPE_DT_MICROPHONE, AUDIO_MICROPHONE }, -{ USB_AUDIO_TERM_TYPE_PERS_MICROPHONE, AUDIO_MICROPHONE }, -{ USB_AUDIO_TERM_TYPE_OMNI_DIR_MICROPHONE, AUDIO_MICROPHONE }, -{ USB_AUDIO_TERM_TYPE_MICROPHONE_ARRAY, AUDIO_MICROPHONE }, -{ USB_AUDIO_TERM_TYPE_PROCESSING_MIC_ARRAY, AUDIO_MICROPHONE }, -{ USB_AUDIO_TERM_TYPE_SPEAKER, AUDIO_SPEAKER }, -{ USB_AUDIO_TERM_TYPE_HEADPHONES, AUDIO_HEADPHONE }, -{ USB_AUDIO_TERM_TYPE_DISPLAY_AUDIO, AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_DT_SPEAKER, AUDIO_SPEAKER }, -{ USB_AUDIO_TERM_TYPE_ROOM_SPEAKER, AUDIO_SPEAKER }, -{ USB_AUDIO_TERM_TYPE_COMM_SPEAKER, AUDIO_SPEAKER }, -{ USB_AUDIO_TERM_TYPE_LF_EFFECTS_SPEAKER, AUDIO_SPEAKER }, -{ USB_AUDIO_TERM_TYPE_HANDSET, AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_HEADSET, AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_SPEAKERPHONE, AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_ECHO_SUPP_SPEAKERPHONE, - AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_ECHO_CANCEL_SPEAKERPHONE, - AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_PHONE_LINE, AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_TELEPHONE, AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_DOWN_LINE_PHONE, AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_ANALOG_CONNECTOR, AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_DIGITAL_AUDIO_IF, AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_LINE_CONNECTOR, AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_LEGACY_AUDIO_CONNECTOR, - AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_SPDIF_IF, AUDIO_SPDIF_IN }, -{ USB_AUDIO_TERM_TYPE_1394_DA_STREAM, - AUDIO_LINE_IN|AUDIO_LINE_OUT }, -{ USB_AUDIO_TERM_TYPE_1394_DV_STREAM_SNDTRCK, - AUDIO_LINE_IN|AUDIO_LINE_OUT }, + + /* Input Terminal Types */ +{ USB_AUDIO_TERM_TYPE_MICROPHONE, USB_PORT_MIC }, +{ USB_AUDIO_TERM_TYPE_DT_MICROPHONE, USB_PORT_MIC }, +{ USB_AUDIO_TERM_TYPE_PERS_MICROPHONE, USB_PORT_MIC }, +{ USB_AUDIO_TERM_TYPE_OMNI_DIR_MICROPHONE, USB_PORT_MIC }, +{ USB_AUDIO_TERM_TYPE_MICROPHONE_ARRAY, USB_PORT_MIC }, +{ USB_AUDIO_TERM_TYPE_PROCESSING_MIC_ARRAY, USB_PORT_MIC }, + + /* Output Terminal Types */ +{ USB_AUDIO_TERM_TYPE_SPEAKER, USB_PORT_SPEAKER }, +{ USB_AUDIO_TERM_TYPE_HEADPHONES, USB_PORT_HEADPHONES }, +{ USB_AUDIO_TERM_TYPE_DISPLAY_AUDIO, USB_PORT_LINEOUT }, +{ USB_AUDIO_TERM_TYPE_DT_SPEAKER, USB_PORT_SPEAKER }, +{ USB_AUDIO_TERM_TYPE_ROOM_SPEAKER, USB_PORT_SPEAKER }, +{ USB_AUDIO_TERM_TYPE_COMM_SPEAKER, USB_PORT_SPEAKER }, +{ USB_AUDIO_TERM_TYPE_LF_EFFECTS_SPEAKER, USB_PORT_SPEAKER }, + + /* Bi-directional Terminal Types */ +{ USB_AUDIO_TERM_TYPE_HANDSET, USB_PORT_HANDSET }, + + /* Telephony Terminal Types */ +{ USB_AUDIO_TERM_TYPE_PHONE_LINE, USB_PORT_PHONE}, +{ USB_AUDIO_TERM_TYPE_TELEPHONE, USB_PORT_PHONE}, +{ USB_AUDIO_TERM_TYPE_DOWN_LINE_PHONE, USB_PORT_PHONE }, + + /* External Terminal Types */ +{ USB_AUDIO_TERM_TYPE_SPDIF_IF, USB_PORT_SPDIFIN }, + /* Embedded Function Terminal Types */ +{ USB_AUDIO_TERM_TYPE_CD_PLAYER, USB_PORT_CD }, { 0, 0 } }; @@ -153,9 +163,6 @@ static int usb_ac_attach(dev_info_t *, ddi_attach_cmd_t); static int usb_ac_detach(dev_info_t *, ddi_detach_cmd_t); static int usb_ac_power(dev_info_t *, int, int); -/* plumbing */ -static usb_ac_plumbed_t *usb_ac_get_plumb_info(usb_ac_state_t *, char *, - uchar_t); static uint_t usb_ac_get_featureID(usb_ac_state_t *, uchar_t, uint_t, uint_t); @@ -163,10 +170,6 @@ static uint_t usb_ac_get_featureID(usb_ac_state_t *, uchar_t, uint_t, int usb_ac_open(dev_info_t *); void usb_ac_close(dev_info_t *); -/* registration */ -static int usb_ac_get_curr_n_channels(usb_ac_state_t *, int); -static usb_audio_formats_t *usb_ac_get_curr_format(usb_ac_state_t *, int); - /* descriptor handling */ static int usb_ac_handle_descriptors(usb_ac_state_t *); static void usb_ac_add_unit_descriptor(usb_ac_state_t *, uchar_t *, size_t); @@ -238,31 +241,24 @@ static int usb_ac_set_gain(usb_ac_state_t *, uint_t, uint_t, uint_t, uint_t, uint_t, uint_t *); static int usb_ac_set_monitor_gain(usb_ac_state_t *, uint_t, uint_t, uint_t, uint_t, uint_t, uint_t *); -static int usb_ac_set_mute(usb_ac_state_t *, uint_t, uint_t, - uint_t, uint_t, uint_t, uint_t *); static int usb_ac_set_volume(usb_ac_state_t *, uint_t, short, int dir, int); static int usb_ac_get_maxmin_volume(usb_ac_state_t *, uint_t, int, int, int, short *); -static int usb_ac_send_as_cmd(usb_ac_state_t *, usb_ac_plumbed_t *, +static int usb_ac_send_as_cmd(usb_ac_state_t *, usb_audio_eng_t *, int, void *); -static int usb_ac_send_format_cmd(audiohdl_t, int, int, int, int, int); -static int usb_ac_do_setup(audiohdl_t, int); -static void usb_ac_do_teardown(audiohdl_t, int); -static void usb_ac_do_stop_play(audiohdl_t); -static void usb_ac_do_stop_record(audiohdl_t); - -/* Mixer entry points */ -static int usb_ac_setup(audiohdl_t, int); -static void usb_ac_teardown(audiohdl_t, int); -static int usb_ac_set_config(audiohdl_t, int, int, int, int); -static int usb_ac_set_format(audiohdl_t, int, int, int, int, int); -static int usb_ac_start_play(audiohdl_t); -static void usb_ac_stop_play(audiohdl_t); -static int usb_ac_start_record(audiohdl_t); -static void usb_ac_stop_record(audiohdl_t); +static int usb_ac_set_format(usb_ac_state_t *, usb_audio_eng_t *); +static int usb_ac_do_setup(usb_ac_state_t *, usb_audio_eng_t *); + +/* usb audio basic function entries */ +static int usb_ac_setup(usb_ac_state_t *, usb_audio_eng_t *); +static void usb_ac_teardown(usb_ac_state_t *, usb_audio_eng_t *); +static int usb_ac_start_play(usb_ac_state_t *, usb_audio_eng_t *); +static int usb_ac_start_record(usb_ac_state_t *, usb_audio_eng_t *); +static void usb_ac_stop_record(usb_ac_state_t *, usb_audio_eng_t *); static int usb_ac_restore_audio_state(usb_ac_state_t *, int); +static int usb_ac_ctrl_restore(usb_ac_state_t *); /* * Mux */ @@ -270,7 +266,7 @@ static int usb_ac_mux_walk_siblings(usb_ac_state_t *); static void usb_ac_print_reg_data(usb_ac_state_t *, usb_as_registration_t *); static int usb_ac_get_reg_data(usb_ac_state_t *, ldi_handle_t, int); -static int usb_ac_setup_plumbed(usb_ac_state_t *, int, int, int); +static int usb_ac_setup_plumbed(usb_ac_state_t *, int, int); static int usb_ac_mixer_registration(usb_ac_state_t *); static void usb_ac_hold_siblings(usb_ac_state_t *); static int usb_ac_online_siblings(usb_ac_state_t *); @@ -286,29 +282,13 @@ static int usb_ac_read_msg(usb_ac_plumbed_t *, mblk_t *); static int usb_ac_do_plumbing(usb_ac_state_t *); static int usb_ac_do_unplumbing(usb_ac_state_t *); -/* just generic, USB Audio, 1.0 spec-compliant */ -static audio_device_t usb_dev_info = - { {"USB Audio"}, {"1.0"}, {"external"} }; - -/* - * mixer registration data - */ -static am_ad_entry_t usb_ac_entry = { - usb_ac_setup, /* ad_setup() */ - usb_ac_teardown, /* ad_teardown() */ - usb_ac_set_config, /* ad_set_config() */ - usb_ac_set_format, /* ad_set_format() */ - usb_ac_start_play, /* ad_start_play() */ - usb_ac_stop_play, /* ad_stop_play() */ - usb_ac_start_record, /* ad_start_record() */ - usb_ac_stop_record, /* ad_stop_record() */ -}; +static int usb_change_phy_vol(usb_ac_state_t *, int); +static void usb_restore_engine(usb_ac_state_t *); /* anchor for soft state structures */ void *usb_ac_statep; - /* * DDI Structures */ @@ -343,6 +323,39 @@ static struct modlinkage usb_ac_modlinkage = { NULL /* NULL terminates the list */ }; +static int usb_audio_register(usb_ac_state_t *); +static int usb_audio_unregister(usb_ac_state_t *); + +static int usb_engine_open(void *, int, unsigned *, unsigned *, caddr_t *); +static void usb_engine_close(void *); +static uint64_t usb_engine_count(void *); +static int usb_engine_start(void *); +static void usb_engine_stop(void *); +static int usb_engine_format(void *); +static int usb_engine_channels(void *); +static int usb_engine_rate(void *); +static void usb_engine_sync(void *, unsigned); +static size_t usb_engine_qlen(void *); + +/* engine buffer size in terms of fragments */ + +audio_engine_ops_t usb_engine_ops = { + AUDIO_ENGINE_VERSION, + usb_engine_open, + usb_engine_close, + usb_engine_start, + usb_engine_stop, + usb_engine_count, + usb_engine_format, + usb_engine_channels, + usb_engine_rate, + usb_engine_sync, + usb_engine_qlen, +}; + + + +_NOTE(SCHEME_PROTECTS_DATA("unique per call", mblk_t)) /* standard entry points */ int @@ -366,7 +379,6 @@ _init(void) return (rval); } - int _fini(void) { @@ -381,14 +393,12 @@ _fini(void) return (rval); } - int _info(struct modinfo *modinfop) { return (mod_info(&usb_ac_modlinkage, modinfop)); } - extern uint_t nproc; #define INIT_PROCESS_CNT 3 @@ -442,7 +452,6 @@ usb_ac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) goto fail; } - /* get log handle */ uacp->usb_ac_log_handle = usb_alloc_log_hdl(dip, "ac", &usb_ac_errlevel, @@ -483,18 +492,6 @@ usb_ac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) uacp->usb_ac_default_ph = uacp->usb_ac_dev_data->dev_default_ph; - uacp->usb_ac_audiohdl = audio_sup_register(dip); - - if (uacp->usb_ac_audiohdl == NULL) { - USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "audio_sup_register failed"); - - goto fail; - } - - /* save softstate pointer in audio handle */ - audio_sup_set_private(uacp->usb_ac_audiohdl, (void *)uacp); - /* parse all class specific descriptors */ if (usb_ac_handle_descriptors(uacp) != USB_SUCCESS) { @@ -590,27 +587,11 @@ usb_ac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) mutex_exit(&uacp->usb_ac_mutex); return (USB_FAILURE); } + mutex_exit(&uacp->usb_ac_mutex); - /* - * call am_unregister() to stop calls into our driver from - * the framework; can fail if the framework is still busy - */ - if (uacp->usb_ac_audiohdl != NULL) { - mutex_exit(&uacp->usb_ac_mutex); + (void) usb_audio_unregister(uacp); - if (am_unregister(uacp->usb_ac_audiohdl) != - AUDIO_SUCCESS) { - USB_DPRINTF_L2(PRINT_MASK_ATTA, - uacp->usb_ac_log_handle, - "usb_ac_detach: am_unregister failed, " - "framework still busy"); - return (USB_FAILURE); - } - mutex_enter(&uacp->usb_ac_mutex); - } - - mutex_exit(&uacp->usb_ac_mutex); /* * unplumb to stop activity from other modules, then @@ -650,7 +631,6 @@ usb_ac_cleanup(dev_info_t *dip, usb_ac_state_t *uacp) usb_ac_power_t *uacpm; int rval = USB_FAILURE; - ASSERT(uacp); mutex_enter(&uacp->usb_ac_mutex); uacpm = uacp->usb_ac_pm; @@ -662,29 +642,7 @@ usb_ac_cleanup(dev_info_t *dip, usb_ac_state_t *uacp) ASSERT(uacp->usb_ac_plumbing_state == USB_AC_STATE_UNPLUMBED); - /* - * deregister with audio framework, if it fails we are hosed - * and we probably don't want to plumb again - */ - if (uacp->usb_ac_audiohdl) { - if (uacp->usb_ac_registered_with_mixer) { - mutex_exit(&uacp->usb_ac_mutex); - if (am_detach(uacp->usb_ac_audiohdl, DDI_DETACH) != - AUDIO_SUCCESS) { - - return (rval); - } - } else { - mutex_exit(&uacp->usb_ac_mutex); - } - if (audio_sup_unregister(uacp->usb_ac_audiohdl) != - AUDIO_SUCCESS) { - - return (rval); - } - } else { - mutex_exit(&uacp->usb_ac_mutex); - } + mutex_exit(&uacp->usb_ac_mutex); /* * Disable the event callbacks, after this point, event @@ -803,11 +761,7 @@ usb_ac_read_msg(usb_ac_plumbed_t *plumb_infop, mblk_t *mp) char val1; struct iocblk *iocp; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_read_msg: mp=0x%p, instance=%d", (void *)mp, - ddi_get_instance(uacp->usb_ac_dip)); - ASSERT(mp != NULL); ASSERT(mutex_owned(&uacp->usb_ac_mutex)); /* @@ -846,11 +800,8 @@ usb_ac_read_msg(usb_ac_plumbed_t *plumb_infop, mblk_t *mp) if (uacp->usb_ac_plumbing_state == USB_AC_STATE_PLUMBED) { mutex_exit(&uacp->usb_ac_mutex); - (void) am_hw_state_change( - uacp->usb_ac_audiohdl, - AM_HWSC_SET_GAIN_DELTA, - AUDIO_PLAY, val, - AUDIO_NO_SLEEP); + (void) usb_change_phy_vol( + uacp, val); mutex_enter(&uacp-> usb_ac_mutex); } @@ -880,8 +831,6 @@ usb_ac_read_msg(usb_ac_plumbed_t *plumb_infop, mblk_t *mp) freemsg(mp); } - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_read_msg: done"); return (error); } @@ -895,6 +844,7 @@ usb_ac_read_msg(usb_ac_plumbed_t *plumb_infop, mblk_t *mp) static int usb_ac_power(dev_info_t *dip, int comp, int level) { + _NOTE(ARGUNUSED(comp)); int instance = ddi_get_instance(dip); usb_ac_state_t *uacp; usb_ac_power_t *uacpm; @@ -902,9 +852,6 @@ usb_ac_power(dev_info_t *dip, int comp, int level) uacp = ddi_get_soft_state(usb_ac_statep, instance); - USB_DPRINTF_L4(PRINT_MASK_PM, uacp->usb_ac_log_handle, - "usb_ac_power: comp=%d level=%d", comp, level); - mutex_enter(&uacp->usb_ac_mutex); uacpm = uacp->usb_ac_pm; @@ -1079,53 +1026,8 @@ usb_ac_create_pm_components(dev_info_t *dip, usb_ac_state_t *uacp) "pm not enabled"); } - USB_DPRINTF_L4(PRINT_MASK_PM, uacp->usb_ac_log_handle, - "usb_ac_create_pm_components: end"); -} - - -/* - * usb_ac_get_plumb_info: - * Get plumb_info pointer that matches module "name" - * If name = "usb_as", match the direction also (record or play) - */ -static usb_ac_plumbed_t * -usb_ac_get_plumb_info(usb_ac_state_t *uacp, char *name, uchar_t reg_play_type) -{ - int n; - usb_ac_plumbed_t *plumb_infop = NULL; - usb_as_registration_t *asreg; - usb_ac_streams_info_t *asinfo; - - for (n = 0; n < USB_AC_MAX_PLUMBED; n++) { - if (uacp->usb_ac_plumbed[n].acp_dip == NULL) { - continue; - } - if (strcmp(ddi_driver_name(uacp-> - usb_ac_plumbed[n].acp_dip), name) != 0) { - continue; - } - if (uacp->usb_ac_plumbed[n].acp_driver == USB_AS_PLUMBED) { - asinfo = uacp->usb_ac_plumbed[n].acp_data; - asreg = asinfo->acs_streams_reg; - /* Match direction */ - if (asreg->reg_mode & reg_play_type) { - break; - } - } else if (uacp->usb_ac_plumbed[n].acp_driver == - USB_AH_PLUMBED) { - break; - } - } - - if (n < USB_AC_MAX_PLUMBED) { - plumb_infop = &uacp->usb_ac_plumbed[n]; - } - - return (plumb_infop); } - /* * usb_ac_get_featureID: * find out if there is at least one feature unit that supports @@ -1158,9 +1060,6 @@ usb_ac_feature_unit_check(usb_ac_state_t *uacp, uint_t featureID, usb_audio_feature_unit_descr1_t *feature_descrp; int n_channel_controls; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_feature_unit_check: ID=%d ch=%d cntrl=%d", - featureID, channel, control); ASSERT(featureID < uacp->usb_ac_max_unit); @@ -1235,10 +1134,6 @@ usb_ac_handle_descriptors(usb_ac_state_t *uacp) usb_alt_if_data_t *altif_data; usb_cvs_data_t *cvs; - USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "config=%ld, interface=%d", - (long)(dev_data->dev_curr_cfg - &dev_data->dev_cfg[0]), - dev_data->dev_curr_if); altif_data = &dev_data->dev_curr_cfg-> cfg_if[dev_data->dev_curr_if].if_alt[0]; @@ -1259,7 +1154,8 @@ usb_ac_handle_descriptors(usb_ac_state_t *uacp) if (index == altif_data->altif_n_cvs) { USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "cannot find descriptor type %d", USB_AUDIO_CS_INTERFACE); + "usb_ac_handle_descriptors:cannot find descriptor type %d", + USB_AUDIO_CS_INTERFACE); return (rval); } @@ -1280,8 +1176,9 @@ usb_ac_handle_descriptors(usb_ac_state_t *uacp) } USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "header: type=0x%x subtype=0x%x bcdADC=0x%x\n\t" + "index %d, header: type=0x%x subtype=0x%x bcdADC=0x%x\n\t" "total=0x%x InCol=0x%x", + index, descr.bDescriptorType, descr.bDescriptorSubType, descr.bcdADC, @@ -1310,12 +1207,8 @@ usb_ac_handle_descriptors(usb_ac_state_t *uacp) usb_ac_setup_connections(uacp); /* determine port types */ - usb_ac_map_termtype_to_port(uacp, AUDIO_PLAY); - usb_ac_map_termtype_to_port(uacp, AUDIO_RECORD); - - USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "input port types=0x%x output port types =0x%x", - uacp->usb_ac_input_ports, uacp->usb_ac_output_ports); + usb_ac_map_termtype_to_port(uacp, USB_AUDIO_PLAY); + usb_ac_map_termtype_to_port(uacp, USB_AUDIO_RECORD); return (rval); @@ -1360,7 +1253,7 @@ usb_ac_setup_connections(usb_ac_state_t *uacp) for (unit = 0; unit < uacp->usb_ac_max_unit; unit++) { USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "traversing unit=0x%x type=0x%x", + "--------traversing unit=0x%x type=0x%x--------", unit, units[unit].acu_type); /* store type in the first unused column */ @@ -1374,8 +1267,8 @@ usb_ac_setup_connections(usb_ac_state_t *uacp) units[unit].acu_descriptor; USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "sourceID=0x%x type=0x%x", d->bSourceID, - units[d->bSourceID].acu_type); + "USB_AUDIO_FEATURE_UNIT:sourceID=0x%x type=0x%x", + d->bSourceID, units[d->bSourceID].acu_type); if (d->bSourceID != 0) { ASSERT(p[unit][d->bSourceID] == B_FALSE); @@ -1390,8 +1283,8 @@ usb_ac_setup_connections(usb_ac_state_t *uacp) units[unit].acu_descriptor; USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "sourceID=0x%x type=0x%x", d->bSourceID, - units[d->bSourceID].acu_type); + "USB_AUDIO_OUTPUT_TERMINAL:sourceID=0x%x type=0x%x", + d->bSourceID, units[d->bSourceID].acu_type); if (d->bSourceID != 0) { ASSERT(p[unit][d->bSourceID] == B_FALSE); @@ -1410,7 +1303,8 @@ usb_ac_setup_connections(usb_ac_state_t *uacp) for (id = 0; id < n_sourceID; id++) { USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "sourceID=0x%x type=0x%x c=%d", + "USB_AUDIO_MIXER_UNIT:sourceID=0x%x" + "type=0x%x c=%d", d->baSourceID[id], units[d->baSourceID[id]].acu_type, p[unit][d->baSourceID[id]]); @@ -1434,8 +1328,8 @@ usb_ac_setup_connections(usb_ac_state_t *uacp) for (id = 0; id < n_sourceID; id++) { USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "sourceID=0x%x type=0x%x", - d->baSourceID[id], + "USB_AUDIO_SELECTOR_UNIT:sourceID=0x%x" + " type=0x%x", d->baSourceID[id], units[d->baSourceID[id]].acu_type); if (d->baSourceID[id] != 0) { @@ -1457,8 +1351,8 @@ usb_ac_setup_connections(usb_ac_state_t *uacp) for (id = 0; id < n_sourceID; id++) { USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "sourceID=0x%x type=0x%x", - d->baSourceID[id], + "USB_AUDIO_PROCESSING_UNIT:sourceID=0x%x" + " type=0x%x", d->baSourceID[id], units[d->baSourceID[id]].acu_type); if (d->baSourceID[id] != 0) { @@ -1480,8 +1374,8 @@ usb_ac_setup_connections(usb_ac_state_t *uacp) for (id = 0; id < n_sourceID; id++) { USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "sourceID=0x%x type=0x%x", - d->baSourceID[id], + "USB_AUDIO_EXTENSION_UNIT:sourceID=0x%x" + "type=0x%x", d->baSourceID[id], units[d->baSourceID[id]].acu_type); if (d->baSourceID[id] != 0) { @@ -1579,9 +1473,6 @@ usb_ac_add_unit_descriptor(usb_ac_state_t *uacp, uchar_t *buffer, char *format; size_t size; - USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "usb_ac_add_unit_descriptor: 0x%x 0x%x 0x%x", - buffer[0], buffer[1], buffer[2]); /* doubling the length should allow for padding */ len = 2 * buffer[0]; @@ -1649,9 +1540,11 @@ usb_ac_add_unit_descriptor(usb_ac_state_t *uacp, uchar_t *buffer, USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "input term: type=0x%x sub=0x%x termid=0x%x\n\t" + "usb_ac_units[%d] ---input term: type=0x%x sub=0x%x" + "termid=0x%x\n\t" "termtype=0x%x assoc=0x%x #ch=%d " "chconf=0x%x ich=0x%x iterm=0x%x", + d->bTerminalID, d->bDescriptorType, d->bDescriptorSubType, d->bTerminalID, d->wTerminalType, d->bAssocTerminal, d->bNrChannels, @@ -1672,8 +1565,10 @@ usb_ac_add_unit_descriptor(usb_ac_state_t *uacp, uchar_t *buffer, USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "output term: type=0x%x sub=0x%x termid=0x%x\n\t" + "usb_ac_units[%d] ---output term: type=0x%x sub=0x%x" + " termid=0x%x\n\t" "termtype=0x%x assoc=0x%x sourceID=0x%x iterm=0x%x", + d->bTerminalID, d->bDescriptorType, d->bDescriptorSubType, d->bTerminalID, d->wTerminalType, d->bAssocTerminal, d->bSourceID, @@ -1693,8 +1588,10 @@ usb_ac_add_unit_descriptor(usb_ac_state_t *uacp, uchar_t *buffer, USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "mixer unit: type=0x%x sub=0x%x unitid=0x%x\n\t" + "usb_ac_units[%d] ---mixer unit: type=0x%x sub=0x%x" + " unitid=0x%x\n\t" "#pins=0x%x sourceid[0]=0x%x", + d->bUnitID, d->bDescriptorType, d->bDescriptorSubType, d->bUnitID, d->bNrInPins, d->baSourceID[0]); usb_ac_alloc_unit(uacp, d->bUnitID); @@ -1711,8 +1608,10 @@ usb_ac_add_unit_descriptor(usb_ac_state_t *uacp, uchar_t *buffer, USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "selector unit: type=0x%x sub=0x%x unitid=0x%x\n\t" + "usb_ac_units[%d] ---selector unit: type=0x%x sub=0x%x" + " unitid=0x%x\n\t" "#pins=0x%x sourceid[0]=0x%x", + d->bUnitID, d->bDescriptorType, d->bDescriptorSubType, d->bUnitID, d->bNrInPins, d->baSourceID[0]); usb_ac_alloc_unit(uacp, d->bUnitID); @@ -1729,8 +1628,10 @@ usb_ac_add_unit_descriptor(usb_ac_state_t *uacp, uchar_t *buffer, USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "feature unit: type=0x%x sub=0x%x unitid=0x%x\n\t" + "usb_ac_units[%d] ---feature unit: type=0x%x sub=0x%x" + " unitid=0x%x\n\t" "sourceid=0x%x size=0x%x", + d->bUnitID, d->bDescriptorType, d->bDescriptorSubType, d->bUnitID, d->bSourceID, d->bControlSize); @@ -1748,8 +1649,10 @@ usb_ac_add_unit_descriptor(usb_ac_state_t *uacp, uchar_t *buffer, USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "processing unit: type=0x%x sub=0x%x unitid=0x%x\n\t" + "usb_ac_units[%d] ---processing unit: type=0x%x sub=0x%x" + " unitid=0x%x\n\t" "#pins=0x%x sourceid[0]=0x%x", + d->bUnitID, d->bDescriptorType, d->bDescriptorSubType, d->bUnitID, d->bNrInPins, d->baSourceID[0]); usb_ac_alloc_unit(uacp, d->bUnitID); @@ -1766,8 +1669,10 @@ usb_ac_add_unit_descriptor(usb_ac_state_t *uacp, uchar_t *buffer, USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "mixer unit: type=0x%x sub=0x%x unitid=0x%x\n\t" + "usb_ac_units[%d] ---mixer unit: type=0x%x sub=0x%x" + " unitid=0x%x\n\t" "#pins=0x%x sourceid[0]=0x%x", + d->bUnitID, d->bDescriptorType, d->bDescriptorSubType, d->bUnitID, d->bNrInPins, d->baSourceID[0]); usb_ac_alloc_unit(uacp, d->bUnitID); @@ -1795,8 +1700,6 @@ usb_ac_alloc_unit(usb_ac_state_t *uacp, uint_t unit) usb_ac_unit_list_t *old = NULL; uint_t max_unit; - USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "usb_ac_alloc_unit: unit=%d", unit); if (uacp->usb_ac_units) { if (unit < uacp->usb_ac_max_unit) { @@ -1838,8 +1741,6 @@ usb_ac_free_all_units(usb_ac_state_t *uacp) return; } - USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, - "usb_ac_alloc_unit: max_unit=%d", uacp->usb_ac_max_unit); for (unit = 0; unit < uacp->usb_ac_max_unit; unit++) { unitp = &uacp->usb_ac_units[unit]; @@ -1866,6 +1767,12 @@ usb_ac_lookup_port_type(ushort_t termtype) { uint_t i; + /* + * Looking for a input/ouput terminal type to match the port + * type, it should not be common streaming type + */ + ASSERT(termtype != USB_AUDIO_TERM_TYPE_STREAMING); + for (i = 0; ; i++) { if (usb_ac_term_type_map[i].term_type == 0) { @@ -1878,7 +1785,7 @@ usb_ac_lookup_port_type(ushort_t termtype) } } - return (AUDIO_LINE_IN|AUDIO_LINE_OUT); + return (USB_PORT_UNKNOWN); } @@ -1891,7 +1798,7 @@ static int usb_ac_update_port(usb_ac_state_t *uacp, uint_t id, uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth) { - if (dir & AUDIO_PLAY) { + if (dir & USB_AUDIO_PLAY) { usb_audio_output_term_descr_t *d = (usb_audio_output_term_descr_t *) uacp->usb_ac_units[id].acu_descriptor; @@ -1899,25 +1806,23 @@ usb_ac_update_port(usb_ac_state_t *uacp, uint_t id, usb_ac_lookup_port_type(d->wTerminalType); USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_update_port: dir=%d type=0x%x port type=%d", - dir, d->wTerminalType, port_type); + "usb_ac_update_port: dir=%d wTerminalType=0x%x, name=%s", + dir, d->wTerminalType, usb_audio_dtypes[port_type]); - uacp->usb_ac_output_ports |= port_type; - uacp->usb_ac_output_ports &= ~AUDIO_LINE_IN; + uacp->usb_ac_output_ports |= (1U << port_type); } else { - usb_audio_output_term_descr_t *d = - (usb_audio_output_term_descr_t *) + usb_audio_input_term_descr_t *d = + (usb_audio_input_term_descr_t *) uacp->usb_ac_units[id].acu_descriptor; uint_t port_type = usb_ac_lookup_port_type(d->wTerminalType); USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_update_port: dir=%d type=0x%x port type=%d", - dir, d->wTerminalType, port_type); + "usb_ac_update_port: dir=%d wTerminalType=0x%x, name=%s", + dir, d->wTerminalType, usb_audio_dtypes[port_type]); + + uacp->usb_ac_input_ports |= (1U << port_type); - uacp->usb_ac_input_ports |= - usb_ac_lookup_port_type(d->wTerminalType); - uacp->usb_ac_input_ports &= ~AUDIO_LINE_OUT; } return (USB_SUCCESS); @@ -1935,11 +1840,9 @@ usb_ac_map_termtype_to_port(usb_ac_state_t *uacp, uint_t dir) { uint_t count = 0; uint_t depth = 0; - uint_t search_type = (dir & AUDIO_PLAY) ? + uint_t search_type = (dir & USB_AUDIO_PLAY) ? USB_AUDIO_OUTPUT_TERMINAL : USB_AUDIO_INPUT_TERMINAL; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_map_term_to_port: dir=%d", dir); (void) usb_ac_traverse_all_units(uacp, dir, search_type, 0, 0, USB_AC_FIND_ALL, &count, 0, &depth, usb_ac_update_port); @@ -1960,11 +1863,9 @@ usb_ac_set_port(usb_ac_state_t *uacp, uint_t dir, uint_t port) uint_t id; uint_t depth = 0; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_set_port: dir=%d port=%d", dir, port); /* we only support the selector for the record side */ - if (dir & AUDIO_RECORD) { + if (dir & USB_AUDIO_RECORD) { id = usb_ac_traverse_all_units(uacp, dir, USB_AUDIO_SELECTOR_UNIT, 0, 0, USB_AC_FIND_ONE, &count, port, &depth, @@ -1993,11 +1894,8 @@ usb_ac_match_port(usb_ac_state_t *uacp, uint_t id, { uint_t port_type; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_match_port: id=%d dir=%d port=%d", - id, dir, arg1); - if (dir & AUDIO_PLAY) { + if (dir & USB_AUDIO_PLAY) { usb_audio_output_term_descr_t *d = (usb_audio_output_term_descr_t *) uacp->usb_ac_units[id].acu_descriptor; @@ -2019,7 +1917,7 @@ usb_ac_match_port(usb_ac_state_t *uacp, uint_t id, dir, d->wTerminalType, port_type, arg1); } - return ((port_type & arg1) ? USB_SUCCESS : USB_FAILURE); + return (((1U << port_type) & arg1) ? USB_SUCCESS : USB_FAILURE); } @@ -2037,7 +1935,7 @@ usb_ac_set_selector(usb_ac_state_t *uacp, uint_t id, uint_t unit = USB_AC_ID_NONE; uint_t pin; uint_t search_target = - (dir & AUDIO_PLAY) ? USB_AUDIO_OUTPUT_TERMINAL : + (dir & USB_AUDIO_PLAY) ? USB_AUDIO_OUTPUT_TERMINAL : USB_AUDIO_INPUT_TERMINAL; usb_audio_selector_unit_descr1_t *d = (usb_audio_selector_unit_descr1_t *) @@ -2045,9 +1943,6 @@ usb_ac_set_selector(usb_ac_state_t *uacp, uint_t id, int n_sourceID = d->bNrInPins; int rval = USB_FAILURE; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_set_selector: id=%d dir=%d port=%d", - id, dir, arg1); /* * for each pin, find a term type that matches the @@ -2098,7 +1993,14 @@ usb_ac_set_selector(usb_ac_state_t *uacp, uint_t id, mutex_exit(&uacp->usb_ac_mutex); - data = allocb_wait(1, BPRI_HI, STR_NOSIG, NULL); + data = allocb(1, BPRI_HI); + if (!data) { + USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, + "usb_ac_set_selector: allocate data failed"); + mutex_enter(&uacp->usb_ac_mutex); + + return (USB_FAILURE); + } /* pins are 1-based */ *(data->b_rptr) = (char)++pin; @@ -2155,11 +2057,6 @@ usb_ac_set_control(usb_ac_state_t *uacp, uint_t dir, uint_t search_target, uint_t id; uint_t depth = 0; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_set_control: dir=%d type=%d ch=%d cntl=%d", - dir, search_target, channel, control); - - id = usb_ac_traverse_all_units(uacp, dir, search_target, channel, control, all_or_one, count, arg1, &depth, func); @@ -2195,12 +2092,7 @@ usb_ac_traverse_all_units(usb_ac_state_t *uacp, uint_t dir, { uint_t unit, start_type, id; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_traverse_all_units: " - "dir=%d type=%d ch=%d cntl=%d all=%d depth=%d", - dir, search_target, channel, control, all_or_one, *depth); - - start_type = (dir & AUDIO_PLAY) ? USB_AUDIO_INPUT_TERMINAL : + start_type = (dir & USB_AUDIO_PLAY) ? USB_AUDIO_INPUT_TERMINAL : USB_AUDIO_OUTPUT_TERMINAL; /* keep track of recursion */ @@ -2219,7 +2111,7 @@ usb_ac_traverse_all_units(usb_ac_state_t *uacp, uint_t dir, } /* start at streaming term types */ - if (dir & AUDIO_PLAY) { + if (dir & USB_AUDIO_PLAY) { usb_audio_input_term_descr_t *d = uacp->usb_ac_units[unit].acu_descriptor; if (d->wTerminalType != @@ -2273,9 +2165,6 @@ usb_ac_set_monitor_gain_control(usb_ac_state_t *uacp, uint_t dir, uint_t unit, id; uint_t depth = 0; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_set_monitor_gain_control: dir=%d type=%d ch=%d cntl=%d", - dir, search_target, channel, control); for (unit = 1; unit < uacp->usb_ac_max_unit; unit++) { usb_audio_output_term_descr_t *d = @@ -2312,23 +2201,16 @@ usb_ac_set_monitor_gain_control(usb_ac_state_t *uacp, uint_t dir, static void usb_ac_push_unit_id(usb_ac_state_t *uacp, uint_t unit) { - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_push_unit_id: pushing %d at %d", unit, - uacp->usb_ac_traverse_path_index); - uacp->usb_ac_traverse_path[uacp->usb_ac_traverse_path_index++] = (uchar_t)unit; ASSERT(uacp->usb_ac_traverse_path_index < uacp->usb_ac_max_unit); } +/* ARGSUSED */ static void usb_ac_pop_unit_id(usb_ac_state_t *uacp, uint_t unit) { - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_push_unit_id: popping %d at %d", unit, - uacp->usb_ac_traverse_path_index); - uacp->usb_ac_traverse_path[uacp->usb_ac_traverse_path_index--] = 0; } @@ -2391,14 +2273,9 @@ usb_ac_traverse_connections(usb_ac_state_t *uacp, uint_t start_unit, uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth)) { uint_t unit, id; - uint_t done = (dir & AUDIO_PLAY) ? USB_AUDIO_OUTPUT_TERMINAL : + uint_t done = (dir & USB_AUDIO_PLAY) ? USB_AUDIO_OUTPUT_TERMINAL : USB_AUDIO_INPUT_TERMINAL; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_traverse_connections: " - "start=%d dir=%d type=%d ch=%d cntl=%d all=%d depth=%d", - start_unit, dir, search_target, channel, control, - all_or_one, *depth); /* keep track of recursion depth */ if ((*depth)++ > USB_AC_MAX_DEPTH) { @@ -2411,7 +2288,7 @@ usb_ac_traverse_connections(usb_ac_state_t *uacp, uint_t start_unit, uint_t dir, usb_ac_push_unit_id(uacp, start_unit); for (unit = 1; unit < uacp->usb_ac_max_unit; unit++) { - uint_t entry = (dir & AUDIO_PLAY) ? + uint_t entry = (dir & USB_AUDIO_PLAY) ? uacp->usb_ac_connections[unit][start_unit] : uacp->usb_ac_connections[start_unit][unit]; @@ -2490,9 +2367,9 @@ usb_ac_disconnect_event_cb(dev_info_t *dip) "usb_ac_disconnect_event_cb:start"); usb_ac_serialize_access(uacp); + mutex_enter(&uacp->usb_ac_mutex); /* setting to disconnect state will prevent replumbing */ - mutex_enter(&uacp->usb_ac_mutex); uacp->usb_ac_dev_state = USB_DEV_DISCONNECTED; if (uacp->usb_ac_busy_count) { @@ -2692,7 +2569,7 @@ usb_ac_am_restore_state(void *arg) */ delay(USB_AC_RESTORE_DELAY); - audio_sup_restore_state(uacp->usb_ac_audiohdl); + usb_restore_engine(uacp); mutex_enter(&uacp->usb_ac_mutex); uacp->usb_ac_plumbing_state = USB_AC_STATE_PLUMBED; @@ -2717,8 +2594,6 @@ usb_ac_restore_audio_state(usb_ac_state_t *uacp, int flag) { ASSERT(mutex_owned(&uacp->usb_ac_mutex)); - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_restore_audio_state: flag=%d", flag); switch (uacp->usb_ac_plumbing_state) { case USB_AC_STATE_PLUMBED: @@ -2775,35 +2650,28 @@ usb_ac_restore_audio_state(usb_ac_state_t *uacp, int flag) * Check power is done in usb_ac_send_as_cmd() */ static int -usb_ac_setup(audiohdl_t ahdl, int flag) +usb_ac_setup(usb_ac_state_t *uacp, usb_audio_eng_t *engine) { - int rval = AUDIO_SUCCESS; - usb_ac_state_t *uacp = audio_sup_get_private(ahdl); + int rval = USB_SUCCESS; - ASSERT(uacp != NULL); mutex_enter(&uacp->usb_ac_mutex); if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) { mutex_exit(&uacp->usb_ac_mutex); - return (AUDIO_FAILURE); + return (USB_FAILURE); } mutex_exit(&uacp->usb_ac_mutex); usb_ac_serialize_access(uacp); - if (flag & AUDIO_PLAY) { - rval = usb_ac_do_setup(ahdl, AUDIO_PLAY); - } - if ((rval == USB_SUCCESS) && (flag & AUDIO_RECORD)) { - rval = usb_ac_do_setup(ahdl, AUDIO_RECORD); - } + rval = usb_ac_do_setup(uacp, engine); usb_ac_release_access(uacp); - return ((rval == USB_SUCCESS) ? AUDIO_SUCCESS : AUDIO_FAILURE); + return (rval); } @@ -2813,23 +2681,15 @@ usb_ac_setup(audiohdl_t ahdl, int flag) * either from audio framework for usb_ac_set_format */ static int -usb_ac_do_setup(audiohdl_t ahdl, int flag) +usb_ac_do_setup(usb_ac_state_t *uacp, usb_audio_eng_t *engine) { - usb_ac_state_t *uacp = audio_sup_get_private(ahdl); - usb_ac_plumbed_t *plumb_infop = NULL; usb_ac_streams_info_t *streams_infop = NULL; - int dir; - ASSERT(uacp != NULL); mutex_enter(&uacp->usb_ac_mutex); - dir = (flag & AUDIO_PLAY) ? AUDIO_PLAY : AUDIO_RECORD; - plumb_infop = usb_ac_get_plumb_info(uacp, "usb_as", dir); - ASSERT(plumb_infop != NULL); - streams_infop = (usb_ac_streams_info_t *)plumb_infop->acp_data; - ASSERT(streams_infop != NULL); + streams_infop = (usb_ac_streams_info_t *)engine->streams; /* * Handle multiple setup calls. Pass the setup call to usb_as only @@ -2846,7 +2706,7 @@ usb_ac_do_setup(audiohdl_t ahdl, int flag) } /* Send setup command to usb_as */ - if (usb_ac_send_as_cmd(uacp, plumb_infop, USB_AUDIO_SETUP, 0) != + if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_SETUP, 0) != USB_SUCCESS) { USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, "usb_ac_do_setup: failure"); @@ -2871,48 +2731,20 @@ usb_ac_do_setup(audiohdl_t ahdl, int flag) * NOTE: allow teardown when disconnected */ static void -usb_ac_teardown(audiohdl_t ahdl, int flag) +usb_ac_teardown(usb_ac_state_t *uacp, usb_audio_eng_t *engine) { - usb_ac_state_t *uacp = audio_sup_get_private(ahdl); - ASSERT(uacp != NULL); + usb_ac_streams_info_t *streams_infop = NULL; usb_ac_serialize_access(uacp); - if (flag & AUDIO_PLAY) { - usb_ac_do_teardown(ahdl, AUDIO_PLAY); - } - - if (flag & AUDIO_RECORD) { - usb_ac_do_teardown(ahdl, AUDIO_RECORD); - } - usb_ac_release_access(uacp); -} + streams_infop = engine->streams; -/* - * usb_ac_do_teardown() - * Check power is done in usb_ac_send_as_cmd() - */ -static void -usb_ac_do_teardown(audiohdl_t ahdl, int flag) -{ - usb_ac_state_t *uacp = audio_sup_get_private(ahdl); - usb_ac_plumbed_t *plumb_infop = NULL; - usb_ac_streams_info_t *streams_infop = NULL; - int dir; - - ASSERT(uacp != NULL); - mutex_enter(&uacp->usb_ac_mutex); - dir = (flag & AUDIO_PLAY) ? AUDIO_PLAY : AUDIO_RECORD; - plumb_infop = usb_ac_get_plumb_info(uacp, "usb_as", dir); - ASSERT(plumb_infop != NULL); - streams_infop = (usb_ac_streams_info_t *)plumb_infop->acp_data; - ASSERT(streams_infop != NULL); /* There should be at least one matching setup call */ ASSERT(streams_infop->acs_setup_teardown_count); @@ -2924,210 +2756,32 @@ usb_ac_do_teardown(audiohdl_t ahdl, int flag) */ if (--(streams_infop->acs_setup_teardown_count)) { USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_do_teardown: more than one setup/teardown, " + "usb_ac_teardown: more than one setup/teardown, " "cnt=%d", streams_infop->acs_setup_teardown_count); - mutex_exit(&uacp->usb_ac_mutex); - - return; + goto done; } /* Send teardown command to usb_as */ - if (usb_ac_send_as_cmd(uacp, plumb_infop, USB_AUDIO_TEARDOWN, + if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_TEARDOWN, (void *)NULL) != USB_SUCCESS) { USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_do_teardown: failure"); + "usb_ac_teardown: failure"); streams_infop->acs_setup_teardown_count++; - mutex_exit(&uacp->usb_ac_mutex); - return; + goto done; } +done: mutex_exit(&uacp->usb_ac_mutex); USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_do_teardown: End"); -} - - -/* - * usb_ac_set_config: - * This routine will send control commands to get the max - * and min gain balance, calculate the gain to be set from the - * arguments and send another control command to set it. - * Check power is done here since we will access the default pipe - */ -static int -usb_ac_set_config(audiohdl_t ahdl, int command, int flag, int arg1, int arg2) -{ - usb_ac_state_t *uacp = audio_sup_get_private(ahdl); - char *what; - int rval = AUDIO_FAILURE; - uint_t channel; - uchar_t n_channels = 0; - uint_t dir, count; - short muteval; - - ASSERT(uacp != NULL); - - mutex_enter(&uacp->usb_ac_mutex); - - if (uacp->usb_ac_plumbing_state < USB_AC_STATE_PLUMBED) { - mutex_exit(&uacp->usb_ac_mutex); - - return (AUDIO_FAILURE); - } - - if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) { - mutex_exit(&uacp->usb_ac_mutex); - - return (AUDIO_FAILURE); - } - mutex_exit(&uacp->usb_ac_mutex); - usb_ac_serialize_access(uacp); - mutex_enter(&uacp->usb_ac_mutex); - - switch (command) { - case AM_SET_GAIN: - /* - * Set the gain for a channel. The audio mixer calculates the - * impact, if any, on the channel's gain. - * - * 0 <= gain <= AUDIO_MAX_GAIN - * - * arg1 --> gain - * arg2 --> channel #, 0 == left, 1 == right - */ - what = "gain"; - channel = ++arg2; - ASSERT(flag != AUDIO_BOTH); - dir = (flag & AUDIO_PLAY) ? AUDIO_PLAY : AUDIO_RECORD; - - /* - * We service the set_config command when the device is - * plumbed and opened. - */ - n_channels = usb_ac_get_curr_n_channels(uacp, dir); - - if (channel > n_channels) { - USB_DPRINTF_L2(PRINT_MASK_ALL, - uacp->usb_ac_log_handle, - "usb_ac_set_config: channel(%d) passed is " - " > n_channels(%d)", channel, n_channels); - - goto done; - } - count = 0; - (void) usb_ac_set_control(uacp, dir, - USB_AUDIO_FEATURE_UNIT, channel, - USB_AUDIO_VOLUME_CONTROL, - USB_AC_FIND_ALL, &count, arg1, usb_ac_set_gain); - - /* - * If feature unit id could not be found, it probably means - * volume/gain control is not available for this device. - * and we just return success if we haven't completed - * the registration with the mixer yet - */ - if (count == 0) { - USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "mixer=%d, no featureID, arg1=%d", - uacp->usb_ac_registered_with_mixer, arg1); - rval = (uacp->usb_ac_registered_with_mixer == 0) ? - AUDIO_SUCCESS : AUDIO_FAILURE; - } else { - rval = AUDIO_SUCCESS; - } - - break; - case AM_SET_PORT: - what = "port"; - ASSERT(flag != AUDIO_BOTH); - dir = (flag & AUDIO_PLAY) ? AUDIO_PLAY : AUDIO_RECORD; - - rval = usb_ac_set_port(uacp, dir, arg1); - rval = (rval == USB_SUCCESS) ? AUDIO_SUCCESS : AUDIO_FAILURE; - - break; - case AM_SET_MONITOR_GAIN: - what = "monitor gain"; - channel = ++arg2; - dir = AUDIO_RECORD; - - /* - * We service the set_config command when the device is - * plumbed and opened. - */ - n_channels = usb_ac_get_curr_n_channels(uacp, dir); - - if (channel > n_channels) { - USB_DPRINTF_L2(PRINT_MASK_ALL, - uacp->usb_ac_log_handle, - "usb_ac_set_config: channel(%d) passed is " - " > n_channels(%d)", channel, n_channels); - - goto done; - } - count = 0; - (void) usb_ac_set_monitor_gain_control(uacp, dir, - USB_AUDIO_INPUT_TERMINAL, channel, - USB_AUDIO_VOLUME_CONTROL, - USB_AC_FIND_ALL, &count, arg1, - usb_ac_set_monitor_gain); - - /* - * always return success since we told the mixer - * we always support this and sdtaudiocontrol displays - * monitor gain regardless. - */ - rval = AUDIO_SUCCESS; - - break; - case AM_OUTPUT_MUTE: - what = "mute"; - ASSERT(flag != AUDIO_BOTH); - dir = (flag & AUDIO_PLAY) ? AUDIO_PLAY : AUDIO_RECORD; - - /* - * arg1 != 0 --> mute - * arg1 == 0 --> unmute - * arg2 --> not used - */ - muteval = (arg1 == 0) ? USB_AUDIO_MUTE_OFF : - USB_AUDIO_MUTE_ON; - count = 0; - (void) usb_ac_set_control(uacp, dir, - USB_AUDIO_FEATURE_UNIT, 0, - USB_AUDIO_MUTE_CONTROL, - USB_AC_FIND_ALL, &count, muteval, - usb_ac_set_mute); - - rval = (count == 0) ? AUDIO_FAILURE : AUDIO_SUCCESS; - - break; - case AM_MIC_BOOST: - what = "mic boost"; - rval = AUDIO_SUCCESS; - break; - default: - what = "unknown"; - rval = AUDIO_FAILURE; - } - -done: - mutex_exit(&uacp->usb_ac_mutex); - - /* Now it's safe to release access to other routines */ + "usb_ac_teardown: End"); usb_ac_release_access(uacp); - - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_set_config: %s done, rval=%d", what, rval); - - return (rval); } @@ -3145,10 +2799,6 @@ usb_ac_set_monitor_gain(usb_ac_state_t *uacp, uint_t unit, USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, "usb_ac_set_monitor_gain: "); - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "id=%d dir=%d ch=%d cntl=%d gain=%d type=%d term type=0x%x", - unit, dir, channel, control, gain, - uacp->usb_ac_unit_type[unit], d->wTerminalType); /* log how we got here */ usb_ac_push_unit_id(uacp, unit); @@ -3285,7 +2935,7 @@ usb_ac_set_gain(usb_ac_state_t *uacp, uint_t featureID, if (gain == 0) { gain = USB_AUDIO_VOLUME_SILENCE; } else { - gain = max - ((max - min) * (0x100 - gain))/0x100; + gain = max - ((max - min) * (AF_MAX_GAIN - gain))/AF_MAX_GAIN; } USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle, @@ -3329,251 +2979,97 @@ usb_ac_set_gain(usb_ac_state_t *uacp, uint_t featureID, * after a set_format command. (2) Check power is done in * usb_ac_send_as_cmd(). */ -static int -usb_ac_set_format(audiohdl_t ahdl, int flag, - int sample, int channels, int precision, int encoding) +int +usb_ac_set_format(usb_ac_state_t *uacp, usb_audio_eng_t *engine) { - usb_ac_state_t *uacp = audio_sup_get_private(ahdl); - usb_audio_formats_t *format; - usb_audio_formats_t old_format; - usb_ac_plumbed_t *plumb_infop; usb_ac_streams_info_t *streams_infop = NULL; - int old_setup_teardown_count; - int dir; - int rval; - - ASSERT(uacp != NULL); + usb_audio_formats_t format; + int old_setup_teardown_count = 0; mutex_enter(&uacp->usb_ac_mutex); + streams_infop = (usb_ac_streams_info_t *)engine->streams; + if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) { mutex_exit(&uacp->usb_ac_mutex); - return (AUDIO_FAILURE); + return (USB_FAILURE); } mutex_exit(&uacp->usb_ac_mutex); usb_ac_serialize_access(uacp); - - ASSERT(flag != AUDIO_BOTH); - mutex_enter(&uacp->usb_ac_mutex); - dir = (flag & AUDIO_PLAY) ? AUDIO_PLAY : AUDIO_RECORD; - plumb_infop = usb_ac_get_plumb_info(uacp, "usb_as", dir); - if (plumb_infop == NULL) { - USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_set_format: no plumb info"); - mutex_exit(&uacp->usb_ac_mutex); - usb_ac_release_access(uacp); + bzero(&format, sizeof (usb_audio_formats_t)); - return (AUDIO_FAILURE); - } + /* save format info */ + format.fmt_sr = (uint_t)engine->fmt.sr; + format.fmt_chns = (uchar_t)engine->fmt.ch; + format.fmt_precision = (uchar_t)engine->fmt.prec; + format.fmt_encoding = (uchar_t)engine->fmt.enc; - streams_infop = (usb_ac_streams_info_t *)plumb_infop->acp_data; - ASSERT(streams_infop != NULL); + old_setup_teardown_count = streams_infop->acs_setup_teardown_count; /* isoc pipe not open and playing is not in progress */ - if (streams_infop->acs_setup_teardown_count == 0) { + if (old_setup_teardown_count) { + streams_infop->acs_setup_teardown_count = 1; mutex_exit(&uacp->usb_ac_mutex); - - rval = usb_ac_send_format_cmd(ahdl, dir, sample, - channels, precision, encoding); - usb_ac_release_access(uacp); - return ((rval == USB_SUCCESS) ? - AUDIO_SUCCESS : AUDIO_FAILURE); - } - - /* isoc pipe is open and playing might be in progress */ - format = &streams_infop->acs_ac_to_as_req.acr_curr_format; - - /* Keep a copy of the old format */ - bcopy((void *)format, (void *)&old_format, - sizeof (usb_audio_formats_t)); - - ASSERT(streams_infop->acs_setup_teardown_count != 0); - - old_setup_teardown_count = streams_infop->acs_setup_teardown_count; - streams_infop->acs_setup_teardown_count = 1; - - mutex_exit(&uacp->usb_ac_mutex); - - if (dir == AUDIO_PLAY) { - usb_ac_do_stop_play(ahdl); - } else if (dir == AUDIO_RECORD) { - usb_ac_do_stop_record(ahdl); - } - - /* This blocks until the current isoc xfer is over */ - usb_ac_do_teardown(ahdl, dir); - - if (usb_ac_send_format_cmd(ahdl, dir, sample, - channels, precision, encoding) != USB_SUCCESS) { - /* - * Setting new alternate has failed, try restoring - * old one. - * If there is a bandwidth failure, hang around - * till bandwidth is available. Also we know that - * there is a matching alternate, so that can't fail. - */ - if (usb_ac_send_format_cmd(ahdl, dir, - old_format.fmt_sr, old_format.fmt_chns, - old_format.fmt_precision, old_format.fmt_encoding) == - USB_FAILURE) { - - /* We closed the pipe; reopen it */ - (void) usb_ac_do_setup(ahdl, dir); - - mutex_enter(&uacp->usb_ac_mutex); - streams_infop->acs_setup_teardown_count = - old_setup_teardown_count; - mutex_exit(&uacp->usb_ac_mutex); - - usb_ac_release_access(uacp); - - return (AUDIO_FAILURE); - } - } - - /* This should block until successful */ - (void) usb_ac_do_setup(ahdl, dir); - - mutex_enter(&uacp->usb_ac_mutex); - streams_infop->acs_setup_teardown_count = old_setup_teardown_count; - mutex_exit(&uacp->usb_ac_mutex); - - usb_ac_release_access(uacp); + usb_ac_stop_play(uacp, engine); + usb_ac_teardown(uacp, engine); - return (AUDIO_SUCCESS); -} - - -/* - * usb_ac_get_curr_n_channels: - * Return no. of channels from the current format table - */ -static int -usb_ac_get_curr_n_channels(usb_ac_state_t *uacp, int dir) -{ - usb_audio_formats_t *cur_fmt = usb_ac_get_curr_format(uacp, dir); - - return (cur_fmt->fmt_chns); -} - - -/* - * usb_ac_get_cur_format: - * Get format for the current alternate - */ -static usb_audio_formats_t * -usb_ac_get_curr_format(usb_ac_state_t *uacp, int dir) -{ - usb_ac_plumbed_t *plumb_infop; - usb_ac_streams_info_t *streams_infop = NULL; - - ASSERT(mutex_owned(&uacp->usb_ac_mutex)); - - plumb_infop = usb_ac_get_plumb_info(uacp, "usb_as", dir); - if (plumb_infop == NULL) { - USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_get_curr_format: no plumb info"); - - return (NULL); - } - - streams_infop = (usb_ac_streams_info_t *)plumb_infop->acp_data; - ASSERT(streams_infop != NULL); - - return (&streams_infop->acs_cur_fmt); -} - - -/* - * usb_ac_send_format_cmd - * Sets format and get alternate setting that matches with - * the format from the usb_as playing or recording interface - * Send the set sample freq command down to usb_as. - */ -static int -usb_ac_send_format_cmd(audiohdl_t ahdl, int dir, - int sample, int channels, int precision, int encoding) -{ - usb_ac_state_t *uacp = audio_sup_get_private(ahdl); - usb_audio_formats_t *format; - usb_ac_plumbed_t *plumb_infop = NULL; - usb_ac_streams_info_t *streams_infop = NULL; - - ASSERT(uacp != NULL); - - mutex_enter(&uacp->usb_ac_mutex); - if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) { - mutex_exit(&uacp->usb_ac_mutex); - - return (USB_FAILURE); + usb_ac_serialize_access(uacp); + mutex_enter(&uacp->usb_ac_mutex); } - plumb_infop = usb_ac_get_plumb_info(uacp, "usb_as", dir); - ASSERT(plumb_infop); - - streams_infop = (usb_ac_streams_info_t *)plumb_infop->acp_data; - ASSERT(streams_infop != NULL); - - ASSERT(dir == AUDIO_PLAY || dir == AUDIO_RECORD); - streams_infop->acs_ac_to_as_req.acr_curr_dir = dir; - - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_send_format_cmd: plumb_infop=0x%p, streams_infop=0x%p", - (void *)plumb_infop, (void *)streams_infop); - - format = &(streams_infop->acs_ac_to_as_req.acr_curr_format); - bzero(format, sizeof (usb_audio_formats_t)); - - /* save format info */ - format->fmt_sr = (uint_t)sample; - format->fmt_chns = (uchar_t)channels; - format->fmt_precision = (uchar_t)precision; - format->fmt_encoding = (uchar_t)encoding; - - streams_infop->acs_cur_fmt = *format; - /* * Set format for the streaming interface with lower write queue * This boils down to set_alternate interface command in * usb_as and the reply mp contains the currently active * alternate number that is stored in the as_req structure */ - if (usb_ac_send_as_cmd(uacp, plumb_infop, - USB_AUDIO_SET_FORMAT, format) != USB_SUCCESS) { + if (usb_ac_send_as_cmd(uacp, engine, + USB_AUDIO_SET_FORMAT, &format) != USB_SUCCESS) { USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_send_format_cmd: failed"); - mutex_exit(&uacp->usb_ac_mutex); + "usb_ac_set_format: failed"); + goto fail; - return (USB_FAILURE); - } else { - /* store matching alternate number */ - streams_infop->acs_ac_to_as_req.acr_curr_format.fmt_alt = - format->fmt_alt; } + int sample = engine->fmt.sr; /* Set the sample rate */ - if (usb_ac_send_as_cmd(uacp, plumb_infop, USB_AUDIO_SET_SAMPLE_FREQ, + if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_SET_SAMPLE_FREQ, &sample) != USB_SUCCESS) { USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_send_format_cmd: setting format failed"); + "usb_ac_set_format: setting format failed"); + goto fail; - mutex_exit(&uacp->usb_ac_mutex); + } - return (USB_FAILURE); + mutex_exit(&uacp->usb_ac_mutex); + + usb_ac_release_access(uacp); + + /* This should block until successful */ + if (old_setup_teardown_count) { + (void) usb_ac_setup(uacp, engine); } + mutex_enter(&uacp->usb_ac_mutex); + streams_infop->acs_setup_teardown_count = old_setup_teardown_count; mutex_exit(&uacp->usb_ac_mutex); return (USB_SUCCESS); -} +fail: + streams_infop->acs_setup_teardown_count = old_setup_teardown_count; + mutex_exit(&uacp->usb_ac_mutex); + usb_ac_release_access(uacp); + return (USB_FAILURE); + +} /* * usb_ac_start_play @@ -3581,22 +3077,17 @@ usb_ac_send_format_cmd(audiohdl_t ahdl, int dir, * Check power is done in usb_ac_send_as_cmd() */ static int -usb_ac_start_play(audiohdl_t ahdl) +usb_ac_start_play(usb_ac_state_t *uacp, usb_audio_eng_t *engine) { - usb_ac_state_t *uacp = audio_sup_get_private(ahdl); - usb_audio_formats_t *cur_fmt; - usb_ac_plumbed_t *plumb_infop = NULL; - int dir, samples; + int samples; usb_audio_play_req_t play_req; - usb_ac_streams_info_t *streams_infop = NULL; - ASSERT(uacp != NULL); mutex_enter(&uacp->usb_ac_mutex); if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) { mutex_exit(&uacp->usb_ac_mutex); - return (AUDIO_FAILURE); + return (USB_FAILURE); } mutex_exit(&uacp->usb_ac_mutex); @@ -3604,33 +3095,19 @@ usb_ac_start_play(audiohdl_t ahdl) mutex_enter(&uacp->usb_ac_mutex); - plumb_infop = usb_ac_get_plumb_info(uacp, "usb_as", AUDIO_PLAY); - ASSERT(plumb_infop); - - streams_infop = (usb_ac_streams_info_t *)plumb_infop->acp_data; - ASSERT(streams_infop != NULL); - - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_start_play: plumb_infop=0x%p, streams_infop=0x%p", - (void *)plumb_infop, (void *)streams_infop); - - dir = streams_infop->acs_ac_to_as_req.acr_curr_dir; - ASSERT(dir == AUDIO_PLAY); - cur_fmt = &streams_infop->acs_ac_to_as_req.acr_curr_format; /* Check for continuous sample rate done in usb_as */ - samples = cur_fmt->fmt_sr * cur_fmt->fmt_chns / - uacp->usb_ac_am_ad_info.ad_play.ad_int_rate; - if (samples & cur_fmt->fmt_chns) { + samples = engine->fmt.sr * engine->fmt.ch / engine->intrate; + if (samples & engine->fmt.ch) { samples++; } play_req.up_samples = samples; - play_req.up_handle = ahdl; + play_req.up_handle = uacp; /* Send setup command to usb_as */ - if (usb_ac_send_as_cmd(uacp, plumb_infop, USB_AUDIO_START_PLAY, + if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_START_PLAY, (void *)&play_req) != USB_SUCCESS) { USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, @@ -3640,29 +3117,29 @@ usb_ac_start_play(audiohdl_t ahdl) usb_ac_release_access(uacp); - return (AUDIO_FAILURE); + return (USB_FAILURE); } mutex_exit(&uacp->usb_ac_mutex); usb_ac_release_access(uacp); - return (AUDIO_SUCCESS); + return (USB_SUCCESS); } /* * usb_ac_stop_play: - * Wrapper function for usb_ac_do_stop_play and gets + * Stop the play engine * called from mixer framework. */ -static void -usb_ac_stop_play(audiohdl_t ahdl) +void +usb_ac_stop_play(usb_ac_state_t *uacp, usb_audio_eng_t *engine) { - usb_ac_state_t *uacp = audio_sup_get_private(ahdl); - - ASSERT(uacp != NULL); + if (engine == NULL) { + engine = &(uacp->engines[0]); + } mutex_enter(&uacp->usb_ac_mutex); if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) { mutex_exit(&uacp->usb_ac_mutex); @@ -3672,34 +3149,10 @@ usb_ac_stop_play(audiohdl_t ahdl) mutex_exit(&uacp->usb_ac_mutex); usb_ac_serialize_access(uacp); - usb_ac_do_stop_play(ahdl); - usb_ac_release_access(uacp); -} - -/* - * usb_ac_do_pause_play: - * Send a pause_play command to usb_as. - * Check power is done in usb_ac_send_as_cmd() - */ -static void -usb_ac_do_stop_play(audiohdl_t ahdl) -{ - usb_ac_state_t *uacp = audio_sup_get_private(ahdl); - usb_ac_plumbed_t *plumb_infop = NULL; - usb_ac_streams_info_t *streams_infop = NULL; - - ASSERT(uacp != NULL); - mutex_enter(&uacp->usb_ac_mutex); - plumb_infop = usb_ac_get_plumb_info(uacp, "usb_as", AUDIO_PLAY); - ASSERT(plumb_infop); - - streams_infop = (usb_ac_streams_info_t *)plumb_infop->acp_data; - ASSERT(streams_infop != NULL); - /* Send setup command to usb_as */ - if (usb_ac_send_as_cmd(uacp, plumb_infop, USB_AUDIO_PAUSE_PLAY, + if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_PAUSE_PLAY, (void *)NULL) != USB_SUCCESS) { USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, @@ -3707,6 +3160,7 @@ usb_ac_do_stop_play(audiohdl_t ahdl) } mutex_exit(&uacp->usb_ac_mutex); + usb_ac_release_access(uacp); } @@ -3716,34 +3170,25 @@ usb_ac_do_stop_play(audiohdl_t ahdl) * Check power is done in usb_ac_send_as_cmd() */ static int -usb_ac_start_record(audiohdl_t ahdl) +usb_ac_start_record(usb_ac_state_t *uacp, usb_audio_eng_t *engine) { - usb_ac_state_t *uacp = audio_sup_get_private(ahdl); - usb_ac_plumbed_t *plumb_infop = NULL; - usb_ac_streams_info_t *streams_infop = NULL; - ASSERT(uacp != NULL); mutex_enter(&uacp->usb_ac_mutex); if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) { mutex_exit(&uacp->usb_ac_mutex); - return (AUDIO_FAILURE); + return (USB_FAILURE); } mutex_exit(&uacp->usb_ac_mutex); usb_ac_serialize_access(uacp); - mutex_enter(&uacp->usb_ac_mutex); - plumb_infop = usb_ac_get_plumb_info(uacp, "usb_as", AUDIO_RECORD); - ASSERT(plumb_infop); - streams_infop = (usb_ac_streams_info_t *)plumb_infop->acp_data; - ASSERT(streams_infop != NULL); /* Send setup command to usb_as */ - if (usb_ac_send_as_cmd(uacp, plumb_infop, USB_AUDIO_START_RECORD, - (void *)&ahdl) != USB_SUCCESS) { + if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_START_RECORD, + (void *)uacp) != USB_SUCCESS) { USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, "usb_ac_start_record: failure"); @@ -3752,14 +3197,13 @@ usb_ac_start_record(audiohdl_t ahdl) usb_ac_release_access(uacp); - return (AUDIO_FAILURE); + return (USB_FAILURE); } mutex_exit(&uacp->usb_ac_mutex); - usb_ac_release_access(uacp); - return (AUDIO_SUCCESS); + return (USB_SUCCESS); } @@ -3769,42 +3213,14 @@ usb_ac_start_record(audiohdl_t ahdl) * called form mixer framework. */ static void -usb_ac_stop_record(audiohdl_t ahdl) +usb_ac_stop_record(usb_ac_state_t *uacp, usb_audio_eng_t *engine) { - usb_ac_state_t *uacp = audio_sup_get_private(ahdl); - - ASSERT(uacp != NULL); usb_ac_serialize_access(uacp); - usb_ac_do_stop_record(ahdl); - usb_ac_release_access(uacp); -} - - -/* - * usb_ac_do_stop_record: - * Sends a stop_record command down. - * Check power is done in usb_ac_send_as_cmd() - */ -static void -usb_ac_do_stop_record(audiohdl_t ahdl) -{ - usb_ac_state_t *uacp = audio_sup_get_private(ahdl); - usb_ac_plumbed_t *plumb_infop = NULL; - usb_ac_streams_info_t *streams_infop = NULL; - - ASSERT(uacp != NULL); - mutex_enter(&uacp->usb_ac_mutex); - plumb_infop = usb_ac_get_plumb_info(uacp, "usb_as", AUDIO_RECORD); - ASSERT(plumb_infop != NULL); - - streams_infop = (usb_ac_streams_info_t *)plumb_infop->acp_data; - ASSERT(streams_infop != NULL); - /* Send setup command to usb_as */ - if (usb_ac_send_as_cmd(uacp, plumb_infop, USB_AUDIO_STOP_RECORD, + if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_STOP_RECORD, NULL) != USB_SUCCESS) { USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, @@ -3812,6 +3228,7 @@ usb_ac_do_stop_record(audiohdl_t ahdl) } mutex_exit(&uacp->usb_ac_mutex); + usb_ac_release_access(uacp); } @@ -3823,6 +3240,7 @@ usb_ac_do_stop_record(audiohdl_t ahdl) * Calculate min or max gain balance and return that. Return * USB_FAILURE for failure cases */ +/* ARGSUSED */ static int usb_ac_get_maxmin_volume(usb_ac_state_t *uacp, uint_t channel, int cmd, int dir, int feature_unitID, short *max_or_minp) @@ -3831,9 +3249,6 @@ usb_ac_get_maxmin_volume(usb_ac_state_t *uacp, uint_t channel, int cmd, usb_cr_t cr; usb_cb_flags_t cb_flags; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_get_maxmin_volume: channel=%d, cmd=%d dir=%d", - channel, cmd, dir); mutex_exit(&uacp->usb_ac_mutex); @@ -3881,6 +3296,7 @@ usb_ac_get_maxmin_volume(usb_ac_state_t *uacp, uint_t channel, int cmd, * usb_ac_set_volume: * Send USBA command down to set the gain balance */ +/* ARGSUSED */ static int usb_ac_set_volume(usb_ac_state_t *uacp, uint_t channel, short gain, int dir, int feature_unitID) @@ -3890,14 +3306,20 @@ usb_ac_set_volume(usb_ac_state_t *uacp, uint_t channel, short gain, int dir, usb_cb_flags_t cb_flags; int rval = USB_FAILURE; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_set_volume: channel=%d gain=%d dir=%d FU=%d", - channel, gain, dir, feature_unitID); mutex_exit(&uacp->usb_ac_mutex); /* Construct the mblk_t from gain for sending to USBA */ - data = allocb_wait(4, BPRI_HI, STR_NOSIG, NULL); + data = allocb(4, BPRI_HI); + if (!data) { + USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, + "usb_ac_set_volume: allocate data failed"); + mutex_enter(&uacp->usb_ac_mutex); + + return (USB_FAILURE); + } + + *(data->b_wptr++) = (char)gain; *(data->b_wptr++) = (char)(gain >> 8); @@ -3931,7 +3353,7 @@ usb_ac_set_volume(usb_ac_state_t *uacp, uint_t channel, short gain, int dir, * usb_ac_set_mute is called for each unit that supports the * requested control from usb_ac_traverse_connections */ -static int +int usb_ac_set_mute(usb_ac_state_t *uacp, uint_t featureID, uint_t dir, uint_t channel, uint_t control, uint_t muteval, uint_t *depth) { @@ -3940,19 +3362,26 @@ usb_ac_set_mute(usb_ac_state_t *uacp, uint_t featureID, uint_t dir, usb_cb_flags_t cb_flags; int rval = USB_FAILURE; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_set_mute: muteval=0x%x, dir=%d", muteval, dir); if (usb_ac_feature_unit_check(uacp, featureID, dir, channel, control, 0, depth) != USB_SUCCESS) { return (USB_FAILURE); } - mutex_exit(&uacp->usb_ac_mutex); /* Construct the mblk_t for sending to USBA */ - data = allocb_wait(1, BPRI_HI, STR_NOSIG, NULL); + data = allocb(1, BPRI_HI); + + if (!data) { + USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, + "usb_ac_set_mute: allocate data failed"); + mutex_enter(&uacp->usb_ac_mutex); + + return (USB_FAILURE); + } + + *(data->b_wptr++) = (char)muteval; if ((rval = usb_pipe_sync_ctrl_xfer( @@ -3973,8 +3402,8 @@ usb_ac_set_mute(usb_ac_state_t *uacp, uint_t featureID, uint_t dir, USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, "usb_ac_set_mute: failed, cr=%d cb=0x%x", cr, cb_flags); } - freemsg(data); + mutex_enter(&uacp->usb_ac_mutex); return (rval); @@ -3990,22 +3419,19 @@ usb_ac_set_mute(usb_ac_state_t *uacp, uint_t featureID, uint_t dir, * it seems better to ensure that both interfaces are at full power */ static int -usb_ac_send_as_cmd(usb_ac_state_t *uacp, usb_ac_plumbed_t *plumb_infop, +usb_ac_send_as_cmd(usb_ac_state_t *uacp, usb_audio_eng_t *engine, int cmd, void *arg) { usb_ac_streams_info_t *streams_infop; + usb_ac_plumbed_t *plumb_infop; int rv; int rval; ldi_handle_t lh; ASSERT(mutex_owned(&uacp->usb_ac_mutex)); - ASSERT(plumb_infop != NULL); - - streams_infop = (usb_ac_streams_info_t *)plumb_infop->acp_data; - ASSERT(streams_infop != NULL); + streams_infop = engine->streams; + plumb_infop = streams_infop->acs_plumbed; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_send_as_cmd: cmd=0x%x, arg=0x%p", cmd, arg); lh = plumb_infop->acp_lh; @@ -4124,15 +3550,10 @@ usb_ac_reader(void *argp) break; } + if ((acp->acp_flags & ACP_ENABLED) && mp != NULL && rv == 0) rv = usb_ac_read_msg(acp, mp); - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "%s%d read from %s%d, rv=%d", - ddi_driver_name(uacp->usb_ac_dip), - ddi_get_instance(uacp->usb_ac_dip), - ddi_driver_name(acp->acp_dip), - ddi_get_instance(acp->acp_dip), rv); } mutex_exit(&uacp->usb_ac_mutex); } @@ -4446,8 +3867,6 @@ usb_ac_mux_unplumbing(usb_ac_state_t *uacp) mutex_enter(&uacp->usb_ac_mutex); - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_mux_unplumbing: state=%d", uacp->usb_ac_plumbing_state); if (uacp->usb_ac_plumbing_state == USB_AC_STATE_UNPLUMBED) { USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, @@ -4510,10 +3929,11 @@ usb_ac_mux_unplumbing(usb_ac_state_t *uacp) ddi_driver_name(acp_dip), inst, minor); if (lh != NULL) { - mutex_exit(&uacp->usb_ac_mutex); acp->acp_flags &= ~ACP_ENABLED; + mutex_exit(&uacp->usb_ac_mutex); + USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, "usb_ac_mux_unplumbing:[%d] - closing", i); @@ -4573,10 +3993,6 @@ usb_ac_mux_walk_siblings(usb_ac_state_t *uacp) pdip = ddi_get_parent(uacp->usb_ac_dip); child_dip = ddi_get_child(pdip); - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_mux_walk_siblings: parent=%s%d", - ddi_driver_name(pdip), ddi_get_instance(pdip)); - while ((child_dip != NULL) && (count < USB_AC_MAX_PLUMBED)) { drv_instance = ddi_get_instance(child_dip); drv_name = (char *)ddi_driver_name(child_dip); @@ -4634,7 +4050,9 @@ usb_ac_mux_walk_siblings(usb_ac_state_t *uacp) error = ldi_ident_from_dip(uacp->usb_ac_dip, &li); if (error == 0) { + mutex_enter(&uacp->usb_ac_mutex); uacp->usb_ac_plumbed[count].acp_flags |= ACP_ENABLED; + mutex_exit(&uacp->usb_ac_mutex); error = ldi_open_by_dev(&drv_devt, OTYP_CHR, FREAD|FWRITE, kcred, &drv_lh, li); @@ -4743,49 +4161,17 @@ usb_ac_mux_walk_siblings(usb_ac_state_t *uacp) /* - * usb_ac_find_default_port: - */ -static int -usb_ac_find_default_port(uint_t port) -{ - int i; - - for (i = 0; i < 32; i++) { - if (port & (1 << i)) { - - return (1 << i); - } - } - - return (0); -} - - -/* * Register with mixer only after first plumbing. * Also do not register if earlier reg data * couldn't be received from at least one * streaming interface */ -_NOTE(SCHEME_PROTECTS_DATA("private", am_ad_info)) static int usb_ac_mixer_registration(usb_ac_state_t *uacp) { - am_ad_info_t *info = &uacp->usb_ac_am_ad_info; - audio_info_t *dflts = &uacp->usb_ac_am_ad_defaults; usb_as_registration_t *asreg; - int n, nplay, nrec; - - ASSERT(uacp != NULL); - - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_mixer_registration:infp=0x%p, dflts=0x%p," - "already registered=%d", (void *)info, (void *)dflts, - uacp->usb_ac_registered_with_mixer); - - ASSERT(dflts != NULL); - ASSERT(info != NULL); + int n; if (uacp->usb_ac_registered_with_mixer) { return (USB_SUCCESS); @@ -4805,45 +4191,23 @@ usb_ac_mixer_registration(usb_ac_state_t *uacp) return (USB_FAILURE); } - info->ad_defaults = dflts; - - dflts->monitor_gain = 0; - dflts->output_muted = B_FALSE; - dflts->hw_features = 0; - dflts->sw_features = AUDIO_SWFEATURE_MIXER; - /* * Fill out streaming interface specific stuff * Note that we handle only one playing and one recording * streaming interface at the most */ - nplay = nrec = 0; for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) { - int ch, chs, default_gain, id; + int ch, chs, id; if (uacp->usb_ac_streams[n].acs_rcvd_reg_data == 0) { continue; } - asreg = uacp->usb_ac_streams[n].acs_streams_reg; + asreg = &(uacp->usb_ac_streams[n].acs_streams_reg); if (asreg->reg_valid == 0) { continue; } - mutex_exit(&uacp->usb_ac_mutex); - - USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_mixer_registration: setting format n=%d", n); - - /* set first format so get_featureID can be succeed */ - (void) usb_ac_set_format(uacp->usb_ac_audiohdl, - asreg->reg_mode, - asreg->reg_srs[0], - asreg->reg_formats[0].fmt_chns, - asreg->reg_formats[0].fmt_precision, - asreg->reg_formats[0].fmt_encoding); - - mutex_enter(&uacp->usb_ac_mutex); chs = asreg->reg_formats[0].fmt_chns; @@ -4861,88 +4225,28 @@ usb_ac_mixer_registration(usb_ac_state_t *uacp) break; } } - default_gain = (id == USB_AC_ID_NONE) ? - AUDIO_MAX_GAIN : (AUDIO_MAX_GAIN/2); + + uacp->usb_ac_streams[n].acs_default_gain = + (id == USB_AC_ID_NONE) ? (AF_MAX_GAIN): (AF_MAX_GAIN*3/4); USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle, "usb_ac_mixer_registration:n= [%d] - mode=%d chs=%d" "default_gain=%d id=%d", - n, asreg->reg_mode, chs, default_gain, id); - - if (asreg->reg_mode == AUDIO_PLAY) { - nplay++; - ASSERT(nplay == 1); - - dflts->play.sample_rate = - asreg->reg_srs[0]; - dflts->play.channels = - asreg->reg_formats[0].fmt_chns; - dflts->play.precision = - asreg->reg_formats[0].fmt_precision; - dflts->play.encoding = - asreg->reg_formats[0].fmt_encoding; - dflts->play.gain = default_gain; - dflts->play.port = usb_ac_find_default_port( - uacp->usb_ac_output_ports); - dflts->play.avail_ports = uacp->usb_ac_output_ports; - dflts->play.mod_ports = 0; - /* no support for mixer unit */ - dflts->play.buffer_size = 8*1024; - dflts->hw_features |= AUDIO_HWFEATURE_PLAY; - - info->ad_play.ad_mixer_srs.ad_srs = asreg->reg_srs; - - info->ad_play.ad_chs = asreg->reg_channels; - info->ad_play.ad_int_rate = 1000; /* every 1 ms */ - info->ad_play.ad_bsize = 8 * 1024; - info->ad_play_comb = asreg->reg_combinations; - } else { - nrec++; - ASSERT(nrec == 1); - - dflts->record.sample_rate = - asreg->reg_srs[0]; - dflts->record.channels = - asreg->reg_formats[0].fmt_chns; - dflts->record.precision = - asreg->reg_formats[0].fmt_precision; - dflts->record.encoding = - asreg->reg_formats[0].fmt_encoding; - dflts->record.gain = default_gain; - dflts->record.port = usb_ac_find_default_port( - uacp->usb_ac_input_ports); - dflts->record.avail_ports = uacp->usb_ac_input_ports; - dflts->record.mod_ports = uacp->usb_ac_input_ports; - dflts->record.buffer_size = 8*1024; - dflts->hw_features |= AUDIO_HWFEATURE_RECORD; - - info->ad_record.ad_mixer_srs.ad_srs = asreg->reg_srs; - - info->ad_record.ad_chs = asreg->reg_channels; - info->ad_record.ad_int_rate = 1000; /* every 1 ms */ - info->ad_record.ad_bsize = 8 * 1024; - info->ad_num_mics = 1; - info->ad_rec_comb = asreg->reg_combinations; - } - } + n, asreg->reg_mode, chs, + uacp->usb_ac_streams[n].acs_default_gain, id); - if (nplay && nrec) { - dflts->hw_features |= AUDIO_HWFEATURE_DUPLEX; } /* the rest */ - info->ad_entry = &usb_ac_entry; - info->ad_dev_info = &usb_dev_info; USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_mixer_registration: calling am_attach"); + "usb_ac_mixer_registration: calling usb_audio_register"); mutex_exit(&uacp->usb_ac_mutex); - if (am_attach(uacp->usb_ac_audiohdl, DDI_ATTACH, info) == - AUDIO_FAILURE) { + if (usb_audio_register(uacp) != USB_SUCCESS) { USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_mixer_registration: am_attach failed"); + "usb_ac_mixer_registration: usb_audio_register failed"); mutex_enter(&uacp->usb_ac_mutex); @@ -4953,16 +4257,12 @@ usb_ac_mixer_registration(usb_ac_state_t *uacp) uacp->usb_ac_registered_with_mixer = 1; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_mixer_registration:- am_attach succeeded"); - return (USB_SUCCESS); } /* - * get registration data from usb_as driver unless we already - * have 2 registrations + * Get registriations data when driver attach */ static int usb_ac_get_reg_data(usb_ac_state_t *uacp, ldi_handle_t drv_lh, int index) @@ -4970,17 +4270,10 @@ usb_ac_get_reg_data(usb_ac_state_t *uacp, ldi_handle_t drv_lh, int index) int n, error, rval; usb_as_registration_t *streams_reg; - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_get_reg_data: index=%d, mixer registered=%d", index, - uacp->usb_ac_registered_with_mixer); - /* if already registered, just setup data structures again */ - if (uacp->usb_ac_registered_with_mixer) { - - return (usb_ac_setup_plumbed(uacp, index, -1, -1)); - } + ASSERT(uacp->usb_ac_registered_with_mixer == 0); - for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n ++) { + for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) { /* * We haven't received registration data * from n-th streaming interface in the array @@ -4999,7 +4292,7 @@ usb_ac_get_reg_data(usb_ac_state_t *uacp, ldi_handle_t drv_lh, int index) } /* take the stream reg struct with the same index */ - streams_reg = &uacp->usb_ac_streams_reg[n]; + streams_reg = &uacp->usb_ac_streams[n].acs_streams_reg; USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, "usb_ac_get_reg_data:regdata from usb_as: streams_reg=0x%p, n=%d", @@ -5019,13 +4312,13 @@ usb_ac_get_reg_data(usb_ac_state_t *uacp, ldi_handle_t drv_lh, int index) } else { mutex_enter(&uacp->usb_ac_mutex); - rval = usb_ac_setup_plumbed(uacp, index, n, n); + rval = usb_ac_setup_plumbed(uacp, index, n); USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, "usb_ac_get_reg_data:usb_ac_streams[%d]: " "received_reg_data=%d type=%s", index, uacp->usb_ac_streams[n].acs_rcvd_reg_data, - ((streams_reg->reg_mode == AUDIO_PLAY) ? + ((streams_reg->reg_mode == USB_AUDIO_PLAY) ? "play" : "record")); usb_ac_print_reg_data(uacp, streams_reg); @@ -5036,64 +4329,21 @@ usb_ac_get_reg_data(usb_ac_state_t *uacp, ldi_handle_t drv_lh, int index) /* - * setup plumbed and stream info structure, either initially or - * after replumbing - * On replumbing, str_idx and reg_idx are -1 + * setup plumbed and stream info structure */ static int -usb_ac_setup_plumbed(usb_ac_state_t *uacp, int plb_idx, int str_idx, - int reg_idx) +usb_ac_setup_plumbed(usb_ac_state_t *uacp, int plb_idx, int str_idx) { - int i; - - USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_setup_plumbed: plb_idx=%d str_idx=%d", - plb_idx, str_idx); - - if (str_idx == -1) { - /* find a free streams info structure */ - for (i = 0; i < USB_AC_MAX_AS_PLUMBED; i++) { - if (uacp->usb_ac_streams[i].acs_plumbed == NULL) { - break; - } - } - ASSERT(i < USB_AC_MAX_AS_PLUMBED); - str_idx = i; - } - uacp->usb_ac_plumbed[plb_idx].acp_data = &uacp->usb_ac_streams[str_idx]; uacp->usb_ac_streams[str_idx].acs_plumbed = &uacp->usb_ac_plumbed[plb_idx]; uacp->usb_ac_streams[str_idx].acs_rcvd_reg_data = 1; - if (reg_idx == -1) { - /* - * find the corresponding registration structure, match - * on interface number and not on dip since dip may have - * changed - */ - for (i = 0; i < USB_AC_MAX_AS_PLUMBED; i++) { - if (uacp->usb_ac_streams_reg[i].reg_ifno == - uacp->usb_ac_plumbed[plb_idx].acp_ifno) { - break; - } - } - if (i == USB_AC_MAX_AS_PLUMBED) { - USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_setup_plumbed:no corresponding registration " - "structure"); - - return (USB_FAILURE); - } - reg_idx = i; - } - uacp-> usb_ac_streams[str_idx].acs_streams_reg = - &uacp->usb_ac_streams_reg[reg_idx]; USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_setup_plumbed: done - plb_idx=%d str_idx=%d reg_idx=%d", - plb_idx, str_idx, reg_idx); + "usb_ac_setup_plumbed: done - plb_idx=%d str_idx=%d ", + plb_idx, str_idx); return (USB_SUCCESS); } @@ -5108,12 +4358,6 @@ usb_ac_print_reg_data(usb_ac_state_t *uacp, { int n; - USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "usb_ac_print_reg_data: Begin valid=%d, play=%d, " - "n_formats=%d, compat srs ptr=0x%p", - reg->reg_valid, reg->reg_mode, reg->reg_n_formats, - (void *)®->reg_srs); - for (n = 0; n < reg->reg_n_formats; n++) { USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle, "format%d: alt=%d chns=%d prec=%d enc=%d", n, @@ -5123,14 +4367,6 @@ usb_ac_print_reg_data(usb_ac_state_t *uacp, reg->reg_formats[n].fmt_encoding); } - USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "combinations: %d %d %d %d %d %d %d %d", - reg->reg_combinations[0].ad_prec, reg->reg_combinations[0].ad_enc, - reg->reg_combinations[1].ad_prec, reg->reg_combinations[1].ad_enc, - reg->reg_combinations[2].ad_prec, reg->reg_combinations[2].ad_enc, - reg->reg_combinations[3].ad_prec, reg->reg_combinations[3].ad_enc); - - for (n = 0; n < USB_AS_N_FORMATS; n++) { USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle, "reg_formats[%d] ptr=0x%p", n, @@ -5142,13 +4378,7 @@ usb_ac_print_reg_data(usb_ac_state_t *uacp, "reg_channels[%d]=%d", n, reg->reg_channels[n]); } - for (n = 0; n < USB_AS_N_COMBINATIONS; n++) { - USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle, - "reg_combinations[%d] ptr=0x%p", n, - (void *)®->reg_combinations[n]); - } - - USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle, + USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle, "usb_ac_print_reg_data: End"); } @@ -5266,3 +4496,1223 @@ usb_ac_rele_siblings(usb_ac_state_t *uacp) } ndi_devi_exit(pdip, circ); } +static void +usb_restore_engine(usb_ac_state_t *statep) +{ + usb_audio_eng_t *engp; + int i; + + for (i = 0; i < USB_AC_ENG_MAX; i++) { + + mutex_enter(&statep->usb_ac_mutex); + engp = &statep->engines[i]; + mutex_exit(&statep->usb_ac_mutex); + + if (engp->af_engp == NULL) + continue; + if (usb_ac_set_format(statep, engp) != USB_SUCCESS) { + USB_DPRINTF_L2(PRINT_MASK_ATTA, + statep->usb_ac_log_handle, + "usb_restore_engine:set format fail, i=%d", i); + return; + } + if (engp->started) { + (void) usb_engine_start(engp); + } + + } + + (void) usb_ac_ctrl_restore(statep); +} + + +/* + * get the maximum format specification the device supports + */ +static void +usb_ac_max_fmt(usb_as_registration_t *reg_data, + usb_audio_format_t *fmtp) +{ + + uint_t *srs, *chs; + uint_t sr, ch, prec, enc, val; + int i; + + usb_audio_formats_t *reg_formats = reg_data->reg_formats; + srs = reg_data->reg_srs; + chs = reg_data->reg_channels; + + for (i = 0, sr = 0; srs[i]; i++) { + val = srs[i]; + if (val > sr) + sr = val; + } + + for (i = 0, ch = 0; chs[i]; i++) { + val = chs[i]; + if (val > ch) + ch = val; + } + + for (i = 0, prec = 0, enc = 0; i < reg_data->reg_n_formats; i++) { + val = reg_formats[i].fmt_precision; + if (val > prec) + prec = val; + + val = reg_formats[i].fmt_encoding; + if (val > enc) + enc = val; + } + + fmtp->sr = sr; + fmtp->ch = ch; + fmtp->prec = prec; + fmtp->enc = enc; +} + + +static void +usb_ac_rem_eng(usb_ac_state_t *statep, usb_audio_eng_t *engp) +{ + if (statep->usb_ac_audio_dev == NULL || engp->af_engp == NULL) + return; + + audio_dev_remove_engine(statep->usb_ac_audio_dev, engp->af_engp); + audio_engine_free(engp->af_engp); + + mutex_enter(&engp->lock); + engp->af_engp = NULL; + engp->streams = NULL; + mutex_exit(&engp->lock); +} + + +static int +usb_ac_add_eng(usb_ac_state_t *uacp, usb_ac_streams_info_t *asinfo) +{ + audio_dev_t *af_devp = uacp->usb_ac_audio_dev; + usb_audio_eng_t *engp; + audio_engine_t *af_engp; + int rv = USB_FAILURE; + int dir = asinfo->acs_streams_reg.reg_mode; + uint_t defgain; + + if (asinfo->acs_rcvd_reg_data == 0) { + + return (USB_SUCCESS); + } + if (dir == USB_AUDIO_PLAY) { + engp = &(uacp->engines[0]); + } else { + engp = &(uacp->engines[1]); + } + + mutex_init(&engp->lock, NULL, MUTEX_DRIVER, NULL); + + mutex_enter(&engp->lock); + + engp->af_eflags = + (dir == USB_AUDIO_PLAY)?ENGINE_OUTPUT_CAP:ENGINE_INPUT_CAP; + engp->statep = uacp; + + /* Set the format for the engine */ + usb_ac_max_fmt(&(asinfo->acs_streams_reg), &engp->fmt); + + /* init the default gain */ + defgain = asinfo->acs_default_gain; + if (engp->fmt.ch == 2) { + engp->af_defgain = AUDIO_CTRL_STEREO_VAL(defgain, defgain); + } else { + engp->af_defgain = defgain; + } + engp->streams = asinfo; + + mutex_exit(&engp->lock); + + af_engp = audio_engine_alloc(&usb_engine_ops, engp->af_eflags); + if (af_engp == NULL) { + + USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, + "audio_engine_alloc failed"); + goto OUT; + } + ASSERT(engp->af_engp == 0); + + mutex_enter(&engp->lock); + engp->af_engp = af_engp; + mutex_exit(&engp->lock); + + audio_engine_set_private(af_engp, engp); + audio_dev_add_engine(af_devp, af_engp); + + /* + * Set the format for this engine + */ + if (usb_ac_set_format(uacp, engp) != USB_SUCCESS) { + USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, + "set format failed, dir = %d", dir); + goto OUT; + } + rv = USB_SUCCESS; + +OUT: + if (rv != USB_SUCCESS) + usb_ac_rem_eng(uacp, engp); + + return (rv); +} + + +static int +usb_ac_ctrl_set_defaults(usb_ac_state_t *statep) +{ + usb_audio_ctrl_t *ctrlp; + int rv = USB_SUCCESS; + USB_DPRINTF_L4(PRINT_MASK_ATTA, statep->usb_ac_log_handle, + "usb_ac_ctrl_set_defaults:begin"); + + for (int i = 0; i < CTL_NUM; i++) { + ctrlp = statep->controls[i]; + if (!ctrlp) { + continue; + } + if (audio_control_write(ctrlp->af_ctrlp, ctrlp->cval)) { + USB_DPRINTF_L2(PRINT_MASK_ATTA, + statep->usb_ac_log_handle, + "usb_ac_ctrl_set_defaults:control write failed"); + rv = USB_FAILURE; + } + + } + USB_DPRINTF_L4(PRINT_MASK_ATTA, statep->usb_ac_log_handle, + "usb_ac_ctrl_set_defaults:end"); + return (rv); +} + + +static int +usb_ac_ctrl_restore(usb_ac_state_t *statep) +{ + usb_audio_ctrl_t *ctrlp; + int rv = USB_SUCCESS; + + for (int i = 0; i < CTL_NUM; i++) { + ctrlp = statep->controls[i]; + if (ctrlp) { + USB_DPRINTF_L3(PRINT_MASK_ATTA, + statep->usb_ac_log_handle, + "usb_ac_ctrl_restore:i = %d", i); + if (audio_control_write(ctrlp->af_ctrlp, ctrlp->cval)) { + rv = USB_FAILURE; + } + } + } + return (rv); +} + + + + +/* + * moves data between driver buffer and framework/shim buffer + */ +static void +usb_eng_bufio(usb_audio_eng_t *engp, void *buf, size_t sz) +{ + size_t cpsz = sz; + caddr_t *src, *dst; + + if (engp->af_eflags & ENGINE_OUTPUT_CAP) { + src = &engp->bufpos; + dst = (caddr_t *)&buf; + } else { + src = (caddr_t *)&buf; + dst = &engp->bufpos; + } + + /* + * Wrap. If sz is exactly the remainder of the buffer + * (bufpos + sz == bufendp) then the second cpsz should be 0 and so + * the second memcpy() should have no effect, with bufpos updated + * to the head of the buffer. + */ + if (engp->bufpos + sz >= engp->bufendp) { + cpsz = (size_t)engp->bufendp - (size_t)engp->bufpos; + (void) memcpy(*dst, *src, cpsz); + + + buf = (caddr_t)buf + cpsz; + engp->bufpos = engp->bufp; + cpsz = sz - cpsz; + } + + if (cpsz) { + (void) memcpy(*dst, *src, cpsz); + + + engp->bufpos += cpsz; + } + engp->bufio_count++; +} + + +/* + * control read callback + */ +static int +usb_audio_ctrl_read(void *arg, uint64_t *cvalp) +{ + usb_audio_ctrl_t *ctrlp = arg; + + mutex_enter(&ctrlp->ctrl_mutex); + *cvalp = ctrlp->cval; + mutex_exit(&ctrlp->ctrl_mutex); + + return (0); +} + + +/* + * stereo level control callback + */ +static int +usb_audio_write_stero_rec(void *arg, uint64_t cval) +{ + usb_audio_ctrl_t *ctrlp = arg; + usb_ac_state_t *statep = ctrlp->statep; + int rv = EIO; + int left, right; + uint_t count = 0; + + + left = AUDIO_CTRL_STEREO_LEFT(cval); + right = AUDIO_CTRL_STEREO_RIGHT(cval); + + if (left < AF_MIN_GAIN || left > AF_MAX_GAIN || + right < AF_MIN_GAIN || right > AF_MAX_GAIN) { + + return (EINVAL); + } + + mutex_enter(&ctrlp->ctrl_mutex); + ctrlp->cval = cval; + mutex_exit(&ctrlp->ctrl_mutex); + + mutex_enter(&statep->usb_ac_mutex); + (void) usb_ac_set_control(statep, USB_AUDIO_RECORD, + USB_AUDIO_FEATURE_UNIT, 1, + USB_AUDIO_VOLUME_CONTROL, + USB_AC_FIND_ALL, &count, left, usb_ac_set_gain); + + (void) usb_ac_set_control(statep, USB_AUDIO_RECORD, + USB_AUDIO_FEATURE_UNIT, 2, + USB_AUDIO_VOLUME_CONTROL, + USB_AC_FIND_ALL, &count, right, usb_ac_set_gain); + rv = 0; + +done: + mutex_exit(&statep->usb_ac_mutex); + return (rv); +} + +static int +usb_audio_write_ster_vol(void *arg, uint64_t cval) +{ + usb_audio_ctrl_t *ctrlp = arg; + usb_ac_state_t *statep = ctrlp->statep; + int rv = EIO; + int left, right; + uint_t count = 0; + + left = AUDIO_CTRL_STEREO_LEFT(cval); + right = AUDIO_CTRL_STEREO_RIGHT(cval); + + if (left < AF_MIN_GAIN || left > AF_MAX_GAIN || + right < AF_MIN_GAIN || right > AF_MAX_GAIN) { + return (EINVAL); + } + + mutex_enter(&ctrlp->ctrl_mutex); + ctrlp->cval = cval; + mutex_exit(&ctrlp->ctrl_mutex); + + + mutex_enter(&statep->usb_ac_mutex); + (void) usb_ac_set_control(statep, USB_AUDIO_PLAY, + USB_AUDIO_FEATURE_UNIT, 1, + USB_AUDIO_VOLUME_CONTROL, + USB_AC_FIND_ALL, &count, left, usb_ac_set_gain); + + (void) usb_ac_set_control(statep, USB_AUDIO_PLAY, + USB_AUDIO_FEATURE_UNIT, 2, + USB_AUDIO_VOLUME_CONTROL, + USB_AC_FIND_ALL, &count, right, usb_ac_set_gain); + rv = 0; + +OUT: + mutex_exit(&statep->usb_ac_mutex); + return (rv); +} + + +/* + * mono level control callback + */ +static int +usb_audio_write_mono_vol(void *arg, uint64_t cval) +{ + usb_audio_ctrl_t *ctrlp = arg; + usb_ac_state_t *statep = ctrlp->statep; + int rv = EIO; + int gain; + + uint_t count = 0; + + if (cval < (uint64_t)AF_MIN_GAIN || cval > (uint64_t)AF_MAX_GAIN) { + return (EINVAL); + } + + mutex_enter(&ctrlp->ctrl_mutex); + ctrlp->cval = cval; + mutex_exit(&ctrlp->ctrl_mutex); + + gain = (int)(cval); + + mutex_enter(&statep->usb_ac_mutex); + (void) usb_ac_set_control(statep, USB_AUDIO_PLAY, + USB_AUDIO_FEATURE_UNIT, 1, + USB_AUDIO_VOLUME_CONTROL, + USB_AC_FIND_ALL, &count, gain, usb_ac_set_gain); + + rv = 0; +OUT: + mutex_exit(&statep->usb_ac_mutex); + + return (rv); +} + + +/* + * mono level control callback + */ +static int +usb_audio_write_monitor_gain(void *arg, uint64_t cval) +{ + usb_audio_ctrl_t *ctrlp = arg; + usb_ac_state_t *statep = ctrlp->statep; + int rv = EIO; + int gain; + uint_t count = 0; + + if (cval < (uint64_t)AF_MIN_GAIN || cval > (uint64_t)AF_MAX_GAIN) { + + return (EINVAL); + } + + mutex_enter(&ctrlp->ctrl_mutex); + ctrlp->cval = cval; + mutex_exit(&ctrlp->ctrl_mutex); + + gain = (int)(cval); + + mutex_enter(&statep->usb_ac_mutex); + (void) usb_ac_set_monitor_gain_control(statep, USB_AUDIO_RECORD, + USB_AUDIO_INPUT_TERMINAL, 1, + USB_AUDIO_VOLUME_CONTROL, + USB_AC_FIND_ALL, &count, gain, + usb_ac_set_monitor_gain); + + rv = 0; +OUT: + mutex_exit(&statep->usb_ac_mutex); + return (rv); +} + +static int +usb_audio_write_mono_rec(void *arg, uint64_t cval) +{ + usb_audio_ctrl_t *ctrlp = arg; + usb_ac_state_t *statep = ctrlp->statep; + int rv = EIO; + int gain; + + uint_t count = 0; + + if (cval < (uint64_t)AF_MIN_GAIN || cval > (uint64_t)AF_MAX_GAIN) { + + return (EINVAL); + } + + mutex_enter(&ctrlp->ctrl_mutex); + ctrlp->cval = cval; + mutex_exit(&ctrlp->ctrl_mutex); + + gain = (int)(cval); + + mutex_enter(&statep->usb_ac_mutex); + (void) usb_ac_set_control(statep, USB_AUDIO_RECORD, + USB_AUDIO_FEATURE_UNIT, 1, + USB_AUDIO_VOLUME_CONTROL, + USB_AC_FIND_ALL, &count, gain, usb_ac_set_gain); + + rv = 0; + + mutex_exit(&statep->usb_ac_mutex); + return (rv); +} + +static int +usb_audio_write_mic_boost(void *arg, uint64_t cval) +{ + usb_audio_ctrl_t *ctrlp = arg; + + mutex_enter(&ctrlp->ctrl_mutex); + ctrlp->cval = cval; + mutex_exit(&ctrlp->ctrl_mutex); + /* do nothing here */ + return (0); +} + +static int +usb_audio_write_rec_src(void *arg, uint64_t cval) +{ + usb_audio_ctrl_t *ctrlp = arg; + usb_ac_state_t *statep = ctrlp->statep; + int rv = 0; + + if (cval & ~(statep->usb_ac_input_ports)) + return (EINVAL); + + mutex_enter(&ctrlp->ctrl_mutex); + ctrlp->cval = cval; + mutex_exit(&ctrlp->ctrl_mutex); + + mutex_enter(&statep->usb_ac_mutex); + if (usb_ac_set_port(statep, USB_AUDIO_RECORD, cval) != USB_SUCCESS) { + + USB_DPRINTF_L2(PRINT_MASK_ALL, statep->usb_ac_log_handle, + "usb_audio_write_rec_src: failed"); + rv = EINVAL; + } + mutex_exit(&statep->usb_ac_mutex); + rv = 0; + +OUT: + return (rv); + +} + + +int +usb_audio_set_mute(usb_ac_state_t *statep, uint64_t cval) +{ + short muteval; + int rval; + + uint_t count; + muteval = (cval == 0) ? USB_AUDIO_MUTE_ON : USB_AUDIO_MUTE_OFF; + count = 0; + /* only support AUDIO_PLAY */ + + mutex_enter(&statep->usb_ac_mutex); + (void) usb_ac_set_control(statep, USB_AUDIO_PLAY, + USB_AUDIO_FEATURE_UNIT, 0, + USB_AUDIO_MUTE_CONTROL, + USB_AC_FIND_ALL, &count, muteval, + usb_ac_set_mute); + mutex_exit(&statep->usb_ac_mutex); + + rval = (count == 0) ? USB_SUCCESS : USB_FAILURE; + + return (rval); +} + + +/* + * port selection control callback + */ +/* + * audio control registration related routines + */ + +static usb_audio_ctrl_t * +usb_audio_ctrl_alloc(usb_ac_state_t *statep, uint32_t num, uint64_t val) +{ + audio_ctrl_desc_t desc; + audio_ctrl_wr_t fn; + usb_audio_ctrl_t *pc; + + pc = kmem_zalloc(sizeof (usb_audio_ctrl_t), KM_SLEEP); + + mutex_init(&pc->ctrl_mutex, NULL, MUTEX_DRIVER, NULL); + + bzero(&desc, sizeof (desc)); + + switch (num) { + case CTL_VOLUME_MONO: + desc.acd_name = AUDIO_CTRL_ID_VOLUME; + desc.acd_type = AUDIO_CTRL_TYPE_MONO; + desc.acd_minvalue = 0; + desc.acd_maxvalue = AF_MAX_GAIN; + desc.acd_flags = AUDIO_CTRL_FLAG_MAINVOL | AUDIO_CTRL_FLAG_RW + | AUDIO_CTRL_FLAG_PLAY | AUDIO_CTRL_FLAG_POLL; + fn = usb_audio_write_mono_vol; + break; + + case CTL_VOLUME_STERO: + desc.acd_name = AUDIO_CTRL_ID_VOLUME; + desc.acd_type = AUDIO_CTRL_TYPE_STEREO; + desc.acd_minvalue = 0; + desc.acd_maxvalue = AF_MAX_GAIN; + desc.acd_flags = AUDIO_CTRL_FLAG_MAINVOL | AUDIO_CTRL_FLAG_RW + | AUDIO_CTRL_FLAG_PLAY | AUDIO_CTRL_FLAG_POLL; + fn = usb_audio_write_ster_vol; + + break; + + case CTL_REC_MONO: + desc.acd_name = AUDIO_CTRL_ID_RECGAIN; + desc.acd_type = AUDIO_CTRL_TYPE_MONO; + desc.acd_minvalue = 0; + desc.acd_maxvalue = AF_MAX_GAIN; + desc.acd_flags = AUDIO_CTRL_FLAG_RECVOL|AUDIO_CTRL_FLAG_REC + | AUDIO_CTRL_FLAG_RW; + fn = usb_audio_write_mono_rec; + break; + case CTL_REC_STERO: + + desc.acd_name = AUDIO_CTRL_ID_RECGAIN; + desc.acd_type = AUDIO_CTRL_TYPE_STEREO; + desc.acd_minvalue = 0; + desc.acd_maxvalue = AF_MAX_GAIN; + desc.acd_flags = AUDIO_CTRL_FLAG_RECVOL|AUDIO_CTRL_FLAG_REC + | AUDIO_CTRL_FLAG_RW; + fn = usb_audio_write_stero_rec; + break; + + case CTL_MONITOR_GAIN: + + desc.acd_name = AUDIO_CTRL_ID_MONGAIN; + desc.acd_type = AUDIO_CTRL_TYPE_MONO; + desc.acd_minvalue = 0; + desc.acd_maxvalue = AF_MAX_GAIN; + desc.acd_flags = AUDIO_CTRL_FLAG_MONVOL |AUDIO_CTRL_FLAG_MONITOR + |AUDIO_CTRL_FLAG_RW; + fn = usb_audio_write_monitor_gain; + break; + + case CTL_MIC_BOOST: + + desc.acd_name = AUDIO_CTRL_ID_MICBOOST; + desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN; + desc.acd_minvalue = 0; + desc.acd_maxvalue = 1; + desc.acd_flags = AUDIO_CTRL_FLAG_RW; + fn = usb_audio_write_mic_boost; + break; + case CTL_REC_SRC: + + desc.acd_name = AUDIO_CTRL_ID_RECSRC; + desc.acd_type = AUDIO_CTRL_TYPE_ENUM; + desc.acd_minvalue = statep->usb_ac_input_ports; + desc.acd_maxvalue = statep->usb_ac_input_ports; + desc.acd_flags = AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC; + for (int i = 0; usb_audio_dtypes[i]; i++) { + desc.acd_enum[i] = usb_audio_dtypes[i]; + } + + fn = usb_audio_write_rec_src; + break; + + + + default: + + break; + } + + mutex_enter(&pc->ctrl_mutex); + + pc->statep = statep; + pc->cval = val; + pc->af_ctrlp = audio_dev_add_control(statep->usb_ac_audio_dev, &desc, + usb_audio_ctrl_read, fn, pc); + + mutex_exit(&pc->ctrl_mutex); + + mutex_enter(&statep->usb_ac_mutex); + statep->controls[num] = pc; + mutex_exit(&statep->usb_ac_mutex); + + + return (pc); +} + + +static void +usb_audio_ctrl_free(usb_audio_ctrl_t *ctrlp) +{ + kmem_free(ctrlp, sizeof (usb_audio_ctrl_t)); +} + +static void +usb_ac_rem_controls(usb_ac_state_t *statep) +{ + usb_audio_ctrl_t *ctrlp; + + for (int i = 0; i < CTL_NUM; i++) { + ctrlp = statep->controls[i]; + if (ctrlp) { + if (ctrlp->af_ctrlp != NULL) + audio_dev_del_control(ctrlp->af_ctrlp); + + usb_audio_ctrl_free(ctrlp); + mutex_enter(&statep->usb_ac_mutex); + statep->controls[i] = NULL; + mutex_exit(&statep->usb_ac_mutex); + } + } + +} + + +static int +usb_ac_add_controls(usb_ac_state_t *statep) +{ + int rv = USB_FAILURE; + usb_audio_format_t *format; + + + if (statep->engines[0].af_engp) { + /* Init controls for play format */ + format = &(statep->engines[0].fmt); + if (format->ch == 2) { + (void) usb_audio_ctrl_alloc(statep, CTL_VOLUME_STERO, + statep->engines[0].af_defgain); + } else { + (void) usb_audio_ctrl_alloc(statep, CTL_VOLUME_MONO, + statep->engines[0].af_defgain); + } + + } + + /* Init controls for rec format */ + if (statep->engines[1].af_engp) { + format = &(statep->engines[1].fmt); + if (format->ch == 2) { + (void) usb_audio_ctrl_alloc(statep, CTL_REC_STERO, + statep->engines[1].af_defgain); + } else { + (void) usb_audio_ctrl_alloc(statep, CTL_REC_MONO, + statep->engines[1].af_defgain); + } + + /* Add monitor control */ + { + (void) usb_audio_ctrl_alloc(statep, + CTL_MONITOR_GAIN, 0); + } + + /* Add ports control */ + { + (void) usb_audio_ctrl_alloc(statep, CTL_REC_SRC, + statep->usb_ac_input_ports); + } + + } + + + rv = USB_SUCCESS; + +OUT: + if (rv != USB_SUCCESS) + usb_ac_rem_controls(statep); + return (rv); +} + + + + + +/*ARGSUSED*/ +static int +usb_audio_unregister(usb_ac_state_t *statep) +{ + int i; + + if (statep == NULL) + return (USB_SUCCESS); + + if (statep->usb_ac_audio_dev == NULL) + return (USB_SUCCESS); + + if ((statep->flags & AF_REGISTERED) && + audio_dev_unregister(statep->usb_ac_audio_dev) != DDI_SUCCESS) { + return (USB_FAILURE); + } + mutex_enter(&statep->usb_ac_mutex); + statep->flags &= ~AF_REGISTERED; + mutex_exit(&statep->usb_ac_mutex); + + for (i = 0; i < USB_AC_ENG_MAX; i++) + usb_ac_rem_eng(statep, &statep->engines[i]); + + usb_ac_rem_controls(statep); + + audio_dev_free(statep->usb_ac_audio_dev); + + mutex_enter(&statep->usb_ac_mutex); + statep->usb_ac_audio_dev = NULL; + mutex_exit(&statep->usb_ac_mutex); + + return (USB_SUCCESS); +} + + +static int +usb_audio_register(usb_ac_state_t *statep) { + audio_dev_t *af_devp; + int rv = USB_FAILURE; + int n; + + af_devp = audio_dev_alloc(statep->usb_ac_dip, 0); + audio_dev_set_description(af_devp, "USB Audio"); + audio_dev_set_version(af_devp, "1.0"); + + mutex_enter(&statep->usb_ac_mutex); + statep->usb_ac_audio_dev = af_devp; + mutex_exit(&statep->usb_ac_mutex); + + + for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) { + if (usb_ac_add_eng(statep, &(statep->usb_ac_streams[n])) + != USB_SUCCESS) { + USB_DPRINTF_L2(PRINT_MASK_ATTA, + statep->usb_ac_log_handle, + "usb_audio_register: add engine n =%d failed", n); + goto OUT; + } + } + + + if (usb_ac_add_controls(statep) != USB_SUCCESS) { + USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle, + "usb_audio_register: add controls failed"); + goto OUT; + } + + if (usb_ac_ctrl_set_defaults(statep) != USB_SUCCESS) { + USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle, + "usb_audio_register: set defaults failed"); + goto OUT; + } + + if (audio_dev_register(af_devp) != DDI_SUCCESS) { + USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle, + "audio_dev_register() failed"); + goto OUT; + } + mutex_enter(&statep->usb_ac_mutex); + statep->flags |= AF_REGISTERED; + mutex_exit(&statep->usb_ac_mutex); + + rv = USB_SUCCESS; + +OUT: + if (rv != USB_SUCCESS) { + (void) usb_audio_unregister(statep); + } + return (rv); +} + + +int +usb_ac_get_audio(void *handle, void *buf, int samples) +{ + usb_ac_state_t *statep = (usb_ac_state_t *)(handle); + usb_audio_eng_t *engp = &(statep->engines[0]); + unsigned reqframes = samples >> engp->frsmshift; + unsigned frames; + unsigned i; + size_t sz; + int bufcnt = 0; + caddr_t bp = buf; + + if (!engp->started) { + return (0); + } + + /* break requests from the driver into fragment sized chunks */ + for (i = 0; i < reqframes; i += frames) { + + mutex_enter(&engp->lock); + frames = reqframes - i; + if (frames > engp->fragfr) + frames = engp->fragfr; + + sz = (frames << engp->frsmshift) << engp->smszshift; + + bufcnt++; + + /* must move data before updating framework */ + usb_eng_bufio(engp, bp, sz); + engp->frames += frames; + bp += sz; + + mutex_exit(&engp->lock); + audio_engine_consume(engp->af_engp); + } + + mutex_enter(&engp->lock); + engp->io_count++; + mutex_exit(&engp->lock); + + return (samples); +} + + + +void +usb_ac_send_audio(void *handle, void *buf, int samples) +{ + usb_ac_state_t *statep = (usb_ac_state_t *)(handle); + usb_audio_eng_t *engp = &(statep->engines[1]); + unsigned reqframes = samples >> engp->frsmshift; + unsigned frames; + unsigned i; + size_t sz; + int bufcnt = 0; + caddr_t bp = buf; + + mutex_enter(&engp->lock); + + if (!engp->started) { + + mutex_exit(&engp->lock); + return; + } + mutex_exit(&engp->lock); + + /* break requests from the driver into fragment sized chunks */ + for (i = 0; i < reqframes; i += frames) { + mutex_enter(&engp->lock); + + frames = reqframes - i; + if (frames > engp->fragfr) + frames = engp->fragfr; + + sz = (frames << engp->frsmshift) << engp->smszshift; + + bufcnt++; + + /* must move data before updating framework */ + usb_eng_bufio(engp, bp, sz); + engp->frames += frames; + bp += sz; + + mutex_exit(&engp->lock); + audio_engine_produce(engp->af_engp); + } + + mutex_enter(&engp->lock); + engp->io_count++; + mutex_exit(&engp->lock); +} + + +/* + * ************************************************************************** + * audio framework engine callbacks + */ +/*ARGSUSED*/ +static int +usb_engine_open(void *arg, int flag, + unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp) +{ + usb_audio_eng_t *engp = (usb_audio_eng_t *)arg; + usb_ac_state_t *statep = engp->statep; + int rv = EIO; + + + if (usb_ac_open(statep->usb_ac_dip) != USB_SUCCESS) { + + USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle, + "usb_ac_open() failed"); + return (EIO); + } + + mutex_enter(&engp->lock); + + engp->intrate = 150; + engp->sampsz = engp->fmt.prec / 8; + engp->framesz = engp->sampsz * engp->fmt.ch; + + if (engp->fmt.ch > 2) { + USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle, + "unsupported channel count: %u", engp->fmt.ch); + mutex_exit(&engp->lock); + goto OUT; + } + if (engp->fmt.prec > 16) { + USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle, + "unsupported precision: %u", engp->fmt.prec); + mutex_exit(&engp->lock); + goto OUT; + } + + engp->frsmshift = engp->fmt.ch / 2; + engp->smszshift = engp->sampsz / 2; + + /* + * In order to match the requested number of samples per interrupt + * from SADA drivers when computing the fragment size, + * we need to first truncate the floating point result from + * sample rate * channels / intr rate + * then adjust up to an even number, before multiplying it + * with the sample size + */ + engp->fragsz = engp->fmt.sr * engp->fmt.ch / engp->intrate; + if (engp->fragsz & 1) + engp->fragsz++; + engp->fragsz *= engp->sampsz; + engp->fragfr = engp->fragsz / engp->framesz; + + engp->nfrags = 10; + engp->bufsz = engp->fragsz * engp->nfrags; + + engp->bufp = kmem_zalloc(engp->bufsz, KM_SLEEP); + engp->bufpos = engp->bufp; + engp->bufendp = engp->bufp + engp->bufsz; + engp->frames = 0; + engp->io_count = 0; + engp->bufio_count = 0; + + *fragfrp = engp->fragfr; + *nfragsp = engp->nfrags; + *bufp = engp->bufp; + + mutex_exit(&engp->lock); + + if (usb_ac_setup(statep, engp) != USB_SUCCESS) { + USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle, + "device setup failed"); + goto OUT; + } + + + + mutex_enter(&statep->usb_ac_mutex); + statep->flags |= AD_SETUP; + mutex_exit(&statep->usb_ac_mutex); + + rv = 0; + + +OUT: + if (rv != 0) + usb_engine_close(arg); + + return (rv); +} + + +static void +usb_engine_close(void *arg) +{ + usb_audio_eng_t *engp = (usb_audio_eng_t *)arg; + usb_ac_state_t *statep = engp->statep; + + if (statep->flags & AD_SETUP) { + usb_ac_teardown(statep, engp); + mutex_enter(&statep->usb_ac_mutex); + statep->flags &= ~AD_SETUP; + mutex_exit(&statep->usb_ac_mutex); + } + mutex_enter(&engp->lock); + + if (engp->bufp != NULL) { + kmem_free(engp->bufp, engp->bufsz); + engp->bufp = NULL; + engp->bufpos = NULL; + engp->bufendp = NULL; + } + + mutex_exit(&engp->lock); + + usb_ac_close(statep->usb_ac_dip); +} + + + +static int +usb_engine_start(void *arg) +{ + usb_audio_eng_t *engp = (usb_audio_eng_t *)arg; + int rv = 0; + int (*start)(usb_ac_state_t *, usb_audio_eng_t *); + + mutex_enter(&engp->lock); + engp->started = B_TRUE; + mutex_exit(&engp->lock); + + usb_ac_state_t *statep = engp->statep; + + start = ((engp)->af_eflags & ENGINE_OUTPUT_CAP) ? + usb_ac_start_play : usb_ac_start_record; + + if ((*start)(statep, engp) != USB_SUCCESS) { + USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle, + "failed to start %d engine", engp->af_eflags); + rv = EIO; + } + + + return (rv); +} + + +static void +usb_engine_stop(void *arg) +{ + usb_audio_eng_t *engp = (usb_audio_eng_t *)arg; + + mutex_enter(&engp->lock); + engp->started = B_FALSE; + mutex_exit(&engp->lock); + + usb_ac_state_t *statep = engp->statep; + void (*stop)(usb_ac_state_t *, usb_audio_eng_t *); + + stop = ((engp)->af_eflags & ENGINE_OUTPUT_CAP) ? + usb_ac_stop_play : usb_ac_stop_record; + + (*stop)(statep, engp); +} + + +static uint64_t +usb_engine_count(void *arg) +{ + usb_audio_eng_t *engp = arg; + uint64_t val; + + mutex_enter(&engp->lock); + val = engp->frames; + mutex_exit(&engp->lock); + + return (val); +} + + +static int +usb_engine_format(void *arg) +{ + usb_audio_eng_t *engp = arg; + + switch (engp->fmt.enc) { + case USB_AUDIO_FORMAT_TYPE1_MULAW: + return (AUDIO_FORMAT_ULAW); + case USB_AUDIO_FORMAT_TYPE1_ALAW: + return (AUDIO_FORMAT_ALAW); + case USB_AUDIO_FORMAT_TYPE1_PCM8: + return (AUDIO_FORMAT_U8); + + case USB_AUDIO_FORMAT_TYPE1_PCM: + break; + default: + return (AUDIO_FORMAT_NONE); + } + + switch (engp->fmt.prec) { + case 8: + return (AUDIO_FORMAT_S8); + case 16: + return (AUDIO_FORMAT_S16_LE); + case 24: + return (AUDIO_FORMAT_S24_LE); + case 32: + return (AUDIO_FORMAT_S32_LE); + default: + break; + } + return (AUDIO_FORMAT_NONE); + + +} + +static int +usb_engine_channels(void *arg) +{ + usb_audio_eng_t *engp = arg; + + return (engp->fmt.ch); +} + + +static int +usb_engine_rate(void *arg) +{ + usb_audio_eng_t *engp = arg; + + return (engp->fmt.sr); +} + + +/*ARGSUSED*/ +static void +usb_engine_sync(void *arg, unsigned nframes) +{ + /* Do nothing */ +} + + +static size_t +usb_engine_qlen(void *arg) +{ + usb_audio_eng_t *engp = (usb_audio_eng_t *)arg; + + return (engp->fragfr); +} + +/* + * ************************************************************************** + * interfaces used by USB audio + */ + +/*ARGSUSED*/ +static int +usb_change_phy_vol(usb_ac_state_t *statep, int value) +{ + usb_audio_ctrl_t *ctrlp; + uint64_t cval = 0; + int64_t left, right, delta = 0; + + ctrlp = statep->controls[CTL_VOLUME_STERO]; + + ASSERT(value != 0); + + delta = (value < 0)?-1:1; + + left = AUDIO_CTRL_STEREO_LEFT(ctrlp->cval) + delta; + right = AUDIO_CTRL_STEREO_RIGHT(ctrlp->cval) + delta; + + if (left > AF_MAX_GAIN) + left = AF_MAX_GAIN; + if (right > AF_MAX_GAIN) + right = AF_MAX_GAIN; + + if (left < AF_MIN_GAIN) + left = AF_MIN_GAIN; + if (right < AF_MIN_GAIN) + right = AF_MIN_GAIN; + + cval = AUDIO_CTRL_STEREO_VAL(left, right); + + if (audio_control_write(ctrlp->af_ctrlp, cval)) { + USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle, + "updateing control to value 0x%llx by driver failed", + (long long unsigned)cval); + return (USB_FAILURE); + } + return (USB_SUCCESS); +} diff --git a/usr/src/uts/common/io/usb/clients/audio/usb_ah/usb_ah.c b/usr/src/uts/common/io/usb/clients/audio/usb_ah/usb_ah.c index 5d4d6fe05a..3b84d3069f 100644 --- a/usr/src/uts/common/io/usb/clients/audio/usb_ah/usb_ah.c +++ b/usr/src/uts/common/io/usb/clients/audio/usb_ah/usb_ah.c @@ -48,10 +48,6 @@ #include <sys/stropts.h> #include <sys/strsun.h> -#include <sys/audio.h> -#include <sys/audio/audio_support.h> -#include <sys/mixer.h> -#include <sys/audio/audio_mixer.h> #include <sys/usb/clients/audio/usb_audio.h> #include <sys/usb/clients/audio/usb_mixer.h> diff --git a/usr/src/uts/common/io/usb/clients/audio/usb_as/usb_as.c b/usr/src/uts/common/io/usb/clients/audio/usb_as/usb_as.c index baa991d736..8777be9ed0 100644 --- a/usr/src/uts/common/io/usb/clients/audio/usb_as/usb_as.c +++ b/usr/src/uts/common/io/usb/clients/audio/usb_as/usb_as.c @@ -25,10 +25,6 @@ /* * Audio Streams Interface Driver: - * This driver is derived from the legacy SADA streams-based usb_as driver - * and serves as an intermediate measure before the full conversion to the - * to the Boomer framework in a follow-on phase of the Boomer project, which - * will utilize more comprehensive USB audio features as well. * * usb_as is responsible for (1) Processing audio data messages during * play and record and management of isoc pipe, (2) Selecting correct @@ -58,16 +54,13 @@ #include <sys/ddi.h> #include <sys/sunddi.h> -#include <sys/audio.h> -#include <sys/audio/audio_support.h> -#include <sys/mixer.h> -#include <sys/audio/audio_mixer.h> +#include <sys/audio/audio_driver.h> #include <sys/usb/clients/audio/usb_audio.h> #include <sys/usb/clients/audio/usb_mixer.h> #include <sys/usb/clients/audio/usb_as/usb_as.h> +#include <sys/usb/clients/audio/usb_ac/usb_ac.h> -#include "../usb_ac/audio_shim.h" /* debug support */ uint_t usb_as_errlevel = USB_LOG_L4; @@ -94,7 +87,6 @@ static void usb_as_prepare_registration_data(usb_as_state_t *); static int usb_as_valid_format(usb_as_state_t *, uint_t, uint_t *, uint_t); static void usb_as_free_alts(usb_as_state_t *); -static int usb_audio_fmt_convert(int); static void usb_as_create_pm_components(dev_info_t *, usb_as_state_t *); static int usb_as_disconnect_event_cb(dev_info_t *); @@ -123,7 +115,7 @@ static int usb_as_set_sample_freq(usb_as_state_t *, int); static int usb_as_send_ctrl_cmd(usb_as_state_t *, uchar_t, uchar_t, ushort_t, ushort_t, ushort_t, mblk_t *, boolean_t); -static int usb_as_start_record(usb_as_state_t *, audiohdl_t); +static int usb_as_start_record(usb_as_state_t *, void *); static int usb_as_stop_record(usb_as_state_t *); static void usb_as_play_cb(usb_pipe_handle_t, usb_isoc_req_t *); static void usb_as_record_cb(usb_pipe_handle_t, usb_isoc_req_t *); @@ -213,6 +205,9 @@ static uint_t usb_as_default_srs[] = { 32000, 33075, 37800, 44100, 48000, 0 }; +_NOTE(SCHEME_PROTECTS_DATA("unique per call", mblk_t)) +_NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_isoc_req_t)) +_NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_isoc_pkt_descr)) int _init(void) @@ -360,6 +355,9 @@ usb_as_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) /* initialize mutex */ mutex_init(&uasp->usb_as_mutex, NULL, MUTEX_DRIVER, uasp->usb_as_dev_data->dev_iblock_cookie); + + cv_init(&uasp->usb_as_pipe_cv, NULL, CV_DRIVER, NULL); + uasp->usb_as_ser_acc = usb_init_serialization(dip, USB_INIT_SER_CHECK_SAME_THREAD); @@ -676,7 +674,7 @@ usb_as_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, usb_as_pause_play(uasp); break; case USB_AUDIO_START_RECORD: - rv = usb_as_start_record(uasp, *(audiohdl_t *)arg); + rv = usb_as_start_record(uasp, (void *)arg); break; case USB_AUDIO_STOP_RECORD: rv = usb_as_stop_record(uasp); @@ -776,8 +774,6 @@ usb_as_set_format(usb_as_state_t *uasp, usb_audio_formats_t *format) return (USB_FAILURE); } - ASSERT(uasp->usb_as_isoc_ph == NULL); - reg = &uasp->usb_as_reg; interface = uasp->usb_as_ifno; @@ -808,7 +804,6 @@ usb_as_set_format(usb_as_state_t *uasp, usb_audio_formats_t *format) return (USB_FAILURE); } - ASSERT(uasp->usb_as_isoc_ph == NULL); USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle, "usb_as_set_format: interface=%d alternate=%d", @@ -850,21 +845,37 @@ usb_as_setup(usb_as_state_t *uasp) usb_ep_descr_t *ep = (usb_ep_descr_t *)uasp->usb_as_alts[alt].alt_ep; int rval; + ASSERT(mutex_owned(&uasp->usb_as_mutex)); USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, "usb_as_setup: Begin usb_as_setup, inst=%d", ddi_get_instance(uasp->usb_as_dip)); - ASSERT(uasp->usb_as_request_count == 0); /* Set record packet size to max packet size */ - if (uasp->usb_as_alts[alt].alt_mode == AUDIO_RECORD) { + if (uasp->usb_as_alts[alt].alt_mode == USB_AUDIO_RECORD) { uasp->usb_as_record_pkt_size = ep->wMaxPacketSize; } else { uasp->usb_as_record_pkt_size = 0; } + if (uasp->usb_as_isoc_ph != NULL) { + while (uasp->usb_as_request_count) { + cv_wait(&uasp->usb_as_pipe_cv, + &uasp->usb_as_mutex); + } + + /* close the isoc pipe which is opened before */ + mutex_exit(&uasp->usb_as_mutex); + usb_pipe_close(uasp->usb_as_dip, uasp->usb_as_isoc_ph, + USB_FLAGS_SLEEP, NULL, (usb_opaque_t)NULL); + + mutex_enter(&uasp->usb_as_mutex); + uasp->usb_as_isoc_ph = NULL; + } + + ASSERT(uasp->usb_as_request_count == 0); mutex_exit(&uasp->usb_as_mutex); /* open isoc pipe, may fail if there is no bandwidth */ @@ -922,27 +933,10 @@ usb_as_teardown(usb_as_state_t *uasp) uasp->usb_as_audio_state = USB_AS_IDLE; - if (uasp->usb_as_isoc_ph) { - USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, - "usb_as_teardown: closing isoc pipe, ph=0x%p", - (void *)uasp->usb_as_isoc_ph); - - mutex_exit(&uasp->usb_as_mutex); - - /* reply mp will be sent up in isoc close callback */ - usb_pipe_close(uasp->usb_as_dip, uasp->usb_as_isoc_ph, - USB_FLAGS_SLEEP, NULL, (usb_opaque_t)NULL); - - mutex_enter(&uasp->usb_as_mutex); - uasp->usb_as_isoc_ph = NULL; + ASSERT(uasp->usb_as_isoc_ph); + /* reset setup flag */ + uasp->usb_as_setup_cnt--; - /* reset setup flag */ - uasp->usb_as_setup_cnt--; - - } else { - USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, - "usb_as_teardown: Pipe already closed"); - } ASSERT(uasp->usb_as_setup_cnt == 0); @@ -1050,7 +1044,7 @@ usb_as_continue_play(usb_as_state_t *uasp) static void usb_as_handle_shutdown(usb_as_state_t *uasp) { - audiohdl_t ahdl; + void *ahdl; USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle, "usb_as_handle_shutdown, inst=%d", @@ -1064,7 +1058,7 @@ usb_as_handle_shutdown(usb_as_state_t *uasp) ahdl = uasp->usb_as_ahdl; mutex_exit(&uasp->usb_as_mutex); - am_play_shutdown(ahdl); + usb_ac_stop_play(ahdl, NULL); mutex_enter(&uasp->usb_as_mutex); } @@ -1077,7 +1071,7 @@ usb_as_play_isoc_data(usb_as_state_t *uasp, usb_audio_play_req_t *play_req) usb_isoc_req_t *isoc_req = NULL; usb_audio_formats_t *format = &uasp->usb_as_curr_format; mblk_t *data = NULL; - audiohdl_t ahdl = uasp->usb_as_ahdl; + void * ahdl = uasp->usb_as_ahdl; int precision; int pkt, frame, n, n_pkts, count; size_t bufsize; @@ -1086,15 +1080,15 @@ usb_as_play_isoc_data(usb_as_state_t *uasp, usb_audio_play_req_t *play_req) ASSERT(mutex_owned(&uasp->usb_as_mutex)); /* we only support two precisions */ - if ((format->fmt_precision != AUDIO_PRECISION_8) && - (format->fmt_precision != AUDIO_PRECISION_16)) { + if ((format->fmt_precision != USB_AUDIO_PRECISION_8) && + (format->fmt_precision != USB_AUDIO_PRECISION_16)) { rval = USB_FAILURE; goto done; } - precision = (format->fmt_precision == AUDIO_PRECISION_8) ? 1 : 2; + precision = (format->fmt_precision == USB_AUDIO_PRECISION_8) ? 1 : 2; frame = uasp->usb_as_pkt_count; @@ -1122,14 +1116,14 @@ usb_as_play_isoc_data(usb_as_state_t *uasp, usb_audio_play_req_t *play_req) } /* - * restriction of Boomer: cannot call am_get_audio() in the context + * restriction of Boomer: cannot call usb_ac_get_audio() in the context * of start so we play a fragment of silence at first */ if (play_req != NULL) { bzero(data->b_wptr, bufsize); count = bufsize / precision; - } else if ((count = am_get_audio(ahdl, (void *)data->b_wptr, + } else if ((count = usb_ac_get_audio(ahdl, (void *)data->b_wptr, bufsize / precision)) == 0) { mutex_enter(&uasp->usb_as_mutex); if (uasp->usb_as_request_count == 0) { @@ -1183,20 +1177,6 @@ usb_as_play_isoc_data(usb_as_state_t *uasp, usb_audio_play_req_t *play_req) } -#if defined(_BIG_ENDIAN) - /* byte swap if necessary */ - if (format->fmt_precision == AUDIO_PRECISION_16) { - int i; - uchar_t tmp; - uchar_t *p = data->b_rptr; - - for (i = 0; i < bufsize; i += 2, p += 2) { - tmp = *p; - *p = *(p + 1); - *(p + 1) = tmp; - } - } -#endif /* initialize the packet descriptor */ for (pkt = 0; pkt < n_pkts; pkt++) { @@ -1231,6 +1211,7 @@ usb_as_play_isoc_data(usb_as_state_t *uasp, usb_audio_play_req_t *play_req) mutex_enter(&uasp->usb_as_mutex); uasp->usb_as_request_count--; + cv_signal(&uasp->usb_as_pipe_cv); uasp->usb_as_send_debug_count--; uasp->usb_as_pkt_count -= n_pkts; @@ -1307,6 +1288,7 @@ usb_as_play_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) usb_free_isoc_req(isoc_req); uasp->usb_as_request_count--; + cv_signal(&uasp->usb_as_pipe_cv); uasp->usb_as_rcv_debug_count++; usb_as_continue_play(uasp); @@ -1355,6 +1337,7 @@ usb_as_play_exc_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) mutex_enter(&uasp->usb_as_mutex); uasp->usb_as_rcv_debug_count++; uasp->usb_as_request_count--; + cv_signal(&uasp->usb_as_pipe_cv); usb_as_handle_shutdown(uasp); USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle, @@ -1373,7 +1356,7 @@ usb_as_play_exc_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) * usb_as_start_record */ static int -usb_as_start_record(usb_as_state_t *uasp, audiohdl_t ahdl) +usb_as_start_record(usb_as_state_t *uasp, void * ahdl) { int rval = USB_FAILURE; usb_isoc_req_t *isoc_req; @@ -1552,7 +1535,7 @@ usb_as_record_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) { usb_as_state_t *uasp = (usb_as_state_t *)isoc_req->isoc_client_private; int i, offset, sz; - audiohdl_t ahdl; + void * ahdl; usb_audio_formats_t *format = &uasp->usb_as_curr_format; int precision; @@ -1572,26 +1555,10 @@ usb_as_record_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) mutex_enter(&uasp->usb_as_mutex); ahdl = uasp->usb_as_ahdl; sz = uasp->usb_as_record_pkt_size; - precision = (format->fmt_precision == AUDIO_PRECISION_8) ? 1 : 2; + precision = (format->fmt_precision == USB_AUDIO_PRECISION_8) ? 1 : 2; if (uasp->usb_as_audio_state != USB_AS_IDLE) { -#if defined(_BIG_ENDIAN) - unsigned char *ptr = isoc_req->isoc_data->b_rptr; -#endif for (offset = i = 0; i < isoc_req->isoc_pkts_count; i++) { -#if defined(_BIG_ENDIAN) - int len = isoc_req->isoc_pkt_descr[i]. - isoc_pkt_actual_length; - /* do byte swap for precision 16 */ - if (format->fmt_precision == AUDIO_PRECISION_16) { - int j; - for (j = 0; j < len; j += 2, ptr += 2) { - char t = *ptr; - *ptr = *(ptr + 1); - *(ptr + 1) = t; - } - } -#endif USB_DPRINTF_L3(PRINT_MASK_CB, uasp->usb_as_log_handle, "\tpkt%d: " "offset=%d pktsize=%d len=%d status=%d resid=%d", @@ -1610,7 +1577,7 @@ usb_as_record_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req) } mutex_exit(&uasp->usb_as_mutex); - am_send_audio(ahdl, + usb_ac_send_audio(ahdl, isoc_req->isoc_data->b_rptr + offset, isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length / precision); @@ -1693,7 +1660,7 @@ usb_as_get_pktsize(usb_as_state_t *uasp, usb_audio_formats_t *format, pkt_size = (((frameno + 1) % cycle) ? pkt : (pkt + extra)); pkt_size *= ((format->fmt_precision == - AUDIO_PRECISION_16) ? 2 : 1) + USB_AUDIO_PRECISION_16) ? 2 : 1) * format->fmt_chns; break; } @@ -2167,7 +2134,7 @@ usb_as_handle_descriptors(usb_as_state_t *uasp) uasp->usb_as_alts[alternate].alt_mode = (ep->bEndpointAddress & USB_EP_DIR_IN) ? - AUDIO_RECORD : AUDIO_PLAY; + USB_AUDIO_RECORD : USB_AUDIO_PLAY; if (ep_data->ep_n_cvs == 0) { USB_DPRINTF_L2(PRINT_MASK_ATTA, @@ -2273,7 +2240,7 @@ usb_as_prepare_registration_data(usb_as_state_t *uasp) usb_audio_type1_format_descr_t *format; uchar_t n_alternates = uasp->usb_as_n_alternates; uchar_t channels[3]; - int alt, n, i, t; + int alt, n; USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle, "usb_as_prepare_registration_data:"); @@ -2334,7 +2301,7 @@ usb_as_prepare_registration_data(usb_as_state_t *uasp) reg->reg_formats[n].fmt_precision = format->bBitResolution; reg->reg_formats[n++].fmt_encoding = - usb_audio_fmt_convert(format->bFormatType); + format->bFormatType; /* count how many mono and stereo we have */ channels[format->bNrChannels]++; } @@ -2353,7 +2320,9 @@ usb_as_prepare_registration_data(usb_as_state_t *uasp) /* dump what we have so far */ for (n = 0; n < reg->reg_n_formats; n++) { USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle, - "format%d: alt=%d chns=%d prec=%d enc=%d", n, + "regformats[%d]: termlink = %d, alt=%d chns=%d" + " prec=%d enc=%d", n, + reg->reg_formats[n].fmt_termlink, reg->reg_formats[n].fmt_alt, reg->reg_formats[n].fmt_chns, reg->reg_formats[n].fmt_precision, @@ -2367,44 +2336,16 @@ usb_as_prepare_registration_data(usb_as_state_t *uasp) */ n = 0; if (channels[1]) { - reg->reg_channels[n++] = AUDIO_CHANNELS_MONO; + reg->reg_channels[n++] = 1; } if (channels[2]) { - reg->reg_channels[n] = AUDIO_CHANNELS_STEREO; + reg->reg_channels[n] = 2; } USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle, "channels %d %d", reg->reg_channels[0], reg->reg_channels[1]); - /* fill out combinations */ - for (i = n = 0; n < reg->reg_n_formats; n++) { - uchar_t prec = reg->reg_formats[n].fmt_precision; - uchar_t enc = reg->reg_formats[n].fmt_encoding; - - /* check if already there */ - for (t = 0; t < n; t++) { - uchar_t ad_prec = reg->reg_combinations[t].ad_prec; - uchar_t ad_enc = reg->reg_combinations[t].ad_enc; - if ((prec == ad_prec) && (enc == ad_enc)) { - break; - } - } - - /* if not, add this combination */ - if (t == n) { - reg->reg_combinations[i].ad_prec = prec; - reg->reg_combinations[i++].ad_enc = enc; - } - } - - - USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle, - "combinations: %d %d %d %d %d %d %d %d", - reg->reg_combinations[0].ad_prec, reg->reg_combinations[0].ad_enc, - reg->reg_combinations[1].ad_prec, reg->reg_combinations[1].ad_enc, - reg->reg_combinations[2].ad_prec, reg->reg_combinations[2].ad_enc, - reg->reg_combinations[3].ad_prec, reg->reg_combinations[3].ad_enc); reg->reg_valid++; } @@ -2489,7 +2430,7 @@ usb_as_valid_format(usb_as_state_t *uasp, uint_t alternate, break; } - USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle, + USB_DPRINTF_L3(PRINT_MASK_PM, uasp->usb_as_log_handle, "checking sr=%d", sr); for (i = 0; i < alt_descr->alt_n_sample_rates; i++) { if (sr == alt_descr->alt_sample_rates[i]) { @@ -2544,30 +2485,6 @@ usb_as_valid_format(usb_as_state_t *uasp, uint_t alternate, } -/* - * convert usb audio format type to SADA type - */ -static int -usb_audio_fmt_convert(int type) -{ - switch (type) { - case USB_AUDIO_FORMAT_TYPE1_PCM: - return (AUDIO_ENCODING_LINEAR); - - case USB_AUDIO_FORMAT_TYPE1_PCM8: - return (AUDIO_ENCODING_LINEAR8); - - case USB_AUDIO_FORMAT_TYPE1_ALAW: - return (AUDIO_ENCODING_ALAW); - - case USB_AUDIO_FORMAT_TYPE1_MULAW: - return (AUDIO_ENCODING_ULAW); - - case USB_AUDIO_FORMAT_TYPE1_IEEE_FLOAT: - default: - return (0); - } -} /* diff --git a/usr/src/uts/common/io/warlock/usb_ac.wlcmd b/usr/src/uts/common/io/warlock/usb_ac.wlcmd index 6a68d90059..8436bdcf91 100644 --- a/usr/src/uts/common/io/warlock/usb_ac.wlcmd +++ b/usr/src/uts/common/io/warlock/usb_ac.wlcmd @@ -28,15 +28,11 @@ one usb_ac_state ### specify the root functions root usb_ac_open root usb_ac_close -root usb_ac_lrput -root usb_ac_uwput root usb_ac_disconnect_event_cb root usb_ac_reconnect_event_cb root usb_ac_power -root usb_ac_pause_play -root usb_ac_set_config root usb_ac_set_format root usb_ac_setup root usb_ac_start_play @@ -45,6 +41,35 @@ root usb_ac_stop_play root usb_ac_stop_record root usb_ac_teardown +root usb_ac_get_audio +root usb_ac_send_audio +root usb_ac_ctrl_restore +root usb_audio_set_mute + +root usb_engine_start +root usb_engine_stop +root usb_engine_sync +root usb_engine_rate +root usb_engine_format +root usb_engine_count +root usb_engine_close +root usb_engine_channels +root usb_engine_open +root usb_engine_qlen + +root usb_ac_mux_plumbing_tq +root usb_ac_mux_unplumbing_tq +root usb_ac_reader + +root usb_audio_write_monitor_gain +root usb_audio_write_mono_rec +root usb_audio_write_mono_vol +root usb_audio_write_ster_vol +root usb_audio_write_stero_rec +root usb_audio_write_rec_src +root usb_audio_write_mic_boost +root usb_audio_ctrl_read + add bus_ops::bus_add_eventcall targets warlock_dummy add bus_ops::bus_get_eventcookie targets warlock_dummy add bus_ops::bus_post_event targets warlock_dummy diff --git a/usr/src/uts/common/io/warlock/usb_ac_with_sada.wlcmd b/usr/src/uts/common/io/warlock/usb_ac_with_sada.wlcmd deleted file mode 100644 index 9442430d7f..0000000000 --- a/usr/src/uts/common/io/warlock/usb_ac_with_sada.wlcmd +++ /dev/null @@ -1,151 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -# warlock command file - -one usb_ac_state -one audio_ch -one audio_apm_info -one audio_state -one am_apm_private - - -# unused functions - -root am_hw_state_change - -root audio_sup_devt_to_ch_type -root audio_sup_get_qptr_data -root audio_sup_open -root audio_sup_close -root audio_sup_rput -root audio_sup_rsvc -root audio_sup_wput -root audio_sup_wsvc -root audio_sup_ch_to_minor -root audio_sup_construct_minor -root audio_sup_devt_to_instance -root audio_sup_free_qptr -root audio_sup_get_channel_number -root audio_sup_get_dip -root audio_sup_get_info -root audio_sup_get_max_chs -root audio_sup_get_qptr_instance -root audio_sup_set_qptr -root audio_sup_save_audio_data -root audio_sup_save_state -root audio_sup_attach -root audio_sup_detach -root audio_sup_update_persist_key -root audio_sup_getinfo - -root am_get_src_data -root am_set_src_data -root am_hw_state_change -root am_get_audio -root am_play_shutdown -root am_send_audio - -# threads -root am_diag_loopback_task -root am_get_chinfo_task -root am_get_mode_task -root am_getinfo_task -root am_mixer_task_acknack -root am_mixerctl_getinfo_task -root am_mixerctl_setinfo_task -root am_multiple_open_task -root am_sample_rate_task -root am_set_chinfo_task -root am_set_mode_task -root am_setinfo_task -root am_single_open_task -root am_hw_task - -### specify the usb_ac root functions -root usb_ac_open -root usb_ac_close -root usb_ac_disconnect_event_cb -root usb_ac_reconnect_event_cb -root usb_ac_power -root usb_ac_lrput -root usb_ac_uwput - -root usb_ac_print_reg_data -root usb_ac_am_restore_state - - -# function pointers -add audio_ch::ch_rput targets am_rput -add audio_ch::ch_rsvc targets am_rsvc -add audio_ch::ch_wput targets am_wput -add audio_ch::ch_wsvc targets am_wsvc -add audio_apm_info::apm_open targets am_open_audio -add audio_apm_info::apm_close targets am_close_audio -add audio_apm_info::apm_open targets am_open_audioctl -add audio_apm_info::apm_close targets am_close_audioctl -add audio_apm_info::apm_restore_state targets am_restore_state -add audio_apm_info::apm_save_state targets am_save_state - - -add am_ad_entry::ad_setup targets usb_ac_setup -add am_ad_entry::ad_teardown targets usb_ac_teardown -add am_ad_entry::ad_set_config targets usb_ac_set_config -add am_ad_entry::ad_set_format targets usb_ac_set_format -add am_ad_entry::ad_start_play targets usb_ac_start_play -add am_ad_entry::ad_pause_play targets usb_ac_pause_play -add am_ad_entry::ad_stop_play targets usb_ac_stop_play -add am_ad_entry::ad_start_record targets usb_ac_start_record -add am_ad_entry::ad_stop_record targets usb_ac_stop_record -add am_ad_entry::ad_ioctl targets warlock_dummy -add am_ad_entry::ad_iocdata targets warlock_dummy - -add bus_ops::bus_add_eventcall targets warlock_dummy -add bus_ops::bus_get_eventcookie targets warlock_dummy -add bus_ops::bus_intr_ctl targets warlock_dummy -add bus_ops::bus_post_event targets warlock_dummy -add bus_ops::bus_remove_eventcall targets warlock_dummy -add bus_ops::bus_config targets warlock_dummy -add bus_ops::bus_unconfig targets warlock_dummy - -add am_ad_src_entry::ad_src_adjust targets am_src2_adjust -add am_ad_src_entry::ad_src_convert targets am_src2_convert -add am_ad_src_entry::ad_src_exit targets am_src2_exit -add am_ad_src_entry::ad_src_init targets am_src2_init -add am_ad_src_entry::ad_src_size targets am_src2_size -add am_ad_src_entry::ad_src_update targets am_src2_update - -add usb_ac_state_space::restore_func targets usb_ac_restore_audio_state - - -# we should never hold as_lock while jumping into another module -# and with this rule we *sometimes* get these -assert order audio_state::as_lock audio_ch::ch_lock usb_ac_state::usb_ac_mutex - -# this locking order catches problems when the framework holds locks -# over calling into the driver -#assert order usb_ac_state::usb_ac_mutex audio_state::as_lock audio_ch::ch_lock - - diff --git a/usr/src/uts/common/io/warlock/usb_ac_with_usba.wlcmd b/usr/src/uts/common/io/warlock/usb_ac_with_usba.wlcmd index dd4c0a0f46..b557303fe5 100644 --- a/usr/src/uts/common/io/warlock/usb_ac_with_usba.wlcmd +++ b/usr/src/uts/common/io/warlock/usb_ac_with_usba.wlcmd @@ -90,6 +90,9 @@ root usb_register_hotplug_cbs root usb_get_current_cfgidx root usb_register_client root usb_reset_device +root usb_register_dev_driver +root usb_unregister_dev_driver + root hcdi_autoclearing root hcdi_cb_thread @@ -156,11 +159,6 @@ root usb_ac_close root usb_ac_disconnect_event_cb root usb_ac_reconnect_event_cb root usb_ac_power -root usb_ac_lrput -root usb_ac_uwput -root usb_ac_power -root usb_ac_pause_play -root usb_ac_set_config root usb_ac_set_format root usb_ac_setup root usb_ac_start_play @@ -169,6 +167,36 @@ root usb_ac_stop_play root usb_ac_stop_record root usb_ac_teardown +root usb_ac_get_audio +root usb_ac_send_audio +root usb_ac_ctrl_restore +root usb_audio_set_mute + +root usb_engine_start +root usb_engine_stop +root usb_engine_sync +root usb_engine_rate +root usb_engine_format +root usb_engine_count +root usb_engine_close +root usb_engine_channels +root usb_engine_open +root usb_engine_qlen + +root usb_ac_mux_plumbing_tq +root usb_ac_mux_unplumbing_tq +root usb_ac_reader + +root usb_audio_write_monitor_gain +root usb_audio_write_mono_rec +root usb_audio_write_mono_vol +root usb_audio_write_ster_vol +root usb_audio_write_stero_rec +root usb_audio_write_rec_src +root usb_audio_write_mic_boost +root usb_audio_ctrl_read + + add hubd::h_cleanup_child targets warlock_dummy add usba_pipe_async_req::sync_func targets usba_pipe_sync_close add usba_pipe_async_req::sync_func targets usba_pipe_sync_reset @@ -191,8 +219,3 @@ add ehci_trans_wrapper::tw_handle_qtd targets ehci_handle_ctrl_qtd add ehci_trans_wrapper::tw_handle_qtd targets ehci_handle_bulk_qtd add ehci_trans_wrapper::tw_handle_qtd targets ehci_handle_intr_qtd -add usb_ac_state_space::restore_func targets usb_ac_restore_audio_state -add usb_ac_state_space::get_featureID_func targets usb_ac_get_featureID -add usb_ac_state_space::pm_busy_component targets usb_ac_pm_busy_component -add usb_ac_state_space::pm_idle_component targets usb_ac_pm_idle_component - diff --git a/usr/src/uts/common/io/warlock/usb_as.wlcmd b/usr/src/uts/common/io/warlock/usb_as.wlcmd index e87d20ecff..4016abb9de 100644 --- a/usr/src/uts/common/io/warlock/usb_as.wlcmd +++ b/usr/src/uts/common/io/warlock/usb_as.wlcmd @@ -1,5 +1,5 @@ # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START @@ -22,23 +22,18 @@ # CDDL HEADER END # -#ident "%Z%%M% %I% %E% SMI" one usb_as_state ### specify the root functions -root usb_as_default_xfer_cb -root usb_as_default_xfer_exc_cb root usb_as_disconnect_event_cb root usb_as_reconnect_event_cb root usb_as_open root usb_as_close -root usb_as_wsrv root usb_as_power -root usb_as_isoc_close_cb root usb_as_play_cb root usb_as_play_exc_cb root usb_as_record_cb diff --git a/usr/src/uts/common/io/warlock/usb_as_with_sada.wlcmd b/usr/src/uts/common/io/warlock/usb_as_with_sada.wlcmd deleted file mode 100644 index f765176771..0000000000 --- a/usr/src/uts/common/io/warlock/usb_as_with_sada.wlcmd +++ /dev/null @@ -1,168 +0,0 @@ -# -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -#ident "%Z%%M% %I% %E% SMI" - -# warlock command file - -one usb_as_state -one audio_ch -one audio_apm_info -one audio_state -one am_apm_private - - -# unused functions - -root am_hw_state_change - -root audio_sup_attach -root audio_sup_devt_to_ch_type -root audio_sup_detach -root audio_sup_get_qptr_data -root audio_sup_open -root audio_sup_close -root audio_sup_rput -root audio_sup_rsvc -root audio_sup_wput -root audio_sup_wsvc -root audio_sup_ch_to_minor -root audio_sup_construct_minor -root audio_sup_devt_to_instance -root audio_sup_free_persist_state -root audio_sup_free_qptr -root audio_sup_get_channel_number -root audio_sup_get_dip -root audio_sup_get_info -root audio_sup_get_max_chs -root audio_sup_get_persist_state -root audio_sup_get_qptr_instance -root audio_sup_set_persist_state -root audio_sup_set_qptr -root audio_sup_save_audio_data -root audio_sup_save_state -root audio_sup_update_persist_key -root audio_sup_getinfo - -root am_get_src_data -root am_set_src_data -root am_hw_state_change -root am_get_audio -root am_play_shutdown -root am_send_audio -root am_save_state -root am_attach -root am_detach -root am_restore_state - -root audio_sup_attach -root audio_sup_detach -root audio_sup_get_private -root audio_sup_getinfo -root audio_sup_set_private -root audio_sup_restore_state - - -# threads -root am_diag_loopback_task -root am_get_chinfo_task -root am_get_mode_task -root am_getinfo_task -root am_mixer_task_acknack -root am_mixerctl_getinfo_task -root am_mixerctl_setinfo_task -root am_multiple_open_task -root am_sample_rate_task -root am_set_chinfo_task -root am_set_mode_task -root am_setinfo_task -root am_single_open_task -root am_hw_task - -### specify the usb_as root functions -root usb_as_open -root usb_as_close -root usb_as_disconnect_event_cb -root usb_as_reconnect_event_cb -root usb_as_power -root usb_as_wsrv -root usb_as_isoc_close_cb -root usb_as_play_cb -root usb_as_play_exc_cb -root usb_as_record_cb -root usb_as_record_exc_cb -root usb_as_default_xfer_cb -root usb_as_default_xfer_exc_cb - - -# function pointers -add audio_ch::ch_rput targets am_rput -add audio_ch::ch_rsvc targets am_rsvc -add audio_ch::ch_wput targets am_wput -add audio_ch::ch_wsvc targets am_wsvc -add audio_apm_info::apm_open targets am_open_audio -add audio_apm_info::apm_close targets am_close_audio -add audio_apm_info::apm_open targets am_open_audioctl -add audio_apm_info::apm_close targets am_close_audioctl -add audio_apm_info::apm_restore_state targets am_restore_state -add audio_apm_info::apm_save_state targets am_save_state - - -add bus_ops::bus_add_eventcall targets warlock_dummy -add bus_ops::bus_get_eventcookie targets warlock_dummy -add bus_ops::bus_intr_ctl targets warlock_dummy -add bus_ops::bus_post_event targets warlock_dummy -add bus_ops::bus_remove_eventcall targets warlock_dummy -add bus_ops::bus_config targets warlock_dummy -add bus_ops::bus_unconfig targets warlock_dummy - -add am_ad_src_entry::ad_src_adjust targets am_src2_adjust -add am_ad_src_entry::ad_src_convert targets am_src2_convert -add am_ad_src_entry::ad_src_exit targets am_src2_exit -add am_ad_src_entry::ad_src_init targets am_src2_init -add am_ad_src_entry::ad_src_size targets am_src2_size -add am_ad_src_entry::ad_src_update targets am_src2_update - -add am_ad_entry::ad_setup targets warlock_dummy -add am_ad_entry::ad_teardown targets warlock_dummy -add am_ad_entry::ad_set_config targets warlock_dummy -add am_ad_entry::ad_set_format targets warlock_dummy -add am_ad_entry::ad_start_play targets warlock_dummy -add am_ad_entry::ad_pause_play targets warlock_dummy -add am_ad_entry::ad_stop_play targets warlock_dummy -add am_ad_entry::ad_start_record targets warlock_dummy -add am_ad_entry::ad_stop_record targets warlock_dummy -add am_ad_entry::ad_ioctl targets warlock_dummy -add am_ad_entry::ad_iocdata targets warlock_dummy - - -# we should never hold cs_lock while jumping into another module -# and with this rule we *sometimes* get these -assert order audio_state::as_lock audio_ch::ch_lock usb_as_state::usb_as_mutex - -# this locking order catches problems when the framework holds locks -# over calling into the driver -#assert order usb_as_state::usb_as_mutex audio_state::as_lock audio_ch::ch_lock - diff --git a/usr/src/uts/common/io/warlock/usb_as_with_usba.wlcmd b/usr/src/uts/common/io/warlock/usb_as_with_usba.wlcmd index 264bd51ec1..e2a932c3c3 100644 --- a/usr/src/uts/common/io/warlock/usb_as_with_usba.wlcmd +++ b/usr/src/uts/common/io/warlock/usb_as_with_usba.wlcmd @@ -1,5 +1,5 @@ # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START @@ -21,7 +21,6 @@ # # CDDL HEADER END # -#ident "%Z%%M% %I% %E% SMI" one ohci_state one ehci_state @@ -45,6 +44,7 @@ root usb_get_if_number root usb_parse_CV_cfg_descr root usb_parse_CV_ep_descr root usb_parse_CV_if_descr +root usb_parse_comp_ep_descr root usb_pipe_get_private root usb_get_current_frame_number root usb_get_max_isoc_pkts @@ -90,6 +90,12 @@ root usb_register_hotplug_cbs root usb_get_current_cfgidx root usb_register_client root usb_reset_device +root usb_register_dev_driver +root usb_unregister_dev_driver + +root ohci_quiesce +root uhci_quiesce +root ehci_quiesce root usb_ugen_attach root usb_ugen_close @@ -106,12 +112,10 @@ root usb_ugen_write ### specify the usb_as root functions root usb_as_open root usb_as_close -root usb_as_wsrv root usb_as_disconnect_event_cb root usb_as_reconnect_event_cb root usb_as_power -root usb_as_isoc_close_cb root usb_as_play_cb root usb_as_play_exc_cb root usb_as_record_cb @@ -152,6 +156,7 @@ root hubd_reset_thread root hubd_cpr_post_user_callb root hubd_bus_power +add hubd::h_cleanup_child targets warlock_dummy add usba_pipe_async_req::sync_func targets usba_pipe_sync_close add usba_pipe_async_req::sync_func targets usba_pipe_sync_reset diff --git a/usr/src/uts/common/sys/usb/clients/audio/usb_ac/usb_ac.h b/usr/src/uts/common/sys/usb/clients/audio/usb_ac/usb_ac.h index 55e3d72d06..7cf81f2112 100644 --- a/usr/src/uts/common/sys/usb/clients/audio/usb_ac/usb_ac.h +++ b/usr/src/uts/common/sys/usb/clients/audio/usb_ac/usb_ac.h @@ -35,6 +35,7 @@ extern "C" { #include <sys/sunldi.h> #include <sys/usb/usba/usbai_private.h> + int usb_ac_open(dev_info_t *); void usb_ac_close(dev_info_t *); @@ -77,7 +78,6 @@ typedef struct usb_ac_plumbed { */ typedef struct usb_ac_to_as_req { usb_audio_formats_t acr_curr_format; /* format data from mixer */ - int acr_curr_dir; } usb_ac_to_as_req_t; @@ -88,15 +88,13 @@ typedef struct usb_ac_streams_info { /* valid registration data rcvd */ uint_t acs_rcvd_reg_data; /* pointer to registration data */ - usb_as_registration_t *acs_streams_reg; + usb_as_registration_t acs_streams_reg; - /* request structure to usb_as; one active at a time */ - usb_ac_to_as_req_t acs_ac_to_as_req; /* Multiple command management */ int acs_setup_teardown_count; - usb_audio_formats_t acs_cur_fmt; /* format data from mixer */ + uint8_t acs_default_gain; } usb_ac_streams_info_t; @@ -121,12 +119,77 @@ _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_power_t::acpm_wakeup_enabled)) _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_power_t::acpm_pwr_states)) _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_power_t::acpm_capabilities)) +typedef struct usb_audio_format { + int sr; /* sample rate */ + uint_t ch; /* channels */ + uint_t prec; /* precision */ + uint_t enc; /* encoding */ +} usb_audio_format_t; + + +typedef struct usb_audio_eng { + void *statep; + usb_ac_streams_info_t *streams; + audio_engine_t *af_engp; + + int af_eflags; /* ENGINE_* flags */ + usb_audio_format_t fmt; + uint64_t af_defgain; + + unsigned intrate; /* interrupt rate */ + unsigned sampsz; /* sample size */ + unsigned framesz; /* frame size */ + unsigned fragsz; /* fragment size */ + unsigned nfrags; /* number of fragments in buffer */ + unsigned fragfr; /* number of frames per fragment */ + unsigned frsmshift; /* right shift: frames in sample cnt */ + unsigned smszshift; /* left shift: sample cnt * sampsz */ + + + caddr_t bufp; /* I/O buf; framework to/from drv */ + unsigned bufsz; /* buffer size */ + caddr_t bufpos; /* buffer position */ + caddr_t bufendp; /* end of buffer */ + + + uint64_t frames; + uint64_t io_count; /* i/o requests from the driver */ + uint64_t bufio_count; /* i/o requests to the framework */ + + boolean_t started; + + kmutex_t lock; +} usb_audio_eng_t; + + /* limits */ #define USB_AC_MAX_PLUMBED 3 /* play, record, hid */ #define USB_AC_MAX_AS_PLUMBED 2 /* play, record */ +typedef struct usb_ac_state usb_ac_state_t; +typedef struct usb_audio_ctrl { + audio_ctrl_t *af_ctrlp; /* framework handle */ + usb_ac_state_t *statep; + + kmutex_t ctrl_mutex; + uint64_t cval; /* current control value */ +} usb_audio_ctrl_t; + +enum { + CTL_VOLUME_MONO = 0, + CTL_VOLUME_STERO, + CTL_REC_MONO, + CTL_REC_STERO, + CTL_REC_SRC, + CTL_MONITOR_GAIN, + CTL_MIC_BOOST, + CTL_NUM +}; + +#define USB_AC_ENG_MAX 2 /* usb_ac soft state */ -typedef struct usb_ac_state { +struct usb_ac_state { + dev_info_t *usb_ac_dip; uint_t usb_ac_instance; usb_log_handle_t usb_ac_log_handle; @@ -136,11 +199,17 @@ typedef struct usb_ac_state { kmutex_t usb_ac_mutex; usb_client_dev_data_t *usb_ac_dev_data; /* registration data */ + audio_dev_t *usb_ac_audio_dev; + + + + + usb_audio_eng_t engines[USB_AC_ENG_MAX]; + + - /* audio framework */ - audiohdl_t usb_ac_audiohdl; - am_ad_info_t usb_ac_am_ad_info; - audio_info_t usb_ac_am_ad_defaults; + int flags; + usb_audio_ctrl_t *controls[CTL_NUM]; /* descriptors */ usb_if_descr_t usb_ac_if_descr; @@ -159,8 +228,8 @@ typedef struct usb_ac_state { uchar_t usb_ac_traverse_path_index; /* port types, eg LINE IN, Micr, Speakers */ - uint_t usb_ac_input_ports; - uint_t usb_ac_output_ports; + uint64_t usb_ac_input_ports; + uint64_t usb_ac_output_ports; /* pipe handle */ usb_pipe_handle_t usb_ac_default_ph; @@ -185,20 +254,21 @@ typedef struct usb_ac_state { /* per streams interface info */ usb_ac_streams_info_t usb_ac_streams[USB_AC_MAX_AS_PLUMBED]; - /* - * preserve streams registration because the mixer does not - * copy registration data - */ - usb_as_registration_t usb_ac_streams_reg[USB_AC_MAX_AS_PLUMBED]; ddi_taskq_t *tqp; char dstr[64]; -} usb_ac_state_t; +}; /* warlock directives, stable data */ _NOTE(MUTEX_PROTECTS_DATA(usb_ac_state_t::usb_ac_mutex, usb_ac_state_t)) _NOTE(MUTEX_PROTECTS_DATA(usb_ac_state_t::usb_ac_mutex, usb_ac_power_t)) +_NOTE(MUTEX_PROTECTS_DATA(usb_ac_state_t::usb_ac_mutex, usb_ac_plumbed_t)) +_NOTE(MUTEX_PROTECTS_DATA(usb_audio_eng_t::lock, usb_audio_eng_t)) +_NOTE(MUTEX_PROTECTS_DATA(usb_audio_eng_t::lock, usb_audio_format_t)) +_NOTE(MUTEX_PROTECTS_DATA(usb_audio_ctrl_t::ctrl_mutex, usb_audio_ctrl_t)) + + _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::usb_ac_dip)) _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::usb_ac_ser_acc)) _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::usb_ac_pm)) @@ -206,9 +276,33 @@ _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::usb_ac_instance)) _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::usb_ac_default_ph)) _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::usb_ac_log_handle)) _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::usb_ac_if_descr)) -_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::usb_ac_audiohdl)) _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::usb_ac_dev_data)) _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::usb_ac_ifno)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::flags)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::usb_ac_input_ports)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::engines)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::usb_ac_audio_dev)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::controls)) + +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_eng_t::af_eflags)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_eng_t::streams)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_eng_t::statep)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_eng_t::fmt)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_eng_t::fragfr)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_eng_t::frsmshift)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_eng_t::started)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_eng_t::af_engp)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_eng_t::io_count)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_eng_t::intrate)) + +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_ctrl_t::statep)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_ctrl_t::af_ctrlp)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_ctrl_t::cval)) + +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_plumbed_t::acp_tqp)) +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_plumbed_t::acp_uacp)) + +_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_audio_format_t::ch)) /* usb_ac driver only care about two states: plumbed or unplumbed */ #define USB_AC_STATE_UNPLUMBED 0 @@ -235,6 +329,36 @@ _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ac_state_t::usb_ac_ifno)) /* other useful macros */ #define offsetof(s, m) ((size_t)(&(((s *)0)->m))) + + + + + +#define AF_REGISTERED 0x1 +#define AD_SETUP 0x10 + + +int usb_audio_attach(usb_ac_state_t *); +/* + * framework gain range + */ +#define AUDIO_CTRL_STEREO_VAL(l, r) (((l) & 0xff) | (((r) & 0xff) << 8)) +#define AUDIO_CTRL_STEREO_LEFT(v) ((uint8_t)((v) & 0xff)) +#define AUDIO_CTRL_STEREO_RIGHT(v) ((uint8_t)(((v) >> 8) & 0xff)) + + +#define AF_MAX_GAIN 100 +#define AF_MIN_GAIN 0 + + + +int usb_ac_get_audio(void *, void *, int); + +void usb_ac_send_audio(void *, void *, int); + +void usb_ac_stop_play(usb_ac_state_t *, usb_audio_eng_t *); + + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/sys/usb/clients/audio/usb_as/usb_as.h b/usr/src/uts/common/sys/usb/clients/audio/usb_as/usb_as.h index e88168b391..047dfff218 100644 --- a/usr/src/uts/common/sys/usb/clients/audio/usb_as/usb_as.h +++ b/usr/src/uts/common/sys/usb/clients/audio/usb_as/usb_as.h @@ -86,6 +86,9 @@ typedef struct usb_as_state { uint_t usb_as_dev_state; uint_t usb_as_ifno; kmutex_t usb_as_mutex; + kcondvar_t usb_as_pipe_cv; + + uint_t usb_as_flag; /* status */ /* mblk containing the current control command */ @@ -111,7 +114,7 @@ typedef struct usb_as_state { /* Isoc pipe stuff */ usb_pipe_handle_t usb_as_isoc_ph; usb_pipe_policy_t usb_as_isoc_pp; - audiohdl_t usb_as_ahdl; + void * usb_as_ahdl; uint_t usb_as_request_count; uint_t usb_as_request_samples; diff --git a/usr/src/uts/common/sys/usb/clients/audio/usb_audio.h b/usr/src/uts/common/sys/usb/clients/audio/usb_audio.h index c8e0c0344e..807d5aa435 100644 --- a/usr/src/uts/common/sys/usb/clients/audio/usb_audio.h +++ b/usr/src/uts/common/sys/usb/clients/audio/usb_audio.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -470,6 +470,12 @@ typedef struct usb_audio_type1_format_descr { #define USB_AUDIO_MUTE_ON 1 #define USB_AUDIO_MUTE_OFF 0 +#define USB_AUDIO_PRECISION_8 8 +#define USB_AUDIO_PRECISION_16 16 + +#define USB_AUDIO_PLAY 0x0001 +#define USB_AUDIO_RECORD 0x0002 + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/sys/usb/clients/audio/usb_mixer.h b/usr/src/uts/common/sys/usb/clients/audio/usb_mixer.h index 87a0d2953e..ab045a58c8 100644 --- a/usr/src/uts/common/sys/usb/clients/audio/usb_mixer.h +++ b/usr/src/uts/common/sys/usb/clients/audio/usb_mixer.h @@ -49,12 +49,11 @@ _NOTE(SCHEME_PROTECTS_DATA("unshared", usb_audio_formats)) typedef struct usb_audio_play_req { int up_samples; - audiohdl_t up_handle; + void *up_handle; } usb_audio_play_req_t; #define USB_AS_N_SRS 20 #define USB_AS_N_FORMATS 20 -#define USB_AS_N_COMBINATIONS USB_AS_N_FORMATS #define USB_AS_N_CHANNELS 3 typedef struct usb_as_registration { @@ -65,7 +64,6 @@ typedef struct usb_as_registration { uint_t reg_srs[USB_AS_N_SRS]; usb_audio_formats_t reg_formats[USB_AS_N_FORMATS]; uint_t reg_channels[USB_AS_N_CHANNELS]; - am_ad_cap_comb_t reg_combinations[USB_AS_N_COMBINATIONS]; } usb_as_registration_t; /* MCTLs between usb_ac and usb_as */ diff --git a/usr/src/uts/intel/usb_ac/Makefile b/usr/src/uts/intel/usb_ac/Makefile index 5b18985111..a69a4cd371 100644 --- a/usr/src/uts/intel/usb_ac/Makefile +++ b/usr/src/uts/intel/usb_ac/Makefile @@ -120,16 +120,9 @@ EHCI_FILES = $(EHCI_OBJS:%.o=../ehci/%.ll) warlock: $(WARLOCK_OK) $(WARLOCK_OK): $(WARLOCK_OUT) warlock_ddi.files \ - warlock_audiosup.files warlock_mixer.files \ - warlock_standalone warlock_with_usba warlock_with_sada + warlock_standalone warlock_usba.files warlock_with_usba $(TOUCH) $(WARLOCK_OK) - -warlock_with_sada: $(WLCMD_DIR)/usb_ac_with_sada.wlcmd \ - $(WARLOCK_OUT) \ - warlock_audiosup.files warlock_mixer.files warlock_amsrc2.files - $(WARLOCK) -c $(WLCMD_DIR)/usb_ac_with_sada.wlcmd $(WARLOCK_OUT) \ - -l ../warlock/ddi_dki_impl.ll - + warlock_with_usba: $(WLCMD_DIR)/usb_ac_with_usba.wlcmd $(WARLOCK_OUT) \ warlock_ddi.files warlock_usba.files warlock_ohci.files \ @@ -159,12 +152,3 @@ warlock_ehci.files: warlock_ddi.files: @cd ../warlock; pwd; $(MAKE) warlock - -warlock_audiosup.files: - @cd ../audiosup; pwd; $(MAKE) warlock - -warlock_mixer.files: - @cd ../mixer; pwd; $(MAKE) warlock - -warlock_amsrc2.files: - @cd ../amsrc2; pwd; $(MAKE) warlock diff --git a/usr/src/uts/intel/usb_as/Makefile b/usr/src/uts/intel/usb_as/Makefile index 9d82ee38a0..e48617d312 100644 --- a/usr/src/uts/intel/usb_as/Makefile +++ b/usr/src/uts/intel/usb_as/Makefile @@ -112,25 +112,19 @@ TEST = test # lock_lint rules # USB_AS_FILES = $(MODULE).ll -USBA_FILES = $(USBA_OBJS:%.o=../usba/%.ll) +USBA_FILES = $(USBA_WITHOUT_WUSB_OBJS:%.o=../usba/%.ll) UHCI_FILES = $(UHCI_OBJS:%.o=../uhci/%.ll) OHCI_FILES = $(OHCI_OBJS:%.o=../ohci/%.ll) EHCI_FILES = $(EHCI_OBJS:%.o=../ehci/%.ll) -AUDIO_SUP_FILES = $(AUDIO_SUP_OBJS:%.o=$(UTSBASE)/intel/audiosup/%.ll) # Warlock targets # warlock: $(WARLOCK_OK) -$(WARLOCK_OK): $(WARLOCK_OUT) warlock_ddi.files warlock_audiosup.files \ - warlock_standalone warlock_with_usba warlock_with_sada +$(WARLOCK_OK): $(WARLOCK_OUT) warlock_ddi.files \ + warlock_standalone warlock_usba.files warlock_with_usba $(TOUCH) $(WARLOCK_OK) -warlock_with_sada: $(WLCMD_DIR)/usb_as_with_sada.wlcmd \ - $(WARLOCK_OUT) warlock_audiosup.files - $(WARLOCK) -c $(WLCMD_DIR)/usb_as_with_sada.wlcmd $(WARLOCK_OUT) \ - $(MIXER_FILES) $(AUDIO_SUP_FILES) $(AMSRC2_FILES) \ - -l ../warlock/ddi_dki_impl.ll warlock_with_usba: $(WLCMD_DIR)/usb_as_with_usba.wlcmd $(WARLOCK_OUT) \ warlock_ddi.files warlock_ohci.files warlock_usba.files \ @@ -160,6 +154,3 @@ warlock_ehci.files: warlock_ddi.files: @cd ../warlock; pwd; $(MAKE) warlock - -warlock_audiosup.files: - @cd ../audiosup; pwd; $(MAKE) warlock diff --git a/usr/src/uts/sparc/usb_ac/Makefile b/usr/src/uts/sparc/usb_ac/Makefile index bf3840846c..14560e1740 100644 --- a/usr/src/uts/sparc/usb_ac/Makefile +++ b/usr/src/uts/sparc/usb_ac/Makefile @@ -107,7 +107,7 @@ TEST = test # # lock_lint rules # -USBA_FILES = $(USBA_OBJS:%.o=../usba/%.ll) +USBA_FILES = $(USBA_WITHOUT_WUSB_OBJS:%.o=../usba/%.ll) UHCI_FILES = $(UHCI_OBJS:%.o=../uhci/%.ll) OHCI_FILES = $(OHCI_OBJS:%.o=../ohci/%.ll) EHCI_FILES = $(EHCI_OBJS:%.o=../ehci/%.ll) @@ -119,15 +119,9 @@ EHCI_FILES = $(EHCI_OBJS:%.o=../ehci/%.ll) warlock: $(WARLOCK_OK) $(WARLOCK_OK): $(WARLOCK_OUT) warlock_ddi.files \ - warlock_audiosup.files warlock_mixer.files warlock_amsrc2.files \ - warlock_standalone warlock_with_usba warlock_with_sada + warlock_standalone warlock_usba.files warlock_with_usba $(TOUCH) $(WARLOCK_OK) -warlock_with_sada: $(WLCMD_DIR)/usb_ac_with_sada.wlcmd \ - $(WARLOCK_OUT) \ - warlock_audiosup.files warlock_amsrc2.files warlock_mixer.files - $(WARLOCK) -c $(WLCMD_DIR)/usb_ac_with_sada.wlcmd $(WARLOCK_OUT) \ - -l ../warlock/ddi_dki_impl.ll warlock_with_usba: $(WLCMD_DIR)/usb_ac_with_usba.wlcmd $(WARLOCK_OUT) \ warlock_ddi.files warlock_usba.files warlock_ohci.files \ @@ -157,12 +151,3 @@ warlock_ehci.files: warlock_ddi.files: @cd ../warlock; pwd; $(MAKE) warlock - -warlock_audiosup.files: - @cd ../audiosup; pwd; $(MAKE) warlock - -warlock_amsrc2.files: - @cd ../amsrc2; pwd; $(MAKE) warlock - -warlock_mixer.files: - @cd ../mixer; pwd; $(MAKE) warlock diff --git a/usr/src/uts/sparc/usb_as/Makefile b/usr/src/uts/sparc/usb_as/Makefile index bc7db4c381..06a86518f9 100644 --- a/usr/src/uts/sparc/usb_as/Makefile +++ b/usr/src/uts/sparc/usb_as/Makefile @@ -108,7 +108,7 @@ TEST = test # # lock_lint rules # -USBA_FILES = $(USBA_OBJS:%.o=../usba/%.ll) +USBA_FILES = $(USBA_WITHOUT_WUSB_OBJS:%.o=../usba/%.ll) UHCI_FILES = $(UHCI_OBJS:%.o=../uhci/%.ll) OHCI_FILES = $(OHCI_OBJS:%.o=../ohci/%.ll) EHCI_FILES = $(EHCI_OBJS:%.o=../ehci/%.ll) @@ -119,14 +119,10 @@ EHCI_FILES = $(EHCI_OBJS:%.o=../ehci/%.ll) # warlock: $(WARLOCK_OK) -$(WARLOCK_OK): $(WARLOCK_OUT) warlock_ddi.files warlock_audiosup.files \ - warlock_standalone warlock_with_usba warlock_with_sada +$(WARLOCK_OK): $(WARLOCK_OUT) warlock_ddi.files \ + warlock_standalone warlock_usba.files warlock_with_usba $(TOUCH) $(WARLOCK_OK) -warlock_with_sada: $(WLCMD_DIR)/usb_as_with_sada.wlcmd \ - $(WARLOCK_OUT) warlock_audiosup.files - $(WARLOCK) -c $(WLCMD_DIR)/usb_as_with_sada.wlcmd $(WARLOCK_OUT) \ - -l ../warlock/ddi_dki_impl.ll warlock_with_usba: $(WLCMD_DIR)/usb_as_with_usba.wlcmd $(WARLOCK_OUT) \ warlock_ddi.files warlock_ohci.files warlock_usba.files \ @@ -157,6 +153,3 @@ warlock_ehci.files: warlock_ddi.files: @cd ../warlock; pwd; $(MAKE) warlock - -warlock_audiosup.files: - @cd ../audiosup; pwd; $(MAKE) warlock |