]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
boot: Add PC speaker support
authorJan Janssen <medhefgo@web.de>
Fri, 14 Jan 2022 13:27:08 +0000 (14:27 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Sun, 16 Jan 2022 10:34:01 +0000 (10:34 +0000)
Fixes: #17508
man/loader.conf.xml
src/boot/efi/boot.c
src/boot/efi/util.c
src/boot/efi/util.h

index 579eaddebe1bbeb25c9844a92a46d8cc3de7b586..844bd631fc014978b080c41e0719e662717b2154 100644 (file)
         by using the <keycap>f</keycap> key.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term>beep</term>
+
+        <listitem><para>Beep once as soon as the boot menu is shown (default disabled). Currently,
+        only x86 is supported, where it uses the PC speaker.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term>reboot-for-bitlocker</term>
 
index c07f629939950e2b17ef873f5a9b5b4cf50ef44c..a128b38b9c6eeb64b73c7410b728f5bc46d0dd0e 100644 (file)
@@ -89,6 +89,7 @@ typedef struct {
         BOOLEAN force_menu;
         BOOLEAN use_saved_entry;
         BOOLEAN use_saved_entry_efivar;
+        BOOLEAN beep;
         INT64 console_mode;
         INT64 console_mode_efivar;
         RandomSeedMode random_seed_mode;
@@ -497,6 +498,7 @@ static void print_status(Config *config, CHAR16 *loaded_image_path) {
           ps_bool(L"                editor: %s\n", config->editor);
           ps_bool(L"          auto-entries: %s\n", config->auto_entries);
           ps_bool(L"         auto-firmware: %s\n", config->auto_firmware);
+          ps_bool(L"                  beep: %s\n", config->beep);
           ps_bool(L"  reboot-for-bitlocker: %s\n", config->reboot_for_bitlocker);
         ps_string(L"      random-seed-mode: %s\n", random_seed_modes_table[config->random_seed_mode]);
 
@@ -588,7 +590,7 @@ static BOOLEAN menu_run(
         _cleanup_freepool_ CHAR16 *clearline = NULL, *status = NULL;
         UINT32 timeout_efivar_saved = config->timeout_sec_efivar;
         UINT32 timeout_remain = config->timeout_sec == TIMEOUT_MENU_FORCE ? 0 : config->timeout_sec;
-        BOOLEAN exit = FALSE, run = TRUE, firmware_setup = FALSE;
+        BOOLEAN exit = FALSE, run = TRUE, firmware_setup = FALSE, do_beep = config->beep;
         INT64 console_mode_initial = ST->ConOut->Mode->Mode, console_mode_efivar_saved = config->console_mode_efivar;
         UINTN default_efivar_saved = config->idx_default_efivar;
 
@@ -725,6 +727,11 @@ static BOOLEAN menu_run(
                         ST->ConOut->OutputString(ST->ConOut, clearline + 1 + x + len);
                 }
 
+                if (do_beep) {
+                        beep();
+                        do_beep = FALSE;
+                }
+
                 err = console_key_read(&key, timeout_remain > 0 ? 1000 * 1000 : UINT64_MAX);
                 if (err == EFI_TIMEOUT) {
                         timeout_remain--;
@@ -1144,6 +1151,12 @@ static void config_defaults_load_from_file(Config *config, CHAR8 *content) {
                         continue;
                 }
 
+                if (strcmpa((CHAR8 *)"beep", key) == 0) {
+                        err = parse_boolean(value, &config->beep);
+                        if (EFI_ERROR(err))
+                                log_error_stall(L"Error parsing 'beep' config option: %a", value);
+                }
+
                 if (strcmpa((CHAR8 *)"reboot-for-bitlocker", key) == 0) {
                         err = parse_boolean(value, &config->reboot_for_bitlocker);
                         if (EFI_ERROR(err))
index 177c1b3d9a6b4e48cda76209df806cf0e9ac8487..42c28badbf4d9db8b8b1290e64f60970ad7ee1f9 100644 (file)
@@ -757,3 +757,46 @@ __attribute__((noinline)) void debug_break(void) {
 #endif
 }
 #endif
+
+#if defined(__i386__) || defined(__x86_64__)
+static inline UINT8 inb(UINT16 port) {
+        UINT8 value;
+        asm volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
+        return value;
+}
+
+static inline void outb(UINT16 port, UINT8 value) {
+        asm volatile("outb %0, %1" : : "a"(value), "Nd"(port));
+}
+
+void beep(void) {
+        enum {
+                PITCH                = 500,
+                DURATION_USEC        = 100 * 1000,
+
+                PIT_FREQUENCY        = 0x1234dd,
+                SPEAKER_CONTROL_PORT = 0x61,
+                SPEAKER_ON_MASK      = 0x03,
+                TIMER_PORT_MAGIC     = 0xB6,
+                TIMER_CONTROL_PORT   = 0x43,
+                TIMER_CONTROL2_PORT  = 0x42,
+        };
+
+        /* Set frequency. */
+        UINT32 counter = PIT_FREQUENCY / PITCH;
+        outb(TIMER_CONTROL_PORT, TIMER_PORT_MAGIC);
+        outb(TIMER_CONTROL2_PORT, counter & 0xFF);
+        outb(TIMER_CONTROL2_PORT, (counter >> 8) & 0xFF);
+
+        /* Turn speaker on. */
+        UINT8 value = inb(SPEAKER_CONTROL_PORT);
+        value |= SPEAKER_ON_MASK;
+        outb(SPEAKER_CONTROL_PORT, value);
+
+        BS->Stall(DURATION_USEC);
+
+        /* Turn speaker off. */
+        value &= ~SPEAKER_ON_MASK;
+        outb(SPEAKER_CONTROL_PORT, value);
+}
+#endif
index 9e8db3e7c9c8d91c099abbd140875d6b54477a6d..8cee20885e52278a7da1c1560ec9c1e8099e708f 100644 (file)
@@ -169,3 +169,9 @@ extern UINT8 _text, _data;
 #else
 #  define debug_hook(identity)
 #endif
+
+#if defined(__i386__) || defined(__x86_64__)
+void beep(void);
+#else
+static inline void beep(void) {}
+#endif