Hi, This diff is an attempt to make identifying audio devices easier by giving each device a human-readable description that can be read from userspace (and without scraping dmesg).
This is implemented on a per-audio-device basis using a new `descr` interface to `audio_hw_if`. For now I've only implemented this on: - azalia(4), which uses the codec info, e.g. `Realtek ALC1150` - uaudio(4), which uses the USB vendor and model info, e.g. `Logitech HD Pro Webcam C920`. For drivers, which currently don't implement this interface, the description string defaults to the audio device node name, e.g. `uaudio2`. The string is exposed to userspace via the AUDIO_GETDEV ioctl(2). I've reclaimed the space currently occupied by the (unused) `version` and `config` fields in `audio_device_t` and used it for a new `descr` field. Thus the size of `audio_device_t` remains the same for now. I've also made audioctl(8) display the description string, e.g.: ``` # audioctl name=azalia1 descr=Realtek ALC1150 ... # audioctl -f /dev/audioctl1 name=uaudio0 descr=SteelSeries SteelSeries Arctis ... ``` I'm hoping that later we can have sndiod read these strings and expose them to its clients. For example, I'd like for sndioctl(1) to allow choosing a device based on the device description string (instead of the sndio device index), and for xfce4-mixer to allow choosing a device via its description in the GUI using a drop-down box. Diff follows. Index: sys/dev/audio.c =================================================================== RCS file: /cvs/src/sys/dev/audio.c,v retrieving revision 1.193 diff -u -p -r1.193 audio.c --- sys/dev/audio.c 16 May 2021 15:12:37 -0000 1.193 +++ sys/dev/audio.c 7 Jul 2021 10:21:25 -0000 @@ -1791,6 +1791,11 @@ audio_getdev(struct audio_softc *sc, str if (sc->dev.dv_parent == NULL) return EIO; strlcpy(adev->name, sc->dev.dv_parent->dv_xname, MAX_AUDIO_DEV_LEN); + if (sc->ops->descr != NULL) + sc->ops->descr(sc->arg, adev->descr, MAX_AUDIO_DESCR_LEN); + else + strlcpy(adev->descr, sc->dev.dv_parent->dv_xname, + MAX_AUDIO_DESCR_LEN); return 0; } Index: sys/dev/audio_if.h =================================================================== RCS file: /cvs/src/sys/dev/audio_if.h,v retrieving revision 1.36 diff -u -p -r1.36 audio_if.h --- sys/dev/audio_if.h 5 Sep 2019 05:33:57 -0000 1.36 +++ sys/dev/audio_if.h 2 Jul 2021 19:15:53 -0000 @@ -137,6 +137,8 @@ struct audio_hw_if { struct audio_params *, struct audio_params *, unsigned int); unsigned int (*set_nblks)(void *, int, struct audio_params *, unsigned int, unsigned int); + + void (*descr)(void*, char *, size_t); /* the device's description */ }; struct audio_attach_args { Index: sys/dev/pci/azalia.c =================================================================== RCS file: /cvs/src/sys/dev/pci/azalia.c,v retrieving revision 1.263 diff -u -p -r1.263 azalia.c --- sys/dev/pci/azalia.c 11 Jun 2021 15:46:09 -0000 1.263 +++ sys/dev/pci/azalia.c 2 Jul 2021 19:15:53 -0000 @@ -256,6 +256,7 @@ unsigned int azalia_set_blksz(void *, in struct audio_params *, struct audio_params *, unsigned int); unsigned int azalia_set_nblks(void *, int, struct audio_params *, unsigned int, unsigned int); +void azalia_descr(void *, char *, size_t); int azalia_halt_output(void *); int azalia_halt_input(void *); int azalia_set_port(void *, mixer_ctrl_t *); @@ -315,7 +316,8 @@ struct audio_hw_if azalia_hw_if = { NULL, /* copy_output */ NULL, /* underrun */ azalia_set_blksz, - azalia_set_nblks + azalia_set_nblks, + azalia_descr /* descr */ }; static const char *pin_devices[16] = { @@ -4019,6 +4021,37 @@ azalia_set_nblks(void *v, int mode, nblks = HDA_BDL_MAX; return nblks; +} + +void +azalia_descr(void *arg, char *descr, size_t len) +{ + azalia_t *az = arg; + codec_t *codec; + const char *vendor; + char buf[MAX_AUDIO_DESCR_LEN]; + int i; + + *descr = '\0'; + for (i = 0; i < az->ncodecs; i++) { + codec = &az->codecs[i]; + /* adapted from azalia_print_codec() */ + if (codec->name == NULL) { + vendor = pci_findvendor(codec->vid >> 16); + if (vendor == NULL) + snprintf(buf, MAX_AUDIO_DESCR_LEN, + "0x%04x/0x%04x", codec->vid >> 16, + codec->vid & 0xffff); + else + snprintf(buf, MAX_AUDIO_DESCR_LEN, "%s/0x%04x", + vendor, codec->vid & 0xffff); + } else + snprintf(buf, MAX_AUDIO_DESCR_LEN, "%s", codec->name); + + if (i > 0) + strlcat(descr, ", ", len); + strlcat(descr, buf, len); + } } int Index: sys/dev/usb/uaudio.c =================================================================== RCS file: /cvs/src/sys/dev/usb/uaudio.c,v retrieving revision 1.161 diff -u -p -r1.161 uaudio.c --- sys/dev/usb/uaudio.c 18 May 2021 10:02:00 -0000 1.161 +++ sys/dev/usb/uaudio.c 2 Jul 2021 19:15:53 -0000 @@ -431,6 +431,7 @@ int uaudio_query_devinfo(void *, struct int uaudio_get_port(void *, struct mixer_ctrl *); int uaudio_set_port(void *, struct mixer_ctrl *); int uaudio_get_props(void *); +void uaudio_descr(void *, char *, size_t); int uaudio_process_unit(struct uaudio_softc *, struct uaudio_unit *, int, @@ -493,7 +494,9 @@ struct audio_hw_if uaudio_hw_if = { uaudio_trigger_input, /* trigger_input */ uaudio_copy_output, /* copy_output */ uaudio_underrun, /* underrun */ - uaudio_set_blksz /* set_blksz */ + uaudio_set_blksz, /* set_blksz */ + NULL, /* set_nblks */ + uaudio_descr, /* descr */ }; /* @@ -4189,6 +4192,14 @@ int uaudio_get_props(void *self) { return AUDIO_PROP_FULLDUPLEX; +} + + +void +uaudio_descr(void *arg, char *descr, size_t len) +{ + struct uaudio_softc *sc = arg; + snprintf(descr, len, "%s %s", sc->udev->vendor, sc->udev->product); } int Index: sys/sys/audioio.h =================================================================== RCS file: /cvs/src/sys/sys/audioio.h,v retrieving revision 1.27 diff -u -p -r1.27 audioio.h --- sys/sys/audioio.h 14 Sep 2016 06:12:20 -0000 1.27 +++ sys/sys/audioio.h 7 Jul 2021 10:23:09 -0000 @@ -76,10 +76,10 @@ struct audio_status { * audio devices. */ #define MAX_AUDIO_DEV_LEN 16 +#define MAX_AUDIO_DESCR_LEN 32 typedef struct audio_device { char name[MAX_AUDIO_DEV_LEN]; - char version[MAX_AUDIO_DEV_LEN]; - char config[MAX_AUDIO_DEV_LEN]; + char descr[MAX_AUDIO_DESCR_LEN]; /* device description string */ } audio_device_t; struct audio_pos { Index: usr.bin/audioctl/audioctl.c =================================================================== RCS file: /cvs/src/usr.bin/audioctl/audioctl.c,v retrieving revision 1.42 diff -u -p -r1.42 audioctl.c --- usr.bin/audioctl/audioctl.c 2 Feb 2020 05:25:41 -0000 1.42 +++ usr.bin/audioctl/audioctl.c 2 Jul 2021 19:15:53 -0000 @@ -46,6 +46,7 @@ struct field { int set; } fields[] = { {"name", &rname.name, NULL, STR}, + {"descr", &rname.descr, NULL, STR}, {"mode", &rstatus.mode, NULL, MODE}, {"pause", &rstatus.pause, NULL, NUM}, {"active", &rstatus.active, NULL, NUM}, Index: share/man/man4/audio.4 =================================================================== RCS file: /cvs/src/share/man/man4/audio.4,v retrieving revision 1.86 diff -u -p -r1.86 audio.4 --- share/man/man4/audio.4 1 Nov 2020 21:32:03 -0000 1.86 +++ share/man/man4/audio.4 7 Jul 2021 13:41:38 -0000 @@ -112,8 +112,7 @@ argument. .Bd -literal typedef struct audio_device { char name[MAX_AUDIO_DEV_LEN]; - char version[MAX_AUDIO_DEV_LEN]; - char config[MAX_AUDIO_DEV_LEN]; + char descr[MAX_AUDIO_DESCR_LEN]; } audio_device_t; .Ed .Pp -- Best Regards Edd Barrett http://www.theunixzoo.co.uk