$NetBSD: patch-ag,v 1.10 2006/10/18 13:11:59 rillig Exp $

--- unix/unix.cpp.orig	2004-12-31 00:15:47 +0200
+++ unix/unix.cpp	2009-03-13 15:14:04 +0200
@@ -117,15 +117,25 @@
 
 #ifdef USE_THREADS
 #include <pthread.h>
+#ifdef __NetBSD__
+#include <sys/sched.h>
+#else
 #include <sched.h>
+#endif
 
 pthread_t thread;
 pthread_mutex_t mutex;
 #endif
 
-#if !defined(NOSOUND) && defined(__linux)
+#if !defined(NOSOUND)
+#if defined(__linux)
 #include <sys/soundcard.h>
 #include <sys/mman.h>
+#elif defined(__NetBSD__)
+#include <soundcard.h>
+#elif defined(__DragonFly__)
+#include <sys/soundcard.h>
+#endif
 #endif
 
 #if !defined(NOSOUND) && defined(__sun)
@@ -140,6 +150,9 @@ pthread_mutex_t mutex;
 //#if defined(__sun) && defined(__GNUC__)
 //typedef void (*SIG_PF)();
 //#endif
+#if defined(__NetBSD__) || defined(__DragonFly__)
+typedef void (*SIG_PF)(int);
+#endif
 
 #include "snes9x.h"
 #include "memmap.h"
@@ -168,6 +181,58 @@ uint32 joypads [5] = {0};
 int NumControllers = 5;
 
 #ifdef JOYSTICK_SUPPORT
+#if defined(__NetBSD__) || defined(__DragonFly__)
+#if defined(HAVE_USBHID_H)
+START_EXTERN_C
+#include <usbhid.h>
+END_EXTERN_C
+#else
+#include <usb.h>
+#endif
+#define class Class
+#if defined(__DragonFly__)
+#include <bus/usb/usb.h>
+#include <bus/usb/usbhid.h>
+#else
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+#endif
+
+struct priv_joydata_struct
+{
+    struct hid_item *hids;
+    int dlen;
+    int offset;
+    char *data_buf;
+} priv_joy_data[4];
+
+int js_fd [4] = {-1, -1, -1, -1};
+int js_map_button [4][16] = {
+    {
+       SNES_A_MASK, SNES_B_MASK, SNES_X_MASK, SNES_Y_MASK,
+       SNES_TL_MASK, SNES_TR_MASK, SNES_START_MASK, SNES_SELECT_MASK,
+       0, 0, 0, 0, 0, 0, 0, 0
+    },
+    {
+       SNES_A_MASK, SNES_B_MASK, SNES_X_MASK, SNES_Y_MASK,
+       SNES_TL_MASK, SNES_TR_MASK, SNES_START_MASK, SNES_SELECT_MASK,
+       0, 0, 0, 0, 0, 0, 0, 0
+    },
+    {
+       SNES_A_MASK, SNES_B_MASK, SNES_X_MASK, SNES_Y_MASK,
+       SNES_TL_MASK, SNES_TR_MASK, SNES_START_MASK, SNES_SELECT_MASK,
+       0, 0, 0, 0, 0, 0, 0, 0
+    },
+    {
+       SNES_A_MASK, SNES_B_MASK, SNES_X_MASK, SNES_Y_MASK,
+       SNES_TL_MASK, SNES_TR_MASK, SNES_START_MASK, SNES_SELECT_MASK,
+       0, 0, 0, 0, 0, 0, 0, 0
+    }
+};
+
+char *js_device [4] = {"/dev/uhid0", "/dev/uhid1", "/dev/uhid2", "/dev/uhid3"};
+
+#endif
 #if defined(__linux)
 #include <linux/joystick.h>
 int js_fd [4] = {-1, -1, -1, -1};
@@ -227,7 +292,7 @@ char *snapshot_filename = NULL;
 char *SDD1_pack = NULL;
 
 //FIXME: I see no reason not to configureenable this for all Unixen
-#if defined(DEBUGGER) && (defined(__linux) || defined(__sun))
+#if defined(DEBUGGER) && (defined(__linux) || defined(__sun) || defined(__NetBSD__) || defined(__DragonFly__))
 static void sigbrkhandler(int)
 {
     CPU.Flags |= DEBUG_MODE_FLAG;
@@ -700,6 +765,104 @@ void S9xInitInputDevices ()
 #ifdef JOYSTICK_SUPPORT
 void InitJoysticks ()
 {
+#if defined(__NetBSD__) || defined(__DragonFly__)
+    int i, size, is_joystick, report_id = 0;
+    struct hid_data *d;
+    struct hid_item h;
+    report_desc_t rd;
+
+    printf("USB joystick interface initialization...\n");
+
+    for (i = 0; i < 4; i++)
+    {
+       if ((js_fd [i] = open (js_device [i], O_RDONLY | O_NONBLOCK)) != -1)
+       {
+           if ((rd = hid_get_report_desc(js_fd [i])) == 0)
+           {
+               perror (js_device [i]);
+               close (js_fd [i]);
+           }
+
+           priv_joy_data[i].hids = NULL;
+
+#if defined(HAVE_USBHID_H)
+           if (ioctl(js_fd [i], USB_GET_REPORT_ID, &report_id) < 0)
+           {
+               perror (js_device [i]);
+               close (js_fd [i]);
+           }
+
+           size = hid_report_size(rd, hid_input, report_id);
+           priv_joy_data[i].offset = 0;
+#else
+           size = hid_report_size(rd, hid_input, &report_id);
+           priv_joy_data[i].offset = (report_id != 0);
+#endif
+           if ((priv_joy_data[i].data_buf = (char*)malloc(size)) == NULL)
+           {
+               printf("error: couldn't malloc %d bytes\n", size);
+               hid_dispose_report_desc(rd);
+           }
+           priv_joy_data[i].dlen = size;
+
+           is_joystick = 0;
+#if defined(HAVE_USBHID_H)
+           for (d = hid_start_parse(rd, 1 << hid_input, report_id); hid_get_item(d, &h); )
+#endif
+           {
+               int axes = 0, buttons = 0, usage, page, interesting_hid;
+
+               page = HID_PAGE(h.usage);
+               usage = HID_USAGE(h.usage);
+
+               is_joystick = is_joystick ||
+                   (h.kind == hid_collection &&
+                    page == HUP_GENERIC_DESKTOP &&
+                    (usage == HUG_JOYSTICK || usage == HUG_GAME_PAD));
+
+               if (h.kind != hid_input)
+                   continue;
+
+               if (!is_joystick)
+                   continue;
+
+               interesting_hid = TRUE;
+               if (page == HUP_GENERIC_DESKTOP)
+               {
+                   if (usage == HUG_X || usage == HUG_RX)
+                       axes = 1;
+                   else if (usage == HUG_Y || usage == HUG_RY)
+                       axes = 2;
+                   else if (usage == HUG_Z || usage == HUG_RZ)
+                       axes = 3;
+                   else
+                       interesting_hid = FALSE;
+               }
+               else if (page == HUP_BUTTON)
+               {
+                   if (usage > 0)
+                       buttons = usage;
+                   else
+                       interesting_hid = FALSE;
+
+               }
+
+               if (interesting_hid)
+               {
+                   h.next = priv_joy_data[i].hids;
+                   priv_joy_data[i].hids = (struct hid_item *)malloc(sizeof *(priv_joy_data[i].hids));
+                   if (priv_joy_data[i].hids == NULL)
+                   {
+                       printf("error: Not enough memory for joystick.\n");
+                       break;
+                   }
+                   *(priv_joy_data[i].hids) = h;
+               }
+           }
+           hid_end_parse(d);
+       }
+    }
+#endif
 #ifdef JSIOCGVERSION
     int version;
     unsigned char axes, buttons;
@@ -756,6 +919,77 @@ void InitJoysticks ()
 
 void ReadJoysticks ()
 {
+#if defined(__NetBSD__) || defined(__DragonFly__)
+    int i, usage, page, d;
+    struct hid_item *h;
+
+    for (i = 0; i < 4 && js_fd [i] >= 0; i++)
+    {
+       int len;
+
+       len = read(js_fd [i], priv_joy_data[i].data_buf, priv_joy_data[i].dlen);
+       if (len < priv_joy_data[i].dlen)
+           continue;
+
+       for (h = priv_joy_data[i].hids; h; h = h->next)
+       {
+           d = hid_get_data(priv_joy_data[i].data_buf + priv_joy_data[i].offset, h);
+
+           page = HID_PAGE(h->usage);
+           usage = HID_USAGE(h->usage);
+
+           if (page == HUP_GENERIC_DESKTOP)
+           {
+               int center, trigger_point;
+
+              center = (h->logical_maximum + h->logical_minimum) / 2;
+              trigger_point = (h->logical_maximum - h->logical_minimum) / 4;
+
+               if (usage == HUG_X || usage == HUG_RX)
+               {
+                   if (d < (center - trigger_point))
+                   {
+                       joypads [i] |= SNES_LEFT_MASK;
+                       joypads [i] &= ~SNES_RIGHT_MASK;
+                       continue;
+                   }
+                   if (d > (center + trigger_point))
+                   {
+                       joypads [i] &= ~SNES_LEFT_MASK;
+                       joypads [i] |= SNES_RIGHT_MASK;
+                       continue;
+                   }
+                   joypads [i] &= ~SNES_LEFT_MASK;
+                   joypads [i] &= ~SNES_RIGHT_MASK;
+               }
+               if (usage == HUG_Y || usage == HUG_RY)
+               {
+                   if (d < (center - trigger_point))
+                   {
+                       joypads [i] |= SNES_UP_MASK;
+                       joypads [i] &= ~SNES_DOWN_MASK;
+                       continue;
+                   }
+                   if (d > (center + trigger_point))
+                   {
+                       joypads [i] &= ~SNES_UP_MASK;
+                       joypads [i] |= SNES_DOWN_MASK;
+                       continue;
+                   }
+                   joypads [i] &= ~SNES_UP_MASK;
+                   joypads [i] &= ~SNES_DOWN_MASK;
+               }
+           }
+           else if (page == HUP_BUTTON)
+           {
+               if (d == h->logical_maximum)
+                   joypads [i] |= js_map_button [i][usage - 1];
+               else
+                   joypads [i] &= ~js_map_button [i][usage - 1];
+           }
+       }
+    }
+#endif
 #ifdef JSIOCGVERSION
     struct js_event js_ev;
     int i;
@@ -1129,11 +1363,11 @@ void _splitpath (const char *path, char 
 {
     *drive = 0;
 
-    char *slash = strrchr (path, '/');
+    const char *slash = strrchr (path, '/');
     if (!slash)
 	slash = strrchr (path, '\\');
 
-    char *dot = strrchr (path, '.');
+    const char *dot = strrchr (path, '.');
 
     if (dot && slash && dot < slash)
 	dot = NULL;
@@ -1646,7 +1880,7 @@ bool8 S9xOpenSoundDevice (int mode, bool
 }
 #endif
 
-#if !defined(NOSOUND) && defined(__linux)
+#if !defined(NOSOUND) && (defined(__linux) || defined(__NetBSD__) || defined(__DragonFly__))
 static int Rates[8] =
 {
     0, 8000, 11025, 16000, 22050, 32000, 44100, 48000
@@ -1662,12 +1896,19 @@ bool8 S9xOpenSoundDevice (int mode, bool
     /* Linux version (OSS) */
     int J, K;
 
+#if defined(__NetBSD__)
+    if ((so.sound_fd = open ("/dev/audio", O_WRONLY)) < 0)
+    {
+       perror ("/dev/audio");
+       return (FALSE);
+    }
+#else
     if ((so.sound_fd = open ("/dev/dsp", O_WRONLY)) < 0)
     {
 	perror ("/dev/dsp");
 	return (FALSE);
     }
-
+#endif
 #ifdef MMAP_SOUND 
    if (ioctl (so.sound_fd, SNDCTL_DSP_GETCAPS, &J) < 0)
     {
@@ -1711,14 +1952,14 @@ bool8 S9xOpenSoundDevice (int mode, bool
 	so.sixteen_bit = TRUE;
 
     so.stereo = stereo;
-    if (ioctl (so.sound_fd, SNDCTL_DSP_STEREO, &so.stereo) < 0)
+    if (ioctl (so.sound_fd, SNDCTL_DSP_STEREO, (void *)&so.stereo) < 0)
     {
 	perror ("ioctl SNDCTL_DSP_STEREO");
 	return (FALSE);
     }
     
     so.playback_rate = Rates[mode & 0x07];
-    if (ioctl (so.sound_fd, SNDCTL_DSP_SPEED, &so.playback_rate) < 0)
+    if (ioctl (so.sound_fd, SNDCTL_DSP_SPEED, (void *)&so.playback_rate) < 0)
     {
 	perror ("ioctl SNDCTL_DSP_SPEED");
 	return (FALSE);
@@ -1743,7 +1984,7 @@ bool8 S9xOpenSoundDevice (int mode, bool
 	perror ("ioctl SNDCTL_DSP_SETFRAGMENT");
 	return (FALSE);
     }
-    ioctl (so.sound_fd, SNDCTL_DSP_GETBLKSIZE, &so.buffer_size);
+    ioctl (so.sound_fd, SNDCTL_DSP_GETBLKSIZE, (void *)&so.buffer_size);
     
 #ifdef MMAP_SOUND
     J = PCM_ENABLE_OUTPUT;
@@ -1768,7 +2009,7 @@ bool8 S9xOpenSoundDevice (int mode, bool
 #endif
 
 
-#if !defined(NOSOUND) && (defined (__linux) || defined (__sun))
+#if !defined(NOSOUND) && (defined (__linux) || defined (__sun) || defined(__NetBSD__) || defined(__DragonFly__))
 void S9xUnixProcessSound (void)
 {
 }
@@ -1810,7 +2051,7 @@ void *S9xProcessSound (void *)
 }
 #endif
 
-#if !defined(NOSOUND) && (defined (__linux) || defined (__sun))
+#if !defined(NOSOUND) && (defined (__linux) || defined (__sun) || defined(__NetBSD__) || defined(__DragonFly__))
 void S9xGenerateSound ()
 {
     /* Linux and Sun versions */
@@ -1902,7 +2143,7 @@ void *S9xProcessSound (void *)
     /* If threads in use, this is to loop indefinitely */
     /* If not, this will be called by timer */
     
-#ifdef __linux
+#if defined(__linux) || defined(__NetBSD__) || defined(__DragonFly__)
     audio_buf_info info;
 
     if (!Settings.ThreadSound &&
