/* LightsDriver_LinuxParallel:				*
 * Light controlling over parallel ports in Linux.	*
 *							*
 * Originally written by Hugo Hromic M., and heavily	*
 * modified by Mark Cannon for pad lights support.	*
 *							*
 * You can find a commented-out-the-wazoo version at:	*
 * vyhd.homelinux.org/stepmania/Lighting/commented.txt	*/


#include "global.h"
#include <sys/io.h>
#include "LightsDriver_LinuxParallel.h"

//The amount of ports we're using. This is intentionally made semi-expandable:
//most people will be fine, but if someone needs to add, they won't have much
//trouble.
static unsigned const int MAX_PORTS = 2;

//Define the port addresses, in hexadecimal, that will be used.
static const short PORT_ADDRESS[MAX_PORTS] =
{
	0x378,		// Cabinet lighting - lp0
	0x278,		// Pad lighting - lp1
};

unsigned char OUT_BYTE[MAX_PORTS] = {};

LightsDriver_LinuxParallel::LightsDriver_LinuxParallel()
{
	for( unsigned i = 0; i < MAX_PORTS; i++)
	{
		ioperm( PORT_ADDRESS[i], 1, 1 );
		outb( 255, PORT_ADDRESS[i] );
	}
}

LightsDriver_LinuxParallel::~LightsDriver_LinuxParallel()
{
	for( unsigned i = 0; i < MAX_PORTS; i++)
	{
		ioperm( PORT_ADDRESS[i], 1, 0 );
		outb( 0, PORT_ADDRESS[i] );
	}
}

void LightsDriver_LinuxParallel::Set( const LightsState *ls )
{
	// Reset our byte values. Data was getting corrupted because the OUT_BYTE
	// value wasn't being reset.
	for( unsigned i = 0; i < MAX_PORTS; i++)
		OUT_BYTE[i] = 0;

	int i = 0;

	FOREACH_CabinetLight( cl )
	{
		if( ls->m_bCabinetLights[cl] )
			// credit to Hugo Hromic M. for this formula - Mark
			OUT_BYTE[0] += (unsigned char)pow((double)2,i);
		i++;
	}

	// reset the iterator - we'll use it again for the game controllers
	i = 0;

	// This loops through the first four buttons on every controller (which will
	// always be the four directional arrows on four-panel mode).
	FOREACH_GameController( gc )
	{
		// HACK: Use this so we can fit two pads into one parallel port.
		// StepMania usually assigns the other four lights to stuff we don't use.
	
		FOREACH_ENUM( GameButton, 4, gb )
		{
			//See the explanation of this formula above.
			if( ls->m_bGameButtonLights[gc][gb] )
				OUT_BYTE[1] += (unsigned char)pow((double)2,i);
			i++;
		}
	}

	for( unsigned i = 0; i < MAX_PORTS; i++)
		outb( OUT_BYTE[i], PORT_ADDRESS[i] );
}

/*
 * (c) 2004 Hugo Hromic M. <hhromic@udec.cl>
 * (c) 2007 Mark Cannon <vyhdycokio@gmail.com>
 *
 * All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, and/or sell copies of the Software, and to permit persons to
 * whom the Software is furnished to do so, provided that the above
 * copyright notice(s) and this permission notice appear in all copies of
 * the Software and that both the above copyright notice(s) and this
 * permission notice appear in supporting documentation.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
 * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
 * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
 * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */
