$NetBSD: patch-ag,v 1.5 2003/09/21 18:22:16 kristerw Exp $
--- unix/unix.cpp.orig	2001-09-18 06:03:40.000000000 +0000
+++ unix/unix.cpp	2003-09-21 17:59:18.000000000 +0000
@@ -51,7 +51,7 @@
 #include <ctype.h>
 #include <dirent.h>
 
-#if defined(__linux) || defined(__sun)
+#if defined(__linux) || defined(__sun) || defined(__NetBSD__)
 #undef USE_THREADS
 #define USE_THREADS
 #include <unistd.h>
@@ -62,7 +62,11 @@
 
 #ifdef USE_THREADS
 #include <pthread.h>
+#ifdef __NetBSD__
+#include <sys/sched.h>
+#else
 #include <sched.h>
+#endif
 
 pthread_t thread;
 pthread_mutex_t mutex;
@@ -72,6 +76,9 @@
 #include <sys/soundcard.h>
 #include <sys/mman.h>
 #endif
+#ifdef __NetBSD__
+#include <soundcard.h>
+#endif
 
 #ifdef __sun
 #ifdef __SVR4
@@ -84,6 +91,9 @@
 #if defined(__sun) && defined(__GNUC__)
 typedef void (*SIG_PF)();
 #endif
+#if defined(__NetBSD__)
+typedef void (*SIG_PF)(int);
+#endif
 
 #include "snes9x.h"
 #include "memmap.h"
@@ -111,6 +121,51 @@
 int NumControllers = 5;
 
 #ifdef JOYSTICK_SUPPORT
+#ifdef __NetBSD__
+#ifdef HAVE_USBHID_H
+#include <usbhid.h>
+#else
+#include <usb.h>
+#endif
+#define class Class
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+
+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
 #ifdef __linux
 #include <linux/joystick.h>
 int js_fd [4] = {-1, -1, -1, -1};
@@ -168,7 +223,7 @@
 char *rom_filename = NULL;
 char *snapshot_filename = NULL;
 
-#if defined(__linux) || defined(__sun)
+#if defined(__linux) || defined(__sun) || defined(__NetBSD__)
 static void sigbrkhandler(int)
 {
 #ifdef DEBUGGER
@@ -612,6 +667,106 @@
 #ifdef JOYSTICK_SUPPORT
 void InitJoysticks ()
 {
+#ifdef __NetBSD__
+    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;
+
+#ifdef 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;
+#ifdef HAVE_USBHID_H
+           for (d = hid_start_parse(rd, 1 << hid_input, report_id); hid_get_item(d, &h); )
+#else
+           for (d = hid_start_parse(rd, 1 << hid_input); 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;
@@ -664,6 +819,77 @@
 
 void ReadJoysticks ()
 {
+#ifdef __NetBSD__
+    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;
@@ -1422,7 +1648,7 @@
 }
 #endif
 
-#if defined(__linux)
+#if defined(__linux) || defined(__NetBSD__)
 static int Rates[8] =
 {
     0, 8192, 11025, 16500, 22050, 29300, 36600, 44000
@@ -1437,11 +1663,19 @@
 {
     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)
@@ -1485,14 +1719,14 @@
 	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);
@@ -1517,7 +1751,7 @@
 	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;
@@ -1541,7 +1775,7 @@
 }
 #endif
 
-#if defined (__linux) || defined (__sun)
+#if defined (__linux) || defined (__sun) || defined(__NetBSD__)
 void S9xUnixProcessSound (void)
 {
 }
@@ -1640,7 +1874,7 @@
 
 void *S9xProcessSound (void *)
 {
-#ifdef __linux
+#if defined(__linux) || defined(__NetBSD__)
     audio_buf_info info;
 
     if (!Settings.ThreadSound &&
