diff options
author | Ahmad Fatoum <ahmad@a3f.at> | 2021-01-31 21:18:41 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2021-02-08 10:57:05 +0100 |
commit | 78dd61b47e5d93240b3d112c51fa3b1896c4f6e6 (patch) | |
tree | dd5c0335559bf6099d57c44816fc7ad327928c87 /drivers | |
parent | 12ad41f91f1824eb141e368294d97860644ab777 (diff) | |
download | barebox-78dd61b47e5d93240b3d112c51fa3b1896c4f6e6.tar.gz barebox-78dd61b47e5d93240b3d112c51fa3b1896c4f6e6.tar.xz |
drivers: add sound card driver support
Add driver core boilerplate for sound support in barebox. Using the
provided API in <sound.h>, consumers can play beeps for a fixed duration
of time.
Playing beeps is not blocking and new beeps can be enqueued while one
is already playing. They will be played in succession by a poller, which
will also turn off the sound card when the beep tune is over.
API is also available for blocking until all beeps are played and for
cancelling an underway beep tune.
The API could be later extended for arbitrary PCM audio, should the
need arise.
Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Kconfig | 1 | ||||
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/sound/Kconfig | 8 | ||||
-rw-r--r-- | drivers/sound/Makefile | 2 | ||||
-rw-r--r-- | drivers/sound/core.c | 121 |
5 files changed, 133 insertions, 0 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index dda2405780..0b87c2af2a 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -13,6 +13,7 @@ source "drivers/mtd/Kconfig" source "drivers/ata/Kconfig" source "drivers/usb/Kconfig" source "drivers/video/Kconfig" +source "drivers/sound/Kconfig" source "drivers/mci/Kconfig" source "drivers/clk/Kconfig" source "drivers/clocksource/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 5a03bdceab..fab3790288 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -43,3 +43,4 @@ obj-y += soc/imx/ obj-y += nvme/ obj-y += ddr/ obj-y += power/ +obj-$(CONFIG_SOUND) += sound/ diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig new file mode 100644 index 0000000000..cce5c760af --- /dev/null +++ b/drivers/sound/Kconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-only +menuconfig SOUND + bool "Sound drivers" + select POLLER + help + Say Y here for sound support. At the moment that's just beep tones. + Tones are played asynchronously in a poller. Check the beep command + for how to exercise the API. diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile new file mode 100644 index 0000000000..e343e0fa72 --- /dev/null +++ b/drivers/sound/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += core.o diff --git a/drivers/sound/core.c b/drivers/sound/core.c new file mode 100644 index 0000000000..801b1fade5 --- /dev/null +++ b/drivers/sound/core.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: © 2021 Ahmad Fatoum + +#include <common.h> +#include <linux/list.h> +#include <sound.h> +#include <poller.h> +#include <linux/iopoll.h> + +static LIST_HEAD(card_list); + +struct beep { + int freq; + unsigned int us; + struct list_head list; +}; + +static int sound_card_do_beep(struct sound_card *card, + int freq, unsigned int us) +{ + if (freq == -1) + freq = card->bell_frequency; + + return card->beep(card, freq, us); +} + +static void sound_card_poller_cb(void *_card) +{ + struct sound_card *card = _card; + struct beep *beep; + + beep = list_first_entry_or_null(&card->tune, struct beep, list); + if (!beep) { + sound_card_do_beep(card, 0, 0); + return; + } + + list_del(&beep->list); + + poller_call_async(&card->poller, beep->us * 1000ULL, + sound_card_poller_cb, card); + sound_card_do_beep(card, beep->freq, beep->us); + + free(beep); +} + +int sound_card_register(struct sound_card *card) +{ + if (!card->name) + return -EINVAL; + + if (card->bell_frequency <= 0) + card->bell_frequency = 1000; + + poller_async_register(&card->poller, card->name); + INIT_LIST_HEAD(&card->tune); + + list_add_tail(&card->list, &card_list); + return 0; +} + +struct sound_card *sound_card_get_default(void) +{ + return list_first_entry_or_null(&card_list, struct sound_card, list); +} + +int sound_card_beep(struct sound_card *card, int freq, unsigned int us) +{ + struct beep *beep; + int ret; + + if (!card) + return -ENODEV; + + if (!poller_async_active(&card->poller)) { + ret = sound_card_do_beep(card, freq, us); + if (!ret) + poller_call_async(&card->poller, us * 1000ULL, + sound_card_poller_cb, card); + + return ret; + } + + beep = malloc(sizeof(*beep)); + if (!beep) + return -ENOMEM; + + beep->freq = freq; + beep->us = us; + + list_add_tail(&beep->list, &card->tune); + + return 0; +} + +int sound_card_beep_wait(struct sound_card *card, unsigned timeout) +{ + bool active; + return read_poll_timeout(poller_async_active, active, + !active, timeout, &card->poller); +} + +int sound_card_beep_cancel(struct sound_card *card) +{ + struct beep *beep, *tmp; + int ret; + + if (!card) + return -ENODEV; + + poller_async_cancel(&card->poller); + + ret = card->beep(card, 0, 0); + + list_for_each_entry_safe(beep, tmp, &card->tune, list) { + list_del(&beep->list); + free(beep); + } + + return ret; +} |