[syslinux] [PATCH] com32/modules: introduce play module
Drew DeVault
sir at cmpwn.com
Tue Jan 21 18:22:58 PST 2020
This plays a tune through the PC speaker and is compatible with the
GRUB2 command of the same name.
Signed-off-by: Drew DeVault <sir at cmpwn.com>
---
com32/modules/Makefile | 2 +-
com32/modules/play.c | 95 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 96 insertions(+), 1 deletion(-)
create mode 100644 com32/modules/play.c
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index c01d6338..5e69a0d7 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -20,7 +20,7 @@ include $(MAKEDIR)/elf.mk
# BIOS-specific modules
MOD_BIOS = disk.c32 elf.c32 ethersel.c32 gpxecmd.c32 ifmemdsk.c32 ifplop.c32 \
- kbdmap.c32 kontron_wdt.c32 pcitest.c32 pmload.c32 poweroff.c32 \
+ kbdmap.c32 kontron_wdt.c32 pcitest.c32 play.c32 pmload.c32 poweroff.c32 \
prdhcp.c32 pxechn.c32 sanboot.c32 sdi.c32 vesainfo.c32
# All-architecture modules
diff --git a/com32/modules/play.c b/com32/modules/play.c
new file mode 100644
index 00000000..68741bf5
--- /dev/null
+++ b/com32/modules/play.c
@@ -0,0 +1,95 @@
+/*
+ * Plays a tune through the PC speaker.
+ *
+ * This file is based loosely on similar GRUB2 code.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/io.h>
+#include <unistd.h>
+
+#define SPEAKER_PIT_FREQUENCY 0x1234dd
+#define BASE_TEMPO (60 * 1000)
+#define T_REST 0
+
+#define PIT_COUNTER_2 0x42
+#define PIT_CTRL 0x43
+#define PIT_SPEAKER_PORT 0x61
+
+#define PIT_SPK_TMR2 0x01
+#define PIT_SPK_DATA 0x02
+#define PIT_SPK_TMR2_LATCH 0x20
+#define PIT_CTRL_SELECT_2 0x80
+#define PIT_CTRL_READLOAD_WORD 0x30
+#define PIT_CTRL_SQUAREWAVE_GEN 0x06
+#define PIT_CTRL_COUNT_BINARY 0x00
+
+static void beep_off(void)
+{
+ unsigned char status;
+
+ status = inb(PIT_SPEAKER_PORT);
+ outb(status & ~(PIT_SPK_TMR2 | PIT_SPK_DATA), PIT_SPEAKER_PORT);
+}
+
+static void beep_on(uint16_t pitch)
+{
+ unsigned char status;
+ unsigned int counter;
+
+ if (pitch < 20)
+ pitch = 20;
+ else if (pitch > 20000)
+ pitch = 20000;
+
+ counter = SPEAKER_PIT_FREQUENCY / pitch;
+ outb(PIT_CTRL_SELECT_2
+ | PIT_CTRL_READLOAD_WORD
+ | PIT_CTRL_SQUAREWAVE_GEN
+ | PIT_CTRL_COUNT_BINARY, PIT_CTRL);
+ outb(counter & 0xff, PIT_COUNTER_2);
+ outb((counter >> 8) & 0xff, PIT_COUNTER_2);
+
+ status = inb(PIT_SPEAKER_PORT);
+ outb(status | PIT_SPK_TMR2 | PIT_SPK_DATA, PIT_SPEAKER_PORT);
+}
+
+static void play(unsigned int tempo, uint16_t pitch, uint16_t duration)
+{
+ unsigned int ms = BASE_TEMPO * duration / tempo;
+
+ switch (pitch) {
+ case T_REST:
+ beep_off();
+ break;
+ default:
+ beep_on(pitch);
+ break;
+ }
+
+ msleep(ms);
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ unsigned int tempo = 0;
+
+ tempo = strtol(argv[1], NULL, 10);
+ if (!tempo) {
+ printf("usage: play [<tempo>] [<pitch> <duration>...]\n");
+ return 1;
+ }
+
+ for (i = 2; i + 1 < argc; i += 2) {
+ uint16_t pitch;
+ uint16_t duration;
+
+ pitch = strtol(argv[i], NULL, 10);
+ duration = strtol(argv[i + 1], NULL, 10);
+ play(tempo, pitch, duration);
+ }
+
+ beep_off();
+ return 0;
+}
--
2.25.0
More information about the Syslinux
mailing list