On Fri, Jan 29, 2021 at 12:42:37PM +0100, Alexandre Ratchov wrote:
> Moving to a global server-wide controls list is necessary to expose
> controls that are not associated to a particular device (ex. a device
> selector).
> 
> The current hack to use the device-side sioctl_desc->addr variable as
> client-side key can't work anymore. So, we use a unique dynamically
> allocated ctl->addr key; this is which much cleaner. A new "scope"
> enum (with two "void *" arguments) is used to determine what the
> control does control. This adds a lot of flexibility and allows to
> easily add new control types that are not associated to devices.
> 
> The diff touches many parts of the code and is quite big. Please test
> and report regressions.
> 

Thanks for the feedback, new diff below. It fixes a server crash when
a client issues an invalid request.

Index: dev.c
===================================================================
RCS file: /cvs/src/usr.bin/sndiod/dev.c,v
retrieving revision 1.89
diff -u -p -u -p -r1.89 dev.c
--- dev.c       29 Jan 2021 11:38:23 -0000      1.89
+++ dev.c       29 Jan 2021 15:15:38 -0000
@@ -106,6 +106,7 @@ struct slotops zomb_slotops = {
        zomb_exit
 };
 
+struct ctl *ctl_list = NULL;
 struct dev *dev_list = NULL;
 unsigned int dev_sndnum = 0;
 
@@ -370,12 +371,14 @@ dev_midi_master(struct dev *d)
                master = d->master;
        else {
                master = 0;
-               for (c = d->ctl_list; c != NULL; c = c->next) {
+               for (c = ctl_list; c != NULL; c = c->next) {
                        if (c->type != CTL_NUM ||
-                           strcmp(c->group, "") != 0 ||
+                           strcmp(c->group, d->name) != 0 ||
                            strcmp(c->node0.name, "output") != 0 ||
                            strcmp(c->func, "level") != 0)
                                continue;
+                       if (c->u.any.arg0 != d)
+                               continue;
                        v = (c->curval * 127 + c->maxval / 2) / c->maxval;
                        if (master < v)
                                master = v;
@@ -465,7 +468,7 @@ dev_midi_omsg(void *arg, unsigned char *
                    slot_array[chan].opt->dev != d)
                        return;
                slot_setvol(slot_array + chan, msg[2]);
-               dev_onval(d, CTLADDR_SLOT_LEVEL(chan), msg[2]);
+               ctl_onval(CTL_SLOT_LEVEL, slot_array + chan, NULL, msg[2]);
                return;
        }
        x = (struct sysex *)msg;
@@ -479,7 +482,7 @@ dev_midi_omsg(void *arg, unsigned char *
                        if (len == SYSEX_SIZE(master)) {
                                dev_master(d, x->u.master.coarse);
                                if (d->master_enabled) {
-                                       dev_onval(d, CTLADDR_MASTER,
+                                       ctl_onval(CTL_DEV_MASTER, d, NULL,
                                           x->u.master.coarse);
                                }
                        }
@@ -1005,14 +1008,16 @@ dev_master(struct dev *d, unsigned int m
                if (d->mode & MODE_PLAY)
                        dev_mix_adjvol(d);
        } else {
-               for (c = d->ctl_list; c != NULL; c = c->next) {
+               for (c = ctl_list; c != NULL; c = c->next) {
+                       if (c->scope != CTL_HW || c->u.hw.dev != d)
+                               continue;
                        if (c->type != CTL_NUM ||
-                           strcmp(c->group, "") != 0 ||
+                           strcmp(c->group, d->name) != 0 ||
                            strcmp(c->node0.name, "output") != 0 ||
                            strcmp(c->func, "level") != 0)
                                continue;
                        v = (master * c->maxval + 64) / 127;
-                       dev_setctl(d, c->addr, v);
+                       ctl_setval(c, v);
                }
        }
 }
@@ -1070,7 +1075,7 @@ dev_new(char *path, struct aparams *par,
        d->master = MIDI_MAXCTL;
        d->mtc.origin = 0;
        d->tstate = MMC_STOP;
-       d->ctl_list = NULL;
+       snprintf(d->name, CTL_NAMEMAX, "%u", d->num);
        d->next = dev_list;
        dev_list = d;
        return d;
@@ -1208,10 +1213,8 @@ dev_allocbufs(struct dev *d)
 int
 dev_open(struct dev *d)
 {
-       int i;
        char name[CTL_NAMEMAX];
        struct dev_alt *a;
-       struct slot *s;
 
        d->master_enabled = 0;
        d->mode = d->reqmode;
@@ -1235,23 +1238,12 @@ dev_open(struct dev *d)
        if (!dev_allocbufs(d))
                return 0;
 
-       for (i = 0, s = slot_array; i < DEV_NSLOT; i++, s++) {
-               if (s->opt == NULL || s->opt->dev != d || s->name[0] == 0)
-                       continue;
-               slot_ctlname(s, name, CTL_NAMEMAX);
-               dev_addctl(d, "app", CTL_NUM,
-                   CTLADDR_SLOT_LEVEL(i),
-                   name, -1, "level",
-                   NULL, -1, 127, s->vol);
-       }
-
        /* 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);
-                       dev_addctl(d, "", CTL_SEL,
-                           CTLADDR_ALT_SEL + a->idx,
-                           "server", -1, "device",
+                       ctl_new(CTL_DEV_ALT, d, &a->idx,
+                           CTL_SEL, d->name, "server", -1, "device",
                            name, -1, 1, a->idx == d->alt_num);
                }
        }
@@ -1326,17 +1318,19 @@ dev_freebufs(struct dev *d)
 void
 dev_close(struct dev *d)
 {
-       struct ctl *c;
+       struct dev_alt *a;
+       unsigned int idx;
 
        d->pstate = DEV_CFG;
        dev_sio_close(d);
        dev_freebufs(d);
 
-       /* there are no clients, just free remaining local controls */
-       while ((c = d->ctl_list) != NULL) {
-               d->ctl_list = c->next;
-               xfree(c);
+       if (d->master_enabled) {
+               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);
 }
 
 /*
@@ -2325,8 +2319,11 @@ ctlslot_new(struct opt *o, struct ctlops
                return NULL;
        s->ops = ops;
        s->arg = arg;
-       for (c = o->dev->ctl_list; c != NULL; c = c->next)
+       for (c = ctl_list; c != NULL; c = c->next) {
+               if (!ctlslot_visible(s, c))
+                       continue;
                c->refs_mask |= s->self;
+       }
        return s;
 }
 
@@ -2338,7 +2335,7 @@ ctlslot_del(struct ctlslot *s)
 {
        struct ctl *c, **pc;
 
-       pc = &s->opt->dev->ctl_list;
+       pc = &ctl_list;
        while ((c = *pc) != NULL) {
                c->refs_mask &= ~s->self;
                if (c->refs_mask == 0) {
@@ -2351,6 +2348,41 @@ ctlslot_del(struct ctlslot *s)
        dev_unref(s->opt->dev);
 }
 
+int
+ctlslot_visible(struct ctlslot *s, struct ctl *c)
+{
+       if (s->opt == NULL)
+               return 1;
+       switch (c->scope) {
+       case CTL_HW:
+       case CTL_DEV_MASTER:
+       case CTL_DEV_ALT:
+               return (s->opt->dev == c->u.any.arg0);
+       case CTL_SLOT_LEVEL:
+               return (s->opt->dev == c->u.slot_level.slot->opt->dev);
+       default:
+               return 0;
+       }
+}
+
+struct ctl *
+ctlslot_lookup(struct ctlslot *s, int addr)
+{
+       struct ctl *c;
+
+       c = ctl_list;
+       while (1) {
+               if (c == NULL)
+                       return NULL;
+               if (c->type != CTL_NONE && c->addr == addr)
+                       break;
+               c = c->next;
+       }
+       if (!ctlslot_visible(s, c))
+               return NULL;
+       return c;
+}
+
 void
 ctl_node_log(struct ctl_node *c)
 {
@@ -2387,18 +2419,112 @@ ctl_log(struct ctl *c)
        }
        log_puts(" at ");
        log_putu(c->addr);
+       log_puts(" -> ");
+       switch (c->scope) {
+       case CTL_HW:
+               log_puts("hw:");
+               log_puts(c->u.hw.dev->name);
+               log_puts("/");
+               log_putu(c->u.hw.addr);
+               break;
+       case CTL_DEV_MASTER:
+               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;
+       default:
+               log_puts("unknown");
+       }
+}
+
+int
+ctl_setval(struct ctl *c, int val)
+{
+       if (c->curval == val) {
+               if (log_level >= 3) {
+                       ctl_log(c);
+                       log_puts(": already set\n");
+               }
+               return 1;
+       }
+       if (val < 0 || val > c->maxval) {
+               if (log_level >= 3) {
+                       log_putu(val);
+                       log_puts(": ctl val out of bounds\n");
+               }
+               return 0;
+       }
+
+       switch (c->scope) {
+       case CTL_HW:
+               if (log_level >= 3) {
+                       ctl_log(c);
+                       log_puts(": marked as dirty\n");
+               }
+               c->curval = val;
+               c->dirty = 1;
+               return dev_ref(c->u.hw.dev);
+       case CTL_DEV_MASTER:
+               if (!c->u.dev_master.dev->master_enabled)
+                       return 1;
+               dev_master(c->u.dev_master.dev, val);
+               dev_midi_master(c->u.dev_master.dev);
+               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()
+               dev_midi_vol(c->u.slot_level.slot->opt->dev, 
c->u.slot_level.slot);
+               c->val_mask = ~0U;
+               c->curval = val;
+               return 1;
+       default:
+               if (log_level >= 2) {
+                       ctl_log(c);
+                       log_puts(": not writable\n");
+               }
+               return 1;
+       }
 }
 
 /*
  * add a ctl
  */
 struct ctl *
-dev_addctl(struct dev *d, char *gstr, int type, int addr,
-    char *str0, int unit0, char *func, char *str1, int unit1, int maxval, int 
val)
+ctl_new(int scope, void *arg0, void *arg1,
+    int type, char *gstr,
+    char *str0, int unit0, char *func,
+    char *str1, int unit1, int maxval, int val)
 {
        struct ctl *c, **pc;
+       struct ctlslot *s;
+       int addr;
        int i;
 
+       /*
+        * find the smallest unused addr number and
+        * the last position in the list
+        */
+       addr = 0;
+       for (pc = &ctl_list; (c = *pc) != NULL; pc = &c->next) {
+               if (c->addr > addr)
+                       addr = c->addr;
+       }
+       addr++;
+
        c = xmalloc(sizeof(struct ctl));
        c->type = type;
        strlcpy(c->func, func, CTL_NAMEMAX);
@@ -2410,65 +2536,138 @@ dev_addctl(struct dev *d, char *gstr, in
                c->node1.unit = unit1;
        } else
                memset(&c->node1, 0, sizeof(struct ctl_node));
+       c->scope = scope;
+       c->u.any.arg0 = arg0;
+       switch (scope) {
+       case CTL_HW:
+               c->u.hw.addr = *(unsigned int *)arg1;
+               break;
+       case CTL_DEV_ALT:
+               c->u.dev_alt.idx = *(unsigned int *)arg1;
+               break;
+       default:
+               c->u.any.arg1 = NULL;
+       }
        c->addr = addr;
        c->maxval = maxval;
        c->val_mask = ~0;
        c->desc_mask = ~0;
        c->curval = val;
        c->dirty = 0;
-       c->refs_mask = 0;
-       for (i = 0; i < DEV_NCTLSLOT; i++) {
-               c->refs_mask |= CTL_DEVMASK;
-               if (ctlslot_array[i].ops != NULL)
+       c->refs_mask = CTL_DEVMASK;
+       for (s = ctlslot_array, i = 0; i < DEV_NCTLSLOT; i++, s++) {
+               if (s->ops == NULL)
+                       continue;
+               if (ctlslot_visible(s, c))
                        c->refs_mask |= 1 << i;
        }
-       for (pc = &d->ctl_list; *pc != NULL; pc = &(*pc)->next)
-               ; /* nothing */
-       c->next = NULL;
+       c->next = *pc;
        *pc = c;
 #ifdef DEBUG
-       if (log_level >= 3) {
-               dev_log(d);
-               log_puts(": adding ");
+       if (log_level >= 2) {
                ctl_log(c);
-               log_puts("\n");
+               log_puts(": added\n");
        }
 #endif
        return c;
 }
 
 void
-dev_rmctl(struct dev *d, int addr)
+ctl_update(struct ctl *c)
+{
+       struct ctlslot *s;
+       unsigned int refs_mask;
+       int i;
+
+       for (s = ctlslot_array, i = 0; i < DEV_NCTLSLOT; i++, s++) {
+               if (s->ops == NULL)
+                       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;
+       }
+}
+
+int
+ctl_match(struct ctl *c, int scope, void *arg0, void *arg1)
+{
+       if (c->type == CTL_NONE || c->scope != scope || c->u.any.arg0 != arg0)
+               return 0;
+       if (arg0 != NULL && c->u.any.arg0 != arg0)
+               return 0;
+       switch (scope) {
+       case CTL_HW:
+               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)
+                       return 0;
+               break;
+       }
+       return 1;
+}
+
+struct ctl *
+ctl_find(int scope, void *arg0, void *arg1)
+{
+       struct ctl *c;
+
+       for (c = ctl_list; c != NULL; c = c->next) {
+               if (ctl_match(c, scope, arg0, arg1))
+                       return c;
+       }
+       return NULL;
+}
+
+int
+ctl_onval(int scope, void *arg0, void *arg1, int val)
+{
+       struct ctl *c;
+
+       c = ctl_find(scope, arg0, arg1);
+       if (c == NULL)
+               return 0;
+       c->curval = val;
+       c->val_mask = ~0U;
+       return 1;
+}
+
+void
+ctl_del(int scope, void *arg0, void *arg1)
 {
        struct ctl *c, **pc;
 
-       pc = &d->ctl_list;
+       pc = &ctl_list;
        for (;;) {
                c = *pc;
                if (c == NULL)
                        return;
-               if (c->type != CTL_NONE && c->addr == addr)
-                       break;
-               pc = &c->next;
-       }
-       c->type = CTL_NONE;
+               if (ctl_match(c, scope, arg0, arg1)) {
 #ifdef DEBUG
-       if (log_level >= 3) {
-               dev_log(d);
-               log_puts(": removing ");
-               ctl_log(c);
-               log_puts(", refs_mask = 0x");
-               log_putx(c->refs_mask);
-               log_puts("\n");
-       }
+                       if (log_level >= 2) {
+                               ctl_log(c);
+                               log_puts(": removed\n");
+                       }
 #endif
-       c->refs_mask &= ~CTL_DEVMASK;
-       if (c->refs_mask == 0) {
-               *pc = c->next;
-               xfree(c);
-               return;
+                       c->refs_mask &= ~CTL_DEVMASK;
+                       if (c->refs_mask == 0) {
+                               *pc = c->next;
+                               xfree(c);
+                               continue;
+                       }
+                       c->type = CTL_NONE;
+                       c->desc_mask = ~0;
+               }
+               pc = &c->next;
        }
-       c->desc_mask = ~0;
 }
 
 void
@@ -2479,10 +2678,11 @@ dev_ctlsync(struct dev *d)
        int found, i;
 
        found = 0;
-       for (c = d->ctl_list; c != NULL; c = c->next) {
-               if (c->addr != CTLADDR_MASTER &&
+       for (c = ctl_list; c != NULL; c = c->next) {
+               if (c->scope == CTL_HW &&
+                   c->u.hw.dev == d &&
                    c->type == CTL_NUM &&
-                   strcmp(c->group, "") == 0 &&
+                   strcmp(c->group, d->name) == 0 &&
                    strcmp(c->node0.name, "output") == 0 &&
                    strcmp(c->func, "level") == 0)
                        found = 1;
@@ -2494,15 +2694,16 @@ dev_ctlsync(struct dev *d)
                        log_puts(": software master level control disabled\n");
                }
                d->master_enabled = 0;
-               dev_rmctl(d, CTLADDR_MASTER);
+               ctl_del(CTL_DEV_MASTER, d, NULL);
        } else if (!d->master_enabled && !found) {
                if (log_level >= 2) {
                        dev_log(d);
                        log_puts(": software master level control enabled\n");
                }
                d->master_enabled = 1;
-               dev_addctl(d, "", CTL_NUM, CTLADDR_MASTER,
-                   "output", -1, "level", NULL, -1, 127, d->master);
+               ctl_new(CTL_DEV_MASTER, d, NULL,
+                   CTL_NUM, d->name, "output", -1, "level",
+                   NULL, -1, 127, d->master);
        }
 
        for (s = ctlslot_array, i = DEV_NCTLSLOT; i > 0; i--, s++) {
@@ -2511,95 +2712,6 @@ dev_ctlsync(struct dev *d)
        }
 }
 
-int
-dev_setctl(struct dev *d, int addr, int val)
-{
-       struct ctl *c;
-       struct slot *s;
-       int num;
-
-       c = d->ctl_list;
-       for (;;) {
-               if (c == NULL) {
-                       if (log_level >= 3) {
-                               dev_log(d);
-                               log_puts(": ");
-                               log_putu(addr);
-                               log_puts(": no such ctl address\n");
-                       }
-                       return 0;
-               }
-               if (c->type != CTL_NONE && c->addr == addr)
-                       break;
-               c = c->next;
-       }
-       if (c->curval == val) {
-               if (log_level >= 3) {
-                       ctl_log(c);
-                       log_puts(": already set\n");
-               }
-               return 1;
-       }
-       if (val < 0 || val > c->maxval) {
-               if (log_level >= 3) {
-                       dev_log(d);
-                       log_puts(": ");
-                       log_putu(val);
-                       log_puts(": ctl val out of bounds\n");
-               }
-               return 0;
-       }
-       if (addr >= CTLADDR_END) {
-               if (log_level >= 3) {
-                       ctl_log(c);
-                       log_puts(": marked as dirty\n");
-               }
-               c->dirty = 1;
-               dev_ref(d);
-       } else {
-               if (addr >= CTLADDR_ALT_SEL) {
-                       if (val) {
-                               num = addr - CTLADDR_ALT_SEL;
-                               dev_setalt(d, num);
-                       }
-                       return 1;
-               } else if (addr == CTLADDR_MASTER) {
-                       if (d->master_enabled) {
-                               dev_master(d, val);
-                               dev_midi_master(d);
-                       }
-               } else {
-                       num = addr - CTLADDR_SLOT_LEVEL(0);
-                       s = slot_array + num;
-                       if (s->opt->dev != d)
-                               return 1;
-                       slot_setvol(s, val);
-                       dev_midi_vol(d, s);
-               }
-               c->val_mask = ~0U;
-       }
-       c->curval = val;
-       return 1;
-}
-
-int
-dev_onval(struct dev *d, int addr, int val)
-{
-       struct ctl *c;
-
-       c = d->ctl_list;
-       for (;;) {
-               if (c == NULL)
-                       return 0;
-               if (c->type != CTL_NONE && c->addr == addr)
-                       break;
-               c = c->next;
-       }
-       c->curval = val;
-       c->val_mask = ~0U;
-       return 1;
-}
-
 void
 dev_label(struct dev *d, int i)
 {
@@ -2608,16 +2720,15 @@ dev_label(struct dev *d, int i)
 
        slot_ctlname(&slot_array[i], name, CTL_NAMEMAX);
 
-       c = d->ctl_list;
+       c = ctl_list;
        for (;;) {
                if (c == NULL) {
-                       dev_addctl(d, "app", CTL_NUM,
-                           CTLADDR_SLOT_LEVEL(i),
-                           name, -1, "level",
+                       ctl_new(CTL_SLOT_LEVEL, slot_array + i, NULL,
+                           CTL_NUM, "app", name, -1, "level",
                            NULL, -1, 127, slot_array[i].vol);
                        return;
                }
-               if (c->addr == CTLADDR_SLOT_LEVEL(i))
+               if (ctl_match(c, CTL_SLOT_LEVEL, slot_array + i, NULL))
                        break;
                c = c->next;
        }
Index: dev.h
===================================================================
RCS file: /cvs/src/usr.bin/sndiod/dev.h,v
retrieving revision 1.37
diff -u -p -u -p -r1.37 dev.h
--- dev.h       29 Jan 2021 11:38:23 -0000      1.37
+++ dev.h       29 Jan 2021 15:15:38 -0000
@@ -22,11 +22,6 @@
 #include "siofile.h"
 #include "dev_sioctl.h"
 
-#define CTLADDR_SLOT_LEVEL(n)  (n)
-#define CTLADDR_MASTER         (DEV_NSLOT)
-#define CTLADDR_ALT_SEL                (CTLADDR_MASTER + 1)
-#define CTLADDR_END            (CTLADDR_ALT_SEL + DEV_NMAX)
-
 /*
  * preallocated audio clients
  */
@@ -119,6 +114,7 @@ struct slot {
 
 struct ctl {
        struct ctl *next;
+
 #define CTL_NONE       0               /* deleted */
 #define CTL_NUM                2               /* number (aka integer value) */
 #define CTL_SW         3               /* on/off switch, only bit 7 counts */
@@ -126,7 +122,34 @@ struct ctl {
 #define CTL_LIST       5               /* switch, element of a list */
 #define CTL_SEL                6               /* element of a selector */
        unsigned int type;              /* one of above */
-       unsigned int addr;              /* control address */
+
+#define CTL_HW         0
+#define CTL_DEV_MASTER 1
+#define CTL_DEV_ALT    2
+#define CTL_SLOT_LEVEL 3
+       unsigned int scope;
+       union {
+               struct {
+                       void *arg0;
+                       void *arg1;
+               } any;
+               struct {
+                       struct dev *dev;
+                       unsigned int addr;
+               } hw;
+               struct {
+                       struct dev *dev;
+               } dev_master;
+               struct {
+                       struct dev *dev;
+                       unsigned int idx;
+               } dev_alt;
+               struct {
+                       struct slot *slot;
+               } slot_level;
+       } u;
+
+       unsigned int addr;              /* slot side control address */
 #define CTL_NAMEMAX    16              /* max name lenght */
        char func[CTL_NAMEMAX];         /* parameter function name */
        char group[CTL_NAMEMAX];        /* group aka namespace */
@@ -161,6 +184,11 @@ struct dev {
        struct midi *midi;
 
        /*
+        * name used for various controls
+        */
+       char name[CTL_NAMEMAX];
+
+       /*
         * audio device (while opened)
         */
        struct dev_sio sio;
@@ -243,15 +271,10 @@ struct dev {
 
        unsigned int master;                    /* software vol. knob */
        unsigned int master_enabled;            /* 1 if h/w has no vo. knob */
-
-       /*
-        * control
-        */
-
-       struct ctl *ctl_list;
 };
 
 extern struct dev *dev_list;
+extern struct ctl *ctl_list;
 extern struct slot slot_array[DEV_NSLOT];
 extern struct ctlslot ctlslot_array[DEV_NCTLSLOT];
 
@@ -307,17 +330,22 @@ void slot_detach(struct slot *);
 /*
  * control related functions
  */
+
+struct ctl *ctl_new(int, void *, void *,
+    int, char *, char *, int, char *, char *, int, int, int);
+void 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 *);
+struct ctl *ctl_find(int, void *, void *);
+void ctl_update(struct ctl *);
+int ctl_onval(int, void *, void *, int);
+
 struct ctlslot *ctlslot_new(struct opt *, struct ctlops *, void *);
 void ctlslot_del(struct ctlslot *);
-int dev_setctl(struct dev *, int, int);
-int dev_onval(struct dev *, int, int);
-int dev_nctl(struct dev *);
+int ctlslot_visible(struct ctlslot *, struct ctl *);
+struct ctl *ctlslot_lookup(struct ctlslot *, int);
 void dev_label(struct dev *, int);
-struct ctl *dev_addctl(struct dev *, char *, int, int,
-    char *, int, char *, char *, int, int, int);
-void dev_rmctl(struct dev *, int);
-int dev_makeunit(struct dev *, char *);
 void dev_ctlsync(struct dev *);
 
 #endif /* !defined(DEV_H) */
Index: dev_sioctl.c
===================================================================
RCS file: /cvs/src/usr.bin/sndiod/dev_sioctl.c,v
retrieving revision 1.6
diff -u -p -u -p -r1.6 dev_sioctl.c
--- dev_sioctl.c        28 Jun 2020 05:21:39 -0000      1.6
+++ dev_sioctl.c        29 Jan 2021 15:15:38 -0000
@@ -50,34 +50,27 @@ struct fileops dev_sioctl_ops = {
 void
 dev_sioctl_ondesc(void *arg, struct sioctl_desc *desc, int val)
 {
-#define GROUP_PREFIX           "hw"
-       char group_buf[CTL_NAMEMAX], *group;
        struct dev *d = arg;
-       int addr;
+       char *group, group_buf[CTL_NAMEMAX];
 
        if (desc == NULL) {
                dev_ctlsync(d);
                return;
        }
 
-       addr = CTLADDR_END + desc->addr;
-       dev_rmctl(d, addr);
+       ctl_del(CTL_HW, d, &desc->addr);
 
-       /*
-        * prefix with "hw/" group names of controls we expose, to
-        * ensure that all controls have unique names when multiple
-        * sndiod's are chained
-        */
-       if (strcmp(desc->group, "app") == 0 || (desc->group[0] == 0 &&
-           strcmp(desc->node0.name, "server") == 0)) {
-               group = group_buf;
-               if (snprintf(group_buf, CTL_NAMEMAX, GROUP_PREFIX "/%s",
-                   desc->group) >= CTL_NAMEMAX)
+       if (desc->group[0] == 0)
+               group = d->name;
+       else {
+               if (snprintf(group_buf, CTL_NAMEMAX, "%s/%s",
+                       d->name, desc->group) >= CTL_NAMEMAX)
                        return;
-       } else
-               group = desc->group;
+               group = group_buf;
+       }
 
-       dev_addctl(d, group, desc->type, addr,
+       ctl_new(CTL_HW, d, &desc->addr,
+           desc->type, group,
            desc->node0.name, desc->node0.unit, desc->func,
            desc->node1.name, desc->node1.unit, desc->maxval, val);
 }
@@ -88,8 +81,6 @@ dev_sioctl_onval(void *arg, unsigned int
        struct dev *d = arg;
        struct ctl *c;
 
-       addr += CTLADDR_END;
-
        dev_log(d);
        log_puts(": onctl: addr = ");
        log_putu(addr);
@@ -97,8 +88,8 @@ dev_sioctl_onval(void *arg, unsigned int
        log_putu(val);
        log_puts("\n");
 
-       for (c = d->ctl_list; c != NULL; c = c->next) {
-               if (c->addr != addr)
+       for (c = ctl_list; c != NULL; c = c->next) {
+               if (c->scope != CTL_HW || c->u.hw.addr != addr)
                        continue;
                ctl_log(c);
                log_puts(": new value -> ");
@@ -138,9 +129,9 @@ dev_sioctl_close(struct dev *d)
        struct ctl *c, **pc;
 
        /* remove controls */
-       pc = &d->ctl_list;
+       pc = &ctl_list;
        while ((c = *pc) != NULL) {
-               if (c->addr >= CTLADDR_END) {
+               if (c->scope == CTL_HW && c->u.hw.dev == d) {
                        c->refs_mask &= ~CTL_DEVMASK;
                        if (c->refs_mask == 0) {
                                *pc = c->next;
@@ -162,8 +153,8 @@ dev_sioctl_pollfd(void *arg, struct poll
        struct ctl *c;
        int events = 0;
 
-       for (c = d->ctl_list; c != NULL; c = c->next) {
-               if (c->dirty)
+       for (c = ctl_list; c != NULL; c = c->next) {
+               if (c->scope == CTL_HW && c->u.hw.dev == d && c->dirty)
                        events |= POLLOUT;
        }
        return sioctl_pollfd(d->sioctl.hdl, pfd, events);
@@ -195,11 +186,10 @@ dev_sioctl_out(void *arg)
         * we've finished iterating on it.
         */
        cnt = 0;
-       for (c = d->ctl_list; c != NULL; c = c->next) {
-               if (!c->dirty)
+       for (c = ctl_list; c != NULL; c = c->next) {
+               if (c->scope != CTL_HW || c->u.hw.dev != d || !c->dirty)
                        continue;
-               if (!sioctl_setval(d->sioctl.hdl,
-                       c->addr - CTLADDR_END, c->curval)) {
+               if (!sioctl_setval(d->sioctl.hdl, c->u.hw.addr, c->curval)) {
                        ctl_log(c);
                        log_puts(": set failed\n");
                        break;
Index: siofile.c
===================================================================
RCS file: /cvs/src/usr.bin/sndiod/siofile.c,v
retrieving revision 1.22
diff -u -p -u -p -r1.22 siofile.c
--- siofile.c   28 Jun 2020 05:21:39 -0000      1.22
+++ siofile.c   29 Jan 2021 15:15:39 -0000
@@ -119,11 +119,10 @@ dev_sio_openlist(struct dev *d, unsigned
                                }
                        }
                        d->alt_num = n->idx;
-                       for (c = d->ctl_list; c != NULL; c = c->next) {
-                               if (c->addr < CTLADDR_ALT_SEL ||
-                                   c->addr >= CTLADDR_ALT_SEL + DEV_NMAX)
+                       for (c = ctl_list; c != NULL; c = c->next) {
+                               if (!ctl_match(c, CTL_DEV_ALT, d, NULL))
                                        continue;
-                               val = (c->addr - CTLADDR_ALT_SEL) == n->idx;
+                               val = c->u.dev_alt.idx == n->idx;
                                if (c->curval == val)
                                        continue;
                                c->curval = val;
Index: sock.c
===================================================================
RCS file: /cvs/src/usr.bin/sndiod/sock.c,v
retrieving revision 1.41
diff -u -p -u -p -r1.41 sock.c
--- sock.c      29 Jan 2021 11:38:23 -0000      1.41
+++ sock.c      29 Jan 2021 15:15:39 -0000
@@ -1240,8 +1240,7 @@ sock_execmsg(struct sock *f)
                f->lastvol = ctl; /* dont trigger feedback message */
                slot_setvol(s, ctl);
                dev_midi_vol(s->opt->dev, s);
-               dev_onval(s->opt->dev,
-                   CTLADDR_SLOT_LEVEL(f->slot - slot_array), ctl);
+               ctl_onval(CTL_SLOT_LEVEL, s, NULL, ctl);
                break;
        case AMSG_CTLSUB:
 #ifdef DEBUG
@@ -1267,9 +1266,10 @@ sock_execmsg(struct sock *f)
                if (m->u.ctlsub.desc) {
                        if (!(f->ctlops & SOCK_CTLDESC)) {
                                ctl = f->ctlslot->self;
-                               c = f->ctlslot->opt->dev->ctl_list;
+                               c = ctl_list;
                                while (c != NULL) {
-                                       c->desc_mask |= ctl;
+                                       if (ctlslot_visible(f->ctlslot, c))
+                                               c->desc_mask |= ctl;
                                        c = c->next;
                                }
                                f->ctlops |= SOCK_CTLDESC;
@@ -1301,13 +1301,23 @@ sock_execmsg(struct sock *f)
                        sock_close(f);
                        return 0;
                }
-               if (!dev_setctl(f->ctlslot->opt->dev,
-                       ntohs(m->u.ctlset.addr),
-                       ntohs(m->u.ctlset.val))) {
+
+               c = ctlslot_lookup(f->ctlslot, ntohs(m->u.ctlset.addr));
+               if (c == NULL) {
+#ifdef DEBUG
+                       if (log_level >= 1) {
+                               sock_log(f);
+                               log_puts(": CTLSET, wrong addr\n");
+                       }
+#endif
+                       sock_close(f);
+                       return 0;
+               }
+               if (!ctl_setval(c, ntohs(m->u.ctlset.val))) {
 #ifdef DEBUG
                        if (log_level >= 1) {
                                sock_log(f);
-                               log_puts(": CTLSET, wrong addr/val\n");
+                               log_puts(": CTLSET, bad value\n");
                        }
 #endif
                        sock_close(f);
@@ -1403,7 +1413,7 @@ sock_execmsg(struct sock *f)
 int
 sock_buildmsg(struct sock *f)
 {
-       unsigned int size, mask;
+       unsigned int size, type, mask;
        struct amsg_ctl_desc *desc;
        struct ctl *c, **pc;
 
@@ -1555,7 +1565,7 @@ sock_buildmsg(struct sock *f)
                desc = f->ctldesc;
                mask = f->ctlslot->self;
                size = 0;
-               pc = &f->ctlslot->opt->dev->ctl_list;
+               pc = &ctl_list;
                while ((c = *pc) != NULL) {
                        if ((c->desc_mask & mask) == 0 ||
                            (c->refs_mask & mask) == 0) {
@@ -1567,7 +1577,11 @@ sock_buildmsg(struct sock *f)
                                break;
                        c->desc_mask &= ~mask;
                        c->val_mask &= ~mask;
-                       strlcpy(desc->group, c->group,
+                       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->node0.name, c->node0.name,
                            AMSG_CTL_NAMEMAX);
@@ -1575,7 +1589,7 @@ sock_buildmsg(struct sock *f)
                        strlcpy(desc->node1.name, c->node1.name,
                            AMSG_CTL_NAMEMAX);
                        desc->node1.unit = ntohs(c->node1.unit);
-                       desc->type = c->type;
+                       desc->type = type;
                        strlcpy(desc->func, c->func, AMSG_CTL_NAMEMAX);
                        desc->addr = htons(c->addr);
                        desc->maxval = htons(c->maxval);
@@ -1584,7 +1598,7 @@ sock_buildmsg(struct sock *f)
                        desc++;
 
                        /* if this is a deleted entry unref it */
-                       if (c->type == CTL_NONE) {
+                       if (type == CTL_NONE) {
                                c->refs_mask &= ~mask;
                                if (c->refs_mask == 0) {
                                        *pc = c->next;
@@ -1612,7 +1626,9 @@ sock_buildmsg(struct sock *f)
        }
        if (f->ctlslot && (f->ctlops & SOCK_CTLVAL)) {
                mask = f->ctlslot->self;
-               for (c = f->ctlslot->opt->dev->ctl_list; c != NULL; c = 
c->next) {
+               for (c = ctl_list; c != NULL; c = c->next) {
+                       if (!ctlslot_visible(f->ctlslot, c))
+                               continue;
                        if ((c->val_mask & mask) == 0)
                                continue;
                        c->val_mask &= ~mask;

Reply via email to