sndiod: properly transmit deleted controls.

This commit is contained in:
Alexandre Ratchov 2019-08-30 16:53:41 +02:00
parent efeed79b56
commit aefc78f715
3 changed files with 75 additions and 13 deletions

View File

@ -1197,7 +1197,7 @@ dev_exitall(struct dev *d)
void void
dev_close_do(struct dev *d) dev_close_do(struct dev *d)
{ {
struct ctl *c; struct ctl *c, **pc;
#ifdef DEBUG #ifdef DEBUG
if (log_level >= 3) { if (log_level >= 3) {
@ -1205,9 +1205,18 @@ dev_close_do(struct dev *d)
log_puts(": closing\n"); log_puts(": closing\n");
} }
#endif #endif
while ((c = d->ctl_list) != NULL) { pc = &d->ctl_list;
d->ctl_list = c->next; while ((c = *pc) != NULL) {
xfree(c); if (c->addr >= CTLADDR_END) {
if (c->refs_mask == 0) {
*pc = c->next;
xfree(c);
continue;
}
c->type = CTL_NONE;
c->desc_mask = ~0;
}
pc = &c->next;
} }
d->pstate = DEV_CFG; d->pstate = DEV_CFG;
dev_sio_close(d); dev_sio_close(d);
@ -1229,8 +1238,16 @@ dev_close_do(struct dev *d)
void void
dev_close(struct dev *d) dev_close(struct dev *d)
{ {
struct ctl *c;
dev_exitall(d); dev_exitall(d);
dev_close_do(d); dev_close_do(d);
/* there are no clients, just free remaining local controls */
while ((c = d->ctl_list) != NULL) {
d->ctl_list = c->next;
xfree(c);
}
} }
/* /*
@ -2154,6 +2171,7 @@ struct ctlslot *
ctlslot_new(struct dev *d, struct ctlops *ops, void *arg) ctlslot_new(struct dev *d, struct ctlops *ops, void *arg)
{ {
struct ctlslot *s; struct ctlslot *s;
struct ctl *c;
int i; int i;
i = 0; i = 0;
@ -2171,6 +2189,8 @@ ctlslot_new(struct dev *d, struct ctlops *ops, void *arg)
return NULL; return NULL;
s->ops = ops; s->ops = ops;
s->arg = arg; s->arg = arg;
for (c = d->ctl_list; c != NULL; c = c->next)
c->refs_mask |= s->mask;
return s; return s;
} }
@ -2180,6 +2200,17 @@ ctlslot_new(struct dev *d, struct ctlops *ops, void *arg)
void void
ctlslot_del(struct ctlslot *s) ctlslot_del(struct ctlslot *s)
{ {
struct ctl *c, **pc;
pc = &s->dev->ctl_list;
while ((c = *pc) != NULL) {
c->refs_mask &= ~s->mask;
if (c->refs_mask == 0) {
*pc = c->next;
xfree(c);
} else
pc = &c->next;
}
s->ops = NULL; s->ops = NULL;
dev_unref(s->dev); dev_unref(s->dev);
} }
@ -2225,7 +2256,8 @@ struct ctl *
dev_addctl(struct dev *d, char *gstr, int gunit, int type, int addr, dev_addctl(struct dev *d, char *gstr, int gunit, int type, int addr,
char *str0, int unit0, char *func, char *str1, int unit1, int val) char *str0, int unit0, char *func, char *str1, int unit1, int val)
{ {
struct ctl *c; struct ctl *c, **pc;
int i;
c = xmalloc(sizeof(struct ctl)); c = xmalloc(sizeof(struct ctl));
c->type = type; c->type = type;
@ -2242,10 +2274,17 @@ dev_addctl(struct dev *d, char *gstr, int gunit, int type, int addr,
c->addr = addr; c->addr = addr;
c->val_mask = ~0; c->val_mask = ~0;
c->desc_mask = ~0; c->desc_mask = ~0;
c->next = d->ctl_list;
d->ctl_list = c;
c->curval = val; c->curval = val;
c->dirty = 0; c->dirty = 0;
c->refs_mask = 0;
for (i = 0; i < DEV_NCTLSLOT; i++) {
if (d->ctlslot[i].ops != NULL)
c->refs_mask |= 1 << i;
}
for (pc = &d->ctl_list; *pc != NULL; pc = &(*pc)->next)
; /* nothing */
c->next = NULL;
*pc = c;
#ifdef DEBUG #ifdef DEBUG
if (log_level >= 3) { if (log_level >= 3) {
dev_log(d); dev_log(d);
@ -2267,18 +2306,23 @@ dev_rmctl(struct dev *d, int addr)
c = *pc; c = *pc;
if (c == NULL) if (c == NULL)
return; return;
if (c->addr == addr) if (c->type != CTL_NONE && c->addr == addr)
break; break;
pc = &c->next; pc = &c->next;
} }
c->type = CTL_NONE;
#ifdef DEBUG #ifdef DEBUG
if (log_level >= 3) { if (log_level >= 3) {
dev_log(d); dev_log(d);
log_puts(": removing "); log_puts(": removing ");
ctl_log(c); ctl_log(c);
log_puts(", refs_mask = 0x");
log_putx(c->refs_mask);
log_puts("\n"); log_puts("\n");
} }
#endif #endif
if (c->refs_mask != 0)
return;
*pc = c->next; *pc = c->next;
xfree(c); xfree(c);
} }
@ -2309,7 +2353,7 @@ dev_setctl(struct dev *d, int addr, int val)
} }
return 0; return 0;
} }
if (c->addr == addr) if (c->type != CTL_NONE && c->addr == addr)
break; break;
c = c->next; c = c->next;
} }
@ -2344,7 +2388,7 @@ dev_onctl(struct dev *d, int addr, int val)
for (;;) { for (;;) {
if (c == NULL) if (c == NULL)
return 0; return 0;
if (c->addr == addr) if (c->type != CTL_NONE && c->addr == addr)
break; break;
c = c->next; c = c->next;
} }

View File

@ -120,6 +120,7 @@ struct opt {
struct ctl { struct ctl {
struct ctl *next; struct ctl *next;
#define CTL_NONE 0 /* deleted */
#define CTL_NUM 2 /* number (aka integer value) */ #define CTL_NUM 2 /* number (aka integer value) */
#define CTL_SW 3 /* on/off switch, only bit 7 counts */ #define CTL_SW 3 /* on/off switch, only bit 7 counts */
#define CTL_VEC 4 /* number, element of vector */ #define CTL_VEC 4 /* number, element of vector */
@ -134,6 +135,7 @@ struct ctl {
} group, chan0, chan1; /* affected channels */ } group, chan0, chan1; /* affected channels */
unsigned int val_mask; unsigned int val_mask;
unsigned int desc_mask; unsigned int desc_mask;
unsigned int refs_mask;
unsigned int curval; unsigned int curval;
int dirty; int dirty;
}; };

View File

@ -1370,7 +1370,7 @@ sock_buildmsg(struct sock *f)
{ {
unsigned int size, mask; unsigned int size, mask;
struct amsg_mix_desc *desc; struct amsg_mix_desc *desc;
struct ctl *c; struct ctl *c, **pc;
/* /*
* If pos changed (or initial tick), build a MOVE message. * If pos changed (or initial tick), build a MOVE message.
@ -1520,9 +1520,13 @@ sock_buildmsg(struct sock *f)
desc = f->ctldesc; desc = f->ctldesc;
mask = f->ctlslot->mask; mask = f->ctlslot->mask;
size = 0; size = 0;
for (c = f->ctlslot->dev->ctl_list; c != NULL; c = c->next) { pc = &f->ctlslot->dev->ctl_list;
if ((c->desc_mask & mask) == 0) while ((c = *pc) != NULL) {
if ((c->desc_mask & mask) == 0 ||
(c->refs_mask & mask) == 0) {
pc = &c->next;
continue; continue;
}
if (size == SOCK_CTLDESC_SIZE * if (size == SOCK_CTLDESC_SIZE *
sizeof(struct amsg_mix_desc)) sizeof(struct amsg_mix_desc))
break; break;
@ -1543,6 +1547,18 @@ sock_buildmsg(struct sock *f)
desc->curval = htons(c->curval); desc->curval = htons(c->curval);
size += sizeof(struct amsg_mix_desc); size += sizeof(struct amsg_mix_desc);
desc++; desc++;
/* if this is a deleted entry unref it */
if (c->type == CTL_NONE) {
c->refs_mask &= ~mask;
if (c->refs_mask == 0) {
*pc = c->next;
xfree(c);
continue;
}
}
pc = &c->next;
} }
if (size > 0) { if (size > 0) {
AMSG_INIT(&f->wmsg); AMSG_INIT(&f->wmsg);