mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2025-02-25 18:55:23 -06:00
Add beep sound upon pass or failure, based on PIT channel 2.
Changes by Lionel Debroux: * disable sound output by default, and make it possible to enable it, but do intentionally not document the feature; * improve commit message; * fix data types; * replace static const variables by #defines - it's a bit early to use C23 constexpr; * make the coding style consistent with the rest of the memtest86+ code base.
This commit is contained in:
parent
9053696e12
commit
8244b5afde
@ -99,6 +99,7 @@ bool enable_sm = true;
|
||||
bool enable_bench = true;
|
||||
bool enable_mch_read = true;
|
||||
bool enable_numa = false;
|
||||
bool enable_sound = false;
|
||||
|
||||
bool enable_ecc_polling = false;
|
||||
|
||||
@ -262,6 +263,8 @@ static void parse_option(const char *option, const char *params)
|
||||
} else if (strncmp(params, "high", 5) == 0) {
|
||||
power_save = POWER_SAVE_HIGH;
|
||||
}
|
||||
} else if (strncmp(option, "sound", 6) == 0) {
|
||||
enable_sound = true;
|
||||
} else if (strncmp(option, "trace", 6) == 0) {
|
||||
enable_trace = true;
|
||||
} else if (strncmp(option, "usbdebug", 9) == 0) {
|
||||
|
@ -63,6 +63,7 @@ extern bool enable_bench;
|
||||
extern bool enable_mch_read;
|
||||
extern bool enable_ecc_polling;
|
||||
extern bool enable_numa;
|
||||
extern bool enable_sound;
|
||||
|
||||
extern bool pause_at_start;
|
||||
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
#include "tests.h"
|
||||
|
||||
#include "sound.h"
|
||||
|
||||
#include "display.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -397,6 +399,10 @@ void display_big_status(bool pass)
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable_sound) {
|
||||
sound_beep(pass);
|
||||
}
|
||||
|
||||
save_screen_region(POP_STATUS_REGION, popup_status_save_buffer);
|
||||
|
||||
set_background_colour(BLACK);
|
||||
@ -576,6 +582,9 @@ void do_tick(int my_cpu)
|
||||
if (update_spinner) {
|
||||
spin_idx = (spin_idx + 1) % NUM_SPIN_STATES;
|
||||
display_spinner(spin_state[spin_idx]);
|
||||
if (enable_sound) {
|
||||
sound_tick_task();
|
||||
}
|
||||
}
|
||||
|
||||
// This only tick one time per second
|
||||
|
47
app/sound.c
Normal file
47
app/sound.c
Normal file
@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2024 Anton Ivanov (aka demiurg_spb+rigler).
|
||||
// Copyright (C) 2024 Lionel Debroux.
|
||||
#include <stdbool.h>
|
||||
#include "pit.h"
|
||||
#include "sound.h" // self to check prototypes
|
||||
|
||||
static bool enabled;
|
||||
static unsigned int duration;
|
||||
|
||||
#define DURATION (7)
|
||||
|
||||
static void beep_off()
|
||||
{
|
||||
if (enabled) {
|
||||
enabled = 0;
|
||||
duration = 0;
|
||||
pit_off();
|
||||
}
|
||||
}
|
||||
|
||||
static void beep_on(unsigned f_hz)
|
||||
{
|
||||
if (!enabled) {
|
||||
enabled = 1;
|
||||
duration = DURATION;
|
||||
pit_init_square_wave_generator(2, f_hz); // pit-ch2 is connected to buzzer
|
||||
}
|
||||
}
|
||||
|
||||
void sound_beep(bool ok)
|
||||
{
|
||||
#define beep_freq_ok (1100)
|
||||
#define beep_freq_er ( 380)
|
||||
|
||||
beep_on(ok ? beep_freq_ok : beep_freq_er);
|
||||
}
|
||||
|
||||
void sound_tick_task(void)
|
||||
{
|
||||
if (duration) {
|
||||
duration--;
|
||||
}
|
||||
else {
|
||||
beep_off();
|
||||
}
|
||||
}
|
18
app/sound.h
Normal file
18
app/sound.h
Normal file
@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef SOUND_H
|
||||
#define SOUND_H
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Provides types and variables used when performing the memory tests.
|
||||
*
|
||||
* Copyright (C) 2024 Anton Ivanov (aka demiurg_spb+rigler).
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
void sound_beep(bool ok);
|
||||
void sound_tick_task(void);
|
||||
|
||||
|
||||
#endif // SOUND_H
|
@ -78,6 +78,7 @@ TST_OBJS = tests/addr_walk1.o \
|
||||
|
||||
APP_OBJS = app/badram.o \
|
||||
app/config.o \
|
||||
app/sound.o \
|
||||
app/display.o \
|
||||
app/error.o \
|
||||
app/interrupt.o \
|
||||
|
@ -77,6 +77,7 @@ TST_OBJS = tests/addr_walk1.o \
|
||||
|
||||
APP_OBJS = app/badram.o \
|
||||
app/config.o \
|
||||
app/sound.o \
|
||||
app/display.o \
|
||||
app/error.o \
|
||||
app/interrupt.o \
|
||||
|
105
system/pit.h
Normal file
105
system/pit.h
Normal file
@ -0,0 +1,105 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef PIT_H
|
||||
#define PIT_H
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Provides types and variables used to work with PIT
|
||||
*
|
||||
* This will work on real hardware and in QEMU if it started with -audiodev pa,id=speaker -machine pcspk-audiodev=speaker.
|
||||
* The code also changes the PIT timer 2 frequency, so you will have to reset that when you're done "beep"ing :)
|
||||
*
|
||||
* hints:
|
||||
* https://wiki.osdev.org/PC_Speaker
|
||||
* https://wiki.osdev.org/Programmable_Interval_Timer
|
||||
* https://stackoverflow.com/questions/8960620/low-level-i-o-access-using-outb-and-inb
|
||||
* https://stackoverflow.com/questions/14194798/is-there-a-specification-of-x86-i-o-port-assignment
|
||||
* https://stackoverflow.com/questions/22355436/how-to-compile-32-bit-apps-on-64-bit-ubuntu
|
||||
*
|
||||
* outb() and friends are hardware-specific. The value argument is
|
||||
* passed first and the port argument is passed second, which is the
|
||||
* opposite order from most DOS implementations.
|
||||
*
|
||||
* void outb(unsigned char value, unsigned short port);
|
||||
*
|
||||
* Copyright (C) 2024 Anton Ivanov (aka demiurg_spb+rigler).
|
||||
* Copyright (C) 2024 Lionel Debroux.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/io.h> // if file not found for 32bit-target in 64bit OS: "sudo apt install gcc-multilib g++-multilib"
|
||||
|
||||
#define PIT_CH0_PORT (0x0040U) // r/w
|
||||
#define PIT_CH1_PORT (0x0041U) // r/w
|
||||
#define PIT_CH2_PORT (0x0042U) // r/w
|
||||
#define PIT_CTL_PORT (0x0043U) // write only
|
||||
#define PIT_STATUS_PORT (0x0061U)
|
||||
|
||||
#define PIT_STATUS_MASK (0b00000011)
|
||||
|
||||
#define _PIT_CTL_CH(x) (((x)&3U)<<6) // 0-ch0, 1-ch1, 2-ch2, 3-Read-back command (8254 only)
|
||||
|
||||
#define PIT_CTL_CH0 _PIT_CTL_CH(0)
|
||||
#define PIT_CTL_CH1 _PIT_CTL_CH(1)
|
||||
#define PIT_CTL_CH2 _PIT_CTL_CH(2)
|
||||
#define PIT_CTL_READ_BACK _PIT_CTL_CH(3)
|
||||
|
||||
|
||||
#define _PIT_CTL_ACCESS(x) (((x)&3U)<<4) // 0-Latch count value command, 1-lbyte, 2-hbyte, 3-lobyte/hibyte
|
||||
|
||||
#define PIT_CTL_ACCESS_LATCH_CNT_VAL _PIT_CTL_ACCESS(0)
|
||||
#define PIT_CTL_ACCESS_LBYTE _PIT_CTL_ACCESS(1)
|
||||
#define PIT_CTL_ACCESS_HBYTE _PIT_CTL_ACCESS(2)
|
||||
#define PIT_CTL_ACCESS_LBYTE_HBYTE _PIT_CTL_ACCESS(3)
|
||||
|
||||
|
||||
#define _PIT_CTL_OP_MODE(x) (((x)&7U)<<1)
|
||||
|
||||
#define PIT_CTL_OP_MODE0 _PIT_CTL_OP_MODE(0) // (interrupt on terminal count)
|
||||
#define PIT_CTL_OP_MODE1 _PIT_CTL_OP_MODE(1) // (hardware re-triggerable one-shot)
|
||||
#define PIT_CTL_OP_MODE2 _PIT_CTL_OP_MODE(2) // (rate generator)
|
||||
#define PIT_CTL_OP_MODE3 _PIT_CTL_OP_MODE(3) // (square wave generator)
|
||||
#define PIT_CTL_OP_MODE4 _PIT_CTL_OP_MODE(4) // (software triggered strobe)
|
||||
#define PIT_CTL_OP_MODE5 _PIT_CTL_OP_MODE(5) // (hardware triggered strobe)
|
||||
|
||||
|
||||
#define _PIT_CTL_BCD_MODE(x) ((x)&1U)
|
||||
|
||||
#define PIT_CTL_BIN16_MODE _PIT_CTL_BCD_MODE(0) // 16-bit binary
|
||||
#define PIT_CTL_BCD4_MODE _PIT_CTL_BCD_MODE(1) // four-digit BCD
|
||||
|
||||
|
||||
static inline uint32_t pit_freq2div(unsigned frequency)
|
||||
{
|
||||
return (uint32_t)(0.5f + 1193180.0f/frequency);
|
||||
}
|
||||
|
||||
static inline void pit_off(void)
|
||||
{
|
||||
const unsigned char x = inb(PIT_STATUS_PORT) & ~PIT_STATUS_MASK;
|
||||
|
||||
outb(x, PIT_STATUS_PORT);
|
||||
}
|
||||
|
||||
static inline void pit_init_square_wave_generator(unsigned char ch, uint32_t frequency)
|
||||
{
|
||||
const uint32_t clk_div = pit_freq2div(frequency);
|
||||
|
||||
const unsigned char cfg = PIT_CTL_OP_MODE3 | PIT_CTL_BIN16_MODE | PIT_CTL_ACCESS_LBYTE_HBYTE | _PIT_CTL_CH(ch);
|
||||
|
||||
const unsigned short PIT_DATA_PORT = PIT_CH0_PORT + ch; // base + offset
|
||||
|
||||
outb(cfg, PIT_CTL_PORT); // 0xb6 = 0b10110110
|
||||
|
||||
outb((uint8_t)clk_div, PIT_DATA_PORT); // low byte
|
||||
outb((uint8_t)(clk_div>>8), PIT_DATA_PORT); // hi byte
|
||||
|
||||
unsigned char x = inb(PIT_STATUS_PORT);
|
||||
|
||||
if (!(x&PIT_STATUS_MASK)) {
|
||||
outb(x|PIT_STATUS_MASK, PIT_STATUS_PORT);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PIT_H
|
Loading…
Reference in New Issue
Block a user