diff options
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 |