remove labels, use the stream name instead. Disallow digits in

stream names and use the "unit" integer instead.
This commit is contained in:
Alexandre Ratchov 2015-09-04 17:08:12 +02:00
parent 10066d5fa1
commit 043bb0950a
14 changed files with 363 additions and 631 deletions

19
configure vendored
View File

@ -18,8 +18,6 @@ Usage: configure [options]
--disable-alsa disable alsa audio & midi backends
--enable-sun enable sun audio backend [$sun]
--disable-sun disable sun audio backend
--enable-sun-mixer enable sun audio mixer backend [$sun_mixer]
--disable-sun-mixer disable sun audio mixer backend
--enable-rmidi enable character device midi backend [$rmidi]
--disable-rmidi disable character device midi backend
--enable-xvolkeys build xvolkeys utility (requires X) [$xvolkeys]
@ -34,7 +32,6 @@ prefix=/usr/local # where to install sndio
so="libsndio.so.\${MAJ}.\${MIN}" # shared libs to build
alsa=no # do we want alsa support ?
sun=no # do we want sun support ?
sun_mixer=no # do we want sun mixer support ?
rmidi=no # do we want support for raw char dev ?
precision=16 # aucat/sndiod arithmetic precision
user=_sndio # non-privileged user for sndio daemon
@ -107,12 +104,6 @@ for i; do
--disable-sun)
sun=no
shift;;
--enable-sun-mixer)
sun_mixer=yes
shift;;
--disable-sun-mixer)
sun_mixer=no
shift;;
--enable-rmidi)
rmidi=yes
shift;;
@ -166,14 +157,7 @@ fi
# if using Sun API, add corresponding parameters
#
if [ $sun = yes ]; then
defs="$defs -DUSE_SUN"
fi
#
# if using Sun mixer API, add corresponding parameters
#
if [ $sun_mixer = yes ]; then
defs="$defs -DUSE_SUN_MIXER"
defs="$defs -DUSE_SUN -DUSE_SUN_MIXER"
fi
#
@ -215,7 +199,6 @@ user..................... $user
precision................ $precision
alsa..................... $alsa
sun...................... $sun
sun mixer................ $sun_mixer
rmidi.................... $rmidi
xvolkeys................. $xvolkeys

View File

@ -46,7 +46,7 @@ MAN7 = sndio.7
# libraries to build and install
#
MAJ = 6
MIN = 0
MIN = 1
SO = @so@
all: ${SO}

View File

@ -115,7 +115,8 @@ struct amsg {
*/
struct amsg_mix_chan {
char str[AMSG_MIX_NAMEMAX]; /* stream name */
char opt[AMSG_MIX_NAMEMAX]; /* stream name */
int16_t unit; /* stream number */
uint8_t __pad[2];
};
/*

View File

@ -86,7 +86,6 @@ _siomix_create(struct siomix_hdl *hdl, struct siomix_ops *ops,
hdl->ctl_cb = NULL;
}
int
_siomix_psleep(struct siomix_hdl *hdl, int event)
{
@ -172,11 +171,12 @@ _siomix_ondesc_cb(struct siomix_hdl *hdl,
struct siomix_desc *desc, unsigned int val)
{
if (desc) {
DPRINTF("%u -> %s[%s].%s=%s[%s]\n",
DPRINTF("_siomix_ondesc_cb: %u -> %s[%d].%s=%s[%d]:%d\n",
desc->addr,
desc->chan0.str, desc->chan0.opt,
desc->chan0.str, desc->chan0.unit,
desc->func,
desc->chan1.str, desc->chan1.opt);
desc->chan1.str, desc->chan1.unit,
val);
}
if (hdl->desc_cb)
hdl->desc_cb(hdl->desc_arg, desc, val);
@ -185,6 +185,7 @@ _siomix_ondesc_cb(struct siomix_hdl *hdl,
void
_siomix_onctl_cb(struct siomix_hdl *hdl, unsigned int addr, unsigned int val)
{
DPRINTF("_siomix_onctl_cb: %u -> %u\n", addr, val);
if (hdl->ctl_cb)
hdl->ctl_cb(hdl->ctl_arg, addr, val);
}

View File

@ -75,9 +75,9 @@ siomix_aucat_rdata(struct siomix_aucat_hdl *hdl)
c = hdl->tmp;
while (size >= sizeof(struct amsg_mix_desc)) {
strlcpy(desc.chan0.str, c->chan0.str, SIOMIX_NAMEMAX);
strlcpy(desc.chan0.opt, c->chan0.opt, SIOMIX_NAMEMAX);
desc.chan0.unit = ntohs(c->chan0.unit);
strlcpy(desc.chan1.str, c->chan1.str, SIOMIX_NAMEMAX);
strlcpy(desc.chan1.opt, c->chan1.opt, SIOMIX_NAMEMAX);
desc.chan1.unit = ntohs(c->chan1.unit);
strlcpy(desc.func, c->func, SIOMIX_NAMEMAX);
desc.type = c->type;
desc.addr = ntohs(c->addr);

View File

@ -108,9 +108,9 @@ It's called once with a NULL argument to indicate that the full
description was sent and that the caller has a consistent
representation of the mixer.
.Pp
Then, whenever a mixer control description changes (currently only
label strings may change, see below), the call-back is invoked with the
updated information followed by a call with a NULL argument.
Then, whenever a mixer control description changes, the call-back is
invoked with the updated information followed by a call with a NULL
argument.
.Pp
Controls are described by the
.Va siomix_ondesc
@ -118,7 +118,7 @@ stucture as follows:
.Bd -literal
struct siomix_chan {
char str[SIOMIX_NAMEMAX]; /* stream name */
char opt[SIOMIX_NAMEMAX]; /* optional channel */
int unit; /* optional number */
};
struct siomix_desc {
@ -127,9 +127,8 @@ struct siomix_desc {
#define SIOMIX_SW 3 /* on/off switch */
#define SIOMIX_VEC 4 /* element of array of numbers */
#define SIOMIX_LIST 5 /* element of array of switches */
#define SIOMIX_LABEL 6 /* string attached to chan0 */
unsigned int type; /* one of above */
char func[SIOMIX_NAMEMAX]; /* parameter group name */
char func[SIOMIX_NAMEMAX]; /* function name */
struct siomix_chan chan0; /* affected channels */
struct siomix_chan chan1; /* dito for vec, and list */
};
@ -145,7 +144,7 @@ The
.Va type
attribute indicates what the structure describes.
Possible types are:
.Bl -tag -width "SIOMIX_LABEL"
.Bl -tag -width "SIOMIX_LIST"
.It SIOMIX_NUM
A continuous control in the 0..SIOMIX_INTMAX range.
For instance the volume of the speaker.
@ -160,18 +159,6 @@ from the line input to the speaker.
An element of an array of on/off switches.
For instance the line-in position of the
speaker source selector.
.It SIOMIX_LABEL
A label attached to the channel.
In mixers exposed by
.Xr sndiod 1 ,
they correspond to program names.
The label string is stored in the
.Va chan1
attribute and is not unique.
Labels may dynamically change, but their
.Va addr
attribute remains the same and can be used to figure out which
label is changing.
.El
.Pp
The

View File

@ -13,14 +13,12 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
*
* TODO
* - fix ac97 based mixers
*
* the way the sun mixer is designed doesn't let us representing
* it easily with the siomix api. For now expose only few
* white-listed controls the same way as we do in kernel
* for the wskbd volume keys.
*/
#ifdef USE_SUN_MIXER
#include <sys/types.h>
#include <sys/ioctl.h>
@ -37,12 +35,24 @@
#include "debug.h"
#include "siomix_priv.h"
#define SUN_TO_SIOMIX(v) (((v) * 127 + 127) / 255)
#define SIOMIX_TO_SUN(v) (((v) * 255 + 63) / 127)
struct wskbd_vol
{
int nch; /* channels in the level control */
int level_idx; /* index of the level control */
int level_val[8]; /* current value */
int mute_idx; /* index of the mute control */
int mute_val; /* per channel state of mute control */
int base_addr;
char *name;
};
struct siomix_sun_hdl {
struct siomix_hdl siomix;
struct mixer_devinfo *info;
struct mixer_ctrl *curval;
int fd, ninfo, events;
int iclass, oclass, rclass;
struct wskbd_vol spkr, mic;
int fd, events;
};
static void siomix_sun_close(struct siomix_hdl *);
@ -66,13 +76,197 @@ struct siomix_ops siomix_sun_ops = {
siomix_sun_ondesc
};
static int
initmute(struct siomix_sun_hdl *hdl, struct mixer_devinfo *info)
{
struct mixer_devinfo mi;
mi.index = info->next;
for (mi.index = info->next; mi.index != -1; mi.index = mi.next) {
if (ioctl(hdl->fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
break;
if (strcmp(mi.label.name, AudioNmute) == 0)
return mi.index;
}
return -1;
}
static int
initvol(struct siomix_sun_hdl *hdl, struct wskbd_vol *vol, char *cn, char *dn)
{
struct mixer_devinfo dev, cls;
for (dev.index = 0; ; dev.index++) {
if (ioctl(hdl->fd, AUDIO_MIXER_DEVINFO, &dev) < 0)
break;
if (dev.type != AUDIO_MIXER_VALUE)
continue;
cls.index = dev.mixer_class;
if (ioctl(hdl->fd, AUDIO_MIXER_DEVINFO, &cls) < 0)
break;
if (strcmp(cls.label.name, cn) == 0 &&
strcmp(dev.label.name, dn) == 0) {
vol->nch = dev.un.v.num_channels;
vol->level_idx = dev.index;
vol->mute_idx = initmute(hdl, &dev);
DPRINTF("using %s.%s, %d channels, %s\n",
cn, dn, vol->nch,
vol->mute_idx >= 0 ? "mute" : "no mute");
return 1;
}
}
vol->level_idx = vol->mute_idx = -1;
return 0;
}
static void
init(struct siomix_sun_hdl *hdl)
{
static struct {
char *cn, *dn;
} spkr_names[] = {
{AudioCoutputs, AudioNmaster},
{AudioCinputs, AudioNdac},
{AudioCoutputs, AudioNdac},
{AudioCoutputs, AudioNoutput}
}, mic_names[] = {
{AudioCrecord, AudioNrecord},
{AudioCrecord, AudioNvolume},
{AudioCinputs, AudioNrecord},
{AudioCinputs, AudioNvolume},
{AudioCinputs, AudioNinput}
};
int i;
for (i = 0; i < sizeof(spkr_names) / sizeof(spkr_names[0]); i++) {
if (initvol(hdl, &hdl->spkr,
spkr_names[i].cn, spkr_names[i].dn)) {
hdl->spkr.name = "spkr";
hdl->spkr.base_addr = 0;
break;
}
}
for (i = 0; i < sizeof(mic_names) / sizeof(mic_names[0]); i++) {
if (initvol(hdl, &hdl->mic,
mic_names[i].cn, mic_names[i].dn)) {
hdl->mic.name = "mic";
hdl->mic.base_addr = 64;
break;
}
}
}
static int
setvol(struct siomix_sun_hdl *hdl, struct wskbd_vol *vol, int addr, int val)
{
struct mixer_ctrl ctrl;
int i;
addr -= vol->base_addr;
if (vol->level_idx >= 0 && addr >= 0 && addr < vol->nch) {
if (vol->level_val[addr] == val) {
DPRINTF("level %d, no change\n", val);
return 0;
}
vol->level_val[addr] = val;
ctrl.dev = vol->level_idx;
ctrl.type = AUDIO_MIXER_VALUE;
ctrl.un.value.num_channels = vol->nch;
for (i = 0; i < vol->nch; i++) {
ctrl.un.value.level[i] =
SIOMIX_TO_SUN(vol->level_val[i]);
}
DPRINTF("vol %d setting to %d\n", addr, vol->level_val[addr]);
if (ioctl(hdl->fd, AUDIO_MIXER_WRITE, &ctrl) < 0) {
DPRINTF("level write failed\n");
return 0;
}
_siomix_onctl_cb(&hdl->siomix, vol->base_addr + i, val);
return 1;
}
addr -= 32;
if (vol->mute_idx >= 0 && addr >= 0 && addr < vol->nch) {
val = val ? 1 : 0;
if (vol->mute_val == val) {
DPRINTF("mute %d, no change\n", val);
return 0;
}
vol->mute_val = val;
ctrl.dev = vol->mute_idx;
ctrl.type = AUDIO_MIXER_ENUM;
ctrl.un.ord = val;
DPRINTF("mute setting to %d\n", val);
if (ioctl(hdl->fd, AUDIO_MIXER_WRITE, &ctrl) < 0) {
DPERROR("mute write\n");
return 0;
}
for (i = 0; i < vol->nch; i++) {
_siomix_onctl_cb(&hdl->siomix,
vol->base_addr + 32 + i, val);
}
return 1;
}
return 1;
}
static int
scanvol(struct siomix_sun_hdl *hdl, struct wskbd_vol *vol)
{
struct siomix_desc desc;
struct mixer_ctrl ctrl;
int i, val;
if (vol->level_idx >= 0) {
ctrl.dev = vol->level_idx;
ctrl.type = AUDIO_MIXER_VALUE;
ctrl.un.value.num_channels = vol->nch;
if (ioctl(hdl->fd, AUDIO_MIXER_READ, &ctrl) < 0) {
DPRINTF("mute read failed\n");
return 0;
}
desc.type = SIOMIX_NUM;
desc.chan1.str[0] = 0;
desc.chan1.unit = -1;
strlcpy(desc.func, "level", SIOMIX_NAMEMAX);
strlcpy(desc.chan0.str, vol->name, SIOMIX_NAMEMAX);
for (i = 0; i < vol->nch; i++) {
desc.chan0.unit = i;
desc.addr = vol->base_addr + i;
val = SUN_TO_SIOMIX(ctrl.un.value.level[i]);
vol->level_val[i] = val;
_siomix_ondesc_cb(&hdl->siomix, &desc, val);
}
}
if (vol->mute_idx >= 0) {
ctrl.dev = vol->mute_idx;
ctrl.type = AUDIO_MIXER_ENUM;
if (ioctl(hdl->fd, AUDIO_MIXER_READ, &ctrl) < 0) {
DPRINTF("mute read failed\n");
return 0;
}
desc.type = SIOMIX_SW;
desc.chan1.str[0] = 0;
desc.chan1.unit = -1;
strlcpy(desc.func, "mute", SIOMIX_NAMEMAX);
strlcpy(desc.chan0.str, vol->name, SIOMIX_NAMEMAX);
val = ctrl.un.ord ? 1 : 0;
vol->mute_val = val;
for (i = 0; i < vol->nch; i++) {
desc.chan0.unit = i;
desc.addr = vol->base_addr + 32 + i;
_siomix_ondesc_cb(&hdl->siomix, &desc, val);
}
}
return 1;
}
struct siomix_hdl *
_siomix_sun_open(const char *str, unsigned int mode, int nbio)
{
struct siomix_sun_hdl *hdl;
int i, fd, flags;
char path[PATH_MAX];
struct mixer_devinfo mi;
int flags;
if (*str != '/') {
DPRINTF("siomix_sun_open: %s: '/<devnum>' expected\n", str);
@ -88,56 +282,15 @@ _siomix_sun_open(const char *str, unsigned int mode, int nbio)
flags = O_RDWR;
else
flags = (mode & SIOMIX_WRITE) ? O_WRONLY : O_RDONLY;
while ((fd = open(path, flags)) < 0) {
while ((hdl->fd = open(path, flags | O_CLOEXEC)) < 0) {
if (errno == EINTR)
continue;
DPERROR(path);
goto bad_free;
}
if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
DPERROR("FD_CLOEXEC");
goto bad_close;
}
hdl->iclass = hdl->oclass = hdl->rclass = -1;
hdl->fd = fd;
/*
* count the number of mixer knobs, and fetch the full mixer
* description
*/
for (mi.index = 0; ; mi.index++) {
if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
break;
}
hdl->ninfo = mi.index;
hdl->info = malloc(hdl->ninfo * sizeof(struct mixer_devinfo));
if (hdl->info == NULL) {
DPERROR("malloc");
goto bad_close;
}
hdl->curval = malloc(hdl->ninfo * sizeof(struct mixer_ctrl));
if (hdl->curval == NULL) {
DPERROR("malloc");
goto bad_freeinfo;
}
for (i = 0; i < hdl->ninfo; i++) {
hdl->info[i].index = i;
if (ioctl(fd, AUDIO_MIXER_DEVINFO, &hdl->info[i]) < 0) {
DPERROR("AUDIO_MIXER_DEVINFO");
goto bad_freeval;
}
free(hdl);
return NULL;
}
init(hdl);
return (struct siomix_hdl *)hdl;
bad_freeval:
free(hdl->curval);
bad_freeinfo:
free(hdl->info);
bad_close:
close(fd);
bad_free:
free(hdl);
return NULL;
}
static void
@ -149,345 +302,15 @@ siomix_sun_close(struct siomix_hdl *addr)
free(hdl);
}
/*
* parse foo-4:5 and convert it to "foo", 4, 2
*/
static int
copy_ch(struct siomix_sun_hdl *hdl,
int icls, char *istr, char *ostr, int *rmin, int *rnum)
{
size_t len;
char *sep, *endp;
long cmin, cmax;
ostr[0] = 0;
sep = strchr(istr, '-');
if (sep) {
len = sep - istr;
if (len >= SIOMIX_NAMEMAX - 1)
return 0;
memcpy(ostr, istr, len);
ostr[len] = 0;
istr = sep + 1;
cmin = strtol(istr, &endp, 10);
if (endp != istr) {
/*
* this a "foo-0:3" style range
*/
istr = endp;
if (*endp == ':') {
istr++;
cmax = strtol(istr, &endp, 10);
if (endp == istr) {
DPRINTF("bad range\n");
return 0;
}
istr = endp;
} else if (*endp == 0) {
cmax = cmin;
} else {
DPRINTF("unknown range\n");
return 0;
}
*rmin = cmin;
*rnum = cmax - cmin + 1;
} else {
if (strcmp(ostr, "line") == 0) {
/* rename make "line-foo" to "foo" */
ostr[0] = 0;
} else {
/* append unknown suffix with '_' */
strlcat(ostr, "_", SIOMIX_NAMEMAX);
}
strlcat(ostr, istr, SIOMIX_NAMEMAX);
*rmin = 0;
*rnum = 0;
}
} else {
*rmin = 0;
*rnum = 0;
strlcpy(ostr, istr, SIOMIX_NAMEMAX);
}
if (icls == -1)
return 1;
/*
* append "_in" and "_out" suffixes, as nowadays
* most jacks are bidirectional
*/
if (strcmp(ostr, "mic") == 0 ||
strcmp(ostr, "spkr") == 0 ||
strcmp(ostr, "hp") == 0 ||
strcmp(ostr, "line") == 0) {
if (icls == hdl->iclass)
strlcat(ostr, "_in", SIOMIX_NAMEMAX);
if (icls == hdl->oclass)
strlcat(ostr, "_out", SIOMIX_NAMEMAX);
}
/*
* record class may conflict with input/output
*/
if (icls == hdl->rclass) {
if (strcmp(ostr, "volume") == 0)
strlcpy(ostr, "rec", SIOMIX_NAMEMAX);
}
return 1;
}
static void
make_opt(char *opt, int min, int num)
{
switch (num) {
case 0:
opt[0] = 0;
break;
case 1:
snprintf(opt, SIOMIX_NAMEMAX, "%u", min);
break;
default:
snprintf(opt, SIOMIX_NAMEMAX, "%u-%u", min, min + num - 1);
break;
}
}
static int
copyname_num(struct siomix_sun_hdl *hdl,
struct mixer_devinfo *info, struct siomix_desc *desc, int *rmin, int *rnum)
{
size_t len;
char *sep, *istr;
sep = strchr(info->label.name, '_');
if (sep) {
strlcpy(desc->func, "mix", SIOMIX_NAMEMAX);
desc->type = SIOMIX_VEC;
len = sep - info->label.name;
if (len >= SIOMIX_NAMEMAX - 1)
return 0;
memcpy(desc->chan0.str, info->label.name, len);
desc->chan0.str[len] = 0;
istr = sep + 1;
if (!copy_ch(hdl, info->mixer_class, istr,
desc->chan1.str, rmin, rnum))
return 0;
} else {
strlcpy(desc->func, "level", SIOMIX_NAMEMAX);
desc->type = SIOMIX_NUM;
istr = info->label.name;
if (!copy_ch(hdl, info->mixer_class, istr,
desc->chan0.str, rmin, rnum))
return 0;
desc->chan1.str[0] = '\0';
}
return 1;
}
static int
copyname_enum(struct siomix_sun_hdl *hdl,
struct mixer_devinfo *info, struct siomix_desc *desc, int *rmin, int *rnum)
{
char istr[SIOMIX_NAMEMAX], *sep;
size_t len;
sep = strrchr(info->label.name, '.');
if (sep == NULL)
sep = strrchr(info->label.name, '_');
if (sep == NULL) {
if (info->prev < 0) {
fprintf(stderr, "no separator\n");
return 0;
}
strlcpy(desc->func, info->label.name, SIOMIX_NAMEMAX);
while (info->prev >= 0)
info = hdl->info + info->prev;
if (!copy_ch(hdl, info->mixer_class, info->label.name,
desc->chan0.str, rmin, rnum))
return 0;
desc->chan1.str[0] = 0;
} else {
strlcpy(desc->func, sep + 1, SIOMIX_NAMEMAX);
len = sep - info->label.name;
if (len >= SIOMIX_NAMEMAX - 1)
return 0;
memcpy(istr, info->label.name, len);
istr[len] = '\0';
if (!copy_ch(hdl, info->mixer_class, istr,
desc->chan0.str, rmin, rnum))
return 0;
desc->chan1.str[0] = 0;
}
/*
* certain cards expose adc[0-1].source and adc[2-3].source
* as different types, which we forbid.
*/
if (strcmp(desc->func, "source") == 0) {
if (info->type == AUDIO_MIXER_SET)
strlcpy(desc->func, "sources", SIOMIX_NAMEMAX);
}
return 1;
}
static int
ord_to_num(struct mixer_devinfo *info, int ord)
{
int i;
for (i = 0; i < info->un.e.num_mem; i++) {
if (ord == info->un.e.member[i].ord)
return i;
}
DPRINTF("mixer bug: order not found\n");
return 0;
}
static int
mask_to_bit(struct mixer_devinfo *info, int index, int val)
{
int mask;
mask = info->un.s.member[index].mask;
if ((mask & val) == mask)
return 1;
else
return 0;
return 0;
}
static int
enum_to_sw(struct mixer_devinfo *info, struct siomix_desc *desc)
{
char *v0, *v1;
if (info->un.e.num_mem != 2)
return 0;
v0 = info->un.e.member[ord_to_num(info, 0)].label.name;
v1 = info->un.e.member[ord_to_num(info, 1)].label.name;
if (strcmp(v0, "off") == 0 && strcmp(v1, "on") == 0)
goto make_sw;
if (strcmp(v0, "unplugged") == 0 && strcmp(v1, "plugged") == 0) {
strlcpy(desc->func,
info->un.e.member[1].label.name,
SIOMIX_NAMEMAX);
goto make_sw;
}
return 0;
make_sw:
desc->chan1.str[0] = 0;
desc->chan1.opt[0] = 0;
desc->type = SIOMIX_SW;
return 1;
}
static int
siomix_sun_ondesc(struct siomix_hdl *addr)
{
struct siomix_sun_hdl *hdl = (struct siomix_sun_hdl *)addr;
struct mixer_devinfo *info;
struct mixer_ctrl *ctrl;
struct siomix_desc desc;
char *ostr;
int i, j, v, cmin, cnum;
for (i = 0; i < hdl->ninfo; i++) {
info = hdl->info + i;
ctrl = hdl->curval + i;
ctrl->dev = i;
ctrl->type = info->type;
if (ctrl->type == AUDIO_MIXER_CLASS) {
if (strcmp(info->label.name, "inputs") == 0)
hdl->iclass = i;
if (strcmp(info->label.name, "outputs") == 0)
hdl->oclass = i;
if (strcmp(info->label.name, "record") == 0)
hdl->rclass = i;
continue;
}
if (ctrl->type == AUDIO_MIXER_VALUE)
ctrl->un.value.num_channels = info->un.v.num_channels;
if (ioctl(hdl->fd, AUDIO_MIXER_READ, ctrl) < 0) {
DPERROR("AUDIO_MIXER_READ");
hdl->siomix.eof = 1;
return 0;
}
}
info = hdl->info;
for (i = 0; i < hdl->ninfo; i++) {
DPRINTF("psarsing \"%s\"\n", info->label.name);
switch (info->type) {
case AUDIO_MIXER_VALUE:
desc.addr = i * 32;
if (!copyname_num(hdl, info, &desc, &cmin, &cnum))
return 0;
make_opt(desc.chan0.opt, cmin, cnum);
desc.chan1.opt[0] = 0;
for (j = 0; j < info->un.v.num_channels; j++) {
v = hdl->curval[i].un.value.level[j] *
127 / 255;
ostr = desc.type == SIOMIX_NUM ?
desc.chan0.opt : desc.chan1.opt;
if (info->un.v.num_channels > 1) {
make_opt(ostr, cmin + j, 1);
} else {
make_opt(ostr, cmin, cnum);
}
_siomix_ondesc_cb(&hdl->siomix, &desc, v);
desc.addr++;
}
break;
case AUDIO_MIXER_ENUM:
desc.addr = i * 32;
if (info->un.e.num_mem <= 1)
break;
if (!copyname_enum(hdl, info, &desc, &cmin, &cnum))
return 0;
if (enum_to_sw(info, &desc)) {
make_opt(desc.chan0.opt, cmin, cnum);
_siomix_ondesc_cb(&hdl->siomix, &desc,
ord_to_num(info, hdl->curval[i].un.ord));
break;
}
for (j = 0; j < info->un.e.num_mem; j++) {
if (!copyname_enum(hdl, info,
&desc, &cmin, &cnum))
return 0;
make_opt(desc.chan0.opt, cmin, cnum);
if (!copy_ch(hdl, info->mixer_class,
info->un.e.member[j].label.name,
desc.chan1.str, &cmin, &cnum))
return 0;
make_opt(desc.chan1.opt, cmin, cnum);
desc.type = SIOMIX_LIST;
v = (j == ord_to_num(info,
hdl->curval[i].un.ord)) ? 1 : 0;
_siomix_ondesc_cb(&hdl->siomix, &desc, v);
desc.addr++;
}
break;
case AUDIO_MIXER_SET:
desc.addr = i * 32;
if (info->un.s.num_mem == 0)
break;
if (!copyname_enum(hdl, info, &desc, &cmin, &cnum))
return 0;
make_opt(desc.chan0.opt, cmin, cnum);
desc.type = SIOMIX_LIST;
for (j = 0; j < info->un.s.num_mem; j++) {
if (!copy_ch(hdl, info->mixer_class,
info->un.s.member[j].label.name,
desc.chan1.str, &cmin, &cnum))
return 0;
make_opt(desc.chan1.opt, cmin, cnum);
_siomix_ondesc_cb(&hdl->siomix, &desc,
mask_to_bit(info, j,
hdl->curval[i].un.mask));
desc.addr++;
}
break;
}
info++;
if (!scanvol(hdl, &hdl->spkr) ||
!scanvol(hdl, &hdl->mic)) {
hdl->siomix.eof = 1;
return 0;
}
_siomix_ondesc_cb(&hdl->siomix, NULL, 0);
return 1;
@ -496,8 +319,6 @@ siomix_sun_ondesc(struct siomix_hdl *addr)
static int
siomix_sun_onctl(struct siomix_hdl *addr)
{
//struct siomix_sun_hdl *hdl = (struct siomix_sun_hdl *)addr;
return 1;
}
@ -505,43 +326,9 @@ static int
siomix_sun_setctl(struct siomix_hdl *arg, unsigned int addr, unsigned int val)
{
struct siomix_sun_hdl *hdl = (struct siomix_sun_hdl *)arg;
struct mixer_ctrl *ctrl;
struct mixer_devinfo *info;
int base, offs, oldv;
DPRINTF("siomix_sun_setctl: %d set to %d\n", addr, val);
base = addr / 32;
offs = addr % 32;
ctrl = hdl->curval + base;
info = hdl->info + base;
switch (ctrl->type) {
case AUDIO_MIXER_VALUE:
oldv = ctrl->un.value.level[offs];
ctrl->un.value.level[offs] = (val * 255 + 63) / 127;
break;
case AUDIO_MIXER_ENUM:
if (val == 0)
return 1;
oldv = ord_to_num(info, ctrl->un.ord);
if (oldv == offs)
return 1;
_siomix_onctl_cb(&hdl->siomix, 32 * base + oldv, 0);
ctrl->un.ord = info->un.e.member[offs].ord;
break;
case AUDIO_MIXER_SET:
if (val)
ctrl->un.mask |= info->un.s.member[offs].mask;
else
ctrl->un.mask &= ~info->un.s.member[offs].mask;
break;
default:
DPRINTF("siomix_sun_setctl: wrong addr %d\n", addr);
hdl->siomix.eof = 1;
return 0;
}
if (ioctl(hdl->fd, AUDIO_MIXER_WRITE, ctrl) < 0) {
DPERROR("siomix_sun_setctl");
if (!setvol(hdl, &hdl->spkr, addr, val) ||
!setvol(hdl, &hdl->mic, addr, val)) {
hdl->siomix.eof = 1;
return 0;
}

View File

@ -98,7 +98,7 @@ struct sio_cap {
*/
struct siomix_chan {
char str[SIOMIX_NAMEMAX]; /* stream name */
char opt[SIOMIX_NAMEMAX]; /* optional (sub-)stream name */
int unit; /* optional stream number */
};
/*
@ -110,9 +110,8 @@ struct siomix_desc {
#define SIOMIX_SW 3 /* on/off switch (0 or 1) */
#define SIOMIX_VEC 4 /* number, element of vector */
#define SIOMIX_LIST 5 /* switch, element of a list */
#define SIOMIX_LABEL 6 /* label attached to chan0 */
unsigned int type; /* one of above */
char func[SIOMIX_NAMEMAX]; /* function name or label */
char func[SIOMIX_NAMEMAX]; /* function name */
struct siomix_chan chan0; /* affected channels */
struct siomix_chan chan1; /* dito for SIOMIX_{VEC,LIST} */
};

View File

@ -50,7 +50,7 @@ Dump data received from
.Pa rmidi/0
to stderr:
.Bd -literal -offset indent
$ midicat -di rmidi/0
$ midicat -di rmidi/0 >/dev/null
.Ed
.Pp
Send data from

View File

@ -50,9 +50,6 @@ Use this
mixer device.
.It Fl m
Monitor and display mixer changes.
.It Fl n
Don't hide program names associated to audio streams (by
default they are displayed as comments).
.It Fl i
Display characteristics of requested parameters
instead of their values.
@ -66,7 +63,8 @@ parameter to hide details that are not essential.
If no commands are specified all valid parameters are displayed on
.Em stdout .
Unless
.Fl d
.Fl d ,
.Fl m ,
or
.Fl i
are used, displayed parameters are valid commands.
@ -80,20 +78,19 @@ parameters respectively:
.Pp
On the left-hand side, the affected substream is specified
by the stream name followed by an optional
channel range.
channel.
Examples of left-hand side terms:
.Pp
.Dl spkr.level
.Dl spkr[2-5].level
.Dl spkr[6].level
.Dl spkr6.level
.Pp
There are three parameter types: numbers, selectors and vectors.
There are 4 parameter types: switches, numbers, selectors, and vectors.
.Pp
Numbers are specified in decimal and follow the same semantics
as MIDI controllers.
Values are in the 0..127 range and 64 is the neutral state (if applicable).
Two-state controls (switches) take any value in the 0..63 range or
in the 64..127 range typically to the
Two-state controls (switches) take either 0 or 1 as value,
typically corresponding to the
.Em off
and
.Em on
@ -108,7 +105,7 @@ is used instead of a number, then the switch is toggled.
Examples:
.Pp
.Dl spkr.level=85
.Dl spkr[4-5].level=+10
.Dl spkr.level=+10
.Dl spkr.mute=0
.Dl spkr.mute=!
.Pp
@ -120,8 +117,8 @@ If no channel range is specified, the same
range as the stream specified on the left-hand side is used.
For instance the following are equivalent:
.Pp
.Dl record[1].source=mic
.Dl record[1].source=mic[1]
.Dl record1.source=mic
.Dl record1.source=mic1
.Pp
.Pp Vectors
Vectors are arrays of numbers.
@ -152,5 +149,5 @@ stream to zero.
.Pp
The following commands are equivalent:
.Pp
.Dl $ sndioctl record[0].source=mic[0] record[1].source=mic[1]
.Dl $ sndioctl record0.source=mic0 record1.source=mic1
.Dl $ sndioctl record.source=mic

View File

@ -24,7 +24,6 @@
#define IS_IDENT(c) (((c) >= 'a' && (c) <= 'z') || \
((c) >= 'A' && (c) <= 'Z') || \
((c) >= '0' && (c) <= '9') || \
((c) == '_'))
struct info {
@ -44,21 +43,21 @@ struct info {
int cmpdesc(struct siomix_desc *, struct siomix_desc *);
int isdiag(struct info *);
struct info *selpos(struct info *);
struct info *vecent(struct info *, char *, char *);
struct info *vecent(struct info *, char *, int);
struct info *nextgrp(struct info *);
struct info *nextpar(struct info *);
struct info *firstent(struct info *, char *);
struct info *nextent(struct info *, int);
int matchpar(struct info *, char *, char *);
int matchent(struct info *, char *, char *);
int matchpar(struct info *, char *, int);
int matchent(struct info *, char *, int);
int ismono(struct info *);
void print_chan(struct siomix_chan *, int);
void print_desc(struct info *, int);
void print_val(struct info *, int);
void print_par(struct info *, int);
void print_par(struct info *, int, char *);
int parse_name(char **, char *);
int parse_dec(char **, unsigned *);
int parse_chan(char **, char *, char *);
int parse_chan(char **, char *, int *);
int parse_modeval(char **, int *, unsigned *);
void dump(void);
int cmd(char *);
@ -69,7 +68,7 @@ void onctl(void *, unsigned, unsigned);
struct siomix_hdl *hdl;
struct info *infolist;
int n_flag = 0, i_flag = 0, v_flag = 0, m_flag = 0;
int i_flag = 0, v_flag = 0, m_flag = 0;
/*
* compare two siomix_desc structures, used to sort infolist
@ -88,7 +87,7 @@ cmpdesc(struct siomix_desc *d1, struct siomix_desc *d2)
res = strcmp(d1->func, d2->func);
if (res != 0)
return res;
res = strcmp(d1->chan0.opt, d2->chan0.opt);
res = d1->chan0.unit - d2->chan0.unit;
if (d1->type == SIOMIX_VEC ||
d1->type == SIOMIX_LIST) {
if (res != 0)
@ -96,7 +95,7 @@ cmpdesc(struct siomix_desc *d1, struct siomix_desc *d2)
res = strcmp(d1->chan1.str, d2->chan1.str);
if (res != 0)
return res;
res = strcmp(d1->chan1.opt, d2->chan1.opt);
res = d1->chan1.unit - d2->chan1.unit;
}
return res;
}
@ -107,10 +106,9 @@ cmpdesc(struct siomix_desc *d1, struct siomix_desc *d2)
int
isdiag(struct info *e)
{
if (strlen(e->desc.chan0.opt) == 0 ||
strlen(e->desc.chan1.opt) == 0)
if (e->desc.chan0.unit < 0 || e->desc.chan1.unit < 0)
return 1;
return strcmp(e->desc.chan1.opt, e->desc.chan0.opt) == 0;
return e->desc.chan1.unit == e->desc.chan0.unit;
}
/*
@ -132,11 +130,11 @@ selpos(struct info *i)
* find the selector or vector entry with the given name and channels
*/
struct info *
vecent(struct info *i, char *vstr, char *vopt)
vecent(struct info *i, char *vstr, int vunit)
{
while (i != NULL) {
if ((strcmp(i->desc.chan1.str, vstr) == 0) &&
(strlen(vopt) == 0 || strcmp(i->desc.chan1.opt, vopt) == 0))
(vunit < 0 || i->desc.chan1.unit == vunit))
break;
i = i->next;
}
@ -167,16 +165,18 @@ nextgrp(struct info *i)
struct info *
nextpar(struct info *i)
{
char *str, *opt, *func;
char *str, *func;
int unit;
func = i->desc.func;
str = i->desc.chan0.str;
opt = i->desc.chan0.opt;
unit = i->desc.chan0.unit;
for (i = i->next; i != NULL; i = i->next) {
if (strcmp(i->desc.chan0.str, str) != 0 ||
strcmp(i->desc.func, func) != 0)
break;
if (strcmp(i->desc.chan0.opt, opt) != 0)
/* XXX: need to check for -1 ? */
if (i->desc.chan0.unit != unit)
return i;
}
return NULL;
@ -213,18 +213,19 @@ firstent(struct info *g, char *vstr)
struct info *
nextent(struct info *i, int mono)
{
char *str, *opt, *func;
char *str, *func;
int unit;
func = i->desc.func;
str = i->desc.chan0.str;
opt = i->desc.chan0.opt;
unit = i->desc.chan0.unit;
for (i = i->next; i != NULL; i = i->next) {
if (strcmp(i->desc.chan0.str, str) != 0 ||
strcmp(i->desc.func, func) != 0)
return NULL;
if (mono)
return i;
if (strcmp(i->desc.chan0.opt, opt) == 0)
if (i->desc.chan0.unit == unit)
return i;
}
return NULL;
@ -234,17 +235,17 @@ nextent(struct info *i, int mono)
* return true if parameter matches the given name and channel range
*/
int
matchpar(struct info *i, char *astr, char *aopt)
matchpar(struct info *i, char *astr, int aunit)
{
if (strcmp(i->desc.chan0.str, astr) != 0)
return 0;
if (strlen(aopt) == 0)
if (aunit < 0)
return 1;
else if (strlen(i->desc.chan0.opt) == 0) {
fprintf(stderr, "opt used for parameter with no opt\n");
else if (i->desc.chan0.unit < 0) {
fprintf(stderr, "unit used for parameter with no unit\n");
exit(1);
}
return strcmp(i->desc.chan0.opt, aopt) == 0;
return i->desc.chan0.unit == aunit;
}
/*
@ -252,17 +253,17 @@ matchpar(struct info *i, char *astr, char *aopt)
* channel range
*/
int
matchent(struct info *i, char *vstr, char *vopt)
matchent(struct info *i, char *vstr, int vunit)
{
if (strcmp(i->desc.chan1.str, vstr) != 0)
return 0;
if (strlen(vopt) == 0)
if (vunit < 0)
return 1;
else if (strlen(i->desc.chan1.opt) == 0) {
fprintf(stderr, "opt used for parameter with no opt\n");
else if (i->desc.chan1.unit < 0) {
fprintf(stderr, "unit used for parameter with no unit\n");
exit(1);
}
return strcmp(i->desc.chan1.opt, vopt) == 0;
return i->desc.chan1.unit == vunit;
}
/*
@ -277,8 +278,6 @@ ismono(struct info *g)
p1 = g;
switch (g->desc.type) {
case SIOMIX_LABEL:
break;
case SIOMIX_NUM:
case SIOMIX_SW:
for (p2 = g; p2 != NULL; p2 = nextpar(p2)) {
@ -296,7 +295,7 @@ ismono(struct info *g)
} else {
e1 = vecent(p1,
e2->desc.chan1.str,
p1->desc.chan0.opt);
p1->desc.chan0.unit);
if (e1 == NULL)
continue;
if (e1->curval != e2->curval)
@ -316,8 +315,8 @@ void
print_chan(struct siomix_chan *c, int mono)
{
printf("%s", c->str);
if (!mono && strlen(c->opt) > 0) {
printf("[%s]", c->opt);
if (!mono && c->unit >= 0) {
printf("%d", c->unit);
}
}
@ -364,10 +363,6 @@ print_val(struct info *p, int mono)
int more;
switch (p->desc.type) {
case SIOMIX_LABEL:
printf("%s", p->desc.chan1.str);
//print_chan(&e->desc.chan1, mono);
break;
case SIOMIX_NUM:
case SIOMIX_SW:
printf("%u", p->curval);
@ -395,34 +390,16 @@ print_val(struct info *p, int mono)
* print ``<parameter>=<value>'' string (including '\n')
*/
void
print_par(struct info *p, int mono)
print_par(struct info *p, int mono, char *comment)
{
struct info *i;
int more;
print_chan(&p->desc.chan0, mono);
printf(".%s=", p->desc.func);
if (i_flag)
print_desc(p, mono);
else
print_val(p, mono);
/* append a comment with the labels (if any) */
if (!n_flag && p->desc.type != SIOMIX_LABEL) {
more = 0;
for (i = infolist; i != NULL; i = i->next) {
if (i->desc.type != SIOMIX_LABEL)
continue;
if (strcmp(i->desc.chan0.str, p->desc.chan0.str) == 0 &&
strcmp(i->desc.chan0.opt, p->desc.chan0.opt) == 0) {
if (!more) {
printf("\t#");
more = 1;
}
printf(" %s=%s", i->desc.func, i->desc.chan1.str);
}
}
}
print_val(p, mono);
if (comment)
printf(" # %s", comment);
printf("\n");
}
@ -436,7 +413,7 @@ parse_name(char **line, char *name)
unsigned len = 0;
if (!IS_IDENT(*p)) {
fprintf(stderr, "letter/digit expected near '%s'\n", p);
fprintf(stderr, "letter expected near '%s'\n", p);
return 0;
}
while (IS_IDENT(*p)) {
@ -483,25 +460,19 @@ parse_dec(char **line, unsigned *num)
* parse a sub-stream, eg. "spkr[4-7]"
*/
int
parse_chan(char **line, char *str, char *opt)
parse_chan(char **line, char *str, int *unit)
{
char *p = *line;
if (!parse_name(&p, str))
return 0;
if (*p != '[') {
*opt = 0;
if (*p < '0' || *p > '9') {
*unit = -1;
*line = p;
return 1;
}
p++;
if (!parse_name(&p, opt))
if (!parse_dec(&p, unit))
return 0;
if (*p != ']') {
fprintf(stderr, "']' expected near '%s'\n", p);
return 0;
}
p++;
*line = p;
return 1;
}
@ -554,9 +525,6 @@ dump(void)
printf(".%s", i->desc.func);
printf("=");
switch (i->desc.type) {
case SIOMIX_LABEL:
print_chan(&i->desc.chan1, 0);
break;
case SIOMIX_NUM:
case SIOMIX_SW:
printf("* (%u)", i->curval);
@ -579,11 +547,11 @@ cmd(char *line)
char *pos = line;
struct info *i, *e, *g;
char func[SIOMIX_NAMEMAX], astr[SIOMIX_NAMEMAX], vstr[SIOMIX_NAMEMAX];
char aopt[SIOMIX_NAMEMAX], vopt[SIOMIX_NAMEMAX];
int aunit, vunit;
unsigned val, npar = 0, nent = 0;
int comma, mode;
if (!parse_chan(&pos, astr, aopt))
if (!parse_chan(&pos, astr, &aunit))
return 0;
if (*pos != '.') {
fprintf(stderr, "'.' expected near '%s'\n", pos);
@ -621,7 +589,7 @@ cmd(char *line)
if (!parse_modeval(&pos, &mode, &val))
return 0;
for (i = g; i != NULL; i = nextpar(i)) {
if (!matchpar(i, astr, aopt))
if (!matchpar(i, astr, aunit))
continue;
i->mode = mode;
i->newval = val;
@ -631,7 +599,7 @@ cmd(char *line)
case SIOMIX_VEC:
case SIOMIX_LIST:
for (i = g; i != NULL; i = nextpar(i)) {
if (!matchpar(i, astr, aopt))
if (!matchpar(i, astr, aunit))
continue;
for (e = i; e != NULL; e = nextent(e, 0)) {
e->newval = 0;
@ -648,7 +616,7 @@ cmd(char *line)
break;
pos++;
}
if (!parse_chan(&pos, vstr, vopt))
if (!parse_chan(&pos, vstr, &vunit))
return 0;
if (*pos == ':') {
pos++;
@ -660,10 +628,10 @@ cmd(char *line)
}
nent = 0;
for (i = g; i != NULL; i = nextpar(i)) {
if (!matchpar(i, astr, aopt))
if (!matchpar(i, astr, aunit))
continue;
for (e = i; e != NULL; e = nextent(e, 0)) {
if (matchent(e, vstr, vopt)) {
if (matchent(e, vstr, vunit)) {
e->newval = val;
e->mode = mode;
nent++;
@ -671,8 +639,9 @@ cmd(char *line)
}
}
if (nent == 0) {
fprintf(stderr, "%s[%s]: invalid value\n", vstr, vopt);
print_par(g, 0);
/* XXX: use print_chan()-like routine */
fprintf(stderr, "%s[%d]: invalid value\n", vstr, vunit);
print_par(g, 0, NULL);
exit(1);
}
comma = 1;
@ -747,15 +716,15 @@ list(void)
if (i_flag) {
if (v_flag) {
for (p = g; p != NULL; p = nextpar(p))
print_par(p, 0);
print_par(p, 0, NULL);
} else
print_par(g, 1);
print_par(g, 1, NULL);
} else {
if (v_flag || !ismono(g)) {
for (p = g; p != NULL; p = nextpar(p))
print_par(p, 0);
print_par(p, 0, NULL);
} else
print_par(g, 1);
print_par(g, 1, NULL);
}
}
}
@ -774,21 +743,27 @@ ondesc(void *arg, struct siomix_desc *d, int curval)
if (d == NULL)
return;
/*
* delete control
*/
for (pi = &infolist; (i = *pi) != NULL; pi = &i->next) {
if (d->addr == i->desc.addr) {
if (m_flag)
print_par(i, 0, "deleted");
*pi = i->next;
free(i);
break;
}
}
/*
* find the right position to insert the new widget
*/
for (pi = &infolist; (i = *pi) != NULL; pi = &i->next) {
cmp = cmpdesc(d, &i->desc);
if (cmp == 0) {
/* label is updated */
if (i->desc.type == SIOMIX_LABEL) {
memcpy(i->desc.chan1.str, d->chan1.str,
SIOMIX_NAMEMAX);
print_par(i, 0);
return;
}
if (cmp == 0) {
fprintf(stderr, "fatal: duplicate mixer knob:\n");
print_par(i, 0);
print_par(i, 0, "duplicate");
exit(1);
}
if (cmp < 0)
@ -805,6 +780,8 @@ ondesc(void *arg, struct siomix_desc *d, int curval)
i->mode = MODE_IGNORE;
i->next = *pi;
*pi = i;
if (m_flag)
print_par(i, 0, "added");
}
/*
@ -815,13 +792,12 @@ onctl(void *arg, unsigned addr, unsigned val)
{
struct info *i;
if (v_flag >= 1)
fprintf(stderr, "onctl (%d, %d)\n", addr, val);
for (i = infolist; i != NULL; i = i->next) {
if (i->ctladdr != addr)
continue;
i->curval = val;
print_par(i, 0);
if (m_flag)
print_par(i, 0, "changed");
}
}
@ -834,7 +810,7 @@ main(int argc, char **argv)
struct pollfd *pfds;
int nfds, revents;
while ((c = getopt(argc, argv, "df:imnv")) != -1) {
while ((c = getopt(argc, argv, "df:imv")) != -1) {
switch (c) {
case 'd':
d_flag = 1;
@ -848,11 +824,8 @@ main(int argc, char **argv)
case 'm':
m_flag = 1;
break;
case 'n':
n_flag = 1;
break;
case 'v':
v_flag = 1;
v_flag++;
break;
default:
fprintf(stderr, "usage: sndioctl "
@ -883,11 +856,8 @@ main(int argc, char **argv)
dump();
} else {
if (argc == 0) {
for (g = infolist; g != NULL; g = nextgrp(g)) {
if (g->desc.type == SIOMIX_LABEL && !n_flag)
continue;
for (g = infolist; g != NULL; g = nextgrp(g))
g->mode = MODE_PRINT;
}
} else {
for (i = 0; i < argc; i++) {
if (!cmd(argv[i]))

View File

@ -1148,9 +1148,6 @@ dev_open(struct dev *d)
c = dev_addctl(d, CTL_NUM,
d->ctl_addr + CTLADDR_SLOT_LEVEL(i),
"prog", unit, "level", NULL, -1, d->slot[i].vol);
dev_addctl(d, CTL_LABEL,
d->ctl_addr + CTLADDR_SLOT_LABEL(i),
"prog", unit, "name", d->slot[i].name, -1, 0);
}
unit = dev_makeunit(d, "sndiod");
c = dev_addctl(d, CTL_NUM,
@ -2048,9 +2045,6 @@ ctl_log(struct ctl *c)
ctl_chan_log(&c->chan1);
log_puts(":");
log_putu(c->curval);
break;
case CTL_LABEL:
ctl_chan_log(&c->chan1);
}
log_puts(" at ");
log_putu(c->addr);
@ -2097,9 +2091,7 @@ dev_addctl(struct dev *d, int type, int addr,
strlcpy(c->func, func, CTL_NAMEMAX);
strlcpy(c->chan0.str, str0, CTL_NAMEMAX);
c->chan0.unit = unit0;
if (c->type == CTL_LABEL ||
c->type == CTL_VEC ||
c->type == CTL_LIST) {
if (c->type == CTL_VEC || c->type == CTL_LIST) {
strlcpy(c->chan1.str, str1, CTL_NAMEMAX);
c->chan1.unit = unit1;
} else
@ -2122,6 +2114,32 @@ dev_addctl(struct dev *d, int type, int addr,
return c;
}
void
dev_rmctl(struct dev *d, int addr)
{
struct ctl *c, **pc;
pc = &d->ctl_list;
for (;;) {
c = *pc;
if (c == NULL)
return;
if (c->addr == addr)
break;
pc = &c->next;
}
#ifdef DEBUG
if (log_level >= 3) {
dev_log(d);
log_puts(": removing ");
ctl_log(c);
log_puts("\n");
}
#endif
*pc = c->next;
xfree(c);
}
int
dev_setctl(struct dev *d, int addr, int val, unsigned int mask)
{
@ -2187,7 +2205,7 @@ dev_label(struct dev *d, int i)
struct ctl *c;
int addr;
addr = d->ctl_addr + CTLADDR_SLOT_LABEL(i);
addr = d->ctl_addr + CTLADDR_SLOT_LEVEL(i);
c = d->ctl_list;
for (;;) {
if (c == NULL)
@ -2196,9 +2214,9 @@ dev_label(struct dev *d, int i)
break;
c = c->next;
}
if (strcmp(c->chan1.str, d->slot[i].name) == 0)
return;
strlcpy(c->chan1.str, d->slot[i].name, CTL_NAMEMAX);
if (strcmp(c->chan0.str, d->slot[i].name) == 0 && c->chan0.unit == i)
return;
strlcpy(c->chan0.str, d->slot[i].name, CTL_NAMEMAX);
c->desc_mask = ~0;
}

View File

@ -23,8 +23,7 @@
#include "dev_siomix.h"
#define CTLADDR_SLOT_LEVEL(n) (n)
#define CTLADDR_SLOT_LABEL(n) (DEV_NSLOT + n)
#define CTLADDR_MASTER (DEV_NSLOT + DEV_NSLOT)
#define CTLADDR_MASTER (DEV_NSLOT)
/*
* audio stream state structure
@ -110,7 +109,6 @@ struct ctl {
#define CTL_SW 3 /* on/off switch, only bit 7 counts */
#define CTL_VEC 4 /* number, element of vector */
#define CTL_LIST 5 /* switch, element of a list */
#define CTL_LABEL 6 /* attach string to stream */
unsigned int type; /* one of above */
unsigned int addr; /* control address */
#define CTL_NAMEMAX 16 /* max name lenght */
@ -290,5 +288,6 @@ int dev_nctl(struct dev *);
void dev_label(struct dev *, int);
struct ctl *dev_addctl(struct dev *, int, int,
char *, int, char *, char *, int, int);
void dev_rmctl(struct dev *, int);
#endif /* !defined(DEV_H) */

View File

@ -52,24 +52,14 @@ void
dev_siomix_ondesc(void *arg, struct siomix_desc *desc, int val)
{
struct dev *d = arg;
struct ctl *c;
if (desc == NULL)
return;
for (c = d->ctl_list; c != NULL; c = c->next) {
if (c->addr != desc->addr)
continue;
if (c->type != SIOMIX_LABEL)
continue;
ctl_log(c);
log_puts(": label -> ");
log_puts(desc->chan0.str);
log_puts("\n");
strlcpy(c->chan0.str, desc->chan0.str, CTL_NAMEMAX);
c->desc_mask = ~0;
return;
}
/*
* XXX: can't we just replace the contents ?
*/
dev_rmctl(d, desc->addr);
dev_addctl(d, desc->type, desc->addr,
desc->chan0.str, desc->chan0.unit, desc->func,
desc->chan1.str, desc->chan1.unit, val);