summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/ps2pad.cpp
blob: 64e1009a3316e8ebc8eea5283c0e570d2f6b0419 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11



                                                                               
                                    





                
                

                   
                                                                             
 
                                                                        





                                                                                                               



                                 

















































































































































































































































































































                                                                                                                              
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/******************************************************************************
*
*   Sony DualShock 2 device skeleton
*
*   To Do:
*     Everything
*
*/

#include "emu.h"
#include "ps2pad.h"

DEFINE_DEVICE_TYPE(SONYPS2_PAD, ps2_pad_device, "ps2pad", "Sony DualShock 2")

/*static*/ const size_t ps2_pad_device::BUFFER_SIZE = 64; // Total guess

ps2_pad_device::ps2_pad_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, SONYPS2_PAD, tag, owner, clock)
{
}

ps2_pad_device::~ps2_pad_device()
{
}

void ps2_pad_device::device_start()
{
	save_item(NAME(m_recv_buf));
	save_item(NAME(m_xmit_buf));
	save_item(NAME(m_curr_recv));
	save_item(NAME(m_curr_xmit));
	save_item(NAME(m_end_recv));
	save_item(NAME(m_end_xmit));
	save_item(NAME(m_cmd));
	save_item(NAME(m_cmd_size));
	save_item(NAME(m_configuring));
}

void ps2_pad_device::device_reset()
{
	memset(m_recv_buf, 0, BUFFER_SIZE);
	memset(m_xmit_buf, 0, BUFFER_SIZE);

	m_curr_recv = 0;
	m_curr_xmit = 0;

	m_end_recv = 0;
	m_end_xmit = 0;

	m_cmd = 0;
	m_cmd_size = 0;
	m_configuring = false;
}

void ps2_pad_device::recv_fifo_push(uint8_t data)
{
	if (m_end_recv >= BUFFER_SIZE)
	{
		return;
	}

	//logerror("%s: Receiving %02x from SIO2\n", machine().describe_context(), data);

	m_recv_buf[m_end_recv++] = data;
}

void ps2_pad_device::xmit_fifo_push(uint8_t data)
{
	if (m_end_xmit >= BUFFER_SIZE)
	{
		return;
	}

	//logerror("%s: Pushing %02x onto transmit FIFO\n", machine().describe_context(), data);

	m_xmit_buf[m_end_xmit++] = data;
}

uint8_t ps2_pad_device::xmit_fifo_pop()
{
	uint8_t ret = 0;
	if (m_curr_xmit < m_end_xmit)
	{
		ret = m_xmit_buf[m_curr_xmit++];
	}
	if (m_curr_xmit == m_end_xmit)
	{
		m_curr_xmit = 0;
		m_end_xmit = 0;
	}
	return ret;
}

uint8_t ps2_pad_device::recv_fifo_pop()
{
	uint8_t ret = 0;
	if (m_curr_recv < m_end_recv)
	{
		ret = m_recv_buf[m_curr_recv++];
	}
	if (m_curr_recv == m_end_recv)
	{
		m_curr_recv = 0;
		m_end_recv = 0;
	}
	return ret;
}

void ps2_pad_device::process_fifos()
{
	m_cmd_size = 0;

	while (recv_fifo_depth())
	{
		const uint8_t data = recv_fifo_pop();
		m_cmd_size++;

		if (m_cmd_size == 1)
		{
			if (data == SIO_DEVICE_ID)
			{
				xmit_fifo_push(0xff);
			}
			else
			{
				logerror("%s: Unknkown command byte 1: %02x\n", machine().describe_context(), data);
			}
		}
		else if (m_cmd_size == 2)
		{
			process_command(data);
		}
	}

	m_curr_recv = 0;
	m_end_recv = 0;
}

void ps2_pad_device::process_command(uint8_t data)
{
	m_cmd = data;

	switch (m_cmd)
	{
		case CMD_READ_BUTTONS:
			//logerror("%s: Pad command: Read Buttons\n", machine().describe_context());
			cmd_read_buttons();
			break;
		case CMD_CONFIG:
			//logerror("%s: Pad command: Config\n", machine().describe_context());
			cmd_config();
			break;
		case CMD_GET_MODEL:
			//logerror("%s: Pad command: Get Model\n", machine().describe_context());
			cmd_get_model();
			break;
		case CMD_GET_ACT:
			//logerror("%s: Pad command: Get Act\n", machine().describe_context());
			cmd_get_act();
			break;
		case CMD_GET_COMB:
			//logerror("%s: Pad command: Get Comb\n", machine().describe_context());
			cmd_get_comb();
			break;
		case CMD_GET_MODE:
			//logerror("%s: Pad command: Get Mode\n", machine().describe_context());
			cmd_get_comb();
			break;
		default:
			logerror("%s: Unknown pad command: %02x, forcing idle\n", machine().describe_context(), m_cmd);
			break;
	}
}

void ps2_pad_device::cmd_read_buttons()
{
	while (recv_fifo_depth())
	{
		recv_fifo_pop();

		if (m_cmd_size == 2)
		{
			xmit_fifo_push(0x41);
			xmit_fifo_push(0x5a);
			xmit_fifo_push(0x00);
			xmit_fifo_push(0x00);
		}

		m_cmd_size++;
	}
}

void ps2_pad_device::cmd_config()
{
	if (m_configuring)
	{
		xmit_fifo_push(0xf3);
		xmit_fifo_push(0x5a);
		xmit_fifo_push(0x00);
		xmit_fifo_push(0x00);
		xmit_fifo_push(0x00);
		xmit_fifo_push(0x00);
		xmit_fifo_push(0x00);
		xmit_fifo_push(0x00);
		return;
	}

	while (recv_fifo_depth())
	{
		const uint8_t data = recv_fifo_pop();

		if (m_cmd_size == 2)
		{
			xmit_fifo_push(0x41);
			xmit_fifo_push(0x5a);
			xmit_fifo_push(0x00);
			xmit_fifo_push(0x00);
		}
		else if (m_cmd_size == 3)
		{
			m_configuring = BIT(data, 0);
			//logerror("%s: Entering config mode? %c\n", machine().describe_context(), m_configuring ? 'Y' : 'N');
		}

		m_cmd_size++;
	}
}

void ps2_pad_device::cmd_get_model()
{
	while (recv_fifo_depth())
	{
		recv_fifo_pop();

		if (m_cmd_size == 2)
		{
			xmit_fifo_push(0xf3);
			xmit_fifo_push(0x5a);
			xmit_fifo_push(0x01);
			xmit_fifo_push(0x02);
			xmit_fifo_push(0x00);
			xmit_fifo_push(0x02);
			xmit_fifo_push(0x01);
			xmit_fifo_push(0x00);
		}

		m_cmd_size++;
	}
}

void ps2_pad_device::cmd_get_act()
{
	while (recv_fifo_depth())
	{
		const uint8_t data = recv_fifo_pop();

		if (m_cmd_size == 3)
		{
			xmit_fifo_push(0xf3);
			xmit_fifo_push(0x5a);
			xmit_fifo_push(0x00);
			xmit_fifo_push(0x00);
			xmit_fifo_push(0x01);
			if (data < 2)
			{
				xmit_fifo_push(0x01);
				xmit_fifo_push(0x01);
				xmit_fifo_push(0x14);
			}
			else
			{
				xmit_fifo_push(0x02);
				xmit_fifo_push(0x00);
				xmit_fifo_push(0x0a);
			}
		}

		m_cmd_size++;
	}
}

void ps2_pad_device::cmd_get_comb()
{
	while (recv_fifo_depth())
	{
		recv_fifo_pop();

		if (m_cmd_size == 2)
		{
			xmit_fifo_push(0xf3);
			xmit_fifo_push(0x5a);
			xmit_fifo_push(0x00);
			xmit_fifo_push(0x00);
			xmit_fifo_push(0x02);
			xmit_fifo_push(0x00);
			xmit_fifo_push(0x01);
			xmit_fifo_push(0x00);
		}

		m_cmd_size++;
	}
}

void ps2_pad_device::cmd_get_mode()
{
	while (recv_fifo_depth())
	{
		const uint8_t data = recv_fifo_pop();

		if (m_cmd_size == 3)
		{
			xmit_fifo_push(0xf3);
			xmit_fifo_push(0x5a);
			xmit_fifo_push(0x00);
			xmit_fifo_push(0x00);
			xmit_fifo_push(0x00);
			if (data < 2)
			{
				xmit_fifo_push(4 + data * 3);
			}
			else
			{
				xmit_fifo_push(0x00);
			}
			xmit_fifo_push(0x00);
			xmit_fifo_push(0x00);
		}

		m_cmd_size++;
	}
}