Added new bochsrc option to control the speaker output mode. The choices 'sound'

(lowlevel sound output), 'system' (system beep on Linux and Windows) and 'gui'
(forward beep to related gui methods) are available.
This commit is contained in:
Volker Ruppert 2013-06-16 18:52:34 +00:00
parent f1c6be0bc8
commit c3740c0e6e
4 changed files with 134 additions and 42 deletions

View File

@ -721,6 +721,17 @@ debugger_log: -
#=======================================================================
parport1: enabled=1, file="parport.out"
#=======================================================================
# SPEAKER:
# This defines the PC speaker output mode. In the 'sound' mode the beep
# is generated by the square wave generator which is a part of the
# lowlevel sound support. The 'system' mode is only available on Linux
# and Windows. On Linux /dev/console is used for output and on Windows
# the Beep() function. The 'gui' mode forwards the beep to the related
# gui methods (currently only used by the Carbon gui).
#=======================================================================
speaker: enabled=1, mode=sound
#=======================================================================
# SB16:
# This defines the SB16 sound emulation. It can have several of the

View File

@ -43,11 +43,71 @@
bx_speaker_c *theSpeaker= NULL;
#define BX_SPK_MODE_NONE 0
#define BX_SPK_MODE_SOUND 1
#define BX_SPK_MODE_SYSTEM 2
#define BX_SPK_MODE_GUI 3
// builtin configuration handling functions
void speaker_init_options(void)
{
static const char *speaker_mode_list[] = {
#if BX_SUPPORT_SOUNDLOW
"sound",
#endif
#if defined(__linux__) || defined(WIN32)
"system",
#endif
"gui",
NULL
};
bx_list_c *sound = (bx_list_c*)SIM->get_param("sound");
bx_list_c *menu = new bx_list_c(sound, "speaker", "PC speaker output configuration");
menu->set_options(menu->SERIES_ASK);
bx_param_bool_c *enabled = new bx_param_bool_c(menu, "enabled", "Enable speaker output",
"Enables the PC speaker output", 1);
bx_param_enum_c *mode = new bx_param_enum_c(menu, "mode", "Speaker output mode",
"The mode can be one these: 'sound', 'system' or 'gui'",
speaker_mode_list, 0, 0);
mode->set_ask_format("Select speker output mode [%s] ");
bx_list_c *deplist = new bx_list_c(NULL);
deplist->add(mode);
enabled->set_dependent_list(deplist);
}
Bit32s speaker_options_parser(const char *context, int num_params, char *params[])
{
if (!strcmp(params[0], "speaker")) {
bx_list_c *base = (bx_list_c*) SIM->get_param(BXPN_SOUND_SPEAKER);
for (int i=1; i<num_params; i++) {
if (SIM->parse_param_from_list(context, params[i], base) < 0) {
BX_ERROR(("%s: unknown parameter for speaker ignored.", context));
}
}
} else {
BX_PANIC(("%s: unknown directive '%s'", context, params[0]));
}
return 0;
}
Bit32s speaker_options_save(FILE *fp)
{
return SIM->write_param_list(fp, (bx_list_c*) SIM->get_param(BXPN_SOUND_SPEAKER), NULL, 0);
}
// device plugin entry points
int libspeaker_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
theSpeaker = new bx_speaker_c();
bx_devices.pluginSpeaker = theSpeaker;
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theSpeaker, BX_PLUGIN_SPEAKER);
// add new configuration parameters for the config interface
speaker_init_options();
// register add-on options for bochsrc and command line
SIM->register_addon_option("speaker", speaker_options_parser, speaker_options_save);
return(0); // Success
}
@ -55,8 +115,12 @@ void libspeaker_LTX_plugin_fini(void)
{
bx_devices.pluginSpeaker = &bx_devices.stubSpeaker;
delete theSpeaker;
SIM->unregister_addon_option("speaker");
((bx_list_c*)SIM->get_param("sound"))->remove("speaker");
}
// the device object
bx_speaker_c::bx_speaker_c()
{
put("speaker", "SPEAK");
@ -80,22 +144,21 @@ bx_speaker_c::~bx_speaker_c()
void bx_speaker_c::init(void)
{
outputinit = 0;
#if defined(WIN32)
useBeep = FALSE;
#endif
}
void bx_speaker_c::reset(unsigned type)
{
if (!outputinit) {
outputinit = 1;
#if BX_SUPPORT_SOUNDLOW
if (DEV_soundmod_beep_off()) {
BX_INFO(("Using lowlevel sound support for output"));
return;
}
#endif
// Read in values from config interface
bx_list_c *base = (bx_list_c*) SIM->get_param(BXPN_SOUND_SPEAKER);
// Check if the device is disabled or not configured
if (!SIM->get_param_bool("enabled", base)->get()) {
BX_INFO(("PC speaker output disabled"));
// mark unused plugin for removal
((bx_param_bool_c*)((bx_list_c*)SIM->get_param(BXPN_PLUGIN_CTRL))->get_by_name("sb16"))->set(0);
return;
}
const char *mode = SIM->get_param_enum("mode", base)->get_selected();
if (!strcmp(mode, "sound")) {
output_mode = BX_SPK_MODE_SOUND;
BX_INFO(("Using lowlevel sound support for output"));
} else if (!strcmp(mode, "system")) {
output_mode = BX_SPK_MODE_SYSTEM;
#ifdef __linux__
consolefd = open("/dev/console", O_WRONLY);
if (consolefd != -1) {
@ -106,7 +169,24 @@ void bx_speaker_c::reset(unsigned type)
}
#elif defined(WIN32)
BX_INFO(("Using system beep for output"));
useBeep = TRUE;
#endif
} else if (!strcmp(mode, "gui")) {
output_mode = BX_SPK_MODE_GUI;
BX_INFO(("Forwarding beep to gui"));
} else {
output_mode = BX_SPK_MODE_NONE;
}
outputinit = 0;
}
void bx_speaker_c::reset(unsigned type)
{
if (!outputinit) {
outputinit = 1;
#if BX_SUPPORT_SOUNDLOW
if (!DEV_soundmod_beep_off()) {
BX_ERROR(("Failed to use lowlevel sound support for output"));
}
#endif
}
@ -116,29 +196,29 @@ void bx_speaker_c::reset(unsigned type)
void bx_speaker_c::beep_on(float frequency)
{
#if defined(WIN32)
if (useBeep && (beep_frequency != 0.0)) {
if ((output_mode == BX_SPK_MODE_SYSTEM) && (beep_frequency != 0.0)) {
beep_off();
}
#endif
beep_frequency = frequency;
if (output_mode == BX_SPK_MODE_SOUND) {
#if BX_SUPPORT_SOUNDLOW
if (DEV_soundmod_beep_on(frequency))
return;
DEV_soundmod_beep_on(frequency);
#endif
} else if (output_mode == BX_SPK_MODE_SYSTEM) {
#ifdef __linux__
if (consolefd != -1) {
this->info("pc speaker on with frequency %f", frequency);
ioctl(consolefd, KIOCSOUND, (int)(clock_tick_rate/frequency));
}
if (consolefd != -1) {
BX_DEBUG(("PC speaker on with frequency %f", frequency));
ioctl(consolefd, KIOCSOUND, (int)(clock_tick_rate/frequency));
}
#elif defined(WIN32)
if (useBeep) {
usec_start = bx_pc_system.time_usec();
}
#endif
// give the gui a chance to signal beep on
bx_gui->beep_on(frequency);
} else if (output_mode == BX_SPK_MODE_GUI) {
// give the gui a chance to signal beep on
bx_gui->beep_on(frequency);
}
}
#if defined(WIN32)
@ -163,28 +243,28 @@ DWORD WINAPI BeepThread(LPVOID)
void bx_speaker_c::beep_off()
{
if (output_mode == BX_SPK_MODE_SOUND) {
#if BX_SUPPORT_SOUNDLOW
if (DEV_soundmod_beep_off())
return;
DEV_soundmod_beep_off();
#endif
if (beep_frequency != 0.0) {
} else if (output_mode == BX_SPK_MODE_SYSTEM) {
if (beep_frequency != 0.0) {
#ifdef __linux__
if (consolefd != -1) {
ioctl(consolefd, KIOCSOUND, 0);
}
if (consolefd != -1) {
ioctl(consolefd, KIOCSOUND, 0);
}
#elif defined(WIN32)
// FIXME: sound should start at beep_on() and end here
if (useBeep) {
// FIXME: sound should start at beep_on() and end here
DWORD threadID;
beep_info.msec = (DWORD)((bx_pc_system.time_usec() - usec_start) / 1000);
beep_info.frequency = (DWORD)beep_frequency;
CreateThread(NULL, 0, BeepThread, NULL, 0, &threadID);
}
#endif
}
} else if (output_mode == BX_SPK_MODE_GUI) {
// give the gui a chance to signal beep off
bx_gui->beep_off();
beep_frequency = 0.0;
}
beep_frequency = 0.0;
}

View File

@ -41,12 +41,12 @@ public:
private:
float beep_frequency; // 0 : beep is off
bx_bool outputinit;
unsigned output_mode;
#ifdef __linux__
/* Do we have access? If not, just skip everything else. */
signed int consolefd;
const static unsigned int clock_tick_rate = 1193180;
#elif defined(WIN32)
BOOL useBeep;
Bit64u usec_start;
#endif
};

View File

@ -172,6 +172,7 @@
#define BXPN_PNIC_ENABLED "network.pcipnic.enabled"
#define BXPN_E1000 "network.e1000"
#define BXPN_E1000_ENABLED "network.e1000.enabled"
#define BXPN_SOUND_SPEAKER "sound.speaker"
#define BXPN_SOUND_SB16 "sound.sb16"
#define BXPN_SB16_DMATIMER "sound.sb16.dmatimer"
#define BXPN_SB16_LOGLEVEL "sound.sb16.loglevel"