[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