From 9a446c6b727ecbf17072f04f5df41037de507ba6 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Thu, 18 Jun 2020 06:27:36 +0200 Subject: [PATCH] Allow alternate devices to be switched with sndioctl --- sndiod/dev.c | 43 ++++++++++++++++++++++++++++++++++++++++++- sndiod/dev.h | 3 ++- sndiod/siofile.c | 14 +++++++++++++- sndiod/sndiod.8 | 5 +++++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/sndiod/dev.c b/sndiod/dev.c index 3c4b8d3..aaf933d 100644 --- a/sndiod/dev.c +++ b/sndiod/dev.c @@ -68,6 +68,7 @@ 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 *); void dev_sync_attach(struct dev *); @@ -1088,6 +1089,30 @@ dev_addname(struct dev *d, char *name) 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 */ @@ -1177,6 +1202,7 @@ dev_open(struct dev *d) { int i; char name[CTL_NAMEMAX]; + struct dev_alt *a; d->master_enabled = 0; d->mode = d->reqmode; @@ -1210,6 +1236,15 @@ dev_open(struct dev *d) NULL, -1, 127, d->slot[i].vol); } + for (a = d->alt_list; a != NULL; a = a->next) { + /* XXX: may already exist, move to hw/ group ? */ + snprintf(name, sizeof(name), "%d", a->idx); + dev_addctl(d, "", CTL_SEL, + CTLADDR_ALT_SEL + a->idx, + "device", -1, "select", + name, -1, 1, a->idx == d->alt_num); + } + d->pstate = DEV_INIT; return 1; } @@ -2473,7 +2508,13 @@ dev_setctl(struct dev *d, int addr, int val) c->dirty = 1; dev_ref(d); } else { - if (addr == CTLADDR_MASTER) { + 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); diff --git a/sndiod/dev.h b/sndiod/dev.h index cbca055..9b1abd8 100644 --- a/sndiod/dev.h +++ b/sndiod/dev.h @@ -24,7 +24,8 @@ #define CTLADDR_SLOT_LEVEL(n) (n) #define CTLADDR_MASTER (DEV_NSLOT) -#define CTLADDR_END (DEV_NSLOT + 1) +#define CTLADDR_ALT_SEL (CTLADDR_MASTER + 1) +#define CTLADDR_END (CTLADDR_ALT_SEL + DEV_NMAX) /* * audio stream state structure diff --git a/sndiod/siofile.c b/sndiod/siofile.c index 5aef2dd..322ec6c 100644 --- a/sndiod/siofile.c +++ b/sndiod/siofile.c @@ -95,7 +95,8 @@ dev_sio_openlist(struct dev *d, unsigned int mode, struct sioctl_hdl **rctlhdl) struct dev_alt *n; struct sio_hdl *hdl; struct sioctl_hdl *ctlhdl; - int idx; + struct ctl *c; + int val; for (n = d->alt_list; n != NULL; n = n->next) { if (d->alt_num == n->idx) @@ -117,6 +118,17 @@ dev_sio_openlist(struct dev *d, unsigned int mode, struct sioctl_hdl **rctlhdl) } } 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) + continue; + val = (c->addr - CTLADDR_ALT_SEL) == n->idx; + if (c->curval == val) + continue; + c->curval = val; + if (val) + c->val_mask = ~0U; + } *rctlhdl = ctlhdl; return hdl; } diff --git a/sndiod/sndiod.8 b/sndiod/sndiod.8 index 40b9ef2..b28a91e 100644 --- a/sndiod/sndiod.8 +++ b/sndiod/sndiod.8 @@ -196,6 +196,11 @@ PCI device allows .Nm to use the USB one preferably when it's connected and to fall back to the PCI one when it's disconnected. +Alternate devices may be switched with the +.Va device.select +control of the +.Xr sndioctl 1 +utility. .It Fl f Ar device Add this .Xr sndio 7