diff options
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/sndiod/dev.c | 423 | ||||
-rw-r--r-- | usr.bin/sndiod/dev.h | 37 | ||||
-rw-r--r-- | usr.bin/sndiod/fdpass.c | 62 | ||||
-rw-r--r-- | usr.bin/sndiod/fdpass.h | 8 | ||||
-rw-r--r-- | usr.bin/sndiod/midi.c | 129 | ||||
-rw-r--r-- | usr.bin/sndiod/midi.h | 9 | ||||
-rw-r--r-- | usr.bin/sndiod/miofile.c | 71 | ||||
-rw-r--r-- | usr.bin/sndiod/miofile.h | 3 | ||||
-rw-r--r-- | usr.bin/sndiod/opt.c | 241 | ||||
-rw-r--r-- | usr.bin/sndiod/opt.h | 13 | ||||
-rw-r--r-- | usr.bin/sndiod/siofile.c | 216 | ||||
-rw-r--r-- | usr.bin/sndiod/siofile.h | 3 | ||||
-rw-r--r-- | usr.bin/sndiod/sndiod.c | 98 | ||||
-rw-r--r-- | usr.bin/sndiod/sock.c | 100 | ||||
-rw-r--r-- | usr.bin/sndiod/utils.c | 46 | ||||
-rw-r--r-- | usr.bin/sndiod/utils.h | 6 |
16 files changed, 829 insertions, 636 deletions
diff --git a/usr.bin/sndiod/dev.c b/usr.bin/sndiod/dev.c index b68b60413ec..b63af2248b1 100644 --- a/usr.bin/sndiod/dev.c +++ b/usr.bin/sndiod/dev.c @@ -1,4 +1,4 @@ -/* $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> * @@ -45,16 +45,13 @@ struct dev *dev_new(char *, struct aparams *, unsigned int, unsigned int, 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 *); @@ -930,10 +927,8 @@ dev_new(char *path, struct aparams *par, 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; @@ -948,6 +943,7 @@ dev_new(char *path, struct aparams *par, 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) ; @@ -957,51 +953,6 @@ dev_new(char *path, struct aparams *par, } /* - * 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 */ void @@ -1099,9 +1050,6 @@ dev_allocbufs(struct dev *d) 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; @@ -1123,16 +1071,6 @@ dev_open(struct dev *d) 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; } @@ -1158,18 +1096,18 @@ dev_abort(struct dev *d) } 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); } @@ -1208,9 +1146,6 @@ dev_freebufs(struct dev *d) void dev_close(struct dev *d) { - struct dev_alt *a; - unsigned int idx; - d->pstate = DEV_CFG; dev_sio_close(d); dev_freebufs(d); @@ -1219,82 +1154,6 @@ dev_close(struct dev *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 @@ -1381,7 +1240,6 @@ void dev_del(struct dev *d) { struct dev **p; - struct dev_alt *a; #ifdef DEBUG if (log_level >= 3) { @@ -1401,10 +1259,6 @@ dev_del(struct dev *d) #endif } *p = d->next; - while ((a = d->alt_list) != NULL) { - d->alt_list = a->next; - xfree(a); - } xfree(d); } @@ -1444,6 +1298,103 @@ dev_wakeup(struct dev *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 */ @@ -1552,6 +1503,43 @@ mtc_loc(struct mtc *mtc, unsigned int origin) } /* + * 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 */ void @@ -1787,7 +1775,8 @@ slot_new(struct opt *opt, unsigned int id, char *who, 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; @@ -1809,8 +1798,6 @@ found: 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); @@ -1839,7 +1826,7 @@ slot_del(struct slot *s) slot_stop(s, 0); break; } - dev_unref(s->opt->dev); + opt_unref(s->opt); } /* @@ -1861,6 +1848,62 @@ slot_setvol(struct slot *s, unsigned int 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 */ void @@ -2202,7 +2245,7 @@ ctlslot_new(struct opt *o, struct ctlops *ops, void *arg) } s->opt = o; s->self = 1 << i; - if (!dev_ref(o->dev)) + if (!opt_ref(o)) return NULL; s->ops = ops; s->arg = arg; @@ -2232,7 +2275,7 @@ ctlslot_del(struct ctlslot *s) pc = &c->next; } s->ops = NULL; - dev_unref(s->opt->dev); + opt_unref(s->opt); } int @@ -2243,8 +2286,9 @@ ctlslot_visible(struct ctlslot *s, struct ctl *c) 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: @@ -2271,6 +2315,28 @@ ctlslot_lookup(struct ctlslot *s, int addr) } 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(c->name); @@ -2318,16 +2384,17 @@ ctl_log(struct ctl *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"); } @@ -2368,9 +2435,6 @@ ctl_setval(struct ctl *c, int val) 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() @@ -2378,6 +2442,10 @@ ctl_setval(struct ctl *c, int val) 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); @@ -2429,8 +2497,8 @@ ctl_new(int scope, void *arg0, void *arg1, 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; @@ -2494,8 +2562,8 @@ ctl_match(struct ctl *c, int scope, void *arg0, void *arg1) 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; } @@ -2600,4 +2668,3 @@ dev_ctlsync(struct dev *d) s->ops->sync(s->arg); } } - diff --git a/usr.bin/sndiod/dev.h b/usr.bin/sndiod/dev.h index 1e778e5bd0d..45ae71f47b9 100644 --- a/usr.bin/sndiod/dev.h +++ b/usr.bin/sndiod/dev.h @@ -1,4 +1,4 @@ -/* $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> * @@ -126,7 +126,7 @@ struct ctl { #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 { @@ -142,12 +142,16 @@ struct ctl { 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 */ @@ -217,6 +221,11 @@ struct dev { char name[CTL_NAMEMAX]; /* + * next to try if this fails + */ + struct dev *alt_next; + + /* * audio device (while opened) */ struct dev_sio sio; @@ -256,12 +265,7 @@ struct dev { #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) @@ -283,12 +287,13 @@ extern struct mtc mtc_array[1]; 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 *); @@ -297,6 +302,7 @@ int dev_ref(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 @@ -330,6 +336,7 @@ struct slot *slot_new(struct opt *, unsigned int, char *, 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 *); @@ -356,6 +363,8 @@ struct ctlslot *ctlslot_new(struct opt *, struct ctlops *, void *); 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 *); diff --git a/usr.bin/sndiod/fdpass.c b/usr.bin/sndiod/fdpass.c index 9f97f35b7e1..d5f7617a282 100644 --- a/usr.bin/sndiod/fdpass.c +++ b/usr.bin/sndiod/fdpass.c @@ -1,4 +1,4 @@ -/* $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> * @@ -36,7 +36,6 @@ struct fdpass_msg { #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, ... */ }; @@ -77,7 +76,7 @@ fdpass_log(struct fdpass *f) } 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; @@ -91,7 +90,6 @@ fdpass_send(struct fdpass *f, int cmd, int num, int idx, int mode, int fd) data.cmd = cmd; data.num = num; - data.idx = idx; data.mode = mode; iov.iov_base = &data; iov.iov_len = sizeof(struct fdpass_msg); @@ -131,8 +129,6 @@ fdpass_send(struct fdpass *f, int cmd, int num, int idx, int mode, int fd) log_puti(cmd); log_puts(", num = "); log_puti(num); - log_puts(", idx = "); - log_puti(idx); log_puts(", mode = "); log_puti(mode); log_puts(", fd = "); @@ -146,7 +142,7 @@ fdpass_send(struct fdpass *f, int cmd, int num, int idx, int mode, int 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; @@ -217,7 +213,6 @@ fdpass_recv(struct fdpass *f, int *cmd, int *num, int *idx, int *mode, int *fd) } *cmd = data.cmd; *num = data.num; - *idx = data.idx; *mode = data.mode; #ifdef DEBUG if (log_level >= 3) { @@ -226,8 +221,6 @@ fdpass_recv(struct fdpass *f, int *cmd, int *num, int *idx, int *mode, int *fd) log_puti(*cmd); log_puts(", num = "); log_puti(*num); - log_puts(", idx = "); - log_puti(*idx); log_puts(", mode = "); log_puti(*mode); log_puts(", fd = "); @@ -243,7 +236,7 @@ fdpass_waitret(struct fdpass *f, int *retfd) { 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) { @@ -257,13 +250,13 @@ fdpass_waitret(struct fdpass *f, int *retfd) } 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; @@ -273,13 +266,13 @@ fdpass_sio_open(int num, int idx, unsigned int mode) } 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; @@ -289,13 +282,13 @@ fdpass_mio_open(int num, int idx, unsigned int mode) } 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; @@ -320,14 +313,12 @@ fdpass_in_worker(void *arg) 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: @@ -340,15 +331,7 @@ fdpass_in_helper(void *arg) 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); @@ -360,12 +343,7 @@ fdpass_in_helper(void *arg) 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); @@ -377,21 +355,13 @@ fdpass_in_helper(void *arg) 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 diff --git a/usr.bin/sndiod/fdpass.h b/usr.bin/sndiod/fdpass.h index e11926e26b0..fec1a23813b 100644 --- a/usr.bin/sndiod/fdpass.h +++ b/usr.bin/sndiod/fdpass.h @@ -1,4 +1,4 @@ -/* $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> * @@ -25,8 +25,8 @@ void fdpass_close(struct fdpass *f); 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) */ diff --git a/usr.bin/sndiod/midi.c b/usr.bin/sndiod/midi.c index fea9441b2e2..371a830908f 100644 --- a/usr.bin/sndiod/midi.c +++ b/usr.bin/sndiod/midi.c @@ -1,4 +1,4 @@ -/* $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> * @@ -433,6 +433,45 @@ midi_abort(struct midi *p) } } +/* + * 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) { @@ -482,19 +521,17 @@ port_exit(void *arg) 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; } @@ -518,7 +555,6 @@ port_del(struct port *c) #endif } *p = c->next; - namelist_clear(&c->path_list); xfree(c); } @@ -555,6 +591,67 @@ port_unref(struct port *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) { struct port *p; @@ -590,6 +687,8 @@ port_close(struct port *c) panic(); } #endif + port_log(c); + log_puts(": closed\n"); c->state = PORT_CFG; port_mio_close(c); return 1; @@ -627,15 +726,3 @@ port_done(struct port *c) 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; -} diff --git a/usr.bin/sndiod/midi.h b/usr.bin/sndiod/midi.h index c8b7d1ed627..cd398de4ca5 100644 --- a/usr.bin/sndiod/midi.h +++ b/usr.bin/sndiod/midi.h @@ -1,4 +1,4 @@ -/* $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> * @@ -89,7 +89,8 @@ struct port { #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; }; @@ -113,6 +114,7 @@ void midi_tag(struct midi *, unsigned int); 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); @@ -124,6 +126,7 @@ int port_init(struct port *); 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) */ diff --git a/usr.bin/sndiod/miofile.c b/usr.bin/sndiod/miofile.c index dbfacc4ab1b..f9818745935 100644 --- a/usr.bin/sndiod/miofile.c +++ b/usr.bin/sndiod/miofile.c @@ -1,4 +1,4 @@ -/* $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> * @@ -45,74 +45,16 @@ struct fileops port_mio_ops = { 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) { @@ -187,9 +129,8 @@ port_mio_hup(void *arg) { 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); } diff --git a/usr.bin/sndiod/miofile.h b/usr.bin/sndiod/miofile.h index 703caa023d5..fd307dc1307 100644 --- a/usr.bin/sndiod/miofile.h +++ b/usr.bin/sndiod/miofile.h @@ -1,4 +1,4 @@ -/* $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> * @@ -25,7 +25,6 @@ struct port_mio { }; int port_mio_open(struct port *); -int port_mio_reopen(struct port *); void port_mio_close(struct port *); #endif /* !defined(MIOFILE_H) */ diff --git a/usr.bin/sndiod/opt.c b/usr.bin/sndiod/opt.c index 99621d738d1..0dfd8baa33f 100644 --- a/usr.bin/sndiod/opt.c +++ b/usr.bin/sndiod/opt.c @@ -1,4 +1,4 @@ -/* $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> * @@ -59,8 +59,7 @@ opt_midi_omsg(void *arg, unsigned char *msg, int len) 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]); @@ -91,6 +90,7 @@ opt_midi_omsg(void *arg, unsigned char *msg, int len) 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"); @@ -102,6 +102,7 @@ opt_midi_omsg(void *arg, unsigned char *msg, int len) 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"); @@ -115,6 +116,7 @@ opt_midi_omsg(void *arg, unsigned char *msg, int len) return; if (o->mtc == NULL) return; + mtc_setdev(o->mtc, o->dev); switch (x->u.loc.hr >> 5) { case MTC_FPS_24: fps = 24; @@ -173,22 +175,28 @@ opt_new(struct dev *d, char *name, 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; @@ -199,9 +207,8 @@ opt_new(struct dev *d, char *name, 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; @@ -220,9 +227,18 @@ opt_new(struct dev *d, char *name, } } + 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 @@ -286,19 +302,29 @@ opt_new(struct dev *d, char *name, } 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) { @@ -316,3 +342,174 @@ 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); +} diff --git a/usr.bin/sndiod/opt.h b/usr.bin/sndiod/opt.h index bb56f445100..7dd9e2f7c71 100644 --- a/usr.bin/sndiod/opt.h +++ b/usr.bin/sndiod/opt.h @@ -1,4 +1,4 @@ -/* $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> * @@ -23,7 +23,7 @@ struct dev; 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 */ @@ -35,6 +35,7 @@ struct opt { 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; @@ -42,6 +43,12 @@ 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) */ diff --git a/usr.bin/sndiod/siofile.c b/usr.bin/sndiod/siofile.c index 3cc939427b2..48bf8623c25 100644 --- a/usr.bin/sndiod/siofile.c +++ b/usr.bin/sndiod/siofile.c @@ -1,4 +1,4 @@ -/* $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> * @@ -87,24 +87,25 @@ dev_sio_timeout(void *arg) 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; @@ -115,76 +116,16 @@ dev_sio_openalt(struct dev *d, struct dev_alt *n, 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; @@ -195,17 +136,40 @@ dev_sio_open(struct dev *d) 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, @@ -266,7 +230,6 @@ dev_sio_open(struct dev *d) goto bad_close; } #endif - d->par.bits = par.bits; d->par.bps = par.bps; d->par.sig = par.sig; @@ -299,88 +262,6 @@ dev_sio_open(struct dev *d) 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) { @@ -399,7 +280,6 @@ dev_sio_close(struct dev *d) sioctl_close(d->sioctl.hdl); d->sioctl.hdl = NULL; } - d->alt_num = -1; } void @@ -662,6 +542,6 @@ dev_sio_hup(void *arg) log_puts(": disconnected\n"); } #endif - if (!dev_reopen(d)) - dev_abort(d); + dev_migrate(d); + dev_abort(d); } diff --git a/usr.bin/sndiod/siofile.h b/usr.bin/sndiod/siofile.h index 4cebf879730..c34f922d523 100644 --- a/usr.bin/sndiod/siofile.h +++ b/usr.bin/sndiod/siofile.h @@ -1,4 +1,4 @@ -/* $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> * @@ -38,7 +38,6 @@ struct dev_sio { }; 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 *); diff --git a/usr.bin/sndiod/sndiod.c b/usr.bin/sndiod/sndiod.c index ad6a2cce7c3..96088e33c04 100644 --- a/usr.bin/sndiod/sndiod.c +++ b/usr.bin/sndiod/sndiod.c @@ -1,4 +1,4 @@ -/* $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> * @@ -318,8 +318,7 @@ mkdev(char *path, struct aparams *par, 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) { @@ -341,8 +340,7 @@ mkport(char *path, int hold) 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); @@ -385,10 +383,8 @@ static int 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; @@ -424,14 +420,11 @@ start_helper(int background) 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"); @@ -461,10 +454,12 @@ main(int argc, char **argv) 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 { @@ -493,6 +488,8 @@ main(int argc, char **argv) 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; @@ -559,11 +556,17 @@ main(int argc, char **argv) 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(); @@ -584,12 +587,18 @@ main(int argc, char **argv) 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); @@ -612,12 +621,27 @@ main(int argc, char **argv) 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(); @@ -652,6 +676,8 @@ main(int argc, char **argv) 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; @@ -680,10 +706,28 @@ main(int argc, char **argv) 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; @@ -695,6 +739,8 @@ main(int argc, char **argv) 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) diff --git a/usr.bin/sndiod/sock.c b/usr.bin/sndiod/sock.c index c29ea58b621..fcf97cf09fc 100644 --- a/usr.bin/sndiod/sock.c +++ b/usr.bin/sndiod/sock.c @@ -1,4 +1,4 @@ -/* $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> * @@ -101,6 +101,48 @@ struct sock *sock_list = NULL; 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) { @@ -130,7 +172,7 @@ sock_log(struct sock *f) void sock_close(struct sock *f) { - struct dev *d; + struct opt *o; struct sock **pf; unsigned int tags, i; @@ -159,8 +201,8 @@ sock_close(struct sock *f) 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; @@ -818,7 +860,6 @@ sock_hello(struct sock *f) { struct amsg_hello *p = &f->rmsg.u.hello; struct port *c; - struct dev *d; struct opt *opt; unsigned int mode; unsigned int id; @@ -876,21 +917,25 @@ sock_hello(struct sock *f) 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); @@ -899,19 +944,15 @@ sock_hello(struct sock *f) 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) { @@ -926,10 +967,8 @@ sock_hello(struct sock *f) 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); @@ -1582,10 +1621,7 @@ sock_buildmsg(struct sock *f) 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); diff --git a/usr.bin/sndiod/utils.c b/usr.bin/sndiod/utils.c index 118f2366b84..228c57001a5 100644 --- a/usr.bin/sndiod/utils.c +++ b/usr.bin/sndiod/utils.c @@ -1,4 +1,4 @@ -/* $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> * @@ -188,47 +188,3 @@ xstrdup(char *s) 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; -} diff --git a/usr.bin/sndiod/utils.h b/usr.bin/sndiod/utils.h index ef589f673b7..a3ba936e243 100644 --- a/usr.bin/sndiod/utils.h +++ b/usr.bin/sndiod/utils.h @@ -1,4 +1,4 @@ -/* $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> * @@ -36,10 +36,6 @@ void *xmalloc(size_t); 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: * |