// 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++; } }