changeset 302:8a86bdf34f0f

Added Atari joystick support (thanks Patrice!)
author Sam Lantinga <slouken@libsdl.org>
date Thu, 07 Mar 2002 20:23:11 +0000
parents fb4c4c6a2773
children 767c10b9ec9f
files README.MiNT configure.in src/joystick/Makefile.am src/joystick/mint/.cvsignore src/joystick/mint/Makefile.am src/joystick/mint/SDL_sysjoystick.c
diffstat 6 files changed, 681 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/README.MiNT	Wed Mar 06 19:14:17 2002 +0000
+++ b/README.MiNT	Thu Mar 07 20:23:11 2002 +0000
@@ -49,19 +49,19 @@
 Mouse (XBIOS, GEM, Ikbd)
 Video (XBIOS (Fullscreen), GEM (Windowed and Fullscreen))
 Timer (VBL vector)
+Joystick and joypad support (Ikbd, Hardware)
 
 - What is missing:
 Audio support (TOS)
 CDROM support (Metados, /dev/cdrom)
-Joystick and joypad support (Hardware)
 Threads support (TOS)
 
 - Driver combinations:
-Video	Kbd	Mouse	Timer
-xbios	ikbd	ikbd	vbl
-xbios	gemdos	xbios	vbl
-xbios	bios	xbios	vbl
-gem	gem	gem	vbl
+Video	Kbd	Mouse	Timer	Jstick	Joypads
+xbios	ikbd	ikbd	vbl	ikbd	hardware
+xbios	gemdos	xbios	vbl	-	hardware
+xbios	bios	xbios	vbl	-	hardware
+gem	gem	gem	vbl	-	hardware
 
 ==============================================================================
 V.  Environment variables:
@@ -75,6 +75,38 @@
 	Set to 'xbios' to force xbios video driver
 	Set to 'gem' to force gem video driver
 
+SDL_JOYSTICK_ATARI:
+	Use any of these strings in the environment variable to enable or
+	disable a joystick:
+
+	'ikbd-joy1-[on|off]' for IKBD joystick on port 1
+	'porta-pad-[on|off]' for joypad on port A
+	'porta-joy0-[on|off]' for joystick 0 on port A
+	'porta-joy1-[on|off]' for joystick 1 on port A
+	'porta-lp-[on|off]' for lightpen on port A
+	'porta-anpad-[on|off]' for analog paddle on port A
+	'portb-pad-[on|off]' for joypad on port B
+	'portb-joy0-[on|off]' for joystick 0 on port B
+	'portb-joy1-[on|off]' for joystick 1 on port B
+	'portb-anpad-[on|off]' for analog paddle on port B
+
+	Default configuration is:
+		'ikbd-joy1-on' (if IKBD events driver enabled)
+		'porta-pad-on portb-pad-on' (if available on the machine)
+
+	port[a|b]-[pad|joy?|lp|anpad]-* strings are mutually exclusives.
+	On such a port, you can only use a joypad OR 1 or 2 joysticks OR
+	a lightpen OR an analog paddle. You must disable joypad before
+	setting another controller.
+
+	IKBD joystick only available when the IKBD events driver is enabled.
+	The second joystick port on IKBD is used by the mouse, so not usable.
+
+	Joypads are multibuttons controller (Atari Jaguar console-like).
+	Joysticks are 1 button, 2 axis controllers.
+	Lightpen and analog paddle are 2 buttons, 2 axis controllers. The 2
+	buttons are those affected to 1 button joysticks on the same port.
+
 -- 
 Patrice Mandin <pmandin@caramail.com>
 http://www.multimania.com/pmandin
--- a/configure.in	Wed Mar 06 19:14:17 2002 +0000
+++ b/configure.in	Thu Mar 07 20:23:11 2002 +0000
@@ -2281,10 +2281,9 @@
             AUDIO_DRIVERS="$AUDIO_DRIVERS sun/libaudio_sun.la"
         fi
         # Set up files for the joystick library
-        # (No joystick support yet)
         if test x$enable_joystick = xyes; then
-            JOYSTICK_SUBDIRS="$JOYSTICK_SUBDIRS dummy"
-            JOYSTICK_DRIVERS="$JOYSTICK_DRIVERS dummy/libjoystick_dummy.la"
+            JOYSTICK_SUBDIRS="$JOYSTICK_SUBDIRS mint"
+            JOYSTICK_DRIVERS="$JOYSTICK_DRIVERS mint/libjoystick_mint.la"
         fi
         # Set up files for the cdrom library
         if test x$enable_cdrom = xyes; then
@@ -2489,6 +2488,7 @@
 src/joystick/dummy/Makefile
 src/joystick/linux/Makefile
 src/joystick/macos/Makefile
+src/joystick/mint/Makefile
 src/joystick/win32/Makefile
 src/cdrom/Makefile
 src/cdrom/aix/Makefile
--- a/src/joystick/Makefile.am	Wed Mar 06 19:14:17 2002 +0000
+++ b/src/joystick/Makefile.am	Thu Mar 07 20:23:11 2002 +0000
@@ -5,7 +5,7 @@
 
 # Define which subdirectories need to be built
 SUBDIRS = @JOYSTICK_SUBDIRS@
-DIST_SUBDIRS = dummy amigaos beos bsd darwin linux macos win32
+DIST_SUBDIRS = dummy amigaos beos bsd darwin linux macos mint win32
 
 DRIVERS = @JOYSTICK_DRIVERS@
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/joystick/mint/.cvsignore	Thu Mar 07 20:23:11 2002 +0000
@@ -0,0 +1,6 @@
+Makefile.in
+Makefile
+.libs
+*.o
+*.lo
+*.la
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/joystick/mint/Makefile.am	Thu Mar 07 20:23:11 2002 +0000
@@ -0,0 +1,8 @@
+
+## Makefile.am for the MiNT joystick driver for SDL
+
+noinst_LTLIBRARIES = libjoystick_mint.la
+libjoystick_mint_la_SOURCES = $(SRCS)
+
+# The SDL joystick driver sources
+SRCS =  SDL_sysjoystick.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/joystick/mint/SDL_sysjoystick.c	Thu Mar 07 20:23:11 2002 +0000
@@ -0,0 +1,625 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id$";
+#endif
+
+/*
+ *	Atari Joystick/Joypad drivers
+ *
+ *	Patrice Mandin
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/cookie.h>
+#include <mint/osbind.h>
+
+#include "SDL_types.h"
+#include "SDL_error.h"
+#include "SDL_joystick.h"
+#include "SDL_sysjoystick.h"
+#include "SDL_joystick_c.h"
+
+#include "../video/ataricommon/SDL_ikbdinterrupt_s.h"
+
+/*--- Const ---*/
+
+/* We can have:
+	1 joystick on IKBD port 1 (port 0 is used by mouse)
+	2 joypads on ports A,B
+	  or 4 joysticks on joypads ports A,B
+	  or 1 lightpen on joypad port A
+	  or 2 analog paddles on joypads ports A,B
+	2 joysticks on parallel port
+*/
+
+enum {
+	IKBD_JOY1=0,
+	PORTA_PAD,
+	PORTB_PAD,
+	PORTA_JOY0,
+	PORTA_JOY1,
+	PORTB_JOY0,
+	PORTB_JOY1,
+	PORTA_LP,
+	PORTA_ANPAD,
+	PORTB_ANPAD,
+#if 0
+	PARA_JOY0,
+	PARA_JOY1,
+#endif
+	MAX_JOYSTICKS
+};
+
+enum {
+	MCH_ST=0,
+	MCH_STE,
+	MCH_TT,
+	MCH_F30
+};
+
+/*	Joypad buttons
+ *		Procontroller note:
+ *			L,R are connected to 4,6
+ *			X,Y,Z are connected to 7,8,9
+ */
+
+enum {
+	JP_UP=0,	JP_DOWN,	JP_LEFT,	JP_RIGHT,
+	JP_KPMULT,	JP_KP7,		JP_KP4,		JP_KP1,
+	JP_KP0,		JP_KP8,		JP_KP5,		JP_KP2,
+	JP_KPNUM,	JP_KP9,		JP_KP6,		JP_KP3,
+	JP_PAUSE,	JP_FIRE0,	JP_UNDEF0,	JP_FIRE1,
+	JP_UNDEF1,	JP_FIRE2,	JP_UNDEF2,	JP_OPTION
+};
+
+#define JP_NUM_BUTTONS 17
+
+#define PORT_JS_RIGHT	(1<<0)
+#define PORT_JS_LEFT	(1<<1)
+#define PORT_JS_DOWN	(1<<2)
+#define PORT_JS_UP		(1<<3)
+#define PORT_JS_FIRE	(1<<4)
+
+/*--- Types ---*/
+
+typedef struct {
+	SDL_bool enabled;
+	unsigned char *name;
+	Uint32 prevstate;
+} atarijoy_t;
+
+/*--- Variables ---*/
+
+static atarijoy_t atarijoysticks[MAX_JOYSTICKS]={
+	{SDL_FALSE,"IKBD joystick port 1",0},
+	{SDL_FALSE,"Joypad port A",0},
+	{SDL_FALSE,"Joypad port B",0},
+	{SDL_FALSE,"Joystick 0 port A",0},
+	{SDL_FALSE,"Joystick 1 port A",0},
+	{SDL_FALSE,"Joystick 0 port B",0},
+	{SDL_FALSE,"Joystick 1 port B",0},
+	{SDL_FALSE,"Lightpen port A",0},
+	{SDL_FALSE,"Analog paddle port A",0},
+	{SDL_FALSE,"Analog paddle port B",0}
+#if 0
+	,{SDL_FALSE,"Joystick 0 parallel port",0},
+	{SDL_FALSE,"Joystick 1 parallel port",0}
+#endif
+};
+
+static const int jp_buttons[JP_NUM_BUTTONS]={
+	JP_KPMULT,	JP_KP7,		JP_KP4,		JP_KP1,
+	JP_KP0,		JP_KP8,		JP_KP5,		JP_KP2,
+	JP_KPNUM,	JP_KP9,		JP_KP6,		JP_KP3,
+	JP_PAUSE,	JP_FIRE0,	JP_FIRE1,	JP_FIRE2,
+	JP_OPTION
+};
+
+static SDL_bool joypad_ports_enabled=SDL_FALSE;
+
+/* Updated joypad ports */
+static Uint16 jp_paddles[4];
+static Uint16 jp_lightpens[2];
+static Uint16 jp_directions;
+static Uint16 jp_fires;
+static Uint32 jp_joypads[2];
+
+/*--- Functions prototypes ---*/
+
+static int GetEnabledAtariJoystick(int index);
+static void UpdateJoypads(void);
+
+/*--- Functions ---*/
+
+int SDL_SYS_JoystickInit(void)
+{
+	int i;
+	unsigned long cookie_mch;
+	const char *envr=getenv("SDL_JOYSTICK_ATARI");
+	const char *env_evt=getenv("SDL_ATARI_EVENTSDRIVER");
+	SDL_bool ikbd_enabled=SDL_FALSE;
+	
+#define TEST_JOY_ENABLED(env,idstring,num) \
+	if (strstr(env,idstring"-off")) { \
+		atarijoysticks[num].enabled=SDL_FALSE; \
+	} \
+	if (strstr(env,idstring"-on")) { \
+		atarijoysticks[num].enabled=SDL_TRUE; \
+	}
+
+	/* Cookie _MCH present ? if not, assume ST machine */
+	if (Getcookie(C__MCH, &cookie_mch) != C_FOUND) {
+		cookie_mch = MCH_ST << 16;
+	}
+
+	/* Enable some default joysticks */
+	if ((cookie_mch == MCH_ST<<16) || ((cookie_mch>>16) == MCH_STE) ||
+		(cookie_mch == MCH_TT<<16) || (cookie_mch == MCH_F30<<16)) {
+		ikbd_enabled=SDL_TRUE;
+		if (env_evt) {
+			if (!strcmp(env_evt,"ikbd")) {
+				ikbd_enabled=SDL_FALSE;
+			}
+		}
+		atarijoysticks[IKBD_JOY1].enabled=ikbd_enabled;
+	}
+	if ((cookie_mch == MCH_STE<<16) || (cookie_mch == MCH_F30<<16)) {
+		atarijoysticks[PORTA_PAD].enabled=SDL_TRUE;
+		atarijoysticks[PORTB_PAD].enabled=SDL_TRUE;
+	}
+
+	/* Read environment for joysticks to enable */
+	if (envr) {
+		/* IKBD on any Atari, maybe clones */
+		if ((cookie_mch == MCH_ST<<16) || ((cookie_mch>>16) == MCH_STE) ||
+			(cookie_mch == MCH_TT<<16) || (cookie_mch == MCH_F30<<16)) {
+			if (env_evt) {
+				if (strcmp(env_evt,"ikbd")) {
+					TEST_JOY_ENABLED(envr, "ikbd-joy1", IKBD_JOY1);
+				}
+			}
+		}
+		/* Joypads ports only on STE and Falcon */
+		if ((cookie_mch == MCH_STE<<16) || (cookie_mch == MCH_F30<<16)) {
+			TEST_JOY_ENABLED(envr, "porta-pad", PORTA_PAD);
+			if (!atarijoysticks[PORTA_PAD].enabled) {
+				TEST_JOY_ENABLED(envr, "porta-joy0", PORTA_JOY0);
+				TEST_JOY_ENABLED(envr, "porta-joy1", PORTA_JOY1);
+				if (!(atarijoysticks[PORTA_JOY0].enabled) && !(atarijoysticks[PORTA_JOY1].enabled)) {
+					TEST_JOY_ENABLED(envr, "porta-lp", PORTA_LP);
+					if (!atarijoysticks[PORTA_LP].enabled) {
+						TEST_JOY_ENABLED(envr, "porta-anpad", PORTA_ANPAD);
+					}
+				}
+			}
+
+			TEST_JOY_ENABLED(envr, "portb-pad", PORTB_PAD);
+			if (!atarijoysticks[PORTB_PAD].enabled) {
+				TEST_JOY_ENABLED(envr, "portb-joy0", PORTB_JOY0);
+				TEST_JOY_ENABLED(envr, "portb-joy1", PORTB_JOY1);
+				if (!(atarijoysticks[PORTB_JOY0].enabled) && !(atarijoysticks[PORTB_JOY1].enabled)) {
+					TEST_JOY_ENABLED(envr, "portb-anpad", PORTB_ANPAD);
+				}
+			}
+		}
+#if 0
+		/* Parallel port on any Atari, maybe clones */
+		if ((cookie_mch == MCH_ST<<16) || ((cookie_mch>>16) == MCH_STE) ||
+			(cookie_mch == MCH_TT<<16) || (cookie_mch == MCH_F30<<16)) {
+			TEST_JOY_ENABLED(envr, "para-joy0", PARA_JOY0);
+			TEST_JOY_ENABLED(envr, "para-joy1", PARA_JOY1);
+		}
+#endif
+	}
+
+	/* Need to update joypad ports ? */
+	joypad_ports_enabled=SDL_FALSE;
+	for (i=PORTA_PAD;i<=PORTB_ANPAD;i++) {
+		if (atarijoysticks[i].enabled) {
+			joypad_ports_enabled=SDL_TRUE;
+			break;
+		}
+	}
+
+	SDL_numjoysticks = 0;
+	for (i=0;i<MAX_JOYSTICKS;i++) {
+		if (atarijoysticks[i].enabled) {
+			++SDL_numjoysticks;
+		}
+	}
+
+	return(SDL_numjoysticks);
+}
+
+static int GetEnabledAtariJoystick(int index)
+{
+	int i,j;
+
+	/* Return the nth'index' enabled atari joystick */
+	j=0;
+	for (i=0;i<MAX_JOYSTICKS;i++) {
+		if (atarijoysticks[i].enabled) {
+			if (j==index) {
+				break;
+			} else {
+				j++;
+			}
+		}
+	}
+	if (i==MAX_JOYSTICKS)
+		return -1;
+
+	return i;
+}
+
+const char *SDL_SYS_JoystickName(int index)
+{
+	int numjoystick;
+
+	numjoystick=GetEnabledAtariJoystick(index);
+	if (numjoystick==-1)
+		return NULL;
+
+	return(atarijoysticks[numjoystick].name);
+}
+
+int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
+{
+	int numjoystick;
+	
+	numjoystick=GetEnabledAtariJoystick(joystick->index);
+	if (numjoystick==-1)
+		return -1;
+	
+	if ((numjoystick==PORTA_PAD) || (numjoystick==PORTB_PAD)) {
+		joystick->nbuttons=JP_NUM_BUTTONS;
+	} else if ((numjoystick==PORTA_LP) || (numjoystick==PORTA_ANPAD) ||
+				(numjoystick==PORTB_ANPAD)) {
+		joystick->nbuttons=2;
+	} else {
+		joystick->nbuttons=1;
+	}
+	joystick->naxes=2;
+	joystick->nballs=0;
+	joystick->nhats=0;
+
+	return(0);
+}
+
+void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
+{
+	int numjoystick;
+	Uint32 curstate,prevstate;
+	Sint16 curaxis;
+	
+	numjoystick=GetEnabledAtariJoystick(joystick->index);
+	if (numjoystick==-1)
+		return;
+
+	prevstate = atarijoysticks[numjoystick].prevstate;
+
+	if (joypad_ports_enabled) {
+		Supexec(UpdateJoypads);
+	}
+
+	switch (numjoystick) {
+		case IKBD_JOY1:
+			{
+				curstate = SDL_AtariIkbd_joystick & 0xff;
+				if (curstate != prevstate) {
+					/* X axis */
+					if ((curstate & (IKBD_JOY_LEFT|IKBD_JOY_RIGHT)) != (prevstate & (IKBD_JOY_LEFT|IKBD_JOY_RIGHT))) {
+						curaxis=0;
+						if (curstate & IKBD_JOY_LEFT) {
+							curaxis=-128;
+						} else if (curstate & IKBD_JOY_RIGHT) {
+							curaxis=127;
+						}					
+						SDL_PrivateJoystickAxis(joystick,0,curaxis);
+					}
+					/* Y axis */
+					if ((curstate & (IKBD_JOY_UP|IKBD_JOY_DOWN)) != (prevstate & (IKBD_JOY_UP|IKBD_JOY_DOWN))) {
+						curaxis=0;
+						if (curstate & IKBD_JOY_UP) {
+							curaxis=-128;
+						} else if (curstate & IKBD_JOY_DOWN) {
+							curaxis=127;
+						}					
+						SDL_PrivateJoystickAxis(joystick,1,curaxis);
+					}
+					/* Button */
+					if ((curstate & IKBD_JOY_FIRE) && !(prevstate & IKBD_JOY_FIRE)) {
+						SDL_PrivateJoystickButton(joystick,0,SDL_PRESSED);
+					}
+					if (!(curstate & IKBD_JOY_FIRE) && (prevstate & IKBD_JOY_FIRE)) {
+						SDL_PrivateJoystickButton(joystick,0,SDL_RELEASED);
+					}
+				}
+				atarijoysticks[IKBD_JOY1].prevstate = curstate;
+			}
+			break;
+		case PORTA_PAD:
+		case PORTB_PAD:
+			{
+				int numjoypad,i;
+				
+				numjoypad=0;
+/*				if (numjoystick==PORTA_PAD) numjoypad=0;*/
+				if (numjoystick==PORTB_PAD) numjoypad=1;
+				
+				curstate=jp_joypads[numjoypad];
+				if (curstate!=prevstate) {
+					/* X axis */
+					if ((curstate & ((1<<JP_LEFT)|(1<<JP_RIGHT))) != (prevstate & ((1<<JP_LEFT)|(1<<JP_RIGHT)))) {
+						curaxis=0;
+						if (curstate & (1<<JP_LEFT)) {
+							curaxis=-128;
+						} else if (curstate & (1<<JP_RIGHT)) {
+							curaxis=127;
+						}					
+						SDL_PrivateJoystickAxis(joystick,0,curaxis);
+					}
+					/* Y axis */
+					if ((curstate & ((1<<JP_UP)|(1<<JP_DOWN))) != (prevstate & ((1<<JP_UP)|(1<<JP_DOWN)))) {
+						curaxis=0;
+						if (curstate & (1<<JP_UP)) {
+							curaxis=-128;
+						} else if (curstate & (1<<JP_DOWN)) {
+							curaxis=127;
+						}					
+						SDL_PrivateJoystickAxis(joystick,1,curaxis);
+					}
+					/* Buttons */
+					for (i=0;i<JP_NUM_BUTTONS;i++) {
+						int button;
+						
+						button=1<<jp_buttons[i];
+
+						if ((curstate & button) && !(prevstate & button)) {
+							SDL_PrivateJoystickButton(joystick,i,SDL_PRESSED);
+						}
+						if (!(curstate & button) && (prevstate & button)) {
+							SDL_PrivateJoystickButton(joystick,i,SDL_RELEASED);
+						}
+					}
+				}
+				atarijoysticks[numjoystick].prevstate = curstate;
+			}
+			break;
+		case PORTA_JOY0:
+		case PORTA_JOY1:
+		case PORTB_JOY0:
+		case PORTB_JOY1:
+			{
+				int fire_shift=0,dir_shift=0;
+				
+				if (numjoystick==PORTA_JOY0) {	fire_shift=0; dir_shift=0; }
+				if (numjoystick==PORTA_JOY1) {	fire_shift=1; dir_shift=4; }
+				if (numjoystick==PORTB_JOY0) {	fire_shift=2; dir_shift=8; }
+				if (numjoystick==PORTB_JOY1) {	fire_shift=3; dir_shift=12; }
+
+				curstate = (jp_directions>>dir_shift) & 15;
+				curstate |= ((jp_fires>>fire_shift) & 1)<<4;
+
+				if (curstate != prevstate) {
+					/* X axis */
+					if ((curstate & (PORT_JS_LEFT|PORT_JS_RIGHT)) != (prevstate & (PORT_JS_LEFT|PORT_JS_RIGHT))) {
+						curaxis=0;
+						if (curstate & PORT_JS_LEFT) {
+							curaxis=-128;
+						} else if (curstate & PORT_JS_RIGHT) {
+							curaxis=127;
+						}					
+						SDL_PrivateJoystickAxis(joystick,0,curaxis);
+					}
+					/* Y axis */
+					if ((curstate & (PORT_JS_UP|PORT_JS_DOWN)) != (prevstate & (PORT_JS_UP|PORT_JS_DOWN))) {
+						curaxis=0;
+						if (curstate & PORT_JS_UP) {
+							curaxis=-128;
+						} else if (curstate & PORT_JS_DOWN) {
+							curaxis=127;
+						}					
+						SDL_PrivateJoystickAxis(joystick,1,curaxis);
+					}
+					/* Button */
+					if ((curstate & PORT_JS_FIRE) && !(prevstate & PORT_JS_FIRE)) {
+						SDL_PrivateJoystickButton(joystick,0,SDL_PRESSED);
+					}
+					if (!(curstate & PORT_JS_FIRE) && (prevstate & PORT_JS_FIRE)) {
+						SDL_PrivateJoystickButton(joystick,0,SDL_RELEASED);
+					}
+				}
+				atarijoysticks[numjoystick].prevstate = curstate;
+			}
+			break;
+		case PORTA_LP:
+			{
+				int i;
+
+				curstate = jp_lightpens[0]>>1;
+				curstate |= (jp_lightpens[1]>>1)<<15;
+				curstate |= (jp_fires & 3)<<30;
+
+				if (curstate != prevstate) {
+					/* X axis */
+					SDL_PrivateJoystickAxis(joystick,0,(jp_lightpens[0]>>8)-128);
+					/* Y axis */
+					SDL_PrivateJoystickAxis(joystick,1,(jp_lightpens[1]>>8)-128);
+					/* Buttons */
+					for (i=0;i<2;i++) {
+						int button;
+						
+						button=1<<(30+i);
+
+						if ((curstate & button) && !(prevstate & button)) {
+							SDL_PrivateJoystickButton(joystick,i,SDL_PRESSED);
+						}
+						if (!(curstate & button) && (prevstate & button)) {
+							SDL_PrivateJoystickButton(joystick,i,SDL_RELEASED);
+						}
+					}
+				}
+				atarijoysticks[numjoystick].prevstate = curstate;
+			}
+			break;
+		case PORTA_ANPAD:
+		case PORTB_ANPAD:
+			{
+				int numpaddle, i;
+				
+				numpaddle=0<<1;
+				if (numjoystick==PORTB_ANPAD) numpaddle=1<<1;
+
+				curstate = jp_paddles[numpaddle]>>1;
+				curstate |= (jp_paddles[numpaddle+1]>>1)<<15;
+				curstate |= ((jp_fires>>numpaddle) & 3)<<30;
+
+				if (curstate != prevstate) {
+					/* X axis */
+					SDL_PrivateJoystickAxis(joystick,0,(jp_paddles[numpaddle]>>8)-128);
+					/* Y axis */
+					SDL_PrivateJoystickAxis(joystick,1,(jp_paddles[numpaddle+1]>>8)-128);
+					/* Buttons */
+					for (i=0;i<2;i++) {
+						int button;
+						
+						button=1<<(30+i);
+
+						if ((curstate & button) && !(prevstate & button)) {
+							SDL_PrivateJoystickButton(joystick,i,SDL_PRESSED);
+						}
+						if (!(curstate & button) && (prevstate & button)) {
+							SDL_PrivateJoystickButton(joystick,i,SDL_RELEASED);
+						}
+					}
+				}
+				atarijoysticks[numjoystick].prevstate = curstate;
+			}
+			break;
+#if 0
+		case PARA_JOY0:
+		case PARA_JOY1:
+			break;
+#endif
+	};
+
+	return;
+}
+
+void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
+{
+	return;
+}
+
+void SDL_SYS_JoystickQuit(void)
+{
+	SDL_numjoysticks=0;
+	return;
+}
+
+/*--- Joypad I/O read/write interface ---*/
+
+#define JOYPAD_IO_BASE (0xffff9200)
+struct JOYPAD_IO_S {
+	Uint16 fires;
+	Uint16 directions;
+	Uint16 dummy1[6];
+	Uint16 paddles[4];
+	Uint16 dummy2[4];
+	Uint16 lightpens[2];
+};
+#define JOYPAD_IO ((*(volatile struct JOYPAD_IO_S *)JOYPAD_IO_BASE))
+
+static void UpdateJoypads(void)
+{
+	Uint16 tmp;
+
+	/*--- This function is called in supervisor mode ---*/
+
+	/* Update joysticks */
+	jp_fires = (~(JOYPAD_IO.fires)) & 15;
+	jp_directions = (~(JOYPAD_IO.directions));
+	
+	/* Update lightpen */
+	tmp = JOYPAD_IO.lightpens[0] & 1023;
+	jp_lightpens[0] = (tmp<<6) | (tmp>>4);
+	tmp = JOYPAD_IO.lightpens[1] & 1023;
+	jp_lightpens[1] = (tmp<<6) | (tmp>>4);
+	
+	/* Update paddles */
+	tmp = (JOYPAD_IO.paddles[0] & 255);
+	jp_paddles[0] = (tmp<<8) | tmp;
+	tmp = (JOYPAD_IO.paddles[1] & 255);
+	jp_paddles[1] = (tmp<<8) | tmp;
+	tmp = (JOYPAD_IO.paddles[2] & 255);
+	jp_paddles[2] = (tmp<<8) | tmp;
+	tmp = (JOYPAD_IO.paddles[3] & 255);
+	jp_paddles[3] = (tmp<<8) | tmp;
+
+	/* Update joypad 0 */	
+	JOYPAD_IO.directions=0xfffe;
+	jp_joypads[0]=((~(JOYPAD_IO.fires)) & 3)<<(16);
+	JOYPAD_IO.directions=0xfffe;
+	jp_joypads[0] |= ((~(JOYPAD_IO.directions))>>8) & 15;
+
+	JOYPAD_IO.directions=0xfffd;
+	jp_joypads[0] |= ((~(JOYPAD_IO.fires)) & 3)<<(16+2);
+	JOYPAD_IO.directions=0xfffd;
+	jp_joypads[0] |= (((~(JOYPAD_IO.directions))>>8) & 15)<<4;
+
+	JOYPAD_IO.directions=0xfffb;
+	jp_joypads[0] |= ((~(JOYPAD_IO.fires)) & 3)<<(16+4);
+	JOYPAD_IO.directions=0xfffb;
+	jp_joypads[0] |= (((~(JOYPAD_IO.directions))>>8) & 15)<<8;
+
+	JOYPAD_IO.directions=0xfff7;
+	jp_joypads[0] |= ((~(JOYPAD_IO.fires)) & 3)<<(16+6);
+	JOYPAD_IO.directions=0xfff7;
+	jp_joypads[0] |= (((~(JOYPAD_IO.directions))>>8) & 15)<<12;
+
+	/* Update joypad 1 */	
+	JOYPAD_IO.directions=0xffef;
+	jp_joypads[1]=((~(JOYPAD_IO.fires)) & (3<<2))<<(16-2);
+	JOYPAD_IO.directions=0xffef;
+	jp_joypads[1] |= ((~(JOYPAD_IO.directions))>>12) & 15;
+
+	JOYPAD_IO.directions=0xffdf;
+	jp_joypads[1] |= ((~(JOYPAD_IO.fires)) & (3<<2))<<(16);
+	JOYPAD_IO.directions=0xffdf;
+	jp_joypads[1] |= (((~(JOYPAD_IO.directions))>>12) & 15)<<4;
+
+	JOYPAD_IO.directions=0xffbf;
+	jp_joypads[1] |= ((~(JOYPAD_IO.fires)) & (3<<2))<<(16+2);
+	JOYPAD_IO.directions=0xffbf;
+	jp_joypads[1] |= (((~(JOYPAD_IO.directions))>>12) & 15)<<8;
+
+	JOYPAD_IO.directions=0xff7f;
+	jp_joypads[1] |= ((~(JOYPAD_IO.fires)) & (3<<2))<<(16+4);
+	JOYPAD_IO.directions=0xff7f;
+	jp_joypads[1] |= (((~(JOYPAD_IO.directions))>>12) & 15)<<12;
+}