-/* $OpenBSD: amsg.h,v 1.13 2020/02/26 13:53:58 ratchov Exp $ */
+/* $OpenBSD: amsg.h,v 1.14 2021/11/01 14:43:24 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
uint16_t mode; /* bitmap of MODE_XXX */
#define AMSG_VERSION 7
uint8_t version; /* protocol version */
+#define AMSG_NODEV 255
uint8_t devnum; /* device number */
uint32_t id; /* client id */
#define AMSG_OPTMAX 12
-/* $OpenBSD: aucat.c,v 1.77 2019/07/12 06:30:55 ratchov Exp $ */
+/* $OpenBSD: aucat.c,v 1.78 2021/11/01 14:43:24 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
DPRINTF("%s: '/' expected\n", str);
return 0;
}
- p = _sndio_parsenum(++p, &devnum, 15);
- if (p == NULL)
- return 0;
- if (*p == '.') {
- p = parsestr(++p, opt, AMSG_OPTMAX);
+ p++;
+ if (type == 0) {
+ devnum = AMSG_NODEV;
+ p = parsestr(p, opt, AMSG_OPTMAX);
if (p == NULL)
return 0;
- } else
- strlcpy(opt, "default", AMSG_OPTMAX);
+ } else {
+ p = _sndio_parsenum(p, &devnum, 15);
+ if (p == NULL)
+ return 0;
+ memset(opt, 0, sizeof(opt));
+ }
if (*p != '\0') {
DPRINTF("%s: junk at end of dev name\n", p);
return 0;
-/* $OpenBSD: sio.c,v 1.25 2020/11/19 08:14:19 ratchov Exp $ */
+/* $OpenBSD: sio.c,v 1.26 2021/11/01 14:43:24 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
str = devany;
}
if (strcmp(str, devany) == 0) {
- hdl = _sio_aucat_open("snd/0", mode, nbio);
+ hdl = _sio_aucat_open("snd/default", mode, nbio);
if (hdl != NULL)
return hdl;
return _sio_sun_open("rsnd/0", mode, nbio);
-/* $OpenBSD: sioctl.c,v 1.1 2020/02/26 13:53:58 ratchov Exp $ */
+/* $OpenBSD: sioctl.c,v 1.2 2021/11/01 14:43:24 ratchov Exp $ */
/*
* Copyright (c) 2014-2020 Alexandre Ratchov <alex@caoua.org>
*
str = devany;
}
if (strcmp(str, devany) == 0) {
- hdl = _sioctl_aucat_open("snd/0", mode, nbio);
+ hdl = _sioctl_aucat_open("snd/default", mode, nbio);
if (hdl != NULL)
return hdl;
return _sioctl_sun_open("rsnd/0", mode, nbio);
-.\" $OpenBSD: sndio.7,v 1.26 2020/11/20 12:13:11 schwarze Exp $
+.\" $OpenBSD: sndio.7,v 1.27 2021/11/01 14:43:24 ratchov Exp $
.\"
.\" Copyright (c) 2007 Alexandre Ratchov <alex@caoua.org>
.\"
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: November 20 2020 $
+.Dd $Mdocdate: November 1 2021 $
.Dt SNDIO 7
.Os
.Sh NAME
.Xr sndiod 8
has a descriptor of the form:
.Bd -literal -offset center
-type[@hostname][,servnum]/devnum[.option]
+type[@hostname][,servnum]/[devnum|option]
.Ed
.Pp
This information is used by programs to determine
.Ev AUDIORECDEVICE
environment variables.
If they are not set, the program first tries to connect to
-.Li snd/0 .
+.Li snd/default .
If that fails, it then tries to use
.Li rsnd/0 .
.Pp
Raw MIDI ports.
.El
.Sh EXAMPLES
-.Bl -tag -width "snd/0.rear" -compact
+.Bl -tag -width "midithru/0" -compact
.It Li snd/0
Audio device referred to by the first
.Fl f
option of
.Xr sndiod 8 .
-.It Li snd/0.rear
+.It Li snd/rear
Sub-device registered with
.Dq -s rear .
.It Li midithru/0
-/* $OpenBSD: dev.c,v 1.102 2021/05/03 04:29:50 ratchov Exp $ */
+/* $OpenBSD: dev.c,v 1.103 2021/11/01 14:43:24 ratchov Exp $ */
/*
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
*
unsigned int, unsigned int, unsigned int, unsigned int);
void dev_adjpar(struct dev *, int, int, int);
int dev_allocbufs(struct dev *);
-int dev_open(struct dev *);
void dev_freebufs(struct dev *);
-void dev_close(struct dev *);
int dev_ref(struct dev *);
void dev_unref(struct dev *);
int dev_init(struct dev *);
void dev_done(struct dev *);
struct dev *dev_bynum(int);
void dev_del(struct dev *);
-void dev_setalt(struct dev *, unsigned int);
unsigned int dev_roundof(struct dev *, unsigned int);
void dev_wakeup(struct dev *);
return NULL;
}
d = xmalloc(sizeof(struct dev));
- d->alt_list = NULL;
- dev_addname(d,path);
+ d->path = path;
d->num = dev_sndnum++;
- d->alt_num = -1;
d->reqpar = *par;
d->reqmode = mode;
d->slot_list = NULL;
d->master = MIDI_MAXCTL;
d->master_enabled = 0;
+ d->alt_next = d;
snprintf(d->name, CTL_NAMEMAX, "%u", d->num);
for (pd = &dev_list; *pd != NULL; pd = &(*pd)->next)
;
return d;
}
-/*
- * add a alternate name
- */
-int
-dev_addname(struct dev *d, char *name)
-{
- struct dev_alt *a;
-
- if (d->alt_list != NULL && d->alt_list->idx == DEV_NMAX - 1) {
- log_puts(name);
- log_puts(": too many alternate names\n");
- return 0;
- }
- a = xmalloc(sizeof(struct dev_alt));
- a->name = name;
- a->idx = (d->alt_list == NULL) ? 0 : d->alt_list->idx + 1;
- a->next = d->alt_list;
- d->alt_list = a;
- return 1;
-}
-
-/*
- * set prefered alt device name
- */
-void
-dev_setalt(struct dev *d, unsigned int idx)
-{
- struct dev_alt **pa, *a;
-
- /* find alt with given index */
- for (pa = &d->alt_list; (a = *pa)->idx != idx; pa = &a->next)
- ;
-
- /* detach from list */
- *pa = a->next;
-
- /* attach at head */
- a->next = d->alt_list;
- d->alt_list = a;
-
- /* reopen device with the new alt */
- if (idx != d->alt_num)
- dev_reopen(d);
-}
-
/*
* adjust device parameters and mode
*/
int
dev_open(struct dev *d)
{
- char name[CTL_NAMEMAX];
- struct dev_alt *a;
-
d->mode = d->reqmode;
d->round = d->reqround;
d->bufsz = d->reqbufsz;
if (!dev_allocbufs(d))
return 0;
- /* if there are multiple alt devs, add server.device knob */
- if (d->alt_list->next != NULL) {
- for (a = d->alt_list; a != NULL; a = a->next) {
- snprintf(name, sizeof(name), "%d", a->idx);
- ctl_new(CTL_DEV_ALT, d, &a->idx,
- CTL_SEL, d->name, "server", -1, "device",
- name, -1, 1, a->idx == d->alt_num);
- }
- }
-
d->pstate = DEV_INIT;
return 1;
}
}
d->slot_list = NULL;
- for (c = ctlslot_array, i = 0; i < DEV_NCTLSLOT; i++, c++) {
- if (c->ops == NULL)
- continue;
- if (c->opt->dev != d)
- continue;
- c->ops->exit(c->arg);
- c->ops = NULL;
- }
-
for (o = opt_list; o != NULL; o = o->next) {
if (o->dev != d)
continue;
+ for (c = ctlslot_array, i = 0; i < DEV_NCTLSLOT; i++, c++) {
+ if (c->ops == NULL)
+ continue;
+ if (c->opt == o) {
+ c->ops->exit(s->arg);
+ c->ops = NULL;
+ }
+ }
+
midi_abort(o->midi);
}
void
dev_close(struct dev *d)
{
- struct dev_alt *a;
- unsigned int idx;
-
d->pstate = DEV_CFG;
dev_sio_close(d);
dev_freebufs(d);
d->master_enabled = 0;
ctl_del(CTL_DEV_MASTER, d, NULL);
}
- for (idx = 0, a = d->alt_list; a != NULL; idx++, a = a->next)
- ctl_del(CTL_DEV_ALT, d, &idx);
-}
-
-/*
- * Close the device, but attempt to migrate everything to a new sndio
- * device.
- */
-int
-dev_reopen(struct dev *d)
-{
- struct mtc *mtc;
- struct slot *s;
- long long pos;
- unsigned int pstate;
- int delta;
-
- /* not opened */
- if (d->pstate == DEV_CFG)
- return 1;
-
- /* save state */
- delta = d->delta;
- pstate = d->pstate;
-
- if (!dev_sio_reopen(d))
- return 0;
-
- /* reopen returns a stopped device */
- d->pstate = DEV_INIT;
-
- /* reallocate new buffers, with new parameters */
- dev_freebufs(d);
- dev_allocbufs(d);
-
- /*
- * adjust time positions, make anything go back delta ticks, so
- * that the new device can start at zero
- */
- for (s = d->slot_list; s != NULL; s = s->next) {
- pos = (long long)s->delta * d->round + s->delta_rem;
- pos -= (long long)delta * s->round;
- s->delta_rem = pos % (int)d->round;
- s->delta = pos / (int)d->round;
- if (log_level >= 3) {
- slot_log(s);
- log_puts(": adjusted: delta -> ");
- log_puti(s->delta);
- log_puts(", delta_rem -> ");
- log_puti(s->delta_rem);
- log_puts("\n");
- }
-
- /* reinitilize the format conversion chain */
- slot_initconv(s);
- }
- mtc = &mtc_array[0];
- if (mtc->dev == d && mtc->tstate == MTC_RUN) {
- mtc->delta -= delta * MTC_SEC;
- if (log_level >= 2) {
- dev_log(mtc->dev);
- log_puts(": adjusted mtc: delta ->");
- log_puti(mtc->delta);
- log_puts("\n");
- }
- }
-
- /* remove old controls and add new ones */
- dev_sioctl_close(d);
- dev_sioctl_open(d);
-
- /* start the device if needed */
- if (pstate == DEV_RUN)
- dev_wakeup(d);
-
- return 1;
}
int
dev_del(struct dev *d)
{
struct dev **p;
- struct dev_alt *a;
#ifdef DEBUG
if (log_level >= 3) {
#endif
}
*p = d->next;
- while ((a = d->alt_list) != NULL) {
- d->alt_list = a->next;
- xfree(a);
- }
xfree(d);
}
}
}
+/*
+ * Return true if both of the given devices can run the same
+ * clients
+ */
+int
+dev_iscompat(struct dev *o, struct dev *n)
+{
+ if (((long long)o->round * n->rate != (long long)n->round * o->rate) ||
+ ((long long)o->bufsz * n->rate != (long long)n->bufsz * o->rate)) {
+ if (log_level >= 1) {
+ log_puts(n->name);
+ log_puts(": not compatible with ");
+ log_puts(o->name);
+ log_puts("\n");
+ }
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Close the device, but attempt to migrate everything to a new sndio
+ * device.
+ */
+struct dev *
+dev_migrate(struct dev *odev)
+{
+ struct dev *ndev;
+ struct opt *o;
+ struct slot *s;
+ int i;
+
+ /* not opened */
+ if (odev->pstate == DEV_CFG)
+ return odev;
+
+ ndev = odev;
+ while (1) {
+ /* try next one, circulating through the list */
+ ndev = ndev->alt_next;
+ if (ndev == odev) {
+ if (log_level >= 1) {
+ dev_log(odev);
+ log_puts(": no fall-back device found\n");
+ }
+ return NULL;
+ }
+
+
+ if (!dev_ref(ndev))
+ continue;
+
+ /* check if new parameters are compatible with old ones */
+ if (!dev_iscompat(odev, ndev)) {
+ dev_unref(ndev);
+ continue;
+ }
+
+ /* found it!*/
+ break;
+ }
+
+ if (log_level >= 1) {
+ dev_log(odev);
+ log_puts(": switching to ");
+ dev_log(ndev);
+ log_puts("\n");
+ }
+
+ if (mtc_array[0].dev == odev)
+ mtc_setdev(&mtc_array[0], ndev);
+
+ /* move opts to new device (also moves clients using the opts) */
+ for (o = opt_list; o != NULL; o = o->next) {
+ if (o->dev != odev)
+ continue;
+ if (strcmp(o->name, o->dev->name) == 0)
+ continue;
+ opt_setdev(o, ndev);
+ }
+
+ /* terminate remaining clients */
+ for (i = 0, s = slot_array; i < DEV_NSLOT; i++, s++) {
+ if (s->opt == NULL || s->opt->dev != odev)
+ continue;
+ if (s->ops != NULL) {
+ s->ops->exit(s);
+ s->ops = NULL;
+ }
+ }
+
+ /* slots and/or MMC hold refs, drop ours */
+ dev_unref(ndev);
+
+ return ndev;
+}
+
/*
* check that all clients controlled by MMC are ready to start, if so,
* attach them all at the same position
mtc_start(mtc);
}
+/*
+ * set MMC device
+ */
+void
+mtc_setdev(struct mtc *mtc, struct dev *d)
+{
+ struct opt *o;
+
+ if (mtc->dev == d)
+ return;
+
+ if (log_level >= 2) {
+ dev_log(d);
+ log_puts(": set to be MIDI clock source\n");
+ }
+
+ /* adjust clock and ref counter, if needed */
+ if (mtc->tstate == MTC_RUN) {
+ mtc->delta -= mtc->dev->delta;
+ dev_unref(mtc->dev);
+ }
+
+ mtc->dev = d;
+
+ if (mtc->tstate == MTC_RUN) {
+ mtc->delta += mtc->dev->delta;
+ dev_ref(mtc->dev);
+ dev_wakeup(mtc->dev);
+ }
+
+ /* move in once anything using MMC */
+ for (o = opt_list; o != NULL; o = o->next) {
+ if (o->mtc == mtc)
+ opt_setdev(o, mtc->dev);
+ }
+}
+
/*
* allocate buffers & conversion chain
*/
NULL, -1, 127, s->vol);
found:
- if (!dev_ref(opt->dev))
+ /* open device, this may change opt's device */
+ if (!opt_ref(s->opt))
return NULL;
s->opt = opt;
s->ops = ops;
if (log_level >= 3) {
slot_log(s);
log_puts(": using ");
- dev_log(s->opt->dev);
- log_puts(".");
log_puts(s->opt->name);
log_puts(", mode = ");
log_putx(mode);
slot_stop(s, 0);
break;
}
- dev_unref(s->opt->dev);
+ opt_unref(s->opt);
}
/*
s->mix.vol = MIDI_TO_ADATA(s->vol);
}
+/*
+ * set device for this slot
+ */
+void
+slot_setopt(struct slot *s, struct opt *o)
+{
+ struct opt *t;
+ struct dev *odev, *ndev;
+ struct ctl *c;
+
+ if (s->opt == NULL || s->opt == o)
+ return;
+
+ if (log_level >= 2) {
+ slot_log(s);
+ log_puts(": moving to opt ");
+ log_puts(o->name);
+ log_puts("\n");
+ }
+
+ odev = s->opt->dev;
+ if (s->ops != NULL) {
+ ndev = opt_ref(o);
+ if (ndev == NULL)
+ return;
+
+ if (!dev_iscompat(odev, ndev)) {
+ opt_unref(o);
+ return;
+ }
+ }
+
+ if (s->pstate == SLOT_RUN || s->pstate == SLOT_STOP)
+ slot_detach(s);
+
+ t = s->opt;
+ s->opt = o;
+
+ c = ctl_find(CTL_SLOT_LEVEL, s, NULL);
+ ctl_update(c);
+
+ if (o->dev != t->dev) {
+ dev_midi_slotdesc(odev, s);
+ dev_midi_slotdesc(ndev, s);
+ dev_midi_vol(ndev, s);
+ }
+
+ if (s->pstate == SLOT_RUN || s->pstate == SLOT_STOP)
+ slot_attach(s);
+
+ if (s->ops != NULL) {
+ opt_unref(t);
+ return;
+ }
+}
+
/*
* attach the slot to the device (ie start playing & recording
*/
}
s->opt = o;
s->self = 1 << i;
- if (!dev_ref(o->dev))
+ if (!opt_ref(o))
return NULL;
s->ops = ops;
s->arg = arg;
pc = &c->next;
}
s->ops = NULL;
- dev_unref(s->opt->dev);
+ opt_unref(s->opt);
}
int
switch (c->scope) {
case CTL_HW:
case CTL_DEV_MASTER:
- case CTL_DEV_ALT:
return (s->opt->dev == c->u.any.arg0);
+ case CTL_OPT_DEV:
+ return (s->opt == c->u.any.arg0);
case CTL_SLOT_LEVEL:
return (s->opt->dev == c->u.slot_level.slot->opt->dev);
default:
return c;
}
+void
+ctlslot_update(struct ctlslot *s)
+{
+ struct ctl *c;
+ unsigned int refs_mask;
+
+ for (c = ctl_list; c != NULL; c = c->next) {
+ if (c->type == CTL_NONE)
+ continue;
+ refs_mask = ctlslot_visible(s, c) ? s->self : 0;
+
+ /* nothing to do if no visibility change */
+ if (((c->refs_mask & s->self) ^ refs_mask) == 0)
+ continue;
+ /* if control becomes visble */
+ if (refs_mask)
+ c->refs_mask |= s->self;
+ /* if control is hidden */
+ c->desc_mask |= s->self;
+ }
+}
+
void
ctl_node_log(struct ctl_node *c)
{
log_puts("dev_master:");
log_puts(c->u.dev_master.dev->name);
break;
- case CTL_DEV_ALT:
- log_puts("dev_alt:");
- log_puts(c->u.dev_alt.dev->name);
- log_putu(c->u.dev_alt.idx);
- break;
case CTL_SLOT_LEVEL:
log_puts("slot_level:");
log_puts(c->u.slot_level.slot->name);
log_putu(c->u.slot_level.slot->unit);
break;
+ case CTL_OPT_DEV:
+ log_puts("opt_dev:");
+ log_puts(c->u.opt_dev.opt->name);
+ log_puts("/");
+ log_puts(c->u.opt_dev.dev->name);
+ break;
default:
log_puts("unknown");
}
c->val_mask = ~0U;
c->curval = val;
return 1;
- case CTL_DEV_ALT:
- dev_setalt (c->u.dev_alt.dev, c->u.dev_alt.idx);
- return 1;
case CTL_SLOT_LEVEL:
slot_setvol(c->u.slot_level.slot, val);
// XXX change dev_midi_vol() into slot_midi_vol()
c->val_mask = ~0U;
c->curval = val;
return 1;
+ case CTL_OPT_DEV:
+ c->u.opt_dev.opt->alt_first = c->u.opt_dev.dev;
+ opt_setdev(c->u.opt_dev.opt, c->u.opt_dev.dev);
+ return 1;
default:
if (log_level >= 2) {
ctl_log(c);
case CTL_HW:
c->u.hw.addr = *(unsigned int *)arg1;
break;
- case CTL_DEV_ALT:
- c->u.dev_alt.idx = *(unsigned int *)arg1;
+ case CTL_OPT_DEV:
+ c->u.any.arg1 = arg1;
break;
default:
c->u.any.arg1 = NULL;
if (arg1 != NULL && c->u.hw.addr != *(unsigned int *)arg1)
return 0;
break;
- case CTL_DEV_ALT:
- if (arg1 != NULL && c->u.dev_alt.idx != *(unsigned int *)arg1)
+ case CTL_OPT_DEV:
+ if (arg1 != NULL && c->u.any.arg1 != arg1)
return 0;
break;
}
s->ops->sync(s->arg);
}
}
-
-/* $OpenBSD: dev.h,v 1.40 2021/03/03 10:19:06 ratchov Exp $ */
+/* $OpenBSD: dev.h,v 1.41 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
*
#define CTL_HW 0
#define CTL_DEV_MASTER 1
-#define CTL_DEV_ALT 2
+#define CTL_OPT_DEV 2
#define CTL_SLOT_LEVEL 3
unsigned int scope;
union {
struct {
struct dev *dev;
} dev_master;
- struct {
- struct dev *dev;
- unsigned int idx;
- } dev_alt;
struct {
struct slot *slot;
} slot_level;
+ struct {
+ struct slot *slot;
+ struct opt *opt;
+ } slot_opt;
+ struct {
+ struct opt *opt;
+ struct dev *dev;
+ } opt_dev;
} u;
unsigned int addr; /* slot side control address */
*/
char name[CTL_NAMEMAX];
+ /*
+ * next to try if this fails
+ */
+ struct dev *alt_next;
+
/*
* audio device (while opened)
*/
#define DEV_INIT 1 /* stopped */
#define DEV_RUN 2 /* playin & recording */
unsigned int pstate; /* one of above */
- struct dev_alt {
- struct dev_alt *next;
- char *name;
- unsigned int idx;
- } *alt_list;
- int alt_num;
+ char *path;
/*
* actual parameters and runtime state (i.e. once opened)
void slot_array_init(void);
void dev_log(struct dev *);
+int dev_open(struct dev *);
+void dev_close(struct dev *);
void dev_abort(struct dev *);
-int dev_reopen(struct dev *);
+struct dev *dev_migrate(struct dev *);
struct dev *dev_new(char *, struct aparams *, unsigned int, unsigned int,
unsigned int, unsigned int, unsigned int, unsigned int);
struct dev *dev_bynum(int);
-int dev_addname(struct dev *, char *);
void dev_del(struct dev *);
void dev_adjpar(struct dev *, int, int, int);
int dev_init(struct dev *);
void dev_unref(struct dev *);
int dev_getpos(struct dev *);
unsigned int dev_roundof(struct dev *, unsigned int);
+int dev_iscompat(struct dev *, struct dev *);
/*
* interface to hardware device
struct slotops *, void *, int);
void slot_del(struct slot *);
void slot_setvol(struct slot *, unsigned int);
+void slot_setopt(struct slot *, struct opt *);
void slot_start(struct slot *);
void slot_stop(struct slot *, int);
void slot_read(struct slot *);
void ctlslot_del(struct ctlslot *);
int ctlslot_visible(struct ctlslot *, struct ctl *);
struct ctl *ctlslot_lookup(struct ctlslot *, int);
+void ctlslot_update(struct ctlslot *);
+
void dev_label(struct dev *, int);
void dev_ctlsync(struct dev *);
-/* $OpenBSD: fdpass.c,v 1.10 2020/06/18 05:11:13 ratchov Exp $ */
+/* $OpenBSD: fdpass.c,v 1.11 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2015 Alexandre Ratchov <alex@caoua.org>
*
#define FDPASS_RETURN 3 /* return after above commands */
unsigned int cmd; /* one of above */
unsigned int num; /* audio device or midi port number */
- unsigned int idx; /* index in the path list */
unsigned int mode; /* SIO_PLAY, SIO_REC, MIO_IN, ... */
};
}
static int
-fdpass_send(struct fdpass *f, int cmd, int num, int idx, int mode, int fd)
+fdpass_send(struct fdpass *f, int cmd, int num, int mode, int fd)
{
struct fdpass_msg data;
struct msghdr msg;
data.cmd = cmd;
data.num = num;
- data.idx = idx;
data.mode = mode;
iov.iov_base = &data;
iov.iov_len = sizeof(struct fdpass_msg);
log_puti(cmd);
log_puts(", num = ");
log_puti(num);
- log_puts(", idx = ");
- log_puti(idx);
log_puts(", mode = ");
log_puti(mode);
log_puts(", fd = ");
}
static int
-fdpass_recv(struct fdpass *f, int *cmd, int *num, int *idx, int *mode, int *fd)
+fdpass_recv(struct fdpass *f, int *cmd, int *num, int *mode, int *fd)
{
struct fdpass_msg data;
struct msghdr msg;
}
*cmd = data.cmd;
*num = data.num;
- *idx = data.idx;
*mode = data.mode;
#ifdef DEBUG
if (log_level >= 3) {
log_puti(*cmd);
log_puts(", num = ");
log_puti(*num);
- log_puts(", idx = ");
- log_puti(*idx);
log_puts(", mode = ");
log_puti(*mode);
log_puts(", fd = ");
{
int cmd, unused;
- if (!fdpass_recv(fdpass_peer, &cmd, &unused, &unused, &unused, retfd))
+ if (!fdpass_recv(fdpass_peer, &cmd, &unused, &unused, retfd))
return 0;
if (cmd != FDPASS_RETURN) {
if (log_level >= 1) {
}
struct sio_hdl *
-fdpass_sio_open(int num, int idx, unsigned int mode)
+fdpass_sio_open(int num, unsigned int mode)
{
int fd;
if (fdpass_peer == NULL)
return NULL;
- if (!fdpass_send(fdpass_peer, FDPASS_OPEN_SND, num, idx, mode, -1))
+ if (!fdpass_send(fdpass_peer, FDPASS_OPEN_SND, num, mode, -1))
return NULL;
if (!fdpass_waitret(fdpass_peer, &fd))
return NULL;
}
struct mio_hdl *
-fdpass_mio_open(int num, int idx, unsigned int mode)
+fdpass_mio_open(int num, unsigned int mode)
{
int fd;
if (fdpass_peer == NULL)
return NULL;
- if (!fdpass_send(fdpass_peer, FDPASS_OPEN_MIDI, num, idx, mode, -1))
+ if (!fdpass_send(fdpass_peer, FDPASS_OPEN_MIDI, num, mode, -1))
return NULL;
if (!fdpass_waitret(fdpass_peer, &fd))
return NULL;
}
struct sioctl_hdl *
-fdpass_sioctl_open(int num, int idx, unsigned int mode)
+fdpass_sioctl_open(int num, unsigned int mode)
{
int fd;
if (fdpass_peer == NULL)
return NULL;
- if (!fdpass_send(fdpass_peer, FDPASS_OPEN_CTL, num, idx, mode, -1))
+ if (!fdpass_send(fdpass_peer, FDPASS_OPEN_CTL, num, mode, -1))
return NULL;
if (!fdpass_waitret(fdpass_peer, &fd))
return NULL;
void
fdpass_in_helper(void *arg)
{
- int cmd, num, idx, mode, fd;
+ int cmd, num, mode, fd;
struct fdpass *f = arg;
struct dev *d;
- struct dev_alt *da;
struct port *p;
- char *path;
- if (!fdpass_recv(f, &cmd, &num, &idx, &mode, &fd))
+ if (!fdpass_recv(f, &cmd, &num, &mode, &fd))
return;
switch (cmd) {
case FDPASS_OPEN_SND:
fdpass_close(f);
return;
}
- for (da = d->alt_list; ; da = da->next) {
- if (da == NULL) {
- fdpass_close(f);
- return;
- }
- if (da->idx == idx)
- break;
- }
- fd = sio_sun_getfd(da->name, mode, 1);
+ fd = sio_sun_getfd(d->path, mode, 1);
break;
case FDPASS_OPEN_MIDI:
p = port_bynum(num);
fdpass_close(f);
return;
}
- path = namelist_byindex(&p->path_list, idx);
- if (path == NULL) {
- fdpass_close(f);
- return;
- }
- fd = mio_rmidi_getfd(path, mode, 1);
+ fd = mio_rmidi_getfd(p->path, mode, 1);
break;
case FDPASS_OPEN_CTL:
d = dev_bynum(num);
fdpass_close(f);
return;
}
- for (da = d->alt_list; ; da = da->next) {
- if (da == NULL) {
- fdpass_close(f);
- return;
- }
- if (da->idx == idx)
- break;
- }
- fd = sioctl_sun_getfd(da->name, mode, 1);
+ fd = sioctl_sun_getfd(d->path, mode, 1);
break;
default:
fdpass_close(f);
return;
}
- fdpass_send(f, FDPASS_RETURN, 0, 0, 0, fd);
+ fdpass_send(f, FDPASS_RETURN, 0, 0, fd);
}
void
-/* $OpenBSD: fdpass.h,v 1.3 2020/02/26 13:53:58 ratchov Exp $ */
+/* $OpenBSD: fdpass.h,v 1.4 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2015 Alexandre Ratchov <alex@caoua.org>
*
extern struct fileops worker_fileops, helper_fileops;
extern struct fdpass *fdpass_peer;
-struct sio_hdl *fdpass_sio_open(int, int, unsigned int);
-struct mio_hdl *fdpass_mio_open(int, int, unsigned int);
-struct sioctl_hdl *fdpass_sioctl_open(int, int, unsigned int);
+struct sio_hdl *fdpass_sio_open(int, unsigned int);
+struct mio_hdl *fdpass_mio_open(int, unsigned int);
+struct sioctl_hdl *fdpass_sioctl_open(int, unsigned int);
#endif /* !defined(FDPASS_H) */
-/* $OpenBSD: midi.c,v 1.28 2021/03/08 09:42:50 ratchov Exp $ */
+/* $OpenBSD: midi.c,v 1.29 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
*
}
}
+/*
+ * connect to "nep" all endpoints currently connected to "oep"
+ */
+void
+midi_migrate(struct midi *oep, struct midi *nep)
+{
+ struct midithru *t;
+ struct midi *ep;
+ int i;
+
+ for (i = 0; i < MIDITHRU_NMAX; i++) {
+ t = midithru + i;
+ if (t->txmask & oep->self) {
+ t->txmask &= ~oep->self;
+ t->txmask |= nep->self;
+ }
+ if (t->rxmask & oep->self) {
+ t->rxmask &= ~oep->self;
+ t->rxmask |= nep->self;
+ }
+ }
+
+ for (i = 0; i < MIDI_NEP; i++) {
+ ep = midi_ep + i;
+ if (ep->txmask & oep->self) {
+ ep->txmask &= ~oep->self;
+ ep->txmask |= nep->self;
+ }
+ }
+
+ for (i = 0; i < MIDI_NEP; i++) {
+ ep = midi_ep + i;
+ if (oep->txmask & ep->self) {
+ oep->txmask &= ~ep->self;
+ nep->txmask |= ep->self;
+ }
+ }
+}
+
void
port_log(struct port *p)
{
struct port *
port_new(char *path, unsigned int mode, int hold)
{
- struct port *c, **pc;
+ struct port *c;
c = xmalloc(sizeof(struct port));
- c->path_list = NULL;
- namelist_add(&c->path_list, path);
+ c->path = path;
c->state = PORT_CFG;
c->hold = hold;
c->midi = midi_new(&port_midiops, c, mode);
c->num = midi_portnum++;
- for (pc = &port_list; *pc != NULL; pc = &(*pc)->next)
- ;
- c->next = *pc;
- *pc = c;
+ c->alt_next = c;
+ c->next = port_list;
+ port_list = c;
return c;
}
#endif
}
*p = c->next;
- namelist_clear(&c->path_list);
xfree(c);
}
port_drain(c);
}
+struct port *
+port_alt_ref(int num)
+{
+ struct port *a, *p;
+
+ a = port_bynum(num);
+ if (a == NULL)
+ return NULL;
+
+ /* circulate to first alt port */
+ while (a->alt_next->num > a->num)
+ a = a->alt_next;
+
+ p = a;
+ while (1) {
+ if (port_ref(p))
+ break;
+ p = p->alt_next;
+ if (p == a)
+ return NULL;
+ }
+
+ return p;
+}
+
+struct port *
+port_migrate(struct port *op)
+{
+ struct port *np;
+
+ /* not opened */
+ if (op->state == PORT_CFG)
+ return op;
+
+ np = op;
+ while (1) {
+ /* try next one, circulating through the list */
+ np = np->alt_next;
+ if (np == op) {
+ if (log_level >= 2) {
+ port_log(op);
+ log_puts(": no fall-back port found\n");
+ }
+ return op;
+ }
+
+ if (port_ref(np))
+ break;
+ }
+
+ if (log_level >= 2) {
+ port_log(op);
+ log_puts(": switching to ");
+ port_log(np);
+ log_puts("\n");
+ }
+
+ midi_migrate(op->midi, np->midi);
+ return np;
+}
+
struct port *
port_bynum(int num)
{
panic();
}
#endif
+ port_log(c);
+ log_puts(": closed\n");
c->state = PORT_CFG;
port_mio_close(c);
return 1;
if (c->state == PORT_INIT)
port_drain(c);
}
-
-int
-port_reopen(struct port *p)
-{
- if (p->state == PORT_CFG)
- return 1;
-
- if (!port_mio_reopen(p))
- return 0;
-
- return 1;
-}
-/* $OpenBSD: midi.h,v 1.14 2021/01/28 11:17:58 ratchov Exp $ */
+/* $OpenBSD: midi.h,v 1.15 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
*
#define PORT_DRAIN 2
unsigned int state;
unsigned int num; /* port serial number */
- struct name *path_list;
+ char *path;
+ struct port *alt_next;
int hold; /* hold the port open ? */
struct midi *midi;
};
unsigned int midi_tags(struct midi *);
void midi_link(struct midi *, struct midi *);
void midi_abort(struct midi *);
+void midi_migrate(struct midi *, struct midi *);
void port_log(struct port *);
struct port *port_new(char *, unsigned int, int);
void port_done(struct port *);
void port_drain(struct port *);
int port_close(struct port *);
-int port_reopen(struct port *);
+struct port *port_alt_ref(int);
+struct port *port_migrate(struct port *);
#endif /* !defined(MIDI_H) */
-/* $OpenBSD: miofile.c,v 1.8 2021/01/28 11:17:58 ratchov Exp $ */
+/* $OpenBSD: miofile.c,v 1.9 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
*
port_mio_hup
};
-/*
- * open the port using one of the provided paths
- */
-static struct mio_hdl *
-port_mio_openlist(struct port *c, unsigned int mode)
-{
- struct mio_hdl *hdl;
- struct name *n;
- int idx;
-
- idx = 0;
- n = c->path_list;
- while (1) {
- if (n == NULL)
- break;
- hdl = fdpass_mio_open(c->num, idx, mode);
- if (hdl != NULL) {
- if (log_level >= 2) {
- port_log(c);
- log_puts(": using ");
- log_puts(n->str);
- log_puts("\n");
- }
- return hdl;
- }
- n = n->next;
- idx++;
- }
- return NULL;
-}
-
int
port_mio_open(struct port *p)
{
- p->mio.hdl = port_mio_openlist(p, p->midi->mode);
+ p->mio.hdl = fdpass_mio_open(p->num, p->midi->mode);
if (p->mio.hdl == NULL)
return 0;
p->mio.file = file_new(&port_mio_ops, p, "port", mio_nfds(p->mio.hdl));
return 1;
}
-/*
- * Open an alternate port. Upon success, close the old port
- * and continue using the new one.
- */
-int
-port_mio_reopen(struct port *p)
-{
- struct mio_hdl *hdl;
-
- hdl = port_mio_openlist(p, p->midi->mode);
- if (hdl == NULL) {
- if (log_level >= 1) {
- port_log(p);
- log_puts(": couldn't open an alternate port\n");
- }
- return 0;
- }
-
- /* close unused device */
- file_del(p->mio.file);
- mio_close(p->mio.hdl);
-
- p->mio.hdl = hdl;
- p->mio.file = file_new(&port_mio_ops, p, "port", mio_nfds(hdl));
- return 1;
-}
-
void
port_mio_close(struct port *p)
{
{
struct port *p = arg;
- if (!port_reopen(p)) {
- midi_abort(p->midi);
- if (p->state != PORT_CFG)
- port_close(p);
- }
+ port_migrate(p);
+ midi_abort(p->midi);
+ if (p->state != PORT_CFG)
+ port_close(p);
}
-/* $OpenBSD: miofile.h,v 1.2 2019/09/21 04:42:46 ratchov Exp $ */
+/* $OpenBSD: miofile.h,v 1.3 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
*
};
int port_mio_open(struct port *);
-int port_mio_reopen(struct port *);
void port_mio_close(struct port *);
#endif /* !defined(MIOFILE_H) */
-/* $OpenBSD: opt.c,v 1.8 2021/03/03 10:19:06 ratchov Exp $ */
+/* $OpenBSD: opt.c,v 1.9 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2008-2011 Alexandre Ratchov <alex@caoua.org>
*
chan = msg[0] & MIDI_CHANMASK;
if (chan >= DEV_NSLOT)
return;
- if (slot_array[chan].opt == NULL ||
- slot_array[chan].opt->dev != o->dev)
+ if (slot_array[chan].opt != o)
return;
slot_setvol(slot_array + chan, msg[2]);
ctl_onval(CTL_SLOT_LEVEL, slot_array + chan, NULL, msg[2]);
return;
if (o->mtc == NULL)
return;
+ mtc_setdev(o->mtc, o->dev);
if (log_level >= 2) {
log_puts(o->name);
log_puts(": mmc stop\n");
return;
if (o->mtc == NULL)
return;
+ mtc_setdev(o->mtc, o->dev);
if (log_level >= 2) {
log_puts(o->name);
log_puts(": mmc start\n");
return;
if (o->mtc == NULL)
return;
+ mtc_setdev(o->mtc, o->dev);
switch (x->u.loc.hr >> 5) {
case MTC_FPS_24:
fps = 24;
int pmin, int pmax, int rmin, int rmax,
int maxweight, int mmc, int dup, unsigned int mode)
{
+ struct dev *a;
struct opt *o, **po;
unsigned int len, num;
char c;
- for (len = 0; name[len] != '\0'; len++) {
- if (len == OPT_NAMEMAX) {
- log_puts(name);
- log_puts(": too long\n");
- return NULL;
- }
- c = name[len];
- if ((c < 'a' || c > 'z') &&
- (c < 'A' || c > 'Z')) {
- log_puts(name);
- log_puts(": only alphabetic chars allowed\n");
- return NULL;
+ if (name == NULL) {
+ name = d->name;
+ len = strlen(name);
+ } else {
+ for (len = 0; name[len] != '\0'; len++) {
+ if (len == OPT_NAMEMAX) {
+ log_puts(name);
+ log_puts(": too long\n");
+ return NULL;
+ }
+ c = name[len];
+ if ((c < 'a' || c > 'z') &&
+ (c < 'A' || c > 'Z')) {
+ log_puts(name);
+ log_puts(": only alphabetic chars allowed\n");
+ return NULL;
+ }
}
}
num = 0;
log_puts(": too many opts\n");
return NULL;
}
- if (opt_byname(d, name)) {
- dev_log(d);
- log_puts(".");
+
+ if (opt_byname(name)) {
log_puts(name);
log_puts(": already defined\n");
return NULL;
}
}
+ if (strcmp(d->name, name) == 0)
+ a = d;
+ else {
+ /* circulate to the first "alternate" device (greatest num) */
+ for (a = d; a->alt_next->num > a->num; a = a->alt_next)
+ ;
+ }
+
o = xmalloc(sizeof(struct opt));
o->num = num;
- o->dev = d;
+ o->alt_first = o->dev = a;
+ o->refcnt = 0;
/*
* XXX: below, we allocate a midi input buffer, since we don't
}
struct opt *
-opt_byname(struct dev *d, char *name)
+opt_byname(char *name)
{
struct opt *o;
for (o = opt_list; o != NULL; o = o->next) {
- if (d != NULL && o->dev != d)
- continue;
if (strcmp(name, o->name) == 0)
return o;
}
return NULL;
}
+struct opt *
+opt_bynum(int num)
+{
+ struct opt *o;
+
+ for (o = opt_list; o != NULL; o = o->next) {
+ if (o->num == num)
+ return o;
+ }
+ return NULL;
+}
+
void
opt_del(struct opt *o)
{
*po = o->next;
xfree(o);
}
+
+void
+opt_init(struct opt *o)
+{
+ struct dev *d;
+
+ if (strcmp(o->name, o->dev->name) != 0) {
+ for (d = dev_list; d != NULL; d = d->next) {
+ ctl_new(CTL_OPT_DEV, o, d,
+ CTL_SEL, o->name, "server", -1, "device",
+ d->name, -1, 1, o->dev == d);
+ }
+ }
+}
+
+void
+opt_done(struct opt *o)
+{
+ struct dev *d;
+
+ if (o->refcnt != 0) {
+ // XXX: all clients are already kicked, so this never happens
+ log_puts(o->name);
+ log_puts(": still has refs\n");
+ }
+ for (d = dev_list; d != NULL; d = d->next)
+ ctl_del(CTL_OPT_DEV, o, d);
+}
+
+/*
+ * Set opt's device, and (if necessary) move clients to
+ * to the new device
+ */
+void
+opt_setdev(struct opt *o, struct dev *ndev)
+{
+ struct dev *odev;
+ struct ctl *c;
+ struct ctlslot *p;
+ struct slot *s;
+ int i;
+
+ if (!dev_ref(ndev))
+ return;
+
+ odev = o->dev;
+ if (odev == ndev) {
+ dev_unref(ndev);
+ return;
+ }
+
+ /* check if clients can use new device */
+ for (i = 0, s = slot_array; i < DEV_NSLOT; i++, s++) {
+ if (s->opt != o)
+ continue;
+ if (s->ops != NULL && !dev_iscompat(odev, ndev)) {
+ dev_unref(ndev);
+ return;
+ }
+ }
+
+ /*
+ * if we're using MMC, move all opts to the new device, mtc_setdev()
+ * will call us back
+ */
+ if (o->mtc != NULL && o->mtc->dev != ndev) {
+ mtc_setdev(o->mtc, ndev);
+ dev_unref(ndev);
+ return;
+ }
+
+ c = ctl_find(CTL_OPT_DEV, o, o->dev);
+ if (c != NULL)
+ c->curval = 0;
+
+ /* detach clients from old device */
+ for (i = 0, s = slot_array; i < DEV_NSLOT; i++, s++) {
+ if (s->opt != o)
+ continue;
+
+ if (s->pstate == SLOT_RUN || s->pstate == SLOT_STOP)
+ slot_detach(s);
+ }
+
+ o->dev = ndev;
+
+ if (o->refcnt > 0) {
+ dev_unref(odev);
+ dev_ref(o->dev);
+ }
+
+ c = ctl_find(CTL_OPT_DEV, o, o->dev);
+ if (c != NULL) {
+ c->curval = 1;
+ c->val_mask = ~0;
+ }
+
+ /* attach clients to new device */
+ for (i = 0, s = slot_array; i < DEV_NSLOT; i++, s++) {
+ if (s->opt != o)
+ continue;
+
+ if (ndev != odev) {
+ dev_midi_slotdesc(odev, s);
+ dev_midi_slotdesc(ndev, s);
+ dev_midi_vol(ndev, s);
+ }
+
+ c = ctl_find(CTL_SLOT_LEVEL, s, NULL);
+ ctl_update(c);
+
+ if (s->pstate == SLOT_RUN || s->pstate == SLOT_STOP) {
+ slot_initconv(s);
+ slot_attach(s);
+ }
+ }
+
+ /* move controlling clients to new device */
+ for (p = ctlslot_array, i = 0; i < DEV_NCTLSLOT; i++, p++) {
+ if (p->ops == NULL)
+ continue;
+ if (p->opt == o)
+ ctlslot_update(p);
+ }
+
+ dev_unref(ndev);
+}
+
+/*
+ * Get a reference to opt's device
+ */
+struct dev *
+opt_ref(struct opt *o)
+{
+ struct dev *d;
+
+ if (o->refcnt == 0) {
+ if (strcmp(o->name, o->dev->name) == 0) {
+ if (!dev_ref(o->dev))
+ return NULL;
+ } else {
+ /* find first working one */
+ d = o->alt_first;
+ while (1) {
+ if (dev_ref(d))
+ break;
+ d = d->alt_next;
+ if (d == o->alt_first)
+ return NULL;
+ }
+
+ /* if device changed, move everything to the new one */
+ if (d != o->dev)
+ opt_setdev(o, d);
+ }
+ }
+
+ o->refcnt++;
+ return o->dev;
+}
+
+/*
+ * Release opt's device
+ */
+void
+opt_unref(struct opt *o)
+{
+ o->refcnt--;
+ if (o->refcnt == 0)
+ dev_unref(o->dev);
+}
-/* $OpenBSD: opt.h,v 1.6 2021/03/03 10:19:06 ratchov Exp $ */
+/* $OpenBSD: opt.h,v 1.7 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
*
struct opt {
struct opt *next;
- struct dev *dev;
+ struct dev *dev, *alt_first;
struct midi *midi;
struct mtc *mtc; /* if set, MMC-controlled MTC source */
int rmin, rmax; /* recording channels */
int dup; /* true if join/expand enabled */
int mode; /* bitmap of MODE_XXX */
+ int refcnt;
};
extern struct opt *opt_list;
struct opt *opt_new(struct dev *, char *, int, int, int, int,
int, int, int, unsigned int);
void opt_del(struct opt *);
-struct opt *opt_byname(struct dev *, char *);
+struct opt *opt_byname(char *);
+struct opt *opt_bynum(int);
+void opt_init(struct opt *);
+void opt_done(struct opt *);
+void opt_setdev(struct opt *, struct dev *);
+struct dev *opt_ref(struct opt *);
+void opt_unref(struct opt *);
#endif /* !defined(OPT_H) */
-/* $OpenBSD: siofile.c,v 1.24 2021/03/03 10:00:27 ratchov Exp $ */
+/* $OpenBSD: siofile.c,v 1.25 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
*
dev_abort(d);
}
-static int
-dev_sio_openalt(struct dev *d, struct dev_alt *n,
- struct sio_hdl **rhdl, struct sioctl_hdl **rctlhdl, unsigned int *rmode)
+/*
+ * open the device.
+ */
+int
+dev_sio_open(struct dev *d)
{
- struct sio_hdl *hdl;
- struct sioctl_hdl *ctlhdl;
- unsigned int mode = d->reqmode & (MODE_PLAY | MODE_REC);
+ struct sio_par par;
+ unsigned int rate, mode = d->reqmode & (SIO_PLAY | SIO_REC);
- hdl = fdpass_sio_open(d->num, n->idx, mode);
- if (hdl == NULL) {
+ d->sio.hdl = fdpass_sio_open(d->num, mode);
+ if (d->sio.hdl == NULL) {
if (mode != (SIO_PLAY | SIO_REC))
return 0;
- hdl = fdpass_sio_open(d->num, n->idx, SIO_PLAY);
- if (hdl != NULL)
+ d->sio.hdl = fdpass_sio_open(d->num, SIO_PLAY);
+ if (d->sio.hdl != NULL)
mode = SIO_PLAY;
else {
- hdl = fdpass_sio_open(d->num, n->idx, SIO_REC);
- if (hdl != NULL)
+ d->sio.hdl = fdpass_sio_open(d->num, SIO_REC);
+ if (d->sio.hdl != NULL)
mode = SIO_REC;
else
return 0;
log_puts(" mode\n");
}
}
+ d->mode = mode;
- ctlhdl = fdpass_sioctl_open(d->num, n->idx, SIOCTL_READ | SIOCTL_WRITE);
- if (ctlhdl == NULL) {
+ d->sioctl.hdl = fdpass_sioctl_open(d->num, SIOCTL_READ | SIOCTL_WRITE);
+ if (d->sioctl.hdl == NULL) {
if (log_level >= 1) {
dev_log(d);
log_puts(": no control device\n");
}
}
- *rhdl = hdl;
- *rctlhdl = ctlhdl;
- *rmode = mode;
- return 1;
-}
-
-/*
- * open the device using one of the provided paths
- */
-static int
-dev_sio_openlist(struct dev *d,
- struct sio_hdl **rhdl, struct sioctl_hdl **rctlhdl, unsigned int *rmode)
-{
- struct dev_alt *n;
- struct ctl *c;
- int val;
-
- for (n = d->alt_list; n != NULL; n = n->next) {
- if (d->alt_num == n->idx)
- continue;
- if (log_level >= 2) {
- dev_log(d);
- log_puts(": trying ");
- log_puts(n->name);
- log_puts("\n");
- }
- if (dev_sio_openalt(d, n, rhdl, rctlhdl, rmode)) {
- if (log_level >= 2) {
- dev_log(d);
- log_puts(": using ");
- log_puts(n->name);
- log_puts("\n");
- }
- d->alt_num = n->idx;
- for (c = ctl_list; c != NULL; c = c->next) {
- if (!ctl_match(c, CTL_DEV_ALT, d, NULL))
- continue;
- val = c->u.dev_alt.idx == n->idx;
- if (c->curval == val)
- continue;
- c->curval = val;
- if (val)
- c->val_mask = ~0U;
- }
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * open the device.
- */
-int
-dev_sio_open(struct dev *d)
-{
- struct sio_par par;
-
- if (!dev_sio_openlist(d, &d->sio.hdl, &d->sioctl.hdl, &d->mode))
- return 0;
-
sio_initpar(&par);
par.bits = d->par.bits;
par.bps = d->par.bps;
par.pchan = d->pchan;
if (d->mode & SIO_REC)
par.rchan = d->rchan;
- if (d->bufsz)
- par.appbufsz = d->bufsz;
- if (d->round)
- par.round = d->round;
- if (d->rate)
- par.rate = d->rate;
+ par.appbufsz = d->bufsz;
+ par.round = d->round;
+ par.rate = d->rate;
if (!sio_setpar(d->sio.hdl, &par))
goto bad_close;
if (!sio_getpar(d->sio.hdl, &par))
goto bad_close;
+ /*
+ * If the requested rate is not supported by the device,
+ * use the new one, but retry using a block size that would
+ * match the requested one
+ */
+ rate = par.rate;
+ if (rate != d->rate) {
+ sio_initpar(&par);
+ par.bits = d->par.bits;
+ par.bps = d->par.bps;
+ par.sig = d->par.sig;
+ par.le = d->par.le;
+ par.msb = d->par.msb;
+ if (mode & SIO_PLAY)
+ par.pchan = d->reqpchan;
+ if (mode & SIO_REC)
+ par.rchan = d->reqrchan;
+ par.appbufsz = d->bufsz * rate / d->rate;
+ par.round = d->round * rate / d->rate;
+ par.rate = rate;
+ if (!sio_setpar(d->sio.hdl, &par))
+ goto bad_close;
+ if (!sio_getpar(d->sio.hdl, &par))
+ goto bad_close;
+ }
+
#ifdef DEBUG
/*
* We support any parameter combination exposed by the kernel,
goto bad_close;
}
#endif
-
d->par.bits = par.bits;
d->par.bps = par.bps;
d->par.sig = par.sig;
return 0;
}
-/*
- * Open an alternate device. Upon success and if the new device is
- * compatible with the old one, close the old device and continue
- * using the new one. The new device is not started.
- */
-int
-dev_sio_reopen(struct dev *d)
-{
- struct sio_par par;
- struct sio_hdl *hdl;
- struct sioctl_hdl *ctlhdl;
- unsigned int mode;
-
- if (!dev_sio_openlist(d, &hdl, &ctlhdl, &mode))
- return 0;
-
- sio_initpar(&par);
- par.bits = d->par.bits;
- par.bps = d->par.bps;
- par.sig = d->par.sig;
- par.le = d->par.le;
- par.msb = d->par.msb;
- if (mode & SIO_PLAY)
- par.pchan = d->reqpchan;
- if (mode & SIO_REC)
- par.rchan = d->reqrchan;
- par.appbufsz = d->bufsz;
- par.round = d->round;
- par.rate = d->rate;
- if (!sio_setpar(hdl, &par))
- goto bad_close;
- if (!sio_getpar(hdl, &par))
- goto bad_close;
-
- /* check if new parameters are compatible with old ones */
- if (par.round != d->round || par.bufsz != d->bufsz ||
- par.rate != d->rate) {
- if (log_level >= 1) {
- dev_log(d);
- log_puts(": alternate device not compatible\n");
- }
- goto bad_close;
- }
-
- /* close unused device */
- timo_del(&d->sio.watchdog);
- file_del(d->sio.file);
- sio_close(d->sio.hdl);
- if (d->sioctl.hdl) {
- file_del(d->sioctl.file);
- sioctl_close(d->sioctl.hdl);
- d->sioctl.hdl = NULL;
- }
-
- /* update parameters */
- d->mode = mode;
- d->par.bits = par.bits;
- d->par.bps = par.bps;
- d->par.sig = par.sig;
- d->par.le = par.le;
- d->par.msb = par.msb;
- if (d->mode & SIO_PLAY)
- d->pchan = par.pchan;
- if (d->mode & SIO_REC)
- d->rchan = par.rchan;
-
- d->sio.hdl = hdl;
- d->sioctl.hdl = ctlhdl;
- d->sio.file = file_new(&dev_sio_ops, d, "dev", sio_nfds(hdl));
- if (d->sioctl.hdl) {
- d->sioctl.file = file_new(&dev_sioctl_ops, d, "mix",
- sioctl_nfds(ctlhdl));
- }
- sio_onmove(hdl, dev_sio_onmove, d);
- return 1;
-bad_close:
- sio_close(hdl);
- if (ctlhdl)
- sioctl_close(ctlhdl);
- return 0;
-}
-
void
dev_sio_close(struct dev *d)
{
sioctl_close(d->sioctl.hdl);
d->sioctl.hdl = NULL;
}
- d->alt_num = -1;
}
void
log_puts(": disconnected\n");
}
#endif
- if (!dev_reopen(d))
- dev_abort(d);
+ dev_migrate(d);
+ dev_abort(d);
}
-/* $OpenBSD: siofile.h,v 1.4 2019/09/21 04:42:46 ratchov Exp $ */
+/* $OpenBSD: siofile.h,v 1.5 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
*
};
int dev_sio_open(struct dev *);
-int dev_sio_reopen(struct dev *);
void dev_sio_close(struct dev *);
void dev_sio_log(struct dev *);
void dev_sio_start(struct dev *);
-/* $OpenBSD: sndiod.c,v 1.46 2021/07/12 15:09:20 beck Exp $ */
+/* $OpenBSD: sndiod.c,v 1.47 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
*
struct dev *d;
for (d = dev_list; d != NULL; d = d->next) {
- if (d->alt_list->next == NULL &&
- strcmp(d->alt_list->name, path) == 0)
+ if (strcmp(d->path, path) == 0)
return d;
}
if (!bufsz && !round) {
struct port *c;
for (c = port_list; c != NULL; c = c->next) {
- if (c->path_list->next == NULL &&
- strcmp(c->path_list->str, path) == 0)
+ if (strcmp(c->path, path) == 0)
return c;
}
c = port_new(path, MODE_MIDIMASK, hold);
start_helper(int background)
{
struct dev *d;
- struct dev_alt *da;
struct port *p;
struct passwd *pw;
- struct name *n;
int s[2];
pid_t pid;
err(1, "cannot drop privileges");
}
for (d = dev_list; d != NULL; d = d->next) {
- for (da = d->alt_list; da != NULL; da = da->next) {
- dounveil(da->name, "rsnd/", "/dev/audio");
- dounveil(da->name, "rsnd/", "/dev/audioctl");
- }
+ dounveil(d->path, "rsnd/", "/dev/audio");
+ dounveil(d->path, "rsnd/", "/dev/audioctl");
}
for (p = port_list; p != NULL; p = p->next) {
- for (n = p->path_list; n != NULL; n = n->next)
- dounveil(n->str, "rmidi/", "/dev/rmidi");
+ dounveil(p->path, "rmidi/", "/dev/rmidi");
}
if (pledge("stdio sendfd rpath wpath", NULL) == -1)
err(1, "pledge");
char base[SOCKPATH_MAX], path[SOCKPATH_MAX];
unsigned int mode, dup, mmc, vol;
unsigned int hold, autovol, bufsz, round, rate;
+ unsigned int reopen_list;
const char *str;
struct aparams par;
- struct dev *d;
- struct port *p;
+ struct opt *o;
+ struct dev *d, *dev_first, *dev_next;
+ struct port *p, *port_first, *port_next;
struct listen *l;
struct passwd *pw;
struct tcpaddr {
rmax = 1;
aparams_init(&par);
mode = MODE_PLAY | MODE_REC;
+ dev_first = dev_next = NULL;
+ port_first = port_next = NULL;
tcpaddr_list = NULL;
d = NULL;
p = NULL;
break;
case 'q':
p = mkport(optarg, hold);
+ /* create new circulate list */
+ port_first = port_next = p;
break;
case 'Q':
if (p == NULL)
errx(1, "-Q %s: no ports defined", optarg);
- namelist_add(&p->path_list, optarg);
+ p = mkport(optarg, hold);
+ /* add to circulate list */
+ p->alt_next = port_next;
+ port_first->alt_next = p;
+ port_next = p;
break;
case 'a':
hold = opt_onoff();
case 'f':
d = mkdev(optarg, &par, 0, bufsz, round,
rate, hold, autovol);
+ /* create new circulate list */
+ dev_first = dev_next = d;
break;
case 'F':
if (d == NULL)
errx(1, "-F %s: no devices defined", optarg);
- if (!dev_addname(d, optarg))
- exit(1);
+ d = mkdev(optarg, &par, 0, bufsz, round,
+ rate, hold, autovol);
+ /* add to circulate list */
+ d->alt_next = dev_next;
+ dev_first->alt_next = d;
+ dev_next = d;
break;
default:
fputs(usagestr, stderr);
bufsz, round, rate, 0, autovol);
}
}
+
+ /*
+ * Add default sub-device (if none) backed by the last device
+ */
+ o = opt_byname("default");
+ if (o == NULL) {
+ o = mkopt("default", dev_list, pmin, pmax, rmin, rmax,
+ mode, vol, 0, dup);
+ if (o == NULL)
+ return 1;
+ }
+
+ /*
+ * For each device create an anonymous sub-device using
+ * the "default" sub-device as template
+ */
for (d = dev_list; d != NULL; d = d->next) {
- if (opt_byname(d, "default"))
- continue;
- if (mkopt("default", d, pmin, pmax, rmin, rmax,
- mode, vol, mmc, dup) == NULL)
+ if (opt_new(d, NULL, o->pmin, o->pmax, o->rmin, o->rmax,
+ o->maxweight, o->mtc != NULL, o->dup, o->mode) == NULL)
return 1;
+ dev_adjpar(d, o->mode, o->pmax, o->rmax);
}
setsig();
if (!dev_init(d))
return 1;
}
+ for (o = opt_list; o != NULL; o = o->next)
+ opt_init(o);
if (background) {
log_flush();
log_level = 0;
break;
if (reopen_flag) {
reopen_flag = 0;
- for (d = dev_list; d != NULL; d = d->next)
- dev_reopen(d);
- for (p = port_list; p != NULL; p = p->next)
- port_reopen(p);
+
+ reopen_list = 0;
+ for (d = dev_list; d != NULL; d = d->next) {
+ if (d->pstate != DEV_CFG)
+ reopen_list |= (1 << d->num);
+ }
+ for (d = dev_list; d != NULL; d = d->next) {
+ if (reopen_list & (1 << d->num))
+ dev_migrate(d);
+ }
+
+ reopen_list = 0;
+ for (p = port_list; p != NULL; p = p->next) {
+ if (p->state != PORT_CFG)
+ reopen_list |= (1 << p->num);
+ }
+ for (p = port_list; p != NULL; p = p->next) {
+ if (reopen_list & (1 << p->num)) {
+ if (port_migrate(p) != p)
+ port_close(p);
+ }
+ }
}
if (!fdpass_peer)
break;
listen_close(listen_list);
while (sock_list != NULL)
sock_close(sock_list);
+ for (o = opt_list; o != NULL; o = o->next)
+ opt_done(o);
for (d = dev_list; d != NULL; d = d->next)
dev_done(d);
for (p = port_list; p != NULL; p = p->next)
-/* $OpenBSD: sock.c,v 1.44 2021/03/03 10:19:06 ratchov Exp $ */
+/* $OpenBSD: sock.c,v 1.45 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
*
unsigned int sock_sesrefs = 0; /* connections to the session */
uint8_t sock_sescookie[AMSG_COOKIELEN]; /* owner of the session */
+/*
+ * Old clients used to send dev number and opt name. This routine
+ * finds proper opt pointer for the given device.
+ */
+static struct opt *
+legacy_opt(int devnum, char *optname)
+{
+ struct dev *d;
+ struct opt *o;
+
+ d = dev_bynum(devnum);
+ if (d == NULL)
+ return NULL;
+ if (strcmp(optname, "default") == 0) {
+ for (o = opt_list; o != NULL; o = o->next) {
+ if (strcmp(o->name, d->name) == 0)
+ return o;
+ }
+ return NULL;
+ } else {
+ o = opt_byname(optname);
+ return (o != NULL && o->dev == d) ? o : NULL;
+ }
+}
+
+/*
+ * If control slot is associated to a particular opt, then
+ * remove the unused group part of the control name to make mixer
+ * look nicer
+ */
+static char *
+ctlgroup(struct sock *f, struct ctl *c)
+{
+ if (f->ctlslot->opt == NULL)
+ return c->group;
+ if (strcmp(c->group, f->ctlslot->opt->name) == 0)
+ return "";
+ if (strcmp(c->group, f->ctlslot->opt->dev->name) == 0)
+ return "";
+ return c->group;
+}
+
void
sock_log(struct sock *f)
{
void
sock_close(struct sock *f)
{
- struct dev *d;
+ struct opt *o;
struct sock **pf;
unsigned int tags, i;
if (f->midi) {
tags = midi_tags(f->midi);
for (i = 0; i < DEV_NMAX; i++) {
- if ((tags & (1 << i)) && (d = dev_bynum(i)) != NULL)
- dev_unref(d);
+ if ((tags & (1 << i)) && (o = opt_bynum(i)) != NULL)
+ opt_unref(o);
}
midi_del(f->midi);
f->midi = NULL;
{
struct amsg_hello *p = &f->rmsg.u.hello;
struct port *c;
- struct dev *d;
struct opt *opt;
unsigned int mode;
unsigned int id;
if (f->midi == NULL)
return 0;
/* XXX: add 'devtype' to libsndio */
- if (p->devnum < 16) {
- d = dev_bynum(p->devnum);
- if (d == NULL)
+ if (p->devnum == AMSG_NODEV) {
+ opt = opt_byname(p->opt);
+ if (opt == NULL)
+ return 0;
+ if (!opt_ref(opt))
return 0;
- opt = opt_byname(d, p->opt);
+ midi_tag(f->midi, opt->num);
+ } else if (p->devnum < 16) {
+ opt = legacy_opt(p->devnum, p->opt);
if (opt == NULL)
return 0;
- if (!dev_ref(d))
+ if (!opt_ref(opt))
return 0;
midi_tag(f->midi, opt->num);
} else if (p->devnum < 32) {
midi_tag(f->midi, p->devnum);
} else if (p->devnum < 48) {
- c = port_bynum(p->devnum - 32);
- if (c == NULL || !port_ref(c))
+ c = port_alt_ref(p->devnum - 32);
+ if (c == NULL)
return 0;
f->port = c;
midi_link(f->midi, c->midi);
return 1;
}
if (mode & MODE_CTLMASK) {
- d = dev_bynum(p->devnum);
- if (d == NULL) {
- if (log_level >= 2) {
- sock_log(f);
- log_puts(": ");
- log_putu(p->devnum);
- log_puts(": no such device\n");
- }
- return 0;
+ if (p->devnum == AMSG_NODEV) {
+ opt = opt_byname(p->opt);
+ if (opt == NULL)
+ return 0;
+ } else {
+ opt = legacy_opt(p->devnum, p->opt);
+ if (opt == NULL)
+ return 0;
}
- opt = opt_byname(d, p->opt);
- if (opt == NULL)
- return 0;
f->ctlslot = ctlslot_new(opt, &sock_ctlops, f);
if (f->ctlslot == NULL) {
if (log_level >= 2) {
f->ctlsyncpending = 0;
return 1;
}
- d = dev_bynum(p->devnum);
- if (d == NULL)
- return 0;
- opt = opt_byname(d, p->opt);
+ opt = (p->devnum == AMSG_NODEV) ?
+ opt_byname(p->opt) : legacy_opt(p->devnum, p->opt);
if (opt == NULL)
return 0;
f->slot = slot_new(opt, id, p->who, &sock_slotops, f, mode);
c->val_mask &= ~mask;
type = ctlslot_visible(f->ctlslot, c) ?
c->type : CTL_NONE;
- strlcpy(desc->group, (f->ctlslot->opt == NULL ||
- strcmp(c->group, f->ctlslot->opt->dev->name) != 0) ?
- c->group : "",
- AMSG_CTL_NAMEMAX);
+ strlcpy(desc->group, ctlgroup(f, c), AMSG_CTL_NAMEMAX);
strlcpy(desc->node0.name, c->node0.name,
AMSG_CTL_NAMEMAX);
desc->node0.unit = ntohs(c->node0.unit);
-/* $OpenBSD: utils.c,v 1.7 2020/01/23 05:40:09 ratchov Exp $ */
+/* $OpenBSD: utils.c,v 1.8 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2003-2012 Alexandre Ratchov <alex@caoua.org>
*
memcpy(p, s, size);
return p;
}
-
-/*
- * copy and append the given string to the name list
- */
-void
-namelist_add(struct name **list, char *str)
-{
- struct name *n;
- size_t size;
-
- size = strlen(str) + 1;
- n = xmalloc(sizeof(struct name) + size);
- memcpy(n->str, str, size);
- n->next = *list;
- *list = n;
-}
-
-void
-namelist_clear(struct name **list)
-{
- struct name *n;
-
- while ((n = *list) != NULL) {
- *list = n->next;
- xfree(n);
- }
-}
-
-char *
-namelist_byindex(struct name **list, unsigned int idx)
-{
- struct name *n;
-
- n = *list;
- while (1) {
- if (n == NULL)
- return NULL;
- if (idx == 0)
- break;
- n = n->next;
- idx--;
- }
- return n->str;
-}
-/* $OpenBSD: utils.h,v 1.5 2020/01/23 05:40:09 ratchov Exp $ */
+/* $OpenBSD: utils.h,v 1.6 2021/11/01 14:43:25 ratchov Exp $ */
/*
* Copyright (c) 2003-2012 Alexandre Ratchov <alex@caoua.org>
*
char *xstrdup(char *);
void xfree(void *);
-void namelist_add(struct name **, char *);
-void namelist_clear(struct name **);
-char *namelist_byindex(struct name **, unsigned int);
-
/*
* Log levels:
*