summaryrefslogtreecommitdiffstats
path: root/drivers/sound/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sound/core.c')
-rw-r--r--drivers/sound/core.c121
1 files changed, 121 insertions, 0 deletions
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;
+}