88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER START
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The contents of this file are subject to the terms of the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Common Development and Distribution License (the "License").
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You may not use this file except in compliance with the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * or http://www.opensolaris.org/os/licensing.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * See the License for the specific language governing permissions
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and limitations under the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER END
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/types.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/list.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/sysmacros.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/ddi.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/sunddi.h>
682cb1044237d21ad6810702564bec833b8c410cGarrett D'Amore#include <sys/atomic.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include "audio_impl.h"
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Audio Control functions.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Given a control structure - free all names
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * strings allocated to it.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ctrl - The control who's names that will be free'd.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio_control_freenames(audio_ctrl_t *ctrl)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int indx;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ctrl->ctrl_name != NULL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore strfree((char *)ctrl->ctrl_name);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->ctrl_name = NULL;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (indx = 0; indx < 64; indx++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ctrl->ctrl_enum[indx] != NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore strfree((char *)ctrl->ctrl_enum[indx]);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->ctrl_enum[indx] = NULL;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will allocate and register a control for my audio device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * d - The audio device the control will be attached to.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * desc - Attributes about this new control
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * read_fn - Callback function in driver to read control
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * write_fn - Callback function in driver to write control.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * arg - driver private context passed to read_fn/write_fn
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * On success this will return a control structure else NULL.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The value passed in for a control number in the audio_ctrl_desc_t
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * has some special meaning. If it is less then AUDIO_CONTROL_EXTBASE
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * then the control is assumed to be a known control. If it is
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * AUDIO_CONTROL_EXTBASE then the framework will allocate a unique
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * control number and replace it in the audio_ctrl_desc_t structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and this control is considered an extended driver private control.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The number that is replaced in audio_ctrl_desc_t will be greater
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * then AUDIO_CONTROL_EXTBASE.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio_ctrl_t *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio_dev_add_control(audio_dev_t *d, audio_ctrl_desc_t *desc,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_ctrl_rd_t read_fn, audio_ctrl_wr_t write_fn, void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_ctrl_t *ctrl;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_ctrl_desc_t *new_desc;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore char scratch[16];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore const char *name;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Verify arguments */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(d);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(desc);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* We cannot deal with unnamed controls */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((name = desc->acd_name) == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (NULL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If this was called with a control name that was already
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * added, then we do some special things. First we reuse the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * control audio_ctrl_t and as far as outside users are
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * concerned the handle is reused. To users this looks like we
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * are changing the controls attributes. But what we really do
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * is free every thing allocated to the control and then
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * reinit everything. That way the same code can get used for
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * both.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We verify anything that could fail before we change the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * control or commit to any changes. If there is something bad
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * return null to indicate an error but the original control
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * is still usable and untouched.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl = auclnt_find_control(d, name);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ctrl == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Allocate a new control */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl = kmem_zalloc(sizeof (*ctrl), KM_SLEEP);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Re-configure an existing control */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (desc->acd_type) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_BOOLEAN:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_STEREO:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_MONO:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_METER:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_ENUM:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore default:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(d, "bad control type %d for %s "
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "not replaced", desc->acd_type, desc->acd_name);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (NULL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * By removing it from the list we prevent the need to lock
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and check for locks on the control itself.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Also by doing this we can use the normal add code to do
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * what it normally does below.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_enter(&d->d_ctrl_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore list_remove(&d->d_controls, ctrl);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_exit(&d->d_ctrl_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_control_freenames(ctrl);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->ctrl_read_fn = NULL;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->ctrl_write_fn = NULL;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->ctrl_arg = NULL;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->ctrl_dev = NULL;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore new_desc = &ctrl->ctrl_des;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Fill in new control description */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore new_desc->acd_type = desc->acd_type;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore new_desc->acd_flags = desc->acd_flags;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore new_desc->acd_maxvalue = desc->acd_maxvalue;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore new_desc->acd_minvalue = desc->acd_minvalue;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore new_desc->acd_name = strdup(name);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Process type of control special actions, if any */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (desc->acd_type) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_BOOLEAN:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_STEREO:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_MONO:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_METER:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_ENUM:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int bit = 0; bit < 64; bit++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (((1U << bit) & desc->acd_maxvalue) == 0)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore continue;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = desc->acd_enum[bit];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (name == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) snprintf(scratch, sizeof (scratch),
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "bit%d", bit);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = scratch;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore new_desc->acd_enum[bit] = strdup(name);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore default:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(d, "bad control type %d for %s",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore desc->acd_type, desc->acd_name);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto ctrl_fail;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->ctrl_dev = d;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (new_desc->acd_flags & AUDIO_CTRL_FLAG_READABLE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(read_fn);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->ctrl_read_fn = read_fn;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->ctrl_arg = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (new_desc->acd_flags & AUDIO_CTRL_FLAG_WRITEABLE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(write_fn);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->ctrl_write_fn = write_fn;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->ctrl_arg = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_enter(&d->d_ctrl_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore list_insert_tail(&d->d_controls, ctrl);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_exit(&d->d_ctrl_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (ctrl);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorectrl_fail:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ctrl) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_control_freenames(ctrl);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kmem_free(ctrl, sizeof (*ctrl));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (NULL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will remove a control from my audio device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ctrl - The control will be removed.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio_dev_del_control(audio_ctrl_t *ctrl)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_t *d;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Verify argument */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(ctrl);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore d = ctrl->ctrl_dev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(d);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_enter(&d->d_ctrl_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore list_remove(&d->d_controls, ctrl);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_exit(&d->d_ctrl_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_control_freenames(ctrl);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kmem_free(ctrl, sizeof (*ctrl));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amorevoid
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio_dev_add_soft_volume(audio_dev_t *d)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_ctrl_desc_t desc;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore bzero(&desc, sizeof (desc));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (d->d_pcmvol_ctrl == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_VOLUME;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_MONO;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore desc.acd_minvalue = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore desc.acd_maxvalue = 100;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore desc.acd_flags = AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_PLAY |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_CTRL_FLAG_PCMVOL;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore d->d_pcmvol_ctrl = audio_dev_add_control(d, &desc,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore auimpl_get_pcmvol, auimpl_set_pcmvol, d);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore d->d_pcmvol = 75;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will notify clients of need to reread control
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * values since they have changed.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * There will be a routine that allows a client to register
682cb1044237d21ad6810702564bec833b8c410cGarrett D'Amore * a callback. For now we just update the serial number.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * d - The device that needs updates.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio_dev_update_controls(audio_dev_t *d)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
682cb1044237d21ad6810702564bec833b8c410cGarrett D'Amore atomic_inc_uint(&d->d_serial);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is used to read the current value of a control.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Note, this will cause a callback into the driver to get the value.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ctrl - should be the valid control being read.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * value - is a pointer to the place that will contain the value read.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * On return zero is returned on success else errno is returned.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio_control_read(audio_ctrl_t *ctrl, uint64_t *value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_dev_t *d = ctrl->ctrl_dev;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore uint64_t my_value;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore int ret;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(value);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_enter(&d->d_ctrl_lock);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore while (d->d_suspended) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore cv_wait(&d->d_ctrl_cv, &d->d_ctrl_lock);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(ctrl->ctrl_flags & AUDIO_CTRL_FLAG_READABLE)) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_exit(&d->d_ctrl_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (ENXIO);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(ctrl->ctrl_read_fn);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ret = ctrl->ctrl_read_fn(ctrl->ctrl_arg, &my_value);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_exit(&d->d_ctrl_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (ret == 0) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *value = my_value;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (ret);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is used to write a value to a control.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Note, this will cause a callback into the driver to write the value.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ctrl - should be the valid control being written.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * value - is value to set the control to.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * On return zero is returned on success else errno is returned.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio_control_write(audio_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int ret;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_t *d = ctrl->ctrl_dev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_enter(&d->d_ctrl_lock);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore while (d->d_suspended) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore cv_wait(&d->d_ctrl_cv, &d->d_ctrl_lock);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(ctrl->ctrl_flags & AUDIO_CTRL_FLAG_WRITEABLE)) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_exit(&d->d_ctrl_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (ENXIO);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(ctrl->ctrl_write_fn);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ret = ctrl->ctrl_write_fn(ctrl->ctrl_arg, value);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (ret == 0) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ctrl->ctrl_saved = value;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ctrl->ctrl_saved_ok = B_TRUE;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_exit(&d->d_ctrl_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (ret == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_update_controls(d);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (ret);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore/*
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * This is used to save control values.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreint
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreauimpl_save_controls(audio_dev_t *d)
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_ctrl_t *ctrl;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore list_t *l;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore int ret;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ASSERT(mutex_owned(&d->d_ctrl_lock));
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore l = &d->d_controls;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore for (ctrl = list_head(l); ctrl; ctrl = list_next(l, ctrl)) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if ((!(ctrl->ctrl_flags & AUDIO_CTRL_FLAG_WRITEABLE)) ||
4a2cf36876399bd3173bcfeede06e04242718fceZhao Edgar Liu - Sun Microsystems (!(ctrl->ctrl_flags & AUDIO_CTRL_FLAG_READABLE))) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore continue;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ret = ctrl->ctrl_read_fn(ctrl->ctrl_arg, &ctrl->ctrl_saved);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (ret != 0) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_dev_warn(d,
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore "Unable to save value of control %s",
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ctrl->ctrl_name);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore return (ret);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore } else {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ctrl->ctrl_saved_ok = B_TRUE;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore return (0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore}
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreint
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreauimpl_restore_controls(audio_dev_t *d)
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_ctrl_t *ctrl;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore list_t *l;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore int ret;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore int rv = 0;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ASSERT(mutex_owned(&d->d_ctrl_lock));
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore l = &d->d_controls;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore for (ctrl = list_head(l); ctrl; ctrl = list_next(l, ctrl)) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (!ctrl->ctrl_saved_ok) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore continue;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ret = ctrl->ctrl_write_fn(ctrl->ctrl_arg, ctrl->ctrl_saved);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (ret != 0) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_dev_warn(d,
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore "Unable to restore value of control %s",
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ctrl->ctrl_name);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore rv = ret;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore return (rv);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore}