Index: code/trunk/src/ois/linux/EventHelpers.cpp
===================================================================
--- code/trunk/src/ois/linux/EventHelpers.cpp	(revision 2710)
+++ code/trunk/src/ois/linux/EventHelpers.cpp	(revision 5695)
@@ -34,7 +34,21 @@
 #ifdef OIS_LINUX_JOY_DEBUG
 # include <iostream>
-  using namespace std;
-#endif
-
+#endif
+
+// Fixes for missing macros in input.h
+#ifndef FF_EFFECT_MIN
+#define FF_EFFECT_MIN FF_RUMBLE
+#endif
+#ifndef FF_EFFECT_MAX
+#define FF_EFFECT_MAX FF_RAMP
+#endif
+#ifndef FF_WAVEFORM_MIN
+#define FF_WAVEFORM_MIN FF_SQUARE
+#endif
+#ifndef FF_WAVEFORM_MAX
+#define FF_WAVEFORM_MAX FF_CUSTOM
+#endif
+
+using namespace std;
 using namespace OIS;
 
@@ -42,33 +56,49 @@
 {
 public:
-	std::vector<int> buttons, relAxes, absAxes, hats;
+	vector<int> buttons, relAxes, absAxes, hats;
 };
 
-bool inline isBitSet(unsigned long bits[], unsigned int bit)
-{
-	return (bits[bit/(sizeof(long)*8)] >> ((bit)%(sizeof(long)*8))) & 1;
-}
+bool inline isBitSet(unsigned char bits[], unsigned int bit)
+{
+  return (bits[(bit)/(sizeof(unsigned char)*8)] >> ((bit)%(sizeof(unsigned char)*8))) & 1;
+}
+
 //-----------------------------------------------------------------------------//
 DeviceComponentInfo getComponentInfo( int deviceID )
 {
-	unsigned long info[2][((KEY_MAX-1)/(sizeof(long)*8)) +1];
-	memset( info, 0, sizeof(info) );
+	unsigned char ev_bits[1 + EV_MAX/8/sizeof(unsigned char)];
+	memset( ev_bits, 0, sizeof(ev_bits) );
+
+	//Read "all" (hence 0) components of the device
+#ifdef OIS_LINUX_JOY_DEBUG
+	cout << "EventUtils::getComponentInfo(" << deviceID 
+		 << ") : Reading device events features" << endl;
+#endif
+	if (ioctl(deviceID, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1)
+		OIS_EXCEPT( E_General, "Could not read device events features");
 
 	DeviceComponentInfo components;
-
-	//Read "all" (hence 0) components of the device - read into first entry
-	ioctl(deviceID, EVIOCGBIT(0, EV_MAX), info[0]);
 
 	for (int i = 0; i < EV_MAX; i++)
 	{
-		if( isBitSet(info[0], i) )
+		if( isBitSet(ev_bits, i) )
 		{
-			memset( info[1], 0, sizeof(info) / 2 );
-			ioctl(deviceID, EVIOCGBIT(i, KEY_MAX), info[1]);
-			for (int j = 0; j < KEY_MAX; j++)
+		    // Absolute axis.
+		    if(i == EV_ABS)
 			{
-				if( isBitSet(info[1], j) )
+			    unsigned char abs_bits[1 + ABS_MAX/8/sizeof(unsigned char)];
+			    memset( abs_bits, 0, sizeof(abs_bits) );
+
+#ifdef OIS_LINUX_JOY_DEBUG
+				cout << "EventUtils::getComponentInfo(" << deviceID 
+					 << ") : Reading device absolute axis features" << endl;
+#endif
+
+				if (ioctl(deviceID, EVIOCGBIT(i, sizeof(abs_bits)), abs_bits) == -1)
+				    OIS_EXCEPT( E_General, "Could not read device absolute axis features");
+
+				for (int j = 0; j < ABS_MAX; j++)
 				{
-					if(i == EV_ABS)
+				    if( isBitSet(abs_bits, j) )
 					{
 						//input_absinfo abInfo;
@@ -89,11 +119,45 @@
 						}
 					}
-					else if(i == EV_REL)
+				}
+			}
+			else if(i == EV_REL)
+			{
+			    unsigned char rel_bits[1 + REL_MAX/8/sizeof(unsigned char)];
+				memset( rel_bits, 0, sizeof(rel_bits) );
+				
+#ifdef OIS_LINUX_JOY_DEBUG
+				cout << "EventUtils::getComponentInfo(" << deviceID 
+					 << ") : Reading device relative axis features" << endl;
+#endif
+
+				if (ioctl(deviceID, EVIOCGBIT(i, sizeof(rel_bits)), rel_bits) == -1)
+				    OIS_EXCEPT( E_General, "Could not read device relative axis features");
+				
+				for (int j = 0; j < REL_MAX; j++)
+				{
+				    if( isBitSet(rel_bits, j) )
 					{
-						components.relAxes.push_back(j);
+					    components.relAxes.push_back(j);
 					}
-					else if(i == EV_KEY)
+				}
+			}
+			else if(i == EV_KEY)
+			{
+			    unsigned char key_bits[1 + KEY_MAX/8/sizeof(unsigned char)];
+				memset( key_bits, 0, sizeof(key_bits) );
+				
+#ifdef OIS_LINUX_JOY_DEBUG
+				cout << "EventUtils::getComponentInfo(" << deviceID 
+					 << ") : Reading device buttons features" << endl;
+#endif
+
+				if (ioctl(deviceID, EVIOCGBIT(i, sizeof(key_bits)), key_bits) == -1)
+				    OIS_EXCEPT( E_General, "Could not read device buttons features");
+				
+				for (int j = 0; j < KEY_MAX; j++)
+				{
+				    if( isBitSet(key_bits, j) )
 					{
-						components.buttons.push_back(j);
+					    components.buttons.push_back(j);
 					}
 				}
@@ -108,5 +172,6 @@
 bool EventUtils::isJoyStick( int deviceID, JoyStickInfo &js )
 {
-	if( deviceID == -1 ) OIS_EXCEPT( E_General, "Error with File Descriptor" );
+	if( deviceID == -1 ) 
+		OIS_EXCEPT( E_General, "Error with File Descriptor" );
 
 	DeviceComponentInfo info = getComponentInfo( deviceID );
@@ -117,10 +182,12 @@
 
 	#ifdef OIS_LINUX_JOY_DEBUG
-	  cout << "\n\nDisplaying ButtonMapping Status:";
+	cout << endl << "Displaying ButtonMapping Status:" << endl;
 	#endif
-	for(std::vector<int>::iterator i = info.buttons.begin(), e = info.buttons.end(); i != e; ++i )
+	for(vector<int>::iterator i = info.buttons.begin(), e = info.buttons.end(); i != e; ++i )
 	{
 		//Check to ensure we find at least one joy only button
-		if( (*i >= BTN_JOYSTICK && *i <= BTN_THUMBR) || (*i >= BTN_WHEEL && *i <= BTN_GEAR_UP ) )
+		if( (*i >= BTN_JOYSTICK && *i < BTN_GAMEPAD)  
+			|| (*i >= BTN_GAMEPAD && *i < BTN_DIGI)
+			|| (*i >= BTN_WHEEL && *i < KEY_OK) )
 			joyButtonFound = true;
 
@@ -128,7 +195,11 @@
 
 		#ifdef OIS_LINUX_JOY_DEBUG
-		  cout << "\nButton Mapping ID (hex): " << hex << *i << " OIS Button Num: " << dec << (buttons-1);
+		  cout << "Button Mapping ID (hex): " << hex << *i 
+			   << " OIS Button Num: " << dec << buttons-1 << endl;
 		#endif
 	}
+	#ifdef OIS_LINUX_JOY_DEBUG
+	cout << endl;
+	#endif
 
 	//Joy Buttons found, so it must be a joystick or pad
@@ -140,20 +211,32 @@
 		js.axes = info.relAxes.size() + info.absAxes.size();
 		js.hats = info.hats.size();
+		#ifdef OIS_LINUX_JOY_DEBUG
+		  cout << endl << "Device name:" << js.vendor << endl;
+		  cout << "Device unique Id:" << getUniqueId(deviceID) << endl;
+		  cout << "Device physical location:" << getPhysicalLocation(deviceID) << endl;
+		#endif
 
 		//Map the Axes
 		#ifdef OIS_LINUX_JOY_DEBUG
-		  cout << "\n\nDisplaying AxisMapping Status:";
+		  cout << endl << "Displaying AxisMapping Status:" << endl;
 		#endif
 		int axes = 0;
-		for(std::vector<int>::iterator i = info.absAxes.begin(), e = info.absAxes.end(); i != e; ++i )
+		for(vector<int>::iterator i = info.absAxes.begin(), e = info.absAxes.end(); i != e; ++i )
 		{
 			js.axis_map[*i] = axes;
 
+#ifdef OIS_LINUX_JOY_DEBUG
+			cout << "EventUtils::isJoyStick(" << deviceID 
+					  << ") : Reading device absolute axis #" << *i << " features" << endl;
+#endif
+
 			input_absinfo absinfo;
-			ioctl(deviceID, EVIOCGABS(*i), &absinfo);
+			if (ioctl(deviceID, EVIOCGABS(*i), &absinfo) == -1)
+				OIS_EXCEPT( E_General, "Could not read device absolute axis features");
 			js.axis_range[axes] = Range(absinfo.minimum, absinfo.maximum);
 
 			#ifdef OIS_LINUX_JOY_DEBUG
-			  cout << "\nAxis Mapping ID (hex): " << hex << *i << " OIS Axis Num: " << dec << axes;
+			  cout << "Axis Mapping ID (hex): " << hex << *i 
+				   << " OIS Axis Num: " << dec << axes << endl;
 			#endif
 
@@ -166,9 +249,45 @@
 
 //-----------------------------------------------------------------------------//
-std::string EventUtils::getName( int deviceID )
-{
+string EventUtils::getName( int deviceID )
+{
+#ifdef OIS_LINUX_JOY_DEBUG
+	cout << "EventUtils::getName(" << deviceID 
+		 << ") : Reading device name" << endl;
+#endif
+
 	char name[OIS_DEVICE_NAME];
-	ioctl(deviceID, EVIOCGNAME(OIS_DEVICE_NAME), name);
-	return std::string(name);
+	if (ioctl(deviceID, EVIOCGNAME(OIS_DEVICE_NAME), name) == -1)
+		OIS_EXCEPT( E_General, "Could not read device name");
+	return string(name);
+}
+
+//-----------------------------------------------------------------------------//
+string EventUtils::getUniqueId( int deviceID )
+{
+#ifdef OIS_LINUX_JOY_DEBUG
+	cout << "EventUtils::getUniqueId(" << deviceID 
+		 << ") : Reading device unique Id" << endl;
+#endif
+
+#define OIS_DEVICE_UNIQUE_ID 128
+	char uId[OIS_DEVICE_UNIQUE_ID];
+	if (ioctl(deviceID, EVIOCGUNIQ(OIS_DEVICE_UNIQUE_ID), uId) == -1)
+		OIS_EXCEPT( E_General, "Could not read device unique Id");
+	return string(uId);
+}
+
+//-----------------------------------------------------------------------------//
+string EventUtils::getPhysicalLocation( int deviceID )
+{
+#ifdef OIS_LINUX_JOY_DEBUG
+	cout << "EventUtils::getPhysicalLocation(" << deviceID 
+		 << ") : Reading device physical location" << endl;
+#endif
+
+#define OIS_DEVICE_PHYSICAL_LOCATION 128
+	char physLoc[OIS_DEVICE_PHYSICAL_LOCATION];
+	if (ioctl(deviceID, EVIOCGPHYS(OIS_DEVICE_PHYSICAL_LOCATION), physLoc) == -1)
+		OIS_EXCEPT( E_General, "Could not read device physical location");
+	return string(physLoc);
 }
 
@@ -177,5 +296,5 @@
 {
 	//Linux Event to OIS Event Mappings
-	std::map<int, Effect::EType> typeMap;
+	map<int, Effect::EType> typeMap;
 	typeMap[FF_CONSTANT] = Effect::Constant;
 	typeMap[FF_RAMP]     = Effect::Ramp;
@@ -191,41 +310,71 @@
 	typeMap[FF_CUSTOM]   = Effect::Custom;
 
-	std::map<int, Effect::EForce> forceMap;
+	map<int, Effect::EForce> forceMap;
 	forceMap[FF_CONSTANT] = Effect::ConstantForce;
-	forceMap[FF_RAMP] = Effect::RampForce;
-	forceMap[FF_PERIODIC] = Effect::PeriodicForce;
-	forceMap[FF_CUSTOM] = Effect::CustomForce;
+	forceMap[FF_RAMP]     = Effect::RampForce;
+	forceMap[FF_SPRING]   = Effect::ConditionalForce;
+	forceMap[FF_FRICTION] = Effect::ConditionalForce;
+	forceMap[FF_SQUARE]   = Effect::PeriodicForce;
+	forceMap[FF_TRIANGLE] = Effect::PeriodicForce;
+	forceMap[FF_SINE]     = Effect::PeriodicForce;
+	forceMap[FF_SAW_UP]   = Effect::PeriodicForce;
+	forceMap[FF_SAW_DOWN] = Effect::PeriodicForce;
+	forceMap[FF_DAMPER]   = Effect::ConditionalForce;
+	forceMap[FF_INERTIA]  = Effect::ConditionalForce;
+	forceMap[FF_CUSTOM]   = Effect::CustomForce;
 
 	//Remove any previously existing memory and create fresh
 	removeForceFeedback( ff );
-	*ff = new LinuxForceFeedback();
-
-	unsigned long info[4] = {0,0,0,0};
-	unsigned long subinfo[4]= {0,0,0,0};
-
-	//Read overall force feedback components of the device
-	ioctl(deviceID, EVIOCGBIT(EV_FF, sizeof(long)*4), info);
+	*ff = new LinuxForceFeedback(deviceID);
+
+	//Read overall force feedback features
+	unsigned char ff_bits[1 + FF_MAX/8/sizeof(unsigned char)];
+	memset(ff_bits, 0, sizeof(ff_bits));
+
+#ifdef OIS_LINUX_JOY_DEBUG
+	cout << "EventUtils::enumerateForceFeedback(" << deviceID 
+		 << ") : Reading device force feedback features" << endl;
+#endif
+
+	if (ioctl(deviceID, EVIOCGBIT(EV_FF, sizeof(ff_bits)), ff_bits) == -1)
+		OIS_EXCEPT( E_General, "Could not read device force feedback features");
+
+
+    #ifdef OIS_LINUX_JOY_DEBUG
+	cout << "FF bits: " << hex;
+	for (int i = 0; i < sizeof(ff_bits); i++)
+		cout << (int)ff_bits[i];
+	cout << endl << dec;
+    #endif
 
 	//FF Axes
-	//if( isBitSet(info, ABS_X) ) //X Axis
-	//if( isBitSet(info, ABS_Y) ) //Y Axis
-	//if( isBitSet(info, ABS_WHEEL) ) //Wheel
+	//if( isBitSet(ff_bits, ABS_X) ) //X Axis
+	//if( isBitSet(ff_bits, ABS_Y) ) //Y Axis
+	//if( isBitSet(ff_bits, ABS_WHEEL) ) //Wheel
 
 	//FF Effects
-	for( int effect = ABS_WHEEL+1; effect < FF_MAX; effect++ )
+	for( int effect = FF_EFFECT_MIN; effect <= FF_WAVEFORM_MAX; effect++ )
 	{
-		if(isBitSet(info, effect))
+		// The RUMBLE force type is ignored, as periodic force one is more powerfull.
+		// The PERIODIC force type is processed later, for each associated periodic effect type.
+		if (effect == FF_RUMBLE || effect == FF_PERIODIC)
+			continue;
+
+		if(isBitSet(ff_bits, effect))
 		{
-			//std::cout << "\tEffect Type: " << effect << std::endl;
-			memset(subinfo, 0, sizeof(subinfo));
-			//Read any info about this supported effect
-			ioctl(deviceID, EVIOCGBIT(effect, sizeof(long)*4), subinfo);
-			for( int force = 0; force < FF_MAX; force++ )
-			{
-				if(isBitSet(subinfo, force))
-					(*ff)->_addEffectTypes( forceMap[force], typeMap[effect] );
-			}
+			#ifdef OIS_LINUX_JOY_DEBUG
+		    cout << "  Effect Type: " << Effect::getEffectTypeName(typeMap[effect]) << endl;
+			#endif
+
+			(*ff)->_addEffectTypes( forceMap[effect], typeMap[effect] );
 		}
 	}
+
+	//FF device properties
+	if (isBitSet(ff_bits, FF_GAIN))
+		(*ff)->_setGainSupport(true);
+		
+	if (isBitSet(ff_bits, FF_AUTOCENTER))
+		(*ff)->_setAutoCenterSupport(true);
 
 	//Check to see if any effects were added, else destroy the pointer
Index: code/trunk/src/ois/linux/EventHelpers.h
===================================================================
--- code/trunk/src/ois/linux/EventHelpers.h	(revision 2710)
+++ code/trunk/src/ois/linux/EventHelpers.h	(revision 5695)
@@ -43,4 +43,6 @@
 
 		static std::string getName( int deviceID );
+		static std::string getUniqueId( int deviceID );
+		static std::string getPhysicalLocation( int deviceID );
 	};
 }
Index: code/trunk/src/ois/linux/LinuxForceFeedback.cpp
===================================================================
--- code/trunk/src/ois/linux/LinuxForceFeedback.cpp	(revision 2710)
+++ code/trunk/src/ois/linux/LinuxForceFeedback.cpp	(revision 5695)
@@ -24,38 +24,536 @@
 #include "OISException.h"
 
+#include <cstdlib>
+#include <errno.h>
+#include <memory.h>
+
 using namespace OIS;
 
-//--------------------------------------------------------------//
-LinuxForceFeedback::LinuxForceFeedback()
-{
-}
+// 0 = No trace; 1 = Important traces; 2 = Debug traces
+#define OIS_LINUX_JOYFF_DEBUG 1
+
+#ifdef OIS_LINUX_JOYFF_DEBUG
+# include <iostream>
+  using namespace std;
+#endif
+
+//--------------------------------------------------------------//
+LinuxForceFeedback::LinuxForceFeedback(int deviceID) :
+	ForceFeedback(), mJoyStick(deviceID)
+{
+}
+
 //--------------------------------------------------------------//
 LinuxForceFeedback::~LinuxForceFeedback()
 {
-}
-
-//--------------------------------------------------------------//
-void LinuxForceFeedback::setMasterGain(float)
-{
-}
-
-//--------------------------------------------------------------//
-void LinuxForceFeedback::setAutoCenterMode(bool)
-{
-}
-
-//--------------------------------------------------------------//
-void LinuxForceFeedback::upload( const Effect* /*effect*/ )
-{
-}
-
-//--------------------------------------------------------------//
-void LinuxForceFeedback::modify( const Effect* /*effect*/ )
-{
-}
-
-//--------------------------------------------------------------//
-void LinuxForceFeedback::remove( const Effect* /*effect*/ )
-{
-}
-
+	// Unload all effects.
+	for(EffectList::iterator i = mEffectList.begin(); i != mEffectList.end(); ++i )
+	{
+		struct ff_effect *linEffect = i->second;
+		if( linEffect )
+			_unload(linEffect->id);
+	}
+
+	mEffectList.clear();
+}
+
+//--------------------------------------------------------------//
+unsigned short LinuxForceFeedback::getFFMemoryLoad()
+{
+	int nEffects = -1;
+	if (ioctl(mJoyStick, EVIOCGEFFECTS, &nEffects) == -1)
+		OIS_EXCEPT(E_General, "Unknown error reading max number of uploaded effects.");
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+	cout << "LinuxForceFeedback("<< mJoyStick  
+		 << ") : Read device max number of uploaded effects : " << nEffects << endl;
+#endif
+
+	return (unsigned short int)(nEffects > 0 ? 100.0*mEffectList.size()/nEffects : 100);
+}
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::setMasterGain(float value)
+{
+	if (!mSetGainSupport)
+	{
+#if (OIS_LINUX_JOYFF_DEBUG > 0)
+		cout << "LinuxForceFeedback("<< mJoyStick << ") : Setting master gain " 
+			 << "is not supported by the device" << endl;
+#endif
+		return;
+	}
+
+	struct input_event event;
+
+	memset(&event, 0, sizeof(event));
+	event.type = EV_FF;
+	event.code = FF_GAIN;
+	if (value < 0.0)
+		value = 0.0;
+	else if (value > 1.0)
+		value = 1.0;
+	event.value = (__s32)(value * 0xFFFFUL);
+
+#if (OIS_LINUX_JOYFF_DEBUG > 0)
+	cout << "LinuxForceFeedback("<< mJoyStick << ") : Setting master gain to " 
+		 << value << " => " << event.value << endl;
+#endif
+
+	if (write(mJoyStick, &event, sizeof(event)) != sizeof(event)) {
+		OIS_EXCEPT(E_General, "Unknown error changing master gain.");
+	}
+}
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::setAutoCenterMode(bool enabled)
+{
+	if (!mSetAutoCenterSupport)
+	{
+#if (OIS_LINUX_JOYFF_DEBUG > 0)
+		cout << "LinuxForceFeedback("<< mJoyStick << ") : Setting auto-center mode " 
+			 << "is not supported by the device" << endl;
+#endif
+		return;
+	}
+
+	struct input_event event;
+
+	memset(&event, 0, sizeof(event));
+	event.type = EV_FF;
+	event.code = FF_AUTOCENTER;
+	event.value = (__s32)(enabled*0xFFFFFFFFUL);
+
+#if (OIS_LINUX_JOYFF_DEBUG > 0)
+	cout << "LinuxForceFeedback("<< mJoyStick << ") : Toggling auto-center to " 
+		 << enabled << " => 0x" << hex << event.value << dec << endl;
+#endif
+
+	if (write(mJoyStick, &event, sizeof(event)) != sizeof(event)) {
+		OIS_EXCEPT(E_General, "Unknown error toggling auto-center.");
+	}
+}
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::upload( const Effect* effect )
+{
+	switch( effect->force )
+	{
+		case OIS::Effect::ConstantForce: 
+			_updateConstantEffect(effect);	
+			break;
+		case OIS::Effect::ConditionalForce: 
+			_updateConditionalEffect(effect);
+			break;
+		case OIS::Effect::PeriodicForce: 
+			_updatePeriodicEffect(effect);
+			break;
+		case OIS::Effect::RampForce: 
+			_updateRampEffect(effect);	
+			break;
+		case OIS::Effect::CustomForce: 
+			//_updateCustomEffect(effect);
+			//break;
+		default: 
+			OIS_EXCEPT(E_NotImplemented, "Requested force not implemented yet, sorry!"); 
+			break;
+	}
+}
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::modify( const Effect* effect )
+{
+	upload(effect);
+}
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::remove( const Effect* effect )
+{
+	//Get the effect - if it exists
+	EffectList::iterator i = mEffectList.find(effect->_handle);
+	if( i != mEffectList.end() )
+	{
+		struct ff_effect *linEffect = i->second;
+		if( linEffect )
+		{
+			_stop(effect->_handle);
+
+			_unload(effect->_handle);
+
+			free(linEffect);
+
+			mEffectList.erase(i);
+		}
+		else
+			mEffectList.erase(i);
+	}
+}
+
+//--------------------------------------------------------------//
+// To Signed16/Unsigned15 safe conversions
+#define MaxUnsigned15Value 0x7FFF
+#define toUnsigned15(value) \
+	(__u16)((value) < 0 ? 0 : ((value) > MaxUnsigned15Value ? MaxUnsigned15Value : (value)))
+
+#define MaxSigned16Value  0x7FFF
+#define MinSigned16Value -0x7FFF
+#define toSigned16(value) \
+  (__s16)((value) < MinSigned16Value ? MinSigned16Value : ((value) > MaxSigned16Value ? MaxSigned16Value : (value)))
+
+// OIS to Linux duration
+#define LinuxInfiniteDuration 0xFFFF
+#define OISDurationUnitMS 1000 // OIS duration unit (microseconds), expressed in milliseconds (theLinux duration unit)
+
+// linux/input.h : All duration values are expressed in ms. Values above 32767 ms (0x7fff)
+//                 should not be used and have unspecified results.
+#define LinuxDuration(oisDuration) ((oisDuration) == Effect::OIS_INFINITE ? LinuxInfiniteDuration \
+									: toUnsigned15((oisDuration)/OISDurationUnitMS))
+
+
+// OIS to Linux levels
+#define OISMaxLevel 10000
+#define LinuxMaxLevel 0x7FFF
+
+// linux/input.h : Valid range for the attack and fade levels is 0x0000 - 0x7fff
+#define LinuxPositiveLevel(oisLevel) toUnsigned15(LinuxMaxLevel*(long)(oisLevel)/OISMaxLevel)
+
+#define LinuxSignedLevel(oisLevel) toSigned16(LinuxMaxLevel*(long)(oisLevel)/OISMaxLevel)
+
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::_setCommonProperties(struct ff_effect *event, 
+											  struct ff_envelope *ffenvelope, 
+											  const Effect* effect, const Envelope *envelope )
+{
+	memset(event, 0, sizeof(struct ff_effect));
+
+	if (envelope && ffenvelope && envelope->isUsed()) {
+		ffenvelope->attack_length = LinuxDuration(envelope->attackLength);
+		ffenvelope->attack_level = LinuxPositiveLevel(envelope->attackLevel);
+		ffenvelope->fade_length = LinuxDuration(envelope->fadeLength);
+		ffenvelope->fade_level = LinuxPositiveLevel(envelope->fadeLevel);
+	}
+	
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+	cout << endl;
+	if (envelope && ffenvelope)
+	{
+		cout << "  Enveloppe :" << endl
+			 << "    AttackLen : " << envelope->attackLength
+			 << " => " << ffenvelope->attack_length << endl 
+			 << "    AttackLvl : " << envelope->attackLevel
+			 << " => " << ffenvelope->attack_level << endl 
+			 << "    FadeLen   : " << envelope->fadeLength
+			 << " => " << ffenvelope->fade_length << endl
+			 << "    FadeLvl   : " << envelope->fadeLevel
+			 << " => " << ffenvelope->fade_level << endl;
+	}
+#endif
+	
+	event->direction = (__u16)(1 + (effect->direction*45.0+135.0)*0xFFFFUL/360.0);
+
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+	cout << "  Direction : " << Effect::getDirectionName(effect->direction)
+		 << " => 0x" << hex << event->direction << dec << endl;
+#endif
+
+	// TODO trigger_button 0 vs. -1
+	event->trigger.button = effect->trigger_button; // < 0 ? 0 : effect->trigger_button;
+	event->trigger.interval = LinuxDuration(effect->trigger_interval);
+
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+	cout << "  Trigger :" << endl
+		 << "    Button   : " << effect->trigger_button 
+		 << " => " << event->trigger.button << endl
+		 << "    Interval : " << effect->trigger_interval 
+		 << " => " << event->trigger.interval << endl;
+#endif
+
+	event->replay.length = LinuxDuration(effect->replay_length);
+	event->replay.delay = LinuxDuration(effect->replay_delay);
+
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+	cout << "  Replay :" << endl
+		 << "    Length : " << effect->replay_length 
+		 << " => " << event->replay.length << endl
+		 << "    Delay  : " << effect->replay_delay 
+		 << " => " << event->replay.delay << endl;
+#endif
+}
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::_updateConstantEffect( const Effect* eff )
+{
+	struct ff_effect event;
+
+	ConstantEffect *effect = static_cast<ConstantEffect*>(eff->getForceEffect());
+
+	_setCommonProperties(&event, &event.u.constant.envelope, eff, &effect->envelope);
+
+	event.type = FF_CONSTANT;
+	event.id = -1;
+
+	event.u.constant.level = LinuxSignedLevel(effect->level);
+
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+	cout << "  Level : " << effect->level
+		 << " => " << event.u.constant.level << endl;
+#endif
+
+	_upload(&event, eff);
+}
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::_updateRampEffect( const Effect* eff )
+{
+	struct ff_effect event;
+
+	RampEffect *effect = static_cast<RampEffect*>(eff->getForceEffect());
+
+	_setCommonProperties(&event, &event.u.constant.envelope, eff, &effect->envelope);
+
+	event.type = FF_RAMP;
+	event.id = -1;
+
+	event.u.ramp.start_level = LinuxSignedLevel(effect->startLevel);
+	event.u.ramp.end_level = LinuxSignedLevel(effect->endLevel);
+
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+	cout << "  StartLevel : " << effect->startLevel
+		 << " => " << event.u.ramp.start_level << endl
+		 << "  EndLevel   : " << effect->endLevel
+		 << " => " << event.u.ramp.end_level << endl;
+#endif
+
+	_upload(&event, eff);
+}
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::_updatePeriodicEffect( const Effect* eff )
+{
+	struct ff_effect event;
+
+	PeriodicEffect *effect = static_cast<PeriodicEffect*>(eff->getForceEffect());
+
+	_setCommonProperties(&event, &event.u.periodic.envelope, eff, &effect->envelope);
+
+	event.type = FF_PERIODIC;
+	event.id = -1;
+
+	switch( eff->type )
+	{
+		case OIS::Effect::Square:
+			event.u.periodic.waveform = FF_SQUARE;
+			break;
+		case OIS::Effect::Triangle:
+			event.u.periodic.waveform = FF_TRIANGLE;
+			break;
+		case OIS::Effect::Sine:
+			event.u.periodic.waveform = FF_SINE;
+			break;
+		case OIS::Effect::SawToothUp:
+			event.u.periodic.waveform = FF_SAW_UP;
+			break;
+		case OIS::Effect::SawToothDown:
+			event.u.periodic.waveform = FF_SAW_DOWN;
+			break;
+		// Note: No support for Custom periodic force effect for the moment
+		//case OIS::Effect::Custom:
+			//event.u.periodic.waveform = FF_CUSTOM;
+			//break;
+		default:
+			OIS_EXCEPT(E_General, "No such available effect for Periodic force!"); 
+			break;
+	}
+
+	event.u.periodic.period    = LinuxDuration(effect->period);
+	event.u.periodic.magnitude = LinuxPositiveLevel(effect->magnitude);
+	event.u.periodic.offset    = LinuxPositiveLevel(effect->offset);
+	event.u.periodic.phase     = (__u16)(effect->phase*event.u.periodic.period/36000.0); // ?????
+
+	// Note: No support for Custom periodic force effect for the moment
+	event.u.periodic.custom_len = 0;
+	event.u.periodic.custom_data = 0;
+
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+	cout << "  Magnitude : " << effect->magnitude
+		 << " => " << event.u.periodic.magnitude << endl
+		 << "  Period    : " << effect->period
+		 << " => " << event.u.periodic.period  << endl
+		 << "  Offset    : " << effect->offset
+		 << " => " << event.u.periodic.offset << endl
+		 << "  Phase     : " << effect->phase
+		 << " => " << event.u.periodic.phase << endl;
+#endif
+
+	_upload(&event, eff);
+}
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::_updateConditionalEffect( const Effect* eff )
+{
+	struct ff_effect event;
+
+	ConditionalEffect *effect = static_cast<ConditionalEffect*>(eff->getForceEffect());
+
+	_setCommonProperties(&event, NULL, eff, NULL);
+
+	switch( eff->type )
+	{
+		case OIS::Effect::Friction:
+			event.type = FF_FRICTION; 
+			break;
+		case OIS::Effect::Damper:
+			event.type = FF_DAMPER; 
+			break;
+		case OIS::Effect::Inertia:
+			event.type = FF_INERTIA; 
+			break;
+		case OIS::Effect::Spring:
+			event.type = FF_SPRING;
+			break;
+		default:
+			OIS_EXCEPT(E_General, "No such available effect for Conditional force!"); 
+			break;
+	}
+
+	event.id = -1;
+
+	event.u.condition[0].right_saturation = LinuxSignedLevel(effect->rightSaturation);
+	event.u.condition[0].left_saturation  = LinuxSignedLevel(effect->leftSaturation);
+	event.u.condition[0].right_coeff      = LinuxSignedLevel(effect->rightCoeff);
+	event.u.condition[0].left_coeff       = LinuxSignedLevel(effect->leftCoeff);
+	event.u.condition[0].deadband         = LinuxPositiveLevel(effect->deadband);// Unit ?? 
+	event.u.condition[0].center           = LinuxSignedLevel(effect->center); // Unit ?? TODO ?
+
+	// TODO support for second condition
+	event.u.condition[1] = event.u.condition[0];
+
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+	cout << "  Condition[0] : " << endl
+		 << "    RightSaturation  : " << effect->rightSaturation
+		 << " => " << event.u.condition[0].right_saturation << endl
+		 << "    LeftSaturation   : " << effect->leftSaturation
+		 << " => " << event.u.condition[0]. left_saturation << endl
+		 << "    RightCoefficient : " << effect->rightCoeff
+		 << " => " << event.u.condition[0].right_coeff << endl
+		 << "    LeftCoefficient : " << effect->leftCoeff
+		 << " => " << event.u.condition[0].left_coeff << endl
+		 << "    DeadBand        : " << effect->deadband
+		 << " => " << event.u.condition[0].deadband  << endl
+		 << "    Center          : " << effect->center
+		 << " => " << event.u.condition[0].center << endl;
+	cout << "  Condition[1] : Not implemented" << endl;
+#endif
+	_upload(&event, eff);
+}
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::_upload( struct ff_effect* ffeffect, const Effect* effect)
+{
+	struct ff_effect *linEffect = 0;
+
+	//Get the effect - if it exists
+	EffectList::iterator i = mEffectList.find(effect->_handle);
+	//It has been created already
+	if( i != mEffectList.end() )
+		linEffect = i->second;
+
+	if( linEffect == 0 )
+	{
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+		cout << endl << "LinuxForceFeedback("<< mJoyStick << ") : Adding new effect : " 
+			 << Effect::getEffectTypeName(effect->type) << endl;
+#endif
+
+		//This effect has not yet been created, so create it in the device
+		if (ioctl(mJoyStick, EVIOCSFF, ffeffect) == -1) {
+			// TODO device full check
+			// OIS_EXCEPT(E_DeviceFull, "Remove an effect before adding more!");
+			OIS_EXCEPT(E_General, "Unknown error creating effect (may be the device is full)->..");
+		}
+
+		// Save returned effect handle
+		effect->_handle = ffeffect->id;
+
+		// Save a copy of the uploaded effect for later simple modifications
+		linEffect = (struct ff_effect *)calloc(1, sizeof(struct ff_effect));
+		memcpy(linEffect, ffeffect, sizeof(struct ff_effect));
+
+		mEffectList[effect->_handle] = linEffect;
+
+		// Start playing the effect.
+		_start(effect->_handle);
+	}
+	else
+	{
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+		cout << endl << "LinuxForceFeedback("<< mJoyStick << ") : Replacing effect : " 
+			 << Effect::getEffectTypeName(effect->type) << endl;
+#endif
+
+		// Keep same id/handle, as this is just an update in the device.
+		ffeffect->id = effect->_handle;
+
+		// Update effect in the device.
+		if (ioctl(mJoyStick, EVIOCSFF, ffeffect) == -1) {
+			OIS_EXCEPT(E_General, "Unknown error updating an effect->..");
+		}
+
+		// Update local linEffect for next time.
+		memcpy(linEffect, ffeffect, sizeof(struct ff_effect));
+	}
+
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+	cout << "LinuxForceFeedback("<< mJoyStick 
+		 << ") : Effect handle : " << effect->_handle << endl;
+#endif
+}
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::_stop( int handle) {
+	struct input_event stop;
+
+	stop.type = EV_FF;
+	stop.code = handle;
+	stop.value = 0;
+
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+	cout << endl << "LinuxForceFeedback("<< mJoyStick 
+		 << ") : Stopping effect with handle " << handle << endl;
+#endif
+
+	if (write(mJoyStick, &stop, sizeof(stop)) != sizeof(stop)) {
+		OIS_EXCEPT(E_General, "Unknown error stopping effect->..");
+	}
+}
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::_start( int handle) {
+	struct input_event play;
+
+	play.type = EV_FF;
+	play.code = handle;
+	play.value = 1; // Play once.
+
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+	cout << endl << "LinuxForceFeedback("<< mJoyStick 
+		 << ") : Starting effect with handle " << handle << endl;
+#endif
+
+	if (write(mJoyStick, &play, sizeof(play)) != sizeof(play)) {
+		OIS_EXCEPT(E_General, "Unknown error playing effect->..");
+	}
+}
+
+//--------------------------------------------------------------//
+void LinuxForceFeedback::_unload( int handle)
+{
+#if (OIS_LINUX_JOYFF_DEBUG > 1)
+	cout << endl << "LinuxForceFeedback("<< mJoyStick 
+		 << ") : Removing effect with handle " << handle << endl;
+#endif
+
+	if (ioctl(mJoyStick, EVIOCRMFF, handle) == -1) {
+		OIS_EXCEPT(E_General, "Unknown error removing effect->..");
+	}
+}
Index: code/trunk/src/ois/linux/LinuxForceFeedback.h
===================================================================
--- code/trunk/src/ois/linux/LinuxForceFeedback.h	(revision 2710)
+++ code/trunk/src/ois/linux/LinuxForceFeedback.h	(revision 5695)
@@ -26,4 +26,5 @@
 #include "linux/LinuxPrereqs.h"
 #include "OISForceFeedback.h"
+#include <linux/input.h>
 
 namespace OIS
@@ -32,5 +33,5 @@
 	{
 	public:
-		LinuxForceFeedback();
+		LinuxForceFeedback(int deviceID);
 		~LinuxForceFeedback();
 
@@ -50,6 +51,34 @@
 		void remove( const Effect* effect );
 
-		/** FF is not yet implemented fully on Linux.. just retun 0 for now. todo, xxx */
-		short int getFFAxesNumber() { return 0; }
+		/** FF is not yet implemented fully on Linux.. just return -1 for now. todo, xxx */
+		short int getFFAxesNumber() { return -1; }
+
+		/** @copydoc ForceFeedback::getFFMemoryLoad */
+		unsigned short getFFMemoryLoad();
+
+	protected:
+
+		//Sets the common properties to all effects
+		void _setCommonProperties(struct ff_effect *event, struct ff_envelope *ffenvelope, 
+								  const Effect* effect, const Envelope *envelope );
+
+		//Specific Effect Settings
+		void _updateConstantEffect( const Effect* effect );
+		void _updateRampEffect( const Effect* effect );
+		void _updatePeriodicEffect( const Effect* effect );
+		void _updateConditionalEffect( const Effect* effect );
+		//void _updateCustomEffect( const Effect* effect );
+
+		void _upload( struct ff_effect* ffeffect, const Effect* effect);
+		void _stop( int handle);
+		void _start( int handle);
+		void _unload( int handle);
+
+		// Map of currently uploaded effects (handle => effect)
+		typedef std::map<int, struct ff_effect *> EffectList;
+		EffectList mEffectList;
+
+		// Joystick device (file) descriptor.
+		int mJoyStick;
 	};
 }
Index: code/trunk/src/ois/linux/LinuxJoyStickEvents.cpp
===================================================================
--- code/trunk/src/ois/linux/LinuxJoyStickEvents.cpp	(revision 2710)
+++ code/trunk/src/ois/linux/LinuxJoyStickEvents.cpp	(revision 5695)
@@ -37,13 +37,10 @@
 
 #include <sstream>
+# include <iostream>
+using namespace std;
 
 using namespace OIS;
 
 //#define OIS_LINUX_JOY_DEBUG
-
-#ifdef OIS_LINUX_JOY_DEBUG
-# include <iostream>
-  using namespace std;
-#endif
 
 //-------------------------------------------------------------------//
@@ -114,5 +111,5 @@
 
 			#ifdef OIS_LINUX_JOY_DEBUG
-			  std::cout << "\nButton Code: " << js[i].code << ", OIS Value: " << button << std::endl;
+			  cout << "\nButton Code: " << js[i].code << ", OIS Value: " << button << endl;
 			#endif
 
@@ -132,5 +129,6 @@
 			break;
 		}
-		case EV_ABS:  //Absoulte Axis
+
+		case EV_ABS:  //Absolute Axis
 		{
 			//A Stick (BrakeDefine is the highest possible Axis)
@@ -138,6 +136,6 @@
 			{
 				int axis = mAxisMap[js[i].code];
-				assert( axis < 32 && "Too many axes, not supported. Report this to OIS forums!" );
-				
+				assert( axis < 32 && "Too many axes (Max supported is 32). Report this to OIS forums!" );
+
 				axisMoved[axis] = true;
 
@@ -190,6 +188,11 @@
 			break;
 		}
-		//Relative Axes (Do any joysticks actually have a relative axis?)
-		case EV_REL:
+
+		
+		case EV_REL: //Relative Axes (Do any joystick actually have a relative axis?)
+#ifdef OIS_LINUX_JOY_DEBUG
+		    cout << "\nWarning: Relatives axes not supported yet" << endl;
+#endif
+			break;
 		default: break;
 		}
@@ -243,12 +246,12 @@
 	for(int i = 0; i < 64; ++i )
 	{
-		std::stringstream s;
+		stringstream s;
 		s << "/dev/input/event" << i;
-		int fd = open( s.str().c_str(), O_RDONLY |O_NONBLOCK );
+		int fd = open( s.str().c_str(), O_RDWR |O_NONBLOCK );
 		if(fd == -1)
 			continue;
-		
+
         #ifdef OIS_LINUX_JOY_DEBUG
-          std::cout << "\nOpening " << s.str() << "...";
+		  cout << "Opening " << s.str() << "..." << endl;
         #endif
 		try
@@ -259,5 +262,5 @@
 				joys.push_back(js);
                 #ifdef OIS_LINUX_JOY_DEBUG
-                  std::cout << "\n__Joystick added to list";
+                  cout << "=> Joystick added to list." << endl;
                 #endif
 			}
@@ -265,5 +268,5 @@
 			{
                 #ifdef OIS_LINUX_JOY_DEBUG
-                  std::cout << "\n__Not a joystick!!";
+                  cout << "=> Not a joystick." << endl;
                 #endif
 				close(fd);
@@ -273,5 +276,5 @@
 		{
             #ifdef OIS_LINUX_JOY_DEBUG
-              std::cout << "\nException caught!!";
+              cout << "Exception caught!!" << endl;
             #endif
 			close(fd);
