From: Alexandre Ratchov Subject: sndio: show the real device name in server.device control To: tech@openbsd.org Date: Thu, 7 Mar 2024 11:33:54 +0100 This diff adds a "display string" to sndio controls, and starts using it to report the device names of the server.device control. Ex: $ sndioctl output.level=1.000 output.mute=0 server.device=6(uaudio2) $ sndioctl -i server.device server.device=0(azalia0),2(envy0),3(envy1),4(uaudio0),5(uaudio1),6(uaudio2) Above strings are simply the driver names. The plan is to change the low-level drivers to report the chipset, the vendor/product name, the codec models, or whatever appropriate; there are preliminary diffs for this. The goal is to avoid having to read the dmesg(8) output and /etc/rc.conf.local to figure out how to get sound from a given piece of hardware. Easing the use of multiple audio devices is almost necessary to work with many USB audio interfaces and will be necessary to enable all azalia(4) codecs (ex. HDMI and digital-only ones). Here's what the diff does: - Add AUDIO_GETDEV ioctl to pledge(4)'s "audio" promise. The ioctl is a simple strlcpy() call in audio(4) copying the driver name. - Add a "char display[]" member to the sioctl_desc structure. To do so, we reuse the padding, which allows binaries linked to the old libsndio to use the new libsndio. So this is a shlib_minor bump, allowing to test this diff without rebuilding all audio ports. - The sndiod(8) network protocol gets a new AMSG_CTLSUB op-code to subscribe to the new version of the control descriptions (with the display string). The old op-code remains, which allows systems or VMs with the old libsndio version (or static binaries) to connect to the new sndiod. - To get the driver names, sndiod needs to open the devices, so server.device will report only *usable* devices, not only the -fF options. This affects the "reopen" logic and as a side effect fixes SIGHUP to do what the man-page says: reopen the devices. Even if that's not required, this diff updates the MIDI bits to behave similarly. This part requires testing. To test this: - rebuild the kernel (to update the pledge(4) promise) - install sndio.h in /usr/include - rebuild and reinstall libsndio - rebuild and reinstall sndiod and sndioctl - reboot Thoughts? OKs? Index: sys/kern/kern_pledge.c =================================================================== RCS file: /cvs/src/sys/kern/kern_pledge.c,v diff -u -p -u -p -r1.310 kern_pledge.c --- sys/kern/kern_pledge.c 12 Dec 2023 17:43:10 -0000 1.310 +++ sys/kern/kern_pledge.c 7 Mar 2024 08:23:30 -0000 @@ -1139,6 +1139,7 @@ pledge_ioctl(struct proc *p, long com, s #if NAUDIO > 0 if ((pledge & PLEDGE_AUDIO)) { switch (com) { + case AUDIO_GETDEV: case AUDIO_GETPOS: case AUDIO_GETPAR: case AUDIO_SETPAR: Index: include/sndio.h =================================================================== RCS file: /cvs/src/include/sndio.h,v diff -u -p -u -p -r1.14 sndio.h --- include/sndio.h 29 Apr 2022 08:30:48 -0000 1.14 +++ include/sndio.h 7 Mar 2024 08:23:30 -0000 @@ -27,8 +27,17 @@ /* * limits + * + * For now SIOCTL_DISPLAYMAX is 12 byte only. It nicely fits in the + * padding of the sioctl_desc structure: this allows any binary linked + * to the library version with no sioctl_desc->display to work with + * this library version. Currently, any string reported by the lower + * layers fits in the 12-byte buffer. Once larger strings start + * being used (or the ABI changes for any other reason) increase + * SIOCTL_DISPLAYMAX and properly pad the sioctl_desc structure. */ #define SIOCTL_NAMEMAX 12 /* max name length */ +#define SIOCTL_DISPLAYMAX 12 /* max display string length */ /* * private ``handle'' structure @@ -115,7 +124,7 @@ struct sioctl_desc { struct sioctl_node node0; /* affected node */ struct sioctl_node node1; /* dito for SIOCTL_{VEC,LIST,SEL} */ unsigned int maxval; /* max value */ - int __pad[3]; + char display[SIOCTL_DISPLAYMAX]; /* free-format hint */ }; /* Index: lib/libsndio/amsg.h =================================================================== RCS file: /cvs/src/lib/libsndio/amsg.h,v diff -u -p -u -p -r1.15 amsg.h --- lib/libsndio/amsg.h 29 Apr 2022 08:30:48 -0000 1.15 +++ lib/libsndio/amsg.h 7 Mar 2024 08:23:30 -0000 @@ -46,6 +46,13 @@ * limits */ #define AMSG_CTL_NAMEMAX 16 /* max name length */ +#define AMSG_CTL_DISPLAYMAX 32 /* max display string length */ + +/* + * Size of the struct amsg_ctl_desc expected by clients + * using the AMSG_CTLSUB_OLD request + */ +#define AMSG_OLD_DESC_SIZE 92 /* * WARNING: since the protocol may be simultaneously used by static @@ -69,9 +76,10 @@ struct amsg { #define AMSG_HELLO 10 /* say hello, check versions and so ... */ #define AMSG_BYE 11 /* ask server to drop connection */ #define AMSG_AUTH 12 /* send authentication cookie */ -#define AMSG_CTLSUB 13 /* ondesc/onctl subscription */ +#define AMSG_CTLSUB_OLD 13 /* amsg_ctl_desc with no "display" attribute */ #define AMSG_CTLSET 14 /* set control value */ #define AMSG_CTLSYNC 15 /* end of controls descriptions */ +#define AMSG_CTLSUB 16 /* ondesc/onctl subscription */ uint32_t cmd; uint32_t __pad; union { @@ -151,7 +159,8 @@ struct amsg_ctl_desc { uint16_t addr; /* control address */ uint16_t maxval; uint16_t curval; - uint32_t __pad2[3]; + uint32_t __pad2[4]; + char display[AMSG_CTL_DISPLAYMAX]; /* free-format hint */ }; /* Index: lib/libsndio/shlib_version =================================================================== RCS file: /cvs/src/lib/libsndio/shlib_version,v diff -u -p -u -p -r1.13 shlib_version --- lib/libsndio/shlib_version 29 Apr 2022 08:30:48 -0000 1.13 +++ lib/libsndio/shlib_version 7 Mar 2024 08:23:30 -0000 @@ -1,2 +1,2 @@ major=7 -minor=2 +minor=3 Index: lib/libsndio/sioctl_aucat.c =================================================================== RCS file: /cvs/src/lib/libsndio/sioctl_aucat.c,v diff -u -p -u -p -r1.1 sioctl_aucat.c --- lib/libsndio/sioctl_aucat.c 26 Feb 2020 13:53:58 -0000 1.1 +++ lib/libsndio/sioctl_aucat.c 7 Mar 2024 08:23:30 -0000 @@ -87,6 +87,7 @@ sioctl_aucat_rdata(struct sioctl_aucat_h strlcpy(desc.node1.name, c->node1.name, SIOCTL_NAMEMAX); desc.node1.unit = (int16_t)ntohs(c->node1.unit); strlcpy(desc.func, c->func, SIOCTL_NAMEMAX); + strlcpy(desc.display, c->display, SIOCTL_DISPLAYMAX); desc.type = c->type; desc.addr = ntohs(c->addr); desc.maxval = ntohs(c->maxval); Index: lib/libsndio/sioctl_open.3 =================================================================== RCS file: /cvs/src/lib/libsndio/sioctl_open.3,v diff -u -p -u -p -r1.13 sioctl_open.3 --- lib/libsndio/sioctl_open.3 3 May 2022 13:03:30 -0000 1.13 +++ lib/libsndio/sioctl_open.3 7 Mar 2024 08:23:30 -0000 @@ -168,6 +168,7 @@ struct sioctl_desc { struct sioctl_node node0; /* affected node */ struct sioctl_node node1; /* dito for SIOCTL_{VEC,LIST,SEL} */ unsigned int maxval; /* max value */ + char display[SIOCTL_DISPLAYMAX]; /* free-format hint */ }; .Ed .Pp @@ -238,6 +239,11 @@ The .Fa maxval attribute indicates the maximum value of this control. For boolean control types it is set to 1. +.Pp +The +.Fa display +attribute contains an optional free-format string providing additional +hints about the control, like the hardware model, or the units. .Ss Changing and reading control values Controls are changed with the .Fn sioctl_setval Index: lib/libsndio/sioctl_sun.c =================================================================== RCS file: /cvs/src/lib/libsndio/sioctl_sun.c,v diff -u -p -u -p -r1.2 sioctl_sun.c --- lib/libsndio/sioctl_sun.c 30 Apr 2020 12:30:47 -0000 1.2 +++ lib/libsndio/sioctl_sun.c 7 Mar 2024 08:23:31 -0000 @@ -53,6 +53,8 @@ struct volume struct sioctl_sun_hdl { struct sioctl_hdl sioctl; + char display[SIOCTL_DISPLAYMAX]; + int display_addr; struct volume output, input; int fd, events; }; @@ -147,6 +149,7 @@ init(struct sioctl_sun_hdl *hdl) {AudioCinputs, AudioNvolume}, {AudioCinputs, AudioNinput} }; + struct audio_device getdev; int i; for (i = 0; i < sizeof(output_names) / sizeof(output_names[0]); i++) { @@ -165,6 +168,13 @@ init(struct sioctl_sun_hdl *hdl) break; } } + + hdl->display_addr = 128; + if (ioctl(hdl->fd, AUDIO_GETDEV, &getdev) == -1) + strlcpy(hdl->display, "unknown", SIOCTL_DISPLAYMAX); + else + strlcpy(hdl->display, getdev.name, SIOCTL_DISPLAYMAX); + DPRINTF("init: server.device: display = %s\n", hdl->display); } static int @@ -407,12 +417,27 @@ static int sioctl_sun_ondesc(struct sioctl_hdl *addr) { struct sioctl_sun_hdl *hdl = (struct sioctl_sun_hdl *)addr; + struct sioctl_desc desc; if (!scanvol(hdl, &hdl->output) || !scanvol(hdl, &hdl->input)) { hdl->sioctl.eof = 1; return 0; } + + /* report "server.device" control */ + memset(&desc, 0, sizeof(struct sioctl_desc)); + desc.type = SIOCTL_SEL; + desc.maxval = 1; + strlcpy(desc.func, "device", SIOCTL_NAMEMAX); + strlcpy(desc.node0.name, "server", SIOCTL_NAMEMAX); + desc.node0.unit = -1; + strlcpy(desc.node1.name, "0", SIOCTL_NAMEMAX); + desc.node1.unit = -1; + strlcpy(desc.display, hdl->display, SIOCTL_DISPLAYMAX); + desc.addr = hdl->display_addr; + _sioctl_ondesc_cb(&hdl->sioctl, &desc, 1); + _sioctl_ondesc_cb(&hdl->sioctl, NULL, 0); return 1; } Index: usr.bin/sndiod/dev.c =================================================================== RCS file: /cvs/src/usr.bin/sndiod/dev.c,v diff -u -p -u -p -r1.107 dev.c --- usr.bin/sndiod/dev.c 9 Dec 2023 22:12:03 -0000 1.107 +++ usr.bin/sndiod/dev.c 7 Mar 2024 08:23:31 -0000 @@ -1055,6 +1055,8 @@ dev_allocbufs(struct dev *d) int dev_open(struct dev *d) { + struct opt *o; + d->mode = d->reqmode; d->round = d->reqround; d->bufsz = d->reqbufsz; @@ -1077,6 +1079,18 @@ dev_open(struct dev *d) return 0; d->pstate = DEV_INIT; + + /* add server.device if device is opened after opt_ref() call */ + for (o = opt_list; o != NULL; o = o->next) { + if (o->refcnt > 0 && !ctl_find(CTL_OPT_DEV, o, d)) { + ctl_new(CTL_OPT_DEV, o, d, + CTL_SEL, dev_getdisplay(d), + o->name, "server", -1, "device", + d->name, -1, 1, o->dev == d); + d->refcnt++; + } + } + return 1; } @@ -1108,7 +1122,7 @@ dev_abort(struct dev *d) if (c->ops == NULL) continue; if (c->opt == o) { - c->ops->exit(s->arg); + c->ops->exit(c->arg); c->ops = NULL; } } @@ -1151,6 +1165,14 @@ dev_freebufs(struct dev *d) void dev_close(struct dev *d) { + struct opt *o; + + /* remove server.device entries */ + for (o = opt_list; o != NULL; o = o->next) { + if (ctl_del(CTL_OPT_DEV, o, d)) + d->refcnt--; + } + d->pstate = DEV_CFG; dev_sio_close(d); dev_freebufs(d); @@ -1777,7 +1799,7 @@ slot_new(struct opt *opt, unsigned int i s->opt = opt; slot_ctlname(s, ctl_name, CTL_NAMEMAX); ctl_new(CTL_SLOT_LEVEL, s, NULL, - CTL_NUM, "app", ctl_name, -1, "level", + CTL_NUM, "", "app", ctl_name, -1, "level", NULL, -1, 127, s->vol); found: @@ -2291,6 +2313,14 @@ ctlslot_visible(struct ctlslot *s, struc return 1; switch (c->scope) { case CTL_HW: + /* + * Disable hardware's server.device control as its + * replaced by sndiod's one + */ + if (strcmp(c->node0.name, "server") == 0 && + strcmp(c->func, "device") == 0) + return 0; + /* FALLTHROUHG */ case CTL_DEV_MASTER: return (s->opt->dev == c->u.any.arg0); case CTL_OPT_DEV: @@ -2404,6 +2434,11 @@ ctl_log(struct ctl *c) default: log_puts("unknown"); } + if (c->display[0] != 0) { + log_puts(" ("); + log_puts(c->display); + log_puts(")"); + } } int @@ -2466,7 +2501,7 @@ ctl_setval(struct ctl *c, int val) */ struct ctl * ctl_new(int scope, void *arg0, void *arg1, - int type, char *gstr, + int type, char *display, char *gstr, char *str0, int unit0, char *func, char *str1, int unit1, int maxval, int val) { @@ -2490,6 +2525,7 @@ ctl_new(int scope, void *arg0, void *arg c->type = type; strlcpy(c->func, func, CTL_NAMEMAX); strlcpy(c->group, gstr, CTL_NAMEMAX); + strlcpy(c->display, display, CTL_DISPLAYMAX); strlcpy(c->node0.name, str0, CTL_NAMEMAX); c->node0.unit = unit0; if (c->type == CTL_VEC || c->type == CTL_LIST || c->type == CTL_SEL) { @@ -2601,16 +2637,18 @@ ctl_onval(int scope, void *arg0, void *a return 1; } -void +int ctl_del(int scope, void *arg0, void *arg1) { struct ctl *c, **pc; + int found; + found = 0; pc = &ctl_list; for (;;) { c = *pc; if (c == NULL) - return; + return found; if (ctl_match(c, scope, arg0, arg1)) { #ifdef DEBUG if (log_level >= 2) { @@ -2618,6 +2656,7 @@ ctl_del(int scope, void *arg0, void *arg log_puts(": removed\n"); } #endif + found++; c->refs_mask &= ~CTL_DEVMASK; if (c->refs_mask == 0) { *pc = c->next; @@ -2632,6 +2671,41 @@ ctl_del(int scope, void *arg0, void *arg } void +dev_setdisplay(struct dev *d, char *display) +{ + struct ctl *c; + + for (c = ctl_list; c != NULL; c = c->next) { + if (c->scope != CTL_OPT_DEV || + c->u.opt_dev.dev != d || + strcmp(c->display, display) == 0) + continue; + strlcpy(c->display, display, CTL_DISPLAYMAX); + c->desc_mask = ~0; + } +} + +char * +dev_getdisplay(struct dev *d) +{ + struct ctl *c; + char *display; + + display = ""; + for (c = ctl_list; c != NULL; c = c->next) { + if (c->scope == CTL_HW && + c->u.hw.dev == d && + c->type == CTL_SEL && + strcmp(c->group, d->name) == 0 && + strcmp(c->node0.name, "server") == 0 && + strcmp(c->func, "device") == 0 && + c->curval == 1) + display = c->display; + } + return display; +} + +void dev_ctlsync(struct dev *d) { struct ctl *c; @@ -2649,6 +2723,8 @@ dev_ctlsync(struct dev *d) found = 1; } + dev_setdisplay(d, dev_getdisplay(d)); + if (d->master_enabled && found) { if (log_level >= 2) { dev_log(d); @@ -2663,7 +2739,7 @@ dev_ctlsync(struct dev *d) } d->master_enabled = 1; ctl_new(CTL_DEV_MASTER, d, NULL, - CTL_NUM, d->name, "output", -1, "level", + CTL_NUM, "", d->name, "output", -1, "level", NULL, -1, 127, d->master); } Index: usr.bin/sndiod/dev.h =================================================================== RCS file: /cvs/src/usr.bin/sndiod/dev.h,v diff -u -p -u -p -r1.43 dev.h --- usr.bin/sndiod/dev.h 26 Dec 2022 19:16:03 -0000 1.43 +++ usr.bin/sndiod/dev.h 7 Mar 2024 08:23:32 -0000 @@ -155,9 +155,11 @@ struct ctl { } u; unsigned int addr; /* slot side control address */ -#define CTL_NAMEMAX 16 /* max name length */ +#define CTL_NAMEMAX 12 /* max name length */ +#define CTL_DISPLAYMAX 24 /* max name length */ char func[CTL_NAMEMAX]; /* parameter function name */ char group[CTL_NAMEMAX]; /* group aka namespace */ + char display[CTL_DISPLAYMAX]; /* free-format hint */ struct ctl_node { char name[CTL_NAMEMAX]; /* stream name */ int unit; @@ -351,8 +353,8 @@ void slot_detach(struct slot *); */ struct ctl *ctl_new(int, void *, void *, - int, char *, char *, int, char *, char *, int, int, int); -void ctl_del(int, void *, void *); + int, char *, char *, char *, int, char *, char *, int, int, int); +int ctl_del(int, void *, void *); void ctl_log(struct ctl *); int ctl_setval(struct ctl *c, int val); int ctl_match(struct ctl *, int, void *, void *); @@ -367,6 +369,8 @@ struct ctl *ctlslot_lookup(struct ctlslo void ctlslot_update(struct ctlslot *); void dev_label(struct dev *, int); +void dev_setdisplay(struct dev *, char *); +char *dev_getdisplay(struct dev *); void dev_ctlsync(struct dev *); #endif /* !defined(DEV_H) */ Index: usr.bin/sndiod/dev_sioctl.c =================================================================== RCS file: /cvs/src/usr.bin/sndiod/dev_sioctl.c,v diff -u -p -u -p -r1.7 dev_sioctl.c --- usr.bin/sndiod/dev_sioctl.c 3 Mar 2021 10:00:27 -0000 1.7 +++ usr.bin/sndiod/dev_sioctl.c 7 Mar 2024 08:23:32 -0000 @@ -70,7 +70,7 @@ dev_sioctl_ondesc(void *arg, struct sioc } ctl_new(CTL_HW, d, &desc->addr, - desc->type, group, + desc->type, desc->display, group, desc->node0.name, desc->node0.unit, desc->func, desc->node1.name, desc->node1.unit, desc->maxval, val); } @@ -89,7 +89,8 @@ dev_sioctl_onval(void *arg, unsigned int log_puts("\n"); for (c = ctl_list; c != NULL; c = c->next) { - if (c->scope != CTL_HW || c->u.hw.addr != addr) + if (c->scope != CTL_HW || c->u.hw.dev != d || + c->u.hw.addr != addr) continue; ctl_log(c); log_puts(": new value -> "); @@ -97,6 +98,14 @@ dev_sioctl_onval(void *arg, unsigned int log_puts("\n"); c->val_mask = ~0U; c->curval = val; + + /* if hardware's server.device changed, update name */ + if (c->type == CTL_SEL && + strcmp(c->group, d->name) == 0 && + strcmp(c->node0.name, "server") == 0 && + strcmp(c->func, "device") == 0 && + c->curval == 1) + dev_setdisplay(d, c->display); } } Index: usr.bin/sndiod/midi.c =================================================================== RCS file: /cvs/src/usr.bin/sndiod/midi.c,v diff -u -p -u -p -r1.29 midi.c --- usr.bin/sndiod/midi.c 1 Nov 2021 14:43:25 -0000 1.29 +++ usr.bin/sndiod/midi.c 7 Mar 2024 08:23:32 -0000 @@ -155,6 +155,23 @@ midi_link(struct midi *ep, struct midi * } /* + * return the list of endpoints the given one receives from + */ +unsigned int +midi_rxmask(struct midi *ep) +{ + int i, rxmask; + + for (rxmask = 0, i = 0; i < MIDI_NEP; i++) { + if ((midi_ep[i].txmask & ep->self) == 0) + continue; + rxmask |= midi_ep[i].self; + } + + return rxmask; +} + +/* * add the midi endpoint in the ``tag'' midi thru box */ void Index: usr.bin/sndiod/midi.h =================================================================== RCS file: /cvs/src/usr.bin/sndiod/midi.h,v diff -u -p -u -p -r1.15 midi.h --- usr.bin/sndiod/midi.h 1 Nov 2021 14:43:25 -0000 1.15 +++ usr.bin/sndiod/midi.h 7 Mar 2024 08:23:32 -0000 @@ -112,6 +112,7 @@ void midi_send(struct midi *, unsigned c void midi_fill(struct midi *); void midi_tag(struct midi *, unsigned int); unsigned int midi_tags(struct midi *); +unsigned int midi_rxmask(struct midi *); void midi_link(struct midi *, struct midi *); void midi_abort(struct midi *); void midi_migrate(struct midi *, struct midi *); Index: usr.bin/sndiod/opt.c =================================================================== RCS file: /cvs/src/usr.bin/sndiod/opt.c,v diff -u -p -u -p -r1.9 opt.c --- usr.bin/sndiod/opt.c 1 Nov 2021 14:43:25 -0000 1.9 +++ usr.bin/sndiod/opt.c 7 Mar 2024 08:23:32 -0000 @@ -346,15 +346,6 @@ opt_del(struct opt *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 @@ -382,6 +373,7 @@ opt_setdev(struct opt *o, struct dev *nd struct ctl *c; struct ctlslot *p; struct slot *s; + char *display; int i; if (!dev_ref(ndev)) @@ -437,6 +429,11 @@ opt_setdev(struct opt *o, struct dev *nd if (c != NULL) { c->curval = 1; c->val_mask = ~0; + display = dev_getdisplay(o->dev); + if (strcmp(c->display, display) != 0) { + strlcpy(c->display, display, CTL_DISPLAYMAX); + c->desc_mask = ~0; + } } /* attach clients to new device */ @@ -496,6 +493,16 @@ opt_ref(struct opt *o) /* if device changed, move everything to the new one */ if (d != o->dev) opt_setdev(o, d); + + /* create server.device control */ + for (d = dev_list; d != NULL; d = d->next) { + if (!dev_ref(d)) + continue; + ctl_new(CTL_OPT_DEV, o, d, + CTL_SEL, dev_getdisplay(d), + o->name, "server", -1, "device", + d->name, -1, 1, o->dev == d); + } } } @@ -509,7 +516,15 @@ opt_ref(struct opt *o) void opt_unref(struct opt *o) { + struct dev *d; + o->refcnt--; - if (o->refcnt == 0) + if (o->refcnt == 0) { + /* delete server.device control */ + for (d = dev_list; d != NULL; d = d->next) { + if (ctl_del(CTL_OPT_DEV, o, d)) + dev_unref(d); + } dev_unref(o->dev); + } } Index: usr.bin/sndiod/siofile.c =================================================================== RCS file: /cvs/src/usr.bin/sndiod/siofile.c,v diff -u -p -u -p -r1.26 siofile.c --- usr.bin/sndiod/siofile.c 29 Apr 2022 08:30:48 -0000 1.26 +++ usr.bin/sndiod/siofile.c 7 Mar 2024 08:23:32 -0000 @@ -84,6 +84,7 @@ dev_sio_timeout(void *arg) dev_log(d); log_puts(": watchdog timeout\n"); + dev_migrate(d); dev_abort(d); } Index: usr.bin/sndiod/sndiod.c =================================================================== RCS file: /cvs/src/usr.bin/sndiod/sndiod.c,v diff -u -p -u -p -r1.48 sndiod.c --- usr.bin/sndiod/sndiod.c 7 Mar 2022 08:58:33 -0000 1.48 +++ usr.bin/sndiod/sndiod.c 7 Mar 2024 08:23:32 -0000 @@ -254,6 +254,79 @@ opt_mode(void) return mode; } +/* + * Open all devices. Possibly switch to the new devices if they have higher + * priorities than the current ones. + */ +static void +dev_reopen(void) +{ + struct opt *o; + struct dev *d, *dpri; + + for (o = opt_list; o != NULL; o = o->next) { + + /* skip unused logical devices and ones with fixed hardware */ + if (o->refcnt == 0 || strcmp(o->name, o->dev->name) == 0) + continue; + + /* open alt devices, find the one with the highest prio */ + dpri = NULL; + d = o->alt_first; + do { + if (d->pstate == DEV_CFG && !dev_open(d)) + continue; + if (dpri == NULL) + dpri = d; + } while ((d = d->alt_next) != o->alt_first); + + /* switch to the alt device with the highest prio */ + if (o->dev != dpri) + opt_setdev(o, dpri); + } +} + +/* + * For each port, open the alt with the highest priority and switch to it + */ +static void +port_reopen(void) +{ + struct port *p, *a, *apri; + int inuse; + + for (p = port_list; p != NULL; p = a->next) { + + /* skip unused ports */ + inuse = 0; + a = p; + while (1) { + if (midi_rxmask(a->midi) || a->midi->txmask) + inuse = 1; + if (a->alt_next == p) + break; + a = a->alt_next; + } + if (!inuse) + continue; + + /* open the alt with the highest prio */ + apri = port_alt_ref(p->num); + + /* switch to it */ + a = p; + while (1) { + if (a != apri) { + midi_migrate(a->midi, apri->midi); + port_unref(a); + } + if (a->alt_next == p) + break; + a = a->alt_next; + } + } +} + void setsig(void) { @@ -461,7 +534,6 @@ 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 opt *o; @@ -712,33 +784,14 @@ main(int argc, char **argv) if (pledge("stdio audio recvfd unix", NULL) == -1) err(1, "pledge"); } + for (;;) { if (quit_flag) break; if (reopen_flag) { reopen_flag = 0; - - 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); - } - } + dev_reopen(); + port_reopen(); } if (!fdpass_peer) break; Index: usr.bin/sndiod/sock.c =================================================================== RCS file: /cvs/src/usr.bin/sndiod/sock.c,v diff -u -p -u -p -r1.47 sock.c --- usr.bin/sndiod/sock.c 26 Dec 2022 19:16:03 -0000 1.47 +++ usr.bin/sndiod/sock.c 7 Mar 2024 08:23:33 -0000 @@ -33,7 +33,7 @@ #include "sock.h" #include "utils.h" -#define SOCK_CTLDESC_SIZE 16 /* number of entries in s->ctldesc */ +#define SOCK_CTLDESC_SIZE 0x800 /* size of s->ctldesc */ void sock_log(struct sock *); void sock_close(struct sock *); @@ -626,8 +626,7 @@ sock_wdata(struct sock *f) else if (f->midi) data = abuf_rgetblk(&f->midi->obuf, &count); else { - data = (unsigned char *)f->ctldesc + - (f->wsize - f->wtodo); + data = f->ctldesc + (f->wsize - f->wtodo); count = f->wtodo; } if (count > f->wtodo) @@ -961,8 +960,7 @@ sock_hello(struct sock *f) } return 0; } - f->ctldesc = xmalloc(SOCK_CTLDESC_SIZE * - sizeof(struct amsg_ctl_desc)); + f->ctldesc = xmalloc(SOCK_CTLDESC_SIZE); f->ctlops = 0; f->ctlsyncpending = 0; return 1; @@ -989,8 +987,10 @@ sock_execmsg(struct sock *f) struct amsg *m = &f->rmsg; unsigned char *data; int size, ctl; + int cmd; - switch (ntohl(m->cmd)) { + cmd = ntohl(m->cmd); + switch (cmd) { case AMSG_DATA: #ifdef DEBUG if (log_level >= 4) { @@ -1284,6 +1284,7 @@ sock_execmsg(struct sock *f) dev_midi_vol(s->opt->dev, s); ctl_onval(CTL_SLOT_LEVEL, s, NULL, ctl); break; + case AMSG_CTLSUB_OLD: case AMSG_CTLSUB: #ifdef DEBUG if (log_level >= 3) { @@ -1316,6 +1317,9 @@ sock_execmsg(struct sock *f) } f->ctlops |= SOCK_CTLDESC; f->ctlsyncpending = 1; + f->ctl_desc_size = (cmd == AMSG_CTLSUB) ? + sizeof(struct amsg_ctl_desc) : + AMSG_OLD_DESC_SIZE; } } else f->ctlops &= ~SOCK_CTLDESC; @@ -1604,7 +1608,6 @@ sock_buildmsg(struct sock *f) * searching for the {desc,val}_mask bits */ if (f->ctlslot && (f->ctlops & SOCK_CTLDESC)) { - desc = f->ctldesc; mask = f->ctlslot->self; size = 0; pc = &ctl_list; @@ -1614,9 +1617,9 @@ sock_buildmsg(struct sock *f) pc = &c->next; continue; } - if (size == SOCK_CTLDESC_SIZE * - sizeof(struct amsg_ctl_desc)) + if (size + f->ctl_desc_size > SOCK_CTLDESC_SIZE) break; + desc = (struct amsg_ctl_desc *)(f->ctldesc + size); c->desc_mask &= ~mask; c->val_mask &= ~mask; type = ctlslot_visible(f->ctlslot, c) ? @@ -1633,8 +1636,14 @@ sock_buildmsg(struct sock *f) desc->addr = htons(c->addr); desc->maxval = htons(c->maxval); desc->curval = htons(c->curval); - size += sizeof(struct amsg_ctl_desc); - desc++; + + /* old clients don't have the 'display' member */ + if (f->ctl_desc_size >= offsetof(struct amsg_ctl_desc, + display) + AMSG_CTL_DISPLAYMAX) { + strlcpy(desc->display, c->display, AMSG_CTL_DISPLAYMAX); + } + + size += f->ctl_desc_size; /* if this is a deleted entry unref it */ if (type == CTL_NONE) { @@ -1660,6 +1669,7 @@ sock_buildmsg(struct sock *f) log_puts(": building control DATA message\n"); } #endif + f->ctlsyncpending = 1; return 1; } } Index: usr.bin/sndiod/sock.h =================================================================== RCS file: /cvs/src/usr.bin/sndiod/sock.h,v diff -u -p -u -p -r1.7 sock.h --- usr.bin/sndiod/sock.h 26 Apr 2020 14:13:22 -0000 1.7 +++ usr.bin/sndiod/sock.h 7 Mar 2024 08:23:33 -0000 @@ -59,7 +59,8 @@ struct sock { struct midi *midi; /* midi endpoint */ struct port *port; /* midi port */ struct ctlslot *ctlslot; - struct amsg_ctl_desc *ctldesc; /* temporary buffer */ + unsigned char *ctldesc; /* temporary buffer */ + size_t ctl_desc_size; /* size of client amsg_ctl_desc */ #define SOCK_CTLDESC 1 /* dump desc and send changes */ #define SOCK_CTLVAL 2 /* send value changes */ unsigned int ctlops; /* bitmap of above */ Index: usr.bin/sndioctl/sndioctl.c =================================================================== RCS file: /cvs/src/usr.bin/sndioctl/sndioctl.c,v diff -u -p -u -p -r1.19 sndioctl.c --- usr.bin/sndioctl/sndioctl.c 31 Jan 2023 21:38:01 -0000 1.19 +++ usr.bin/sndioctl/sndioctl.c 7 Mar 2024 08:23:33 -0000 @@ -47,6 +47,7 @@ int matchpar(struct info *, char *, int) int matchent(struct info *, char *, int); int ismono(struct info *); void print_node(struct sioctl_node *, int); +void print_display(struct info *); void print_desc(struct info *, int); void print_num(struct info *); void print_ent(struct info *, char *); @@ -310,6 +311,9 @@ ismono(struct info *g) continue; if (e1->curval != e2->curval) return 0; + if (strcmp(e1->desc.display, + e2->desc.display) != 0) + return 0; } } } @@ -330,6 +334,28 @@ print_node(struct sioctl_node *c, int mo } /* + * print display string, with '(' and ')' and non-printable chars removed + * in order to match command syntax + */ +void +print_display(struct info *p) +{ + char buf[SIOCTL_NAMEMAX], *s, *d; + unsigned int c; + + s = p->desc.display; + d = buf; + while ((c = *s++) != 0) { + if (c == '(' || c == ')' || c < ' ') + continue; + *d++ = c; + } + *d = 0; + if (buf[0] != 0) + printf("(%s)", buf); +} + +/* * print info about the parameter */ void @@ -342,6 +368,7 @@ print_desc(struct info *p, int mono) case SIOCTL_NUM: case SIOCTL_SW: printf("*"); + print_display(p); break; case SIOCTL_SEL: case SIOCTL_VEC: @@ -359,6 +386,8 @@ print_desc(struct info *p, int mono) print_node(&e->desc.node1, mono); if (p->desc.type != SIOCTL_SEL) printf(":*"); + if (e->desc.display[0] != 0) + print_display(e); more = 1; } } @@ -404,6 +433,7 @@ print_ent(struct info *e, char *comment) case SIOCTL_NUM: print_num(e); } + print_display(e); if (comment) printf("\t# %s", comment); printf("\n"); @@ -422,6 +452,7 @@ print_val(struct info *p, int mono) case SIOCTL_NUM: case SIOCTL_SW: print_num(p); + print_display(p); break; case SIOCTL_SEL: case SIOCTL_VEC: @@ -439,6 +470,7 @@ print_val(struct info *p, int mono) if (more) printf(","); print_node(&e->desc.node1, mono); + print_display(e); more = 1; } } else { @@ -447,6 +479,7 @@ print_val(struct info *p, int mono) print_node(&e->desc.node1, mono); printf(":"); print_num(e); + print_display(e); more = 1; } } @@ -631,6 +664,7 @@ dump(void) print_node(&i->desc.node1, 0); printf(":0..%d (%u)", i->desc.maxval, i->curval); } + print_display(i); printf("\n"); } } @@ -753,6 +787,12 @@ cmd(char *line) } } } + if (*pos == '(') { + while (*pos != 0) { + if (*pos++ == ')') + break; + } + } if (nent == 0) { /* XXX: use print_node()-like routine */ fprintf(stderr, "%s[%d]: invalid value\n", vstr, vunit); @@ -879,12 +919,7 @@ ondesc(void *arg, struct sioctl_desc *d, */ for (pi = &infolist; (i = *pi) != NULL; pi = &i->next) { cmp = cmpdesc(d, &i->desc); - if (cmp == 0) { - fprintf(stderr, "fatal: duplicate control:\n"); - print_ent(i, "duplicate"); - exit(1); - } - if (cmp < 0) + if (cmp <= 0) break; } i = malloc(sizeof(struct info));