--- unix/unix.cpp.orig	Wed Feb 28 13:12:23 2001
+++ unix/unix.cpp	Sat Sep 28 20:16:36 2002
@@ -51,9 +51,11 @@
 #include <ctype.h>
 
 
-#if defined(__linux) || defined(__sun)
+#if defined(__linux) || defined(__sun) || defined(__FreeBSD__)
+#if !defined(__FreeBSD__)
 #undef USE_THREADS
 #define USE_THREADS
+#endif
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
@@ -68,8 +70,12 @@
 pthread_mutex_t mutex;
 #endif
 
-#ifdef __linux
+#ifndef __sun
+#if defined(__linux) || defined(__FreeBSD__)
 #include <sys/soundcard.h>
+#else
+#include <machine/soundcard.h>
+#endif
 #include <sys/mman.h>
 #endif
 
@@ -85,6 +91,11 @@
 typedef void (*SIG_PF)();
 #endif
 
+#if defined(__FreeBSD__)
+typedef sig_t SIG_PF;
+#include <err.h>
+#endif
+
 #include "snes9x.h"
 #include "memmap.h"
 #include "debug.h"
@@ -111,7 +122,10 @@
 int NumControllers = 5;
 
 #ifdef JOYSTICK_SUPPORT
+#define	JOYSTICK_MAX_DEVICES	4
+int JoystickShift = 0;
 #ifdef __linux
+#define	JOYSTICK_MAX_BUTTONS	4
 #include <linux/joystick.h>
 int js_fd [4] = {-1, -1, -1, -1};
 int js_map_button [4][16] = {
@@ -158,6 +172,63 @@
 char *js_device [4] = {"/dev/js0", "/dev/js1", "/dev/js2", "/dev/js3"};
 #endif
 
+#if defined(__FreeBSD__)
+#include <sys/types.h>
+
+extern "C" {
+#define class klass
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+#undef class
+
+#include <libusbhid.h>
+}
+
+#define	JOYSTICK_MAX_BUTTONS	16
+
+#define JOYSTICK_MAP_BUTTON_INITIALIZER				\
+    {								\
+	SNES_Y_MASK, SNES_B_MASK, SNES_A_MASK,			\
+	SNES_X_MASK, SNES_TL_MASK, SNES_TR_MASK,		\
+	SNES_TL_MASK, SNES_TR_MASK,				\
+	SNES_SELECT_MASK, SNES_START_MASK, 0, 0, 0, 0, 0, 0	\
+    }
+
+int js_map_button[JOYSTICK_MAX_BUTTONS][16] = {
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER,
+	JOYSTICK_MAP_BUTTON_INITIALIZER
+};
+char *js_device [4] = {"/dev/uhid0", "/dev/uhid1", "/dev/uhid2", "/dev/uhid3"};
+struct js_range {
+	int min, max, lower_third, higher_third;
+};
+struct js_info {
+	char *buf;
+	int reportlen;
+	int offset;
+	struct js_range x, y;
+	int buttons;
+	struct hid_item *hids;
+	int fd;
+	int joy;
+} js_info[4];
+int js_count = 0;
+#endif
+
 void InitJoysticks ();
 void ReadJoysticks ();
 #endif
@@ -168,7 +239,7 @@
 char *rom_filename = NULL;
 char *snapshot_filename = NULL;
 
-#if defined(__linux) || defined(__sun)
+#if defined(__linux) || defined(__sun) || defined(__FreeBSD__)
 static void sigbrkhandler(int)
 {
 #ifdef DEBUGGER
@@ -195,91 +266,43 @@
     if (strcmp (argv [i], "-j") == 0 ||
 	     strcasecmp (argv [i], "-nojoy") == 0)
 	Settings.JoystickEnabled = FALSE;
-    else if (strcasecmp (argv [i], "-joydev1") == 0)
-    {
-	if (i + 1 < argc)
-	    js_device[0] = argv[++i];
-	else
-	    S9xUsage ();
-    }
-    else if (strcasecmp (argv [i], "-joydev2") == 0)
-    {
-	if (i + 1 < argc)
-	    js_device[1] = argv[++i];
-	else
-	    S9xUsage ();
-    }
-    else if (strcasecmp (argv [i], "-joymap1") == 0)
-    {
-	if (i + 8 < argc)
-	{
-	    int t;
-
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [0][t] = SNES_A_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [0][t] = SNES_B_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [0][t] = SNES_X_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [0][t] = SNES_Y_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [0][t] = SNES_TL_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [0][t] = SNES_TR_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [0][t] = SNES_START_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [0][t] = SNES_SELECT_MASK;
-	}
-	else
-	    S9xUsage ();
-    }
-    else if (strcasecmp (argv [i], "-joymap2") == 0)
-    {
-	if (i + 8 < argc)
-	{
-	    int t;
-
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [1][t] = SNES_A_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [1][t] = SNES_B_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [1][t] = SNES_X_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [1][t] = SNES_Y_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [1][t] = SNES_TL_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [1][t] = SNES_TR_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [1][t] = SNES_START_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [1][t] = SNES_SELECT_MASK;
-	}
-	else
-	    S9xUsage ();
-    }
-    else if (strcasecmp (argv [i], "-joymap3") == 0)
-    {
-	if (i + 8 < argc)
-	{
-	    int t;
-
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [2][t] = SNES_A_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [2][t] = SNES_B_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [2][t] = SNES_X_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [2][t] = SNES_Y_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [2][t] = SNES_TL_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [2][t] = SNES_TR_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [2][t] = SNES_START_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [2][t] = SNES_SELECT_MASK;
-	}
+#ifdef __FreeBSD__
+    else if (strcasecmp(argv[i], "-joyshift") == 0)
+	JoystickShift = 1;
+#endif
+    else if (strncasecmp(argv[i], "-joydev", sizeof("-joydev") - 1) == 0) {
+	char *end, *snum = argv[i] + sizeof("-joydev") - 1;
+	unsigned long num;
+
+	if (*snum == '\0' || argc < i + 1)
+		S9xUsage();
+	if ((num = strtoul(snum, &end, 10)) < JOYSTICK_MAX_DEVICES &&
+	    num > 0 && *end == '\0')
+		js_device[num - 1] = argv[++i];
 	else
-	    S9xUsage ();
+		S9xUsage();
     }
-    else if (strcasecmp (argv [i], "-joymap4") == 0)
-    {
-	if (i + 8 < argc)
-	{
-	    int t;
-
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [3][t] = SNES_A_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [3][t] = SNES_B_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [3][t] = SNES_X_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [3][t] = SNES_Y_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [3][t] = SNES_TL_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [3][t] = SNES_TR_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [3][t] = SNES_START_MASK;
-	    if ((t = atoi (argv [++i])) < 15) js_map_button [3][t] = SNES_SELECT_MASK;
-	}
-	else
-	    S9xUsage ();
+    else if (strncasecmp(argv[i], "-joymap", sizeof("-joymap") - 1) == 0) {
+	static const int button_masks[] = {
+		SNES_A_MASK, SNES_B_MASK, SNES_X_MASK, SNES_Y_MASK,
+		SNES_TL_MASK, SNES_TR_MASK, SNES_START_MASK, SNES_SELECT_MASK
+	};
+	char *end, *snum = argv[i] + sizeof("-joymap") - 1;
+	unsigned long num;
+	int *js_buttons, b;
+
+	if (argc < i + (sizeof(button_masks) / sizeof(int)) || *snum == '\0')
+		S9xUsage();
+	num = strtoul(snum, &end, 10);
+	if (*end != '\0')
+		S9xUsage();
+	if (num == 0 || num > 4)	/* hardcode: max joysticks */
+		S9xUsage();
+	js_buttons = js_map_button[num - 1];
+	for (b = 0; b < (sizeof(button_masks) / sizeof(int)); b++)
+		if ((num = strtoul(argv[++i], &end, 10)) <= 16 && num != 0 &&
+		    *end == '\0')
+			js_buttons[num - 1] = button_masks[b];
     }
     else 
 #endif
@@ -418,7 +441,7 @@
 #if !defined(__MSDOS) && defined(DEBUGGER)
 #if defined(__unix) && !defined(__NeXT__)
     struct sigaction sa;
-#if defined(__linux)
+#if defined(__linux) || defined(__FreeBSD__)
     sa.sa_handler = sigbrkhandler;
 #else
     sa.sa_handler = (SIG_PF) sigbrkhandler;
@@ -610,6 +633,7 @@
 }
 
 #ifdef JOYSTICK_SUPPORT
+#ifdef linux
 void InitJoysticks ()
 {
 #ifdef JSIOCGVERSION
@@ -730,6 +754,184 @@
     }
 #endif
 }
+#endif
+#if defined(__FreeBSD__)
+
+/*
+ * USB HID code for FreeBSD/NetBSD
+ * Brian Feldman <green@FreeBSD.org>
+ *
+ * Reference used:
+ * X-Mame USB HID joystick driver for NetBSD.
+ *
+ * Written by Krister Walfridsson <cato@df.lth.se>
+ */
+
+int
+InitJoystickFd(int fd, char *dev) {
+	report_desc_t rd;
+	struct hid_data *d;
+	struct hid_item h, new_h;
+	struct js_info *my_info;
+	int reportlen, report_id, is_joystick;
+
+	my_info = &js_info[js_count];
+	rd = hid_get_report_desc(fd);
+	if (rd == 0) {
+		warn("%s", dev);
+		return (-1);
+	}
+	report_id = 0;
+#if __FreeBSD__ >= 5
+	reportlen = hid_report_size(rd, report_id, hid_input);
+#else
+	reportlen = hid_report_size(rd, hid_input, &report_id);
+#endif
+	my_info->buf = (char *)malloc(reportlen);
+	if (my_info->buf == NULL)
+		err(1, "malloc");
+	my_info->reportlen = reportlen;
+	my_info->offset = report_id != 0;
+	my_info->buttons = 0;
+	my_info->hids = NULL;
+
+	is_joystick = 0;
+	for (d = hid_start_parse(rd, 1 << hid_input); hid_get_item(d, &h);) {
+		int usage, page, link_it = 0;
+		struct js_range *axis;
+
+		page = HID_PAGE(h.usage);
+		usage = HID_USAGE(h.usage);
+		if (!is_joystick)
+			is_joystick = (h.kind == hid_collection &&
+			    page == HUP_GENERIC_DESKTOP &&
+			    (usage == HUG_JOYSTICK || usage == HUG_GAME_PAD));
+		if (h.kind != hid_input || !is_joystick)
+			continue;
+		axis = NULL;
+		if (page == HUP_GENERIC_DESKTOP) {
+			switch (usage) {
+			case HUG_X:
+			case HUG_RX:
+				axis = &my_info->x;
+				break;
+			case HUG_Y:
+			case HUG_RY:
+				axis = &my_info->y;
+				break;
+			}
+		}
+		if (axis != NULL) {
+			axis->min = h.logical_minimum;
+			axis->max = h.logical_maximum;
+			axis->lower_third = axis->min +
+			   (axis->max - axis->min) / 3;
+			axis->higher_third = axis->min +
+			   (axis->max - axis->min) * 2 / 3;
+			link_it = 1;
+		}
+		if (!link_it) {
+			if (page != HUP_BUTTON || usage > 16)
+				continue;
+			if (usage > my_info->buttons)
+				my_info->buttons = usage;
+		}
+		new_h = h;
+		new_h.next = my_info->hids;
+		my_info->hids = (struct hid_item *)
+		    malloc(sizeof(*my_info->hids));
+		if (my_info->hids == NULL)
+			err(1, "malloc");
+		*my_info->hids = new_h;
+	}
+	printf("Joystick %s: %d buttons, X range %d - %d, Y range %d - %d\n",
+	    dev, my_info->buttons, my_info->x.min, my_info->x.max,
+	    my_info->y.min, my_info->y.max);
+	my_info->fd = fd;
+	if (JoystickShift) {
+		my_info->joy = js_count + 1;
+	} else
+		my_info->joy = js_count;
+	return (0);
+}
+
+void
+InitJoysticks() {
+	int i, fd;
+
+	for (i = 0; i < (sizeof(js_device) / sizeof(js_device[0])); i++) {
+		fd = open(js_device[i], O_RDONLY | O_NONBLOCK);
+		if (fd == -1)
+			continue;
+		if (InitJoystickFd(fd, js_device[i]) == 0)
+			js_count++;
+		else
+			close(fd);
+	}
+}
+
+void
+ReadJoysticks() {
+	struct hid_item *h;
+	int page, usage, njoy, joy;
+
+	for (njoy = 0; njoy < js_count; njoy++) {
+		struct js_info *jsi;
+
+		jsi = &js_info[njoy];
+		joy = jsi->joy;
+
+		if (read(jsi->fd, jsi->buf, jsi->reportlen) != jsi->reportlen)
+			continue;
+		for (h = jsi->hids; h != NULL; h = h->next) {
+			int d;
+
+			d = hid_get_data(jsi->buf + jsi->offset, h);
+			page = HID_PAGE(h->usage);
+			usage = HID_USAGE(h->usage);
+
+			switch (page) {
+			case HUP_GENERIC_DESKTOP:
+				switch (usage) {
+				case HUG_X:
+				case HUG_RX:
+					if (d < jsi->x.lower_third) {
+						joypads[joy] |= SNES_LEFT_MASK;
+						joypads[joy] &= ~SNES_RIGHT_MASK;
+					} else if (d < jsi->x.higher_third) {
+						joypads[joy] &= ~SNES_LEFT_MASK;
+						joypads[joy] &= ~SNES_RIGHT_MASK;
+					} else {
+						joypads[joy] &= ~SNES_LEFT_MASK;
+						joypads[joy] |= SNES_RIGHT_MASK;
+					}
+					break;
+				case HUG_Y:
+				case HUG_RY:
+					if (d < jsi->y.lower_third) {
+						joypads[joy] |= SNES_UP_MASK;
+						joypads[joy] &= ~SNES_DOWN_MASK;
+					} else if (d < jsi->y.higher_third) {
+						joypads[joy] &= ~SNES_UP_MASK;
+						joypads[joy] &= ~SNES_DOWN_MASK;
+					} else {
+						joypads[joy] &= ~SNES_UP_MASK;
+						joypads[joy] |= SNES_DOWN_MASK;
+					}
+					break;
+				}
+				break;
+			case HUP_BUTTON:
+				if (d)
+					joypads[joy] |= js_map_button[njoy][usage - 1];
+				else
+					joypads[joy] &= ~js_map_button[njoy][usage - 1];
+				break;
+			}
+		}
+	}
+}
+#endif // defined(__FreeBSD__)
 #endif // defined (JOYSTICK_SUPPORT)
 
 const char *GetHomeDirectory ()
@@ -1422,7 +1624,7 @@
 }
 #endif
 
-#if defined(__linux)
+#if defined(__linux) || defined(__FreeBSD__)
 static int Rates[8] =
 {
     0, 8192, 11025, 16500, 22050, 29300, 36600, 44000
@@ -1541,7 +1743,7 @@
 }
 #endif
 
-#if defined (__linux) || defined (__sun)
+#if defined (__linux) || defined (__sun) || defined(__FreeBSD__)
 void S9xUnixProcessSound (void)
 {
 }
@@ -1640,7 +1842,7 @@
 
 void *S9xProcessSound (void *)
 {
-#ifdef __linux
+#if defined(__linux) || defined(__FreeBSD__)
     audio_buf_info info;
 
     if (!Settings.ThreadSound &&
