--- unix/unix.cpp Fri Jun 30 08:34:57 2006 +++ unix/unix.cpp Wed Dec 27 00:07:21 2006 @@ -178,8 +178,12 @@ pthread_mutex_t mutex; #endif -#if !defined(NOSOUND) && defined(__linux) +#ifndef __sun +#if !defined(NOSOUND) && (defined(__linux) || defined(__FreeBSD__)) #include +#else +#include +#endif #include #endif @@ -191,6 +195,11 @@ #endif #endif +#if defined(__FreeBSD__) +typedef sig_t SIG_PF; +#include +#endif + //Breaks sol9 and probably others. //#if defined(__sun) && defined(__GNUC__) //typedef void (*SIG_PF)(); @@ -222,13 +231,78 @@ #endif #ifdef JOYSTICK_SUPPORT +#define JOYSTICK_MAX_DEVICES 4 +int JoystickShift = 0 #if defined(__linux) +#define JOYSTICK_MAX_BUTTONS 4 #include uint8 js_mod [8] = {0, 0, 0, 0, 0, 0, 0, 0}; int js_fd [8] = {-1, -1, -1, -1, -1, -1, -1, -1}; char *js_device [8] = {"/dev/js0", "/dev/js1", "/dev/js2", "/dev/js3", "/dev/js4", "/dev/js5", "/dev/js6", "/dev/js7" }; #endif +#if defined(__FreeBSD__) +#include +#include + +extern "C" { +#define class klass +#include +#include +#undef class + +#if __FreeBSD_version < 500111 +#include +#else +#include +#endif +} + +#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 @@ -249,7 +323,7 @@ const char *inc_format="%03d"; //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(__FreeBSD__)) static void sigbrkhandler(int) { CPU.Flags |= DEBUG_MODE_FLAG; @@ -287,22 +361,54 @@ void S9xParseArg (char **argv, int &i, int argc) { +#ifdef JOYSTICK_SUPPORT if (strcmp (argv [i], "-j") == 0 || strcasecmp (argv [i], "-nojoy") == 0) { -#ifdef JOYSTICK_SUPPORT - Settings.JoystickEnabled = FALSE; -#endif - } else if (strncasecmp (argv [i], "-joydev", 7) == 0 && argv[i][7]>='1' && argv[i][7]<='8' && argv[i][8]=='\0') - { - int j = argv[i][7]-'1'; - if (i + 1 < argc) { -#ifdef JOYSTICK_SUPPORT - js_device[j] = argv[++i]; -#else - S9xMessage(S9X_WARNING, S9X_USAGE, "Joystick support is not available!"); + Settings.JoystickEnabled = FALSE; + } + +#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 (); + } + 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 - } else S9xUsage (); - } else if (strcasecmp (argv [i], "-b") == 0 || + if (strcasecmp (argv [i], "-b") == 0 || strcasecmp (argv [i], "-bs") == 0 || strcasecmp (argv [i], "-buffersize") == 0) { @@ -413,7 +519,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; @@ -613,6 +719,7 @@ } #ifdef JOYSTICK_SUPPORT +#ifdef __linux void InitJoysticks () { #ifdef JSIOCGVERSION @@ -697,6 +804,189 @@ } #endif } +#endif +#if defined(__FreeBSD__) + +/* + * USB HID code for FreeBSD/NetBSD + * Brian Feldman + * + * Reference used: + * X-Mame USB HID joystick driver for NetBSD. + * + * Written by Krister Walfridsson + */ + +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_version < 500111 + 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; +#if __FreeBSD_version < 500111 + for (d = hid_start_parse(rd, 1 << hid_input); +#else + for (d = hid_start_parse(rd, 1 << hid_input, report_id); +#endif + 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) START_EXTERN_C @@ -1522,7 +1812,7 @@ } #endif -#if !defined(NOSOUND) && defined(__linux) +#if !defined(NOSOUND) && (defined(__linux) || defined(__FreeBSD__)) static int Rates[8] = { 0, 8000, 11025, 16000, 22050, 32000, 44100, 48000 @@ -1644,7 +1934,7 @@ #endif -#if !defined(NOSOUND) && (defined (__linux) || defined (__sun)) +#if !defined(NOSOUND) && (defined (__linux) || defined (__sun) || defined(__FreeBSD__)) void S9xUnixProcessSound (void) { } @@ -1687,7 +1977,7 @@ } #endif -#if !defined(NOSOUND) && (defined (__linux) || defined (__sun)) +#if !defined(NOSOUND) && (defined (__linux) || defined (__sun) || defined(__FreeBSD__)) void S9xGenerateSound () { /* Linux and Sun versions */ @@ -1779,7 +2069,7 @@ /* If threads in use, this is to loop indefinitely */ /* If not, this will be called by timer */ -#ifdef __linux +#if defined(__linux) || defined(__FreeBSD__) audio_buf_info info; if (!Settings.ThreadSound &&