foxygit / doom Log in
commit eba59fdf4448693b73b19ba12a11bff265d4ddfc
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Fri Mar 9 23:30:46 2007 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Fri Mar 9 23:30:46 2007 +0000

    Add pcsound Linux driver.

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 851
---
 configure.in            |   2 +
 pcsound/Makefile.am     |   1 +
 pcsound/pcsound.c       |   9 ++++
 pcsound/pcsound.h       |   2 +
 pcsound/pcsound_linux.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 140 insertions(+)

diff --git a/configure.in b/configure.in
index 7559470f..bf0cdce6 100644
--- a/configure.in
+++ b/configure.in
@@ -22,6 +22,8 @@ then
         CFLAGS="-O$OPT_LEVEL -g -Wall $orig_CFLAGS"
 fi

+AC_CHECK_HEADERS([linux/kd.h])
+
 AM_PATH_SDL(1.1.3)

 AC_CHECK_LIB(SDL_mixer,Mix_LoadMUS,[
diff --git a/pcsound/Makefile.am b/pcsound/Makefile.am
index 77957d72..b51268df 100644
--- a/pcsound/Makefile.am
+++ b/pcsound/Makefile.am
@@ -6,5 +6,6 @@ noinst_LIBRARIES=libpcsound.a
 libpcsound_a_SOURCES =                            \
         pcsound.c           pcsound.h             \
         pcsound_sdl.c                             \
+        pcsound_linux.c                           \
         pcsound_win32.c

diff --git a/pcsound/pcsound.c b/pcsound/pcsound.c
index 9c18eb01..1491ff61 100644
--- a/pcsound/pcsound.c
+++ b/pcsound/pcsound.c
@@ -27,15 +27,24 @@
 #include <stdlib.h>
 #include <string.h>

+#include "config.h"
 #include "pcsound.h"

 #ifdef _WIN32
 extern pcsound_driver_t pcsound_win32_driver;
 #endif
+
+#ifdef HAVE_LINUX_KD_H
+extern pcsound_driver_t pcsound_linux_driver;
+#endif
+
 extern pcsound_driver_t pcsound_sdl_driver;

 static pcsound_driver_t *drivers[] =
 {
+#ifdef HAVE_LINUX_KD_H
+    &pcsound_linux_driver,
+#endif
 #ifdef _WIN32
     &pcsound_win32_driver,
 #endif
diff --git a/pcsound/pcsound.h b/pcsound/pcsound.h
index 1adee416..12a4ffe9 100644
--- a/pcsound/pcsound.h
+++ b/pcsound/pcsound.h
@@ -26,6 +26,8 @@
 #ifndef PCSOUND_H
 #define PCSOUND_H

+#define PCSOUND_8253_FREQUENCY 1193280
+
 typedef struct pcsound_driver_s pcsound_driver_t;
 typedef void (*pcsound_callback_func)(int *duration, int *frequency);
 typedef int (*pcsound_init_func)(pcsound_callback_func callback);
diff --git a/pcsound/pcsound_linux.c b/pcsound/pcsound_linux.c
new file mode 100644
index 00000000..df2015d5
--- /dev/null
+++ b/pcsound/pcsound_linux.c
@@ -0,0 +1,126 @@
+// Emacs style mode select   -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2007 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//    PC speaker driver for Linux.
+//
+//-----------------------------------------------------------------------------
+
+#include "config.h"
+
+#ifdef HAVE_LINUX_KD_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/kd.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "SDL.h"
+#include "SDL_thread.h"
+
+#include "pcsound.h"
+
+#define CONSOLE_DEVICE "/dev/console"
+
+static int console_handle;
+static pcsound_callback_func callback;
+static int sound_thread_running = 0;
+static SDL_Thread *sound_thread_handle;
+
+static int SoundThread(void *unused)
+{
+    int frequency;
+    int duration;
+    int cycles;
+
+    while (sound_thread_running)
+    {
+        callback(&duration, &frequency);
+
+        if (frequency != 0)
+        {
+            cycles = PCSOUND_8253_FREQUENCY / frequency;
+        }
+        else
+        {
+            cycles = 0;
+        }
+
+        ioctl(console_handle, KIOCSOUND, cycles);
+
+        usleep(duration * 1000);
+    }
+
+    return 0;
+}
+
+static int PCSound_Linux_Init(pcsound_callback_func callback_func)
+{
+    // Try to open the console
+
+    console_handle = open(CONSOLE_DEVICE, O_WRONLY);
+
+    if (console_handle == -1)
+    {
+        // Don't have permissions for the console device?
+
+	fprintf(stderr, "PCSound_Linux_Init: Failed to open '%s': %s\n",
+			CONSOLE_DEVICE, strerror(errno));
+        return 0;
+    }
+
+    if (ioctl(console_handle, KIOCSOUND, 0) < 0)
+    {
+        // KIOCSOUND not supported: non-PC linux?
+
+        close(console_handle);
+        return 0;
+    }
+
+    // Start a thread up to generate PC speaker output
+
+    callback = callback_func;
+    sound_thread_running = 1;
+
+    sound_thread_handle = SDL_CreateThread(SoundThread, NULL);
+
+    return 1;
+}
+
+static void PCSound_Linux_Shutdown(void)
+{
+    sound_thread_running = 0;
+    SDL_WaitThread(sound_thread_handle, NULL);
+    close(console_handle);
+}
+
+pcsound_driver_t pcsound_linux_driver =
+{
+    "Linux",
+    PCSound_Linux_Init,
+    PCSound_Linux_Shutdown,
+};
+
+#endif /* #ifdef HAVE_LINUX_KD_H */
+