From 0f35a5bfe309301b661fa969eb670d89de3b8c7a Mon Sep 17 00:00:00 2001 From: Mike Gerow Date: Sun, 17 May 2015 20:29:41 -0700 Subject: [PATCH] Add ioctl interface for snd mixer --- kernel/include/mod/snd.h | 2 + modules/ac97.c | 16 +++--- modules/snd.c | 117 ++++++++++++++++++++++++++++++++++----- userspace/lib/sound.h | 21 +++---- 4 files changed, 124 insertions(+), 32 deletions(-) diff --git a/kernel/include/mod/snd.h b/kernel/include/mod/snd.h index 5e688292..11c86647 100644 --- a/kernel/include/mod/snd.h +++ b/kernel/include/mod/snd.h @@ -27,6 +27,8 @@ typedef struct snd_device { uint32_t num_knobs; int (*mixer_read)(uint32_t knob_id, uint32_t *val); int (*mixer_write)(uint32_t knob_id, uint32_t val); + + uint32_t id; } snd_device_t; /* diff --git a/modules/ac97.c b/modules/ac97.c index 0097d5f3..079a0045 100644 --- a/modules/ac97.c +++ b/modules/ac97.c @@ -104,16 +104,16 @@ static int ac97_mixer_read(uint32_t knob_id, uint32_t *val); static int ac97_mixer_write(uint32_t knob_id, uint32_t val); static snd_device_t _snd = { - AC97_SND_NAME, - &_device, - AC97_PLAYBACK_SPEED, - AC97_PLAYBACK_FORMAT, + .name = AC97_SND_NAME, + .device = &_device, + .playback_speed = AC97_PLAYBACK_SPEED, + .playback_format = AC97_PLAYBACK_FORMAT, - _knobs, - N_ELEMENTS(_knobs), + .knobs = _knobs, + .num_knobs = N_ELEMENTS(_knobs), - ac97_mixer_read, - ac97_mixer_write, + .mixer_read = ac97_mixer_read, + .mixer_write = ac97_mixer_write, }; /* diff --git a/modules/snd.c b/modules/snd.c index e0891805..aaac2b1f 100644 --- a/modules/snd.c +++ b/modules/snd.c @@ -13,6 +13,7 @@ #include +#include #include #include #include @@ -24,30 +25,43 @@ #define SND_BUF_SIZE 0x1000 -static uint32_t snd_write(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer); -static int snd_ioctl(fs_node_t * node, int request, void * argp); -static void snd_open(fs_node_t * node, unsigned int flags); -static void snd_close(fs_node_t * node); +static uint32_t snd_dsp_write(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer); +static int snd_dsp_ioctl(fs_node_t * node, int request, void * argp); +static void snd_dsp_open(fs_node_t * node, unsigned int flags); +static void snd_dsp_close(fs_node_t * node); + +static int snd_mixer_ioctl(fs_node_t * node, int request, void * argp); +static void snd_mixer_open(fs_node_t * node, unsigned int flags); +static void snd_mixer_close(fs_node_t * node); static uint8_t _devices_lock; static list_t _devices; -static fs_node_t _main_fnode = { +static fs_node_t _dsp_fnode = { .name = "dsp", .device = &_devices, .flags = FS_CHARDEVICE, - .ioctl = snd_ioctl, - .write = snd_write, - .open = snd_open, - .close = snd_close, + .ioctl = snd_dsp_ioctl, + .write = snd_dsp_write, + .open = snd_dsp_open, + .close = snd_dsp_close, +}; +static fs_node_t _mixer_fnode = { + .name = "mixer", + .ioctl = snd_mixer_ioctl, + .open = snd_mixer_open, + .close = snd_mixer_close, }; static uint8_t _buffers_lock; static list_t _buffers; +static uint32_t _next_device_id = SND_DEVICE_MAIN; int snd_register(snd_device_t * device) { int rv = 0; debug_print(WARNING, "[snd] _devices lock: %d", _devices_lock); spin_lock(&_devices_lock); + device->id = _next_device_id; + _next_device_id++; if (list_find(&_devices, device)) { debug_print(WARNING, "[snd] attempt to register duplicate %s", device->name); rv = -1; @@ -78,16 +92,16 @@ snd_unregister_cleanup: return rv; } -static uint32_t snd_write(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { +static uint32_t snd_dsp_write(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { return ring_buffer_write(node->device, size, buffer); } -static int snd_ioctl(fs_node_t * node, int request, void * argp) { +static int snd_dsp_ioctl(fs_node_t * node, int request, void * argp) { /* Potentially use this to set sample rates in the future */ return -1; } -static void snd_open(fs_node_t * node, unsigned int flags) { +static void snd_dsp_open(fs_node_t * node, unsigned int flags) { /* * XXX(gerow): A process could take the memory of the entire system by opening * too many of these... @@ -99,12 +113,86 @@ static void snd_open(fs_node_t * node, unsigned int flags) { spin_unlock(&_buffers_lock); } -static void snd_close(fs_node_t * node) { +static void snd_dsp_close(fs_node_t * node) { spin_lock(&_buffers_lock); list_delete(&_buffers, list_find(&_buffers, node->device)); spin_unlock(&_buffers_lock); } +static snd_device_t * snd_device_by_id(uint32_t device_id) { + spin_lock(&_devices_lock); + snd_device_t * out = NULL; + snd_device_t * cur = NULL; + + foreach(node, &_devices) { + cur = node->value; + if (cur->id == device_id) { + out = cur; + } + } + spin_unlock(&_devices_lock); + + return out; +} + +static int snd_mixer_ioctl(fs_node_t * node, int request, void * argp) { + switch (request) { + case SND_MIXER_GET_KNOBS: { + snd_knob_list_t * list = argp; + snd_device_t * device = snd_device_by_id(list->device); + if (!device) { + return -EINVAL; + } + list->num = device->num_knobs; + for (uint32_t i = 0; i < device->num_knobs; i++) { + list->ids[i] = device->knobs[i].id; + } + return 0; + } + case SND_MIXER_GET_KNOB_INFO: { + snd_knob_info_t * info = argp; + snd_device_t * device = snd_device_by_id(info->device); + if (!device) { + return -EINVAL; + } + for (uint32_t i = 0; i < device->num_knobs; i++) { + if (device->knobs[i].id == info->id) { + memcpy(info->name, device->knobs[i].name, sizeof(info->name)); + return 0; + } + } + return -EINVAL; + } + case SND_MIXER_READ_KNOB: { + snd_knob_value_t * value = argp; + snd_device_t * device = snd_device_by_id(value->device); + if (!device) { + return -EINVAL; + } + return device->mixer_read(value->id, &value->val); + } + case SND_MIXER_WRITE_KNOB: { + snd_knob_value_t * value = argp; + snd_device_t * device = snd_device_by_id(value->device); + if (!device) { + return -EINVAL; + } + return device->mixer_write(value->id, value->val); + } + default: { + return -EINVAL; + } + } +} + +static void snd_mixer_open(fs_node_t * node, unsigned int flags) { + return; +} + +static void snd_mixer_close(fs_node_t * node) { + return; +} + int snd_request_buf(snd_device_t * device, uint32_t size, uint8_t *buffer) { static uint8_t tmp_buf[0x100]; @@ -171,7 +259,8 @@ DEFINE_SHELL_FUNCTION(snd_off, "[debug] turn snd master to lowest volume") { } static int init(void) { - vfs_mount("/dev/dsp", &_main_fnode); + vfs_mount("/dev/dsp", &_dsp_fnode); + vfs_mount("/dev/mixer", &_mixer_fnode); BIND_SHELL_FUNCTION(snd_full); BIND_SHELL_FUNCTION(snd_half); diff --git a/userspace/lib/sound.h b/userspace/lib/sound.h index 0aecb821..ba8785ff 100644 --- a/userspace/lib/sound.h +++ b/userspace/lib/sound.h @@ -1,30 +1,31 @@ #ifndef USERSPACE_LIB_SOUND_H #define USERSPACE_LIB_SOUND_H -#include +#include #define SND_MAX_KNOBS 256 #define SND_KNOB_NAME_SIZE 256 +#define SND_KNOB_MAX_VALUE UINT32_MAX #define SND_KNOB_MASTER 0 #define SND_DEVICE_MAIN 0 typedef struct snd_knob_list { - uint32_t device; - uint32_t num; - uint32_t ids[SND_MAX_KNOBS]; + uint32_t device; /* IN */ + uint32_t num; /* OUT */ + uint32_t ids[SND_MAX_KNOBS]; /* OUT */ } snd_knob_list_t; typedef struct snd_knob_info { - uint32_t device; - uint32_t id; - char name[SND_KNOB_NAME_SIZE]; + uint32_t device; /* IN */ + uint32_t id; /* IN */ + char name[SND_KNOB_NAME_SIZE]; /* OUT */ } snd_knob_info_t; typedef struct snd_knob_value { - uint32_t device; - uint32_t id; - uint32_t val; + uint32_t device; /* IN */ + uint32_t id; /* IN */ + uint32_t val; /* OUT for SND_MIXER_READ_KNOB, IN for SND_MIXER_WRITE_KNOB */ } snd_knob_value_t;