예제 #1
0
파일: cellPad.cpp 프로젝트: mob41/rpcs3
s32 cellPadGetInfo2(vm::ptr<CellPadInfo2> info)
{
	sys_io.trace("cellPadGetInfo2(info=*0x%x)", info);

	const auto handler = fxm::get<PadHandlerBase>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	const PadInfo& rinfo = handler->GetInfo();
	info->max_connect = rinfo.max_connect;
	info->now_connect = rinfo.now_connect;
	info->system_info = rinfo.system_info;

	std::vector<Pad>& pads = handler->GetPads();

	for (u32 i=0; i<CELL_PAD_MAX_PORT_NUM; ++i)
	{
		if (i >= pads.size())
			break;

		info->port_status[i] = pads[i].m_port_status;
		pads[i].m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES;
		info->port_setting[i] = pads[i].m_port_setting;
		info->device_capability[i] = pads[i].m_device_capability;
		info->device_type[i] = pads[i].m_device_type;
	}

	return CELL_OK;
}
예제 #2
0
파일: cellPad.cpp 프로젝트: mob41/rpcs3
s32 cellPadGetInfo(vm::ptr<CellPadInfo> info)
{
	sys_io.trace("cellPadGetInfo(info=*0x%x)", info);

	const auto handler = fxm::get<PadHandlerBase>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	const PadInfo& rinfo = handler->GetInfo();
	info->max_connect = rinfo.max_connect;
	info->now_connect = rinfo.now_connect;
	info->system_info = rinfo.system_info;

	std::vector<Pad>& pads = handler->GetPads();

	for (u32 i=0; i<CELL_MAX_PADS; ++i)
	{
		if (i >= pads.size())
			break;

		info->status[i] = pads[i].m_port_status;
		pads[i].m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES;
		info->product_id[i] = 0x0268;
		info->vendor_id[i] = 0x054C;
	}

	return CELL_OK;
}
예제 #3
0
파일: cellPad.cpp 프로젝트: mpm11011/rpcs3
error_code cellPadPeriphGetData(u32 port_no, vm::ptr<CellPadPeriphData> data)
{
	sys_io.trace("cellPadPeriphGetData(port_no=%d, data=*0x%x)", port_no, data);
	const auto handler = fxm::get<pad_thread>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	// port_no can only be 0-6 in this function
	if (port_no >= CELL_PAD_MAX_PORT_NUM || !data)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	const auto& pads = handler->GetPads();

	if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	const auto pad = pads[port_no];

	if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
		return CELL_PAD_ERROR_NO_DEVICE;

	// todo: support for 'unique' controllers, which goes in offsets 24+ in padData
	data->pclass_type = CELL_PAD_PCLASS_TYPE_STANDARD;
	data->pclass_profile = 0x0;

	return cellPadGetData(port_no, vm::get_addr(&data->cellpad_data));
}
예제 #4
0
파일: cellPad.cpp 프로젝트: mpm11011/rpcs3
error_code cellPadGetRawData(u32 port_no, vm::ptr<CellPadData> data)
{
	sys_io.todo("cellPadGetRawData(port_no=%d, data=*0x%x)", port_no, data);

	const auto handler = fxm::get<pad_thread>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	if (port_no >= CELL_MAX_PADS || !data)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	const auto& pads = handler->GetPads();

	if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	const auto pad = pads[port_no];

	if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
		return CELL_PAD_ERROR_NO_DEVICE;

	// ?

	return CELL_OK;
}
예제 #5
0
파일: cellPad.cpp 프로젝트: mpm11011/rpcs3
error_code cellPadSetPortSetting(u32 port_no, u32 port_setting)
{
	sys_io.trace("cellPadSetPortSetting(port_no=%d, port_setting=0x%x)", port_no, port_setting);

	const auto handler = fxm::get<pad_thread>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	if (port_no >= CELL_MAX_PADS)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	const auto& pads = handler->GetPads();

	// CELL_PAD_ERROR_NO_DEVICE is not returned in this case.
	// TODO: Set the setting regardless
	if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect)
		return CELL_OK;

	const auto pad = pads[port_no];
	pad->m_port_setting = port_setting;

	// can also return CELL_PAD_ERROR_UNSUPPORTED_GAMEPAD

	return CELL_OK;
}
예제 #6
0
파일: cellPad.cpp 프로젝트: mpm11011/rpcs3
error_code cellPadGetCapabilityInfo(u32 port_no, vm::ptr<CellPadCapabilityInfo> info)
{
	sys_io.trace("cellPadGetCapabilityInfo(port_no=%d, data_addr:=0x%x)", port_no, info.addr());

	const auto handler = fxm::get<pad_thread>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	if (port_no >= CELL_MAX_PADS || !info)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	const auto& pads = handler->GetPads();

	if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	const auto pad = pads[port_no];

	if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
		return CELL_PAD_ERROR_NO_DEVICE;

	// Should return the same as device capability mask, psl1ght has it backwards in pad->h
	info->info[port_no] = pad->m_device_capability;

	return CELL_OK;
}
예제 #7
0
파일: cellPad.cpp 프로젝트: mpm11011/rpcs3
error_code cellPadGetInfo(vm::ptr<CellPadInfo> info)
{
	sys_io.trace("cellPadGetInfo(info=*0x%x)", info);

	const auto handler = fxm::get<pad_thread>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	if (!info)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	std::memset(info.get_ptr(), 0, sizeof(CellPadInfo));

	const PadInfo& rinfo = handler->GetInfo();
	info->max_connect = rinfo.max_connect;
	info->now_connect = rinfo.now_connect;
	info->system_info = rinfo.system_info;

	const auto& pads = handler->GetPads();

	for (u32 i = 0; i < CELL_MAX_PADS; ++i)
	{
		if (i >= pads.size())
			break;

		info->status[i] = pads[i]->m_port_status;
		pads[i]->m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES;
		info->product_id[i] = 0x0268;
		info->vendor_id[i] = 0x054C;
	}

	return CELL_OK;
}
예제 #8
0
파일: cellPad.cpp 프로젝트: mpm11011/rpcs3
error_code cellPadGetInfo2(vm::ptr<CellPadInfo2> info)
{
	sys_io.trace("cellPadGetInfo2(info=*0x%x)", info);

	const auto handler = fxm::get<pad_thread>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	if (!info)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	std::memset(info.get_ptr(), 0, sizeof(CellPadInfo2));

	const PadInfo& rinfo = handler->GetInfo();
	info->max_connect = rinfo.max_connect;
	info->now_connect = rinfo.now_connect;
	info->system_info = rinfo.system_info;

	const auto& pads = handler->GetPads();

	for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; ++i)
	{
		if (i >= pads.size())
			break;

		info->port_status[i] = pads[i]->m_port_status;
		pads[i]->m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES;
		info->port_setting[i] = pads[i]->m_port_setting;
		info->device_capability[i] = pads[i]->m_device_capability;
		info->device_type[i] = pads[i]->m_device_type;
	}

	return CELL_OK;
}
예제 #9
0
파일: cellPad.cpp 프로젝트: mpm11011/rpcs3
error_code cellPadSetSensorMode(u32 port_no, u32 mode)
{
	sys_io.trace("cellPadSetSensorMode(port_no=%d, mode=%d)", port_no, mode);

	const auto handler = fxm::get<pad_thread>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	if (port_no >= CELL_MAX_PADS)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	const auto& pads = handler->GetPads();

	// CELL_PAD_ERROR_NO_DEVICE is not returned in this case.
	// TODO: Set the setting regardless
	if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect)
		return CELL_OK;

	const auto pad = pads[port_no];

	// TODO: find out if this is checked here or later or at all
	if (!(pad->m_device_capability & CELL_PAD_CAPABILITY_SENSOR_MODE))
		return CELL_PAD_ERROR_UNSUPPORTED_GAMEPAD;

	if (mode)
		pad->m_port_setting |= CELL_PAD_SETTING_SENSOR_ON;
	else
		pad->m_port_setting &= ~CELL_PAD_SETTING_SENSOR_ON;

	return CELL_OK;
}
예제 #10
0
파일: cellPad.cpp 프로젝트: mpm11011/rpcs3
error_code cellPadSetActDirect(u32 port_no, vm::ptr<CellPadActParam> param)
{
	sys_io.trace("cellPadSetActDirect(port_no=%d, param=*0x%x)", port_no, param);

	const auto handler = fxm::get<pad_thread>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	if (port_no >= CELL_MAX_PADS || !param)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	const auto& pads = handler->GetPads();

	if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	const auto pad = pads[port_no];

	if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
		return CELL_PAD_ERROR_NO_DEVICE;

	// TODO: find out if this is checked here or later or at all
	if (!(pad->m_device_capability & CELL_PAD_CAPABILITY_ACTUATOR))
		return CELL_PAD_ERROR_UNSUPPORTED_GAMEPAD;

	// make sure reserved bits are 0. Looks like this happens after checking the pad status
	for (int i = 0; i < 6; i++)
		if (param->reserved[i])
			return CELL_PAD_ERROR_INVALID_PARAMETER;

	handler->SetRumble(port_no, param->motor[1], param->motor[0] > 0);

	return CELL_OK;
}
예제 #11
0
파일: cellPad.cpp 프로젝트: mob41/rpcs3
s32 cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info)
{
	sys_io.trace("cellPadPeriphGetInfo(info=*0x%x)", info);

	const auto handler = fxm::get<PadHandlerBase>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	const PadInfo& rinfo = handler->GetInfo();

	info->max_connect = rinfo.max_connect;
	info->now_connect = rinfo.now_connect;
	info->system_info = rinfo.system_info;

	std::vector<Pad>& pads = handler->GetPads();

	// TODO: Support other types of controllers
	for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; ++i)
	{
		if (i >= pads.size())
			break;

		info->port_status[i] = pads[i].m_port_status;
		info->port_setting[i] = pads[i].m_port_setting;
		info->device_capability[i] = pads[i].m_device_capability;
		info->device_type[i] = pads[i].m_device_type;
		info->pclass_type[i] = CELL_PAD_PCLASS_TYPE_STANDARD;
		info->pclass_profile[i] = 0x0;
	}

	return CELL_OK;
}
예제 #12
0
파일: cellPad.cpp 프로젝트: mob41/rpcs3
s32 cellPadSetSensorMode(u32 port_no, u32 mode)
{
	sys_io.trace("cellPadSetSensorMode(port_no=%d, mode=%d)", port_no, mode);

	const auto handler = fxm::get<PadHandlerBase>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	if (mode != 0 && mode != 1)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	const PadInfo& rinfo = handler->GetInfo();

	if (port_no >= rinfo.max_connect)
		return CELL_PAD_ERROR_INVALID_PARAMETER;
	if (port_no >= rinfo.now_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	std::vector<Pad>& pads = handler->GetPads();

	if (mode)
		pads[port_no].m_port_setting |= CELL_PAD_SETTING_SENSOR_ON;
	else
		pads[port_no].m_port_setting &= ~CELL_PAD_SETTING_SENSOR_ON;

	return CELL_OK;
}
예제 #13
0
파일: cellPad.cpp 프로젝트: mob41/rpcs3
s32 cellPadInfoSensorMode(u32 port_no)
{
	sys_io.trace("cellPadInfoSensorMode(port_no=%d)", port_no);

	const auto handler = fxm::get<PadHandlerBase>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	const PadInfo& rinfo = handler->GetInfo();

	if (port_no >= rinfo.max_connect)
		return CELL_PAD_ERROR_INVALID_PARAMETER;
	if (port_no >= rinfo.now_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	const std::vector<Pad>& pads = handler->GetPads();

	return (pads[port_no].m_device_capability & CELL_PAD_CAPABILITY_SENSOR_MODE) > 0;
}
예제 #14
0
파일: cellPad.cpp 프로젝트: mob41/rpcs3
s32 cellPadSetPortSetting(u32 port_no, u32 port_setting)
{
	sys_io.trace("cellPadSetPortSetting(port_no=%d, port_setting=0x%x)", port_no, port_setting);

	const auto handler = fxm::get<PadHandlerBase>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	const PadInfo& rinfo = handler->GetInfo();

	if (port_no >= rinfo.max_connect)
		return CELL_PAD_ERROR_INVALID_PARAMETER;
	if (port_no >= rinfo.now_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	std::vector<Pad>& pads = handler->GetPads();
	pads[port_no].m_port_setting = port_setting;

	return CELL_OK;
}
예제 #15
0
파일: cellPad.cpp 프로젝트: mpm11011/rpcs3
error_code cellPadClearBuf(u32 port_no)
{
	sys_io.trace("cellPadClearBuf(port_no=%d)", port_no);

	const auto handler = fxm::get<pad_thread>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	if (port_no >= CELL_MAX_PADS)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	const auto& pads = handler->GetPads();

	if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	const auto pad = pads[port_no];

	if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
		return CELL_PAD_ERROR_NO_DEVICE;

	// Set 'm_buffer_cleared' to force a resend of everything
	// might as well also reset everything in our pad 'buffer' to nothing as well

	pad->m_buffer_cleared = true;
	pad->m_analog_left_x = pad->m_analog_left_y = pad->m_analog_right_x = pad->m_analog_right_y = 128;

	pad->m_digital_1 = pad->m_digital_2 = 0;
	pad->m_press_right = pad->m_press_left = pad->m_press_up = pad->m_press_down = 0;
	pad->m_press_triangle = pad->m_press_circle = pad->m_press_cross = pad->m_press_square = 0;
	pad->m_press_L1 = pad->m_press_L2 = pad->m_press_R1 = pad->m_press_R2 = 0;

	// ~399 on sensor y is a level non moving controller
	pad->m_sensor_y = 399;
	pad->m_sensor_x = pad->m_sensor_z = pad->m_sensor_g = 512;

	return CELL_OK;
}
예제 #16
0
파일: cellPad.cpp 프로젝트: mpm11011/rpcs3
error_code cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info)
{
	sys_io.trace("cellPadPeriphGetInfo(info=*0x%x)", info);

	const auto handler = fxm::get<pad_thread>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	if (!info)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	const PadInfo& rinfo = handler->GetInfo();

	std::memset(info.get_ptr(), 0, sizeof(CellPadPeriphInfo));

	info->max_connect = rinfo.max_connect;
	info->now_connect = rinfo.now_connect;
	info->system_info = rinfo.system_info;

	const auto& pads = handler->GetPads();

	// TODO: Support other types of controllers
	for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; ++i)
	{
		if (i >= pads.size())
			break;

		info->port_status[i] = pads[i]->m_port_status;
		pads[i]->m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES;
		info->port_setting[i] = pads[i]->m_port_setting;
		info->device_capability[i] = pads[i]->m_device_capability;
		info->device_type[i] = pads[i]->m_device_type;
		info->pclass_type[i] = CELL_PAD_PCLASS_TYPE_STANDARD;
		info->pclass_profile[i] = 0x0;
	}

	return CELL_OK;
}
예제 #17
0
파일: cellPad.cpp 프로젝트: mob41/rpcs3
s32 cellPadGetCapabilityInfo(u32 port_no, vm::ptr<CellCapabilityInfo> info)
{
	sys_io.trace("cellPadGetCapabilityInfo(port_no=%d, data_addr:=0x%x)", port_no, info.addr());

	const auto handler = fxm::get<PadHandlerBase>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	const PadInfo& rinfo = handler->GetInfo();

	if (port_no >= rinfo.max_connect)
		return CELL_PAD_ERROR_INVALID_PARAMETER;
	if (port_no >= rinfo.now_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	const std::vector<Pad>& pads = handler->GetPads();

	//Should return the same as device capability mask, psl1ght has it backwards in pad.h
	info->info[0] = pads[port_no].m_device_capability;

	return CELL_OK;
}
예제 #18
0
파일: cellPad.cpp 프로젝트: mob41/rpcs3
s32 cellPadClearBuf(u32 port_no)
{
	sys_io.trace("cellPadClearBuf(port_no=%d)", port_no);

	const auto handler = fxm::get<PadHandlerBase>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	const PadInfo& rinfo = handler->GetInfo();

	if (port_no >= rinfo.max_connect)
		return CELL_PAD_ERROR_INVALID_PARAMETER;
	if (port_no >= rinfo.now_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	//Set 'm_buffer_cleared' to force a resend of everything
	//might as well also reset everything in our pad 'buffer' to nothing as well

	std::vector<Pad>& pads = handler->GetPads();
	Pad& pad = pads[port_no];

	pad.m_buffer_cleared = true;
	pad.m_analog_left_x = pad.m_analog_left_y = pad.m_analog_right_x = pad.m_analog_right_y = 128;

	pad.m_digital_1 = pad.m_digital_2 = 0;
	pad.m_press_right = pad.m_press_left = pad.m_press_up = pad.m_press_down = 0;
	pad.m_press_triangle = pad.m_press_circle = pad.m_press_cross = pad.m_press_square = 0;
	pad.m_press_L1 = pad.m_press_L2 = pad.m_press_R1 = pad.m_press_R2 = 0;

	//~399 on sensor y is a level non moving controller
	pad.m_sensor_y = 399;
	pad.m_sensor_x = pad.m_sensor_z = pad.m_sensor_g = 512;
	
	return CELL_OK;
}
예제 #19
0
파일: cellGem.cpp 프로젝트: mpm11011/rpcs3
/**
 * \brief Maps external Move controller data to DS3 input
 *	      Implementation detail: CellGemExtPortData's digital/analog fields map the same way as
 *	      libPad, so no translation is needed.
 * \param port_no DS3 port number to use
 * \param ext External data to modify
 * \return true on success, false if port_no controller is invalid
 */
static bool map_ext_to_ds3_input(const u32 port_no, CellGemExtPortData& ext)
{
	const auto handler = fxm::get<pad_thread>();

	if (!handler)
	{
		return false;
	}

	auto& pads = handler->GetPads();

	const PadInfo& rinfo = handler->GetInfo();

	if (port_no >= rinfo.max_connect)
	{
		return false;
	}

	//We have a choice here of NO_DEVICE or READ_FAILED...lets try no device for now
	if (port_no >= rinfo.now_connect)
	{
		return false;
	}

	auto pad = pads[port_no];

	ext.status = 0; // CELL_GEM_EXT_CONNECTED | CELL_GEM_EXT_EXT0 | CELL_GEM_EXT_EXT1
	ext.analog_left_x = pad->m_analog_left_x;
	ext.analog_left_y = pad->m_analog_left_y;
	ext.analog_right_x = pad->m_analog_right_x;
	ext.analog_right_y = pad->m_analog_right_y;
	ext.digital1 = pad->m_digital_1;
	ext.digital2 = pad->m_digital_2;

	return true;
}
예제 #20
0
파일: cellPad.cpp 프로젝트: mpm11011/rpcs3
s32 cellPadInfoSensorMode(u32 port_no)
{
	sys_io.trace("cellPadInfoSensorMode(port_no=%d)", port_no);

	const auto handler = fxm::get<pad_thread>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	if (port_no >= CELL_MAX_PADS)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	const auto& pads = handler->GetPads();

	if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	const auto pad = pads[port_no];

	if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
		return CELL_PAD_ERROR_NO_DEVICE;

	return (pad->m_device_capability & CELL_PAD_CAPABILITY_SENSOR_MODE) > 0;
}
예제 #21
0
파일: cellPad.cpp 프로젝트: mpm11011/rpcs3
error_code cellPadGetDataExtra(u32 port_no, vm::ptr<u32> device_type, vm::ptr<CellPadData> data)
{
	sys_io.trace("cellPadGetDataExtra(port_no=%d, device_type=*0x%x, data=*0x%x)", port_no, device_type, data);

	const auto handler = fxm::get<pad_thread>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	if (port_no >= CELL_MAX_PADS || !data)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	const auto& pads = handler->GetPads();

	if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	const auto pad = pads[port_no];

	if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
		return CELL_PAD_ERROR_NO_DEVICE;

	// TODO: This is used just to get data from a BD/CEC remote,
	// but if the port isnt a remote, device type is set to 0 and just regular cellPadGetData is returned

	if (device_type) // no error is returned on NULL
	{
		*device_type = 0;
	}

	// set BD data before just incase
	data->button[24] = 0x0;
	data->button[25] = 0x0;

	return cellPadGetData(port_no, data);
}
예제 #22
0
파일: cellGem.cpp 프로젝트: mpm11011/rpcs3
/**
 * \brief Maps Move controller data (digital buttons, and analog Trigger data) to DS3 pad input.
 *        Unavoidably buttons conflict with DS3 mappings, which is problematic for some games.
 * \param port_no DS3 port number to use
 * \param digital_buttons Bitmask filled with CELL_GEM_CTRL_* values
 * \param analog_t Analog value of Move's Trigger. Currently mapped to R2.
 * \return true on success, false if port_no controller is invalid
 */
static bool map_to_ds3_input(const u32 port_no, be_t<u16>& digital_buttons, be_t<u16>& analog_t)
{
	const auto handler = fxm::get<pad_thread>();

	if (!handler)
	{
		return false;
	}

	const PadInfo& rinfo = handler->GetInfo();

	if (port_no >= rinfo.max_connect || port_no >= rinfo.now_connect)
	{
		return false;
	}

	auto& pads = handler->GetPads();
	auto pad = pads[port_no];

	for (Button& button : pad->m_buttons)
	{
		//here we check btns, and set pad accordingly,
		if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2)
		{
			if (button.m_pressed) pad->m_digital_2 |= button.m_outKeyCode;
			else pad->m_digital_2 &= ~button.m_outKeyCode;

			switch (button.m_outKeyCode)
			{
			case CELL_PAD_CTRL_SQUARE:
				pad->m_press_square = button.m_value;
				break;
			case CELL_PAD_CTRL_CROSS:
				pad->m_press_cross = button.m_value;
				break;
			case CELL_PAD_CTRL_CIRCLE:
				pad->m_press_circle = button.m_value;
				break;
			case CELL_PAD_CTRL_TRIANGLE:
				pad->m_press_triangle = button.m_value;
				break;
			case CELL_PAD_CTRL_R1:
				pad->m_press_R1 = button.m_value;
				break;
			case CELL_PAD_CTRL_L1:
				pad->m_press_L1 = button.m_value;
				break;
			case CELL_PAD_CTRL_R2:
				pad->m_press_R2 = button.m_value;
				break;
			case CELL_PAD_CTRL_L2:
				pad->m_press_L2 = button.m_value;
				break;
			default: break;
			}
		}

		if (button.m_flush)
		{
			button.m_pressed = false;
			button.m_flush = false;
			button.m_value = 0;
		}
	}

	memset(&digital_buttons, 0, sizeof(digital_buttons));

	// map the Move key to R1 and the Trigger to R2

	if (pad->m_press_R1)
		digital_buttons |= CELL_GEM_CTRL_MOVE;
	if (pad->m_press_R2)
		digital_buttons |= CELL_GEM_CTRL_T;

	if (pad->m_press_cross)
		digital_buttons |= CELL_GEM_CTRL_CROSS;
	if (pad->m_press_circle)
		digital_buttons |= CELL_GEM_CTRL_CIRCLE;
	if (pad->m_press_square)
		digital_buttons |= CELL_GEM_CTRL_SQUARE;
	if (pad->m_press_triangle)
		digital_buttons |= CELL_GEM_CTRL_TRIANGLE;
	if (pad->m_digital_1)
		digital_buttons |= CELL_GEM_CTRL_SELECT;
	if (pad->m_digital_2)
		digital_buttons |= CELL_GEM_CTRL_START;

	analog_t = pad->m_press_R2;

	return true;
}
예제 #23
0
파일: cellPad.cpp 프로젝트: mpm11011/rpcs3
error_code cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
{
	sys_io.trace("cellPadGetData(port_no=%d, data=*0x%x)", port_no, data);

	const auto handler = fxm::get<pad_thread>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	if (port_no >= CELL_MAX_PADS || !data)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	const auto& pads = handler->GetPads();

	if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	const auto pad = pads[port_no];

	if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
		return CELL_PAD_ERROR_NO_DEVICE;

	u16 d1Initial, d2Initial;
	d1Initial = pad->m_digital_1;
	d2Initial = pad->m_digital_2;
	bool btnChanged = false;

	for (Button& button : pad->m_buttons)
	{
		// here we check btns, and set pad accordingly,
		// if something changed, set btnChanged

		if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1)
		{
			if (button.m_pressed) pad->m_digital_1 |= button.m_outKeyCode;
			else pad->m_digital_1 &= ~button.m_outKeyCode;

			switch (button.m_outKeyCode)
			{
			case CELL_PAD_CTRL_LEFT:
				if (pad->m_press_left != button.m_value) btnChanged = true;
				pad->m_press_left = button.m_value;
				break;
			case CELL_PAD_CTRL_DOWN:
				if (pad->m_press_down != button.m_value) btnChanged = true;
				pad->m_press_down = button.m_value;
				break;
			case CELL_PAD_CTRL_RIGHT:
				if (pad->m_press_right != button.m_value) btnChanged = true;
				pad->m_press_right = button.m_value;
				break;
			case CELL_PAD_CTRL_UP:
				if (pad->m_press_up != button.m_value) btnChanged = true;
				pad->m_press_up = button.m_value;
				break;
			// These arent pressure btns
			case CELL_PAD_CTRL_R3:
			case CELL_PAD_CTRL_L3:
			case CELL_PAD_CTRL_START:
			case CELL_PAD_CTRL_SELECT:
			default: break;
			}
		}
		else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2)
		{
			if (button.m_pressed) pad->m_digital_2 |= button.m_outKeyCode;
			else pad->m_digital_2 &= ~button.m_outKeyCode;

			switch (button.m_outKeyCode)
			{
			case CELL_PAD_CTRL_SQUARE:
				if (pad->m_press_square != button.m_value) btnChanged = true;
				pad->m_press_square = button.m_value;
				break;
			case CELL_PAD_CTRL_CROSS:
				if (pad->m_press_cross != button.m_value) btnChanged = true;
				pad->m_press_cross = button.m_value;
				break;
			case CELL_PAD_CTRL_CIRCLE:
				if (pad->m_press_circle != button.m_value) btnChanged = true;
				pad->m_press_circle = button.m_value;
				break;
			case CELL_PAD_CTRL_TRIANGLE:
				if (pad->m_press_triangle != button.m_value) btnChanged = true;
				pad->m_press_triangle = button.m_value;
				break;
			case CELL_PAD_CTRL_R1:
				if (pad->m_press_R1 != button.m_value) btnChanged = true;
				pad->m_press_R1 = button.m_value;
				break;
			case CELL_PAD_CTRL_L1:
				if (pad->m_press_L1 != button.m_value) btnChanged = true;
				pad->m_press_L1 = button.m_value;
				break;
			case CELL_PAD_CTRL_R2:
				if (pad->m_press_R2 != button.m_value) btnChanged = true;
				pad->m_press_R2 = button.m_value;
				break;
			case CELL_PAD_CTRL_L2:
				if (pad->m_press_L2 != button.m_value) btnChanged = true;
				pad->m_press_L2 = button.m_value;
				break;
			default: break;
			}
		}

		if (button.m_flush)
		{
			button.m_pressed = false;
			button.m_flush = false;
			button.m_value = 0;
		}
	}

	for (const AnalogStick& stick : pad->m_sticks)
	{
		switch (stick.m_offset)
		{
		case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X:
			if (pad->m_analog_left_x != stick.m_value) btnChanged = true;
			pad->m_analog_left_x = stick.m_value;
			break;
		case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y:
			if (pad->m_analog_left_y != stick.m_value) btnChanged = true;
			pad->m_analog_left_y = stick.m_value;
			break;
		case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X:
			if (pad->m_analog_right_x != stick.m_value) btnChanged = true;
			pad->m_analog_right_x = stick.m_value;
			break;
		case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y:
			if (pad->m_analog_right_y != stick.m_value) btnChanged = true;
			pad->m_analog_right_y = stick.m_value;
			break;
		default: break;
		}
	}

	for (const AnalogSensor& sensor : pad->m_sensors)
	{
		switch (sensor.m_offset)
		{
		case CELL_PAD_BTN_OFFSET_SENSOR_X:
			if (pad->m_sensor_x != sensor.m_value) btnChanged = true;
			pad->m_sensor_x = sensor.m_value;
			break;
		case CELL_PAD_BTN_OFFSET_SENSOR_Y:
			if (pad->m_sensor_y != sensor.m_value) btnChanged = true;
			pad->m_sensor_y = sensor.m_value;
			break;
		case CELL_PAD_BTN_OFFSET_SENSOR_Z:
			if (pad->m_sensor_z != sensor.m_value) btnChanged = true;
			pad->m_sensor_z = sensor.m_value;
			break;
		case CELL_PAD_BTN_OFFSET_SENSOR_G:
			if (pad->m_sensor_g != sensor.m_value) btnChanged = true;
			pad->m_sensor_g = sensor.m_value;
			break;
		default: break;
		}
	}

	if (d1Initial != pad->m_digital_1 || d2Initial != pad->m_digital_2)
	{
		btnChanged = true;
	}

	// the real hardware only fills the buffer up to "len" elements (16 bit each)
	if (pad->m_port_setting & CELL_PAD_SETTING_SENSOR_ON)
	{
		// report back new data every ~10 ms even if the input doesn't change
		// this is observed behaviour when using a Dualshock 3 controller
		static std::chrono::time_point<steady_clock> last_update[CELL_PAD_MAX_PORT_NUM] = { };
		const std::chrono::time_point<steady_clock> now = steady_clock::now();

		if (btnChanged || pad->m_buffer_cleared || (std::chrono::duration_cast<std::chrono::milliseconds>(now - last_update[port_no]).count() >= 10))
		{
			data->len = CELL_PAD_LEN_CHANGE_SENSOR_ON;
			last_update[port_no] = now;
		}
		else
		{
			data->len = CELL_PAD_LEN_NO_CHANGE;
		}
	}
	else if (btnChanged || pad->m_buffer_cleared)
	{
		// only give back valid data if a controller state changed
		data->len = (pad->m_port_setting & CELL_PAD_SETTING_PRESS_ON) ? CELL_PAD_LEN_CHANGE_PRESS_ON : CELL_PAD_LEN_CHANGE_DEFAULT;
	}
	else
	{
		// report no state changes
		data->len = CELL_PAD_LEN_NO_CHANGE;
	}

	pad->m_buffer_cleared = false;

	// only update parts of the output struct depending on the controller setting
	if (data->len > CELL_PAD_LEN_NO_CHANGE)
	{
		memset(data->button, 0, sizeof(data->button));

		data->button[0] = 0x0; // always 0
		// bits 15-8 reserved, 7-4 = 0x7, 3-0: data->len/2;
		data->button[1] = (0x7 << 4) | std::min(data->len / 2, 15);

		data->button[CELL_PAD_BTN_OFFSET_DIGITAL1] = pad->m_digital_1;
		data->button[CELL_PAD_BTN_OFFSET_DIGITAL2] = pad->m_digital_2;
		data->button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X] = pad->m_analog_right_x;
		data->button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y] = pad->m_analog_right_y;
		data->button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X] = pad->m_analog_left_x;
		data->button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y] = pad->m_analog_left_y;
		data->button[CELL_PAD_BTN_OFFSET_PRESS_RIGHT] = pad->m_press_right;
		data->button[CELL_PAD_BTN_OFFSET_PRESS_LEFT] = pad->m_press_left;
		data->button[CELL_PAD_BTN_OFFSET_PRESS_UP] = pad->m_press_up;
		data->button[CELL_PAD_BTN_OFFSET_PRESS_DOWN] = pad->m_press_down;
	}

	if (data->len >= CELL_PAD_LEN_CHANGE_PRESS_ON)
	{
		data->button[CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE] = pad->m_press_triangle;
		data->button[CELL_PAD_BTN_OFFSET_PRESS_CIRCLE] = pad->m_press_circle;
		data->button[CELL_PAD_BTN_OFFSET_PRESS_CROSS] = pad->m_press_cross;
		data->button[CELL_PAD_BTN_OFFSET_PRESS_SQUARE] = pad->m_press_square;
		data->button[CELL_PAD_BTN_OFFSET_PRESS_L1] = pad->m_press_L1;
		data->button[CELL_PAD_BTN_OFFSET_PRESS_L2] = pad->m_press_L2;
		data->button[CELL_PAD_BTN_OFFSET_PRESS_R1] = pad->m_press_R1;
		data->button[CELL_PAD_BTN_OFFSET_PRESS_R2] = pad->m_press_R2;
	}

	if (data->len == CELL_PAD_LEN_CHANGE_SENSOR_ON)
	{
		data->button[CELL_PAD_BTN_OFFSET_SENSOR_X] = pad->m_sensor_x;
		data->button[CELL_PAD_BTN_OFFSET_SENSOR_Y] = pad->m_sensor_y;
		data->button[CELL_PAD_BTN_OFFSET_SENSOR_Z] = pad->m_sensor_z;
		data->button[CELL_PAD_BTN_OFFSET_SENSOR_G] = pad->m_sensor_g;
	}

	return CELL_OK;
}
예제 #24
0
파일: overlays.cpp 프로젝트: AniLeo/rpcs3
		s32 user_interface::run_input_loop()
		{
			std::array<std::chrono::steady_clock::time_point, CELL_PAD_MAX_PORT_NUM> timestamp;
			timestamp.fill(std::chrono::steady_clock::now());

			std::array<std::array<bool, pad_button::pad_button_max_enum>, CELL_PAD_MAX_PORT_NUM> button_state;
			for (auto& state : button_state)
			{
				state.fill(true);
			}

			input_timer.Start();

			pad::SetIntercepted(true);

			while (!exit)
			{
				if (Emu.IsStopped())
					return selection_code::canceled;

				std::this_thread::sleep_for(1ms);

				std::lock_guard lock(pad::g_pad_mutex);

				const auto handler = pad::get_current_handler();

				const PadInfo& rinfo = handler->GetInfo();

				if (Emu.IsPaused() || !rinfo.now_connect)
				{
					continue;
				}

				int pad_index = -1;
				for (const auto &pad : handler->GetPads())
				{
					if (++pad_index >= CELL_PAD_MAX_PORT_NUM)
					{
						LOG_FATAL(RSX, "The native overlay cannot handle more than 7 pads! Current number of pads: %d", pad_index + 1);
						continue;
					}

					for (auto &button : pad->m_buttons)
					{
						u8 button_id = 255;
						if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1)
						{
							switch (button.m_outKeyCode)
							{
							case CELL_PAD_CTRL_LEFT:
								button_id = pad_button::dpad_left;
								break;
							case CELL_PAD_CTRL_RIGHT:
								button_id = pad_button::dpad_right;
								break;
							case CELL_PAD_CTRL_DOWN:
								button_id = pad_button::dpad_down;
								break;
							case CELL_PAD_CTRL_UP:
								button_id = pad_button::dpad_up;
								break;
							case CELL_PAD_CTRL_SELECT:
								button_id = pad_button::select;
								break;
							case CELL_PAD_CTRL_START:
								button_id = pad_button::start;
								break;
							}
						}
						else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2)
						{
							switch (button.m_outKeyCode)
							{
							case CELL_PAD_CTRL_TRIANGLE:
								button_id = pad_button::triangle;
								break;
							case CELL_PAD_CTRL_CIRCLE:
								button_id = g_cfg.sys.enter_button_assignment == enter_button_assign::circle ? pad_button::cross : pad_button::circle;
								break;
							case CELL_PAD_CTRL_SQUARE:
								button_id = pad_button::square;
								break;
							case CELL_PAD_CTRL_CROSS:
								button_id = g_cfg.sys.enter_button_assignment == enter_button_assign::circle ? pad_button::circle : pad_button::cross;
								break;
							case CELL_PAD_CTRL_L1:
								button_id = pad_button::L1;
								break;
							case CELL_PAD_CTRL_R1:
								button_id = pad_button::R1;
								break;
							}
						}

						if (button_id < 255)
						{
							if (button.m_pressed)
							{
								if (button_id < 4) // d-pad button
								{
									if (!button_state[pad_index][button_id] || input_timer.GetMsSince(timestamp[pad_index]) > 400)
									{
										// d-pad button was not pressed, or was pressed more than 400ms ago
										timestamp[pad_index] = std::chrono::steady_clock::now();
										on_button_pressed(static_cast<pad_button>(button_id));
									}
								}
								else if (!button_state[pad_index][button_id])
								{
									// button was not pressed
									on_button_pressed(static_cast<pad_button>(button_id));
								}
							}

							button_state[pad_index][button_id] = button.m_pressed;
						}

						if (button.m_flush)
						{
							button.m_pressed = false;
							button.m_flush = false;
							button.m_value = 0;
						}

						if (exit)
							return 0;
					}
				}

				refresh();
			}

			// Unreachable
			return 0;
		}
예제 #25
0
파일: cellPad.cpp 프로젝트: mob41/rpcs3
s32 cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
{
	sys_io.trace("cellPadGetData(port_no=%d, data=*0x%x)", port_no, data);

	const auto handler = fxm::get<PadHandlerBase>();

	if (!handler)
		return CELL_PAD_ERROR_UNINITIALIZED;

	std::vector<Pad>& pads = handler->GetPads();

	const PadInfo& rinfo = handler->GetInfo();

	if (port_no >= rinfo.max_connect)
		return CELL_PAD_ERROR_INVALID_PARAMETER;

	//We have a choice here of NO_DEVICE or READ_FAILED...lets try no device for now
	if (port_no >= rinfo.now_connect)
		return CELL_PAD_ERROR_NO_DEVICE;

	Pad& pad = pads[port_no];

	u16 d1Initial, d2Initial; 
	d1Initial = pad.m_digital_1;
	d2Initial = pad.m_digital_2;
	bool btnChanged = false;
	for(Button& button : pad.m_buttons)
	{
		//here we check btns, and set pad accordingly, 
		//if something changed, set btnChanged

		if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1)
		{
			if (button.m_pressed) pad.m_digital_1 |= button.m_outKeyCode;
			else pad.m_digital_1 &= ~button.m_outKeyCode;

			switch (button.m_outKeyCode)
			{
			case CELL_PAD_CTRL_LEFT: 
				if (pad.m_press_left != button.m_value) btnChanged = true;
				pad.m_press_left = button.m_value;
				break;
			case CELL_PAD_CTRL_DOWN: 
				if (pad.m_press_down != button.m_value) btnChanged = true;
				pad.m_press_down = button.m_value; 
				break;
			case CELL_PAD_CTRL_RIGHT: 
				if (pad.m_press_right != button.m_value) btnChanged = true;
				pad.m_press_right = button.m_value; 
				break;
			case CELL_PAD_CTRL_UP: 
				if (pad.m_press_up != button.m_value) btnChanged = true;
				pad.m_press_up = button.m_value; 
				break;
			//These arent pressure btns
			case CELL_PAD_CTRL_R3:
			case CELL_PAD_CTRL_L3:
			case CELL_PAD_CTRL_START:
			case CELL_PAD_CTRL_SELECT:
			default: break;
			}
		}
		else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2)
		{
			if (button.m_pressed) pad.m_digital_2 |= button.m_outKeyCode;
			else pad.m_digital_2 &= ~button.m_outKeyCode;

			switch (button.m_outKeyCode)
			{
			case CELL_PAD_CTRL_SQUARE:
				if (pad.m_press_square != button.m_value) btnChanged = true;
				pad.m_press_square = button.m_value;
				break;
			case CELL_PAD_CTRL_CROSS:
				if (pad.m_press_cross != button.m_value) btnChanged = true;
				pad.m_press_cross = button.m_value; 
				break;
			case CELL_PAD_CTRL_CIRCLE: 
				if (pad.m_press_circle != button.m_value) btnChanged = true;
				pad.m_press_circle = button.m_value;
				break;
			case CELL_PAD_CTRL_TRIANGLE:
				if (pad.m_press_triangle != button.m_value) btnChanged = true;
				pad.m_press_triangle = button.m_value;
				break;
			case CELL_PAD_CTRL_R1: 
				if (pad.m_press_R1 != button.m_value) btnChanged = true;
				pad.m_press_R1 = button.m_value; 
				break;
			case CELL_PAD_CTRL_L1: 
				if (pad.m_press_L1 != button.m_value) btnChanged = true;
				pad.m_press_L1 = button.m_value; 
				break;
			case CELL_PAD_CTRL_R2: 
				if (pad.m_press_R2 != button.m_value) btnChanged = true;
				pad.m_press_R2 = button.m_value; 
				break;
			case CELL_PAD_CTRL_L2: 
				if (pad.m_press_L2 != button.m_value) btnChanged = true;
				pad.m_press_L2 = button.m_value; 
				break;
			default: break;
			}
		}

		if(button.m_flush)
		{
			button.m_pressed = false;
			button.m_flush = false;
			button.m_value = 0;
		}
	}

	for (const AnalogStick& stick : pad.m_sticks)
	{
		switch (stick.m_offset)
		{
		case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X: 
			if (pad.m_analog_left_x != stick.m_value) btnChanged = true;
			pad.m_analog_left_x = stick.m_value; 
			break;
		case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y: 
			if (pad.m_analog_left_y != stick.m_value) btnChanged = true;
			pad.m_analog_left_y = stick.m_value; 
			break;
		case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X: 
			if (pad.m_analog_right_x != stick.m_value) btnChanged = true;
			pad.m_analog_right_x = stick.m_value; 
			break;
		case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y: 
			if (pad.m_analog_right_y != stick.m_value) btnChanged = true;
			pad.m_analog_right_y = stick.m_value; 
			break;
		default: break;
		}
	}

	for (const AnalogSensor& sensor : pad.m_sensors)
	{
		switch (sensor.m_offset)
		{
		case CELL_PAD_BTN_OFFSET_SENSOR_X:
			if (pad.m_sensor_x != sensor.m_value) btnChanged = true;
			pad.m_sensor_x = sensor.m_value;
			break;
		case CELL_PAD_BTN_OFFSET_SENSOR_Y:
			if (pad.m_sensor_y != sensor.m_value) btnChanged = true;
			pad.m_sensor_y = sensor.m_value;
			break;
		case CELL_PAD_BTN_OFFSET_SENSOR_Z:
			if (pad.m_sensor_z != sensor.m_value) btnChanged = true;
			pad.m_sensor_z = sensor.m_value;
			break;
		case CELL_PAD_BTN_OFFSET_SENSOR_G:
			if (pad.m_sensor_g != sensor.m_value) btnChanged = true;
			pad.m_sensor_g = sensor.m_value;
			break;
		default: break;
		}
	}

	if (d1Initial != pad.m_digital_1 || d2Initial != pad.m_digital_2)
	{
		btnChanged = true;
	}

	//not sure if this should officially change with capabilities/portsettings :(
	data->len = 24;

	if (pad.m_buffer_cleared)
	{
		pad.m_buffer_cleared = false;
	}
	else if (!btnChanged)
	{
		data->len = 0;
	}
	data->button[0] = 0x0; // always 0
	// bits 15-8 reserved, 7-4 = 0x7, 3-0: data->len/2;
	data->button[1] = (0x7 << 4) | std::min(data->len / 2, 15) & 0xF;
	//lets still send new data anyway, not sure whats expected still
	data->button[CELL_PAD_BTN_OFFSET_DIGITAL1]       = pad.m_digital_1;
	data->button[CELL_PAD_BTN_OFFSET_DIGITAL2]       = pad.m_digital_2;
	data->button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X] = pad.m_analog_right_x;
	data->button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y] = pad.m_analog_right_y;
	data->button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X]  = pad.m_analog_left_x;
	data->button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y]  = pad.m_analog_left_y;
	data->button[CELL_PAD_BTN_OFFSET_PRESS_RIGHT]    = pad.m_press_right;
	data->button[CELL_PAD_BTN_OFFSET_PRESS_LEFT]     = pad.m_press_left;
	data->button[CELL_PAD_BTN_OFFSET_PRESS_UP]       = pad.m_press_up;
	data->button[CELL_PAD_BTN_OFFSET_PRESS_DOWN]     = pad.m_press_down;
	data->button[CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE] = pad.m_press_triangle;
	data->button[CELL_PAD_BTN_OFFSET_PRESS_CIRCLE]   = pad.m_press_circle;
	data->button[CELL_PAD_BTN_OFFSET_PRESS_CROSS]    = pad.m_press_cross;
	data->button[CELL_PAD_BTN_OFFSET_PRESS_SQUARE]   = pad.m_press_square;
	data->button[CELL_PAD_BTN_OFFSET_PRESS_L1]       = pad.m_press_L1;
	data->button[CELL_PAD_BTN_OFFSET_PRESS_L2]       = pad.m_press_L2;
	data->button[CELL_PAD_BTN_OFFSET_PRESS_R1]       = pad.m_press_R1;
	data->button[CELL_PAD_BTN_OFFSET_PRESS_R2]       = pad.m_press_R2;
	data->button[CELL_PAD_BTN_OFFSET_SENSOR_X]       = pad.m_sensor_x;
	data->button[CELL_PAD_BTN_OFFSET_SENSOR_Y]       = pad.m_sensor_y;
	data->button[CELL_PAD_BTN_OFFSET_SENSOR_Z]       = pad.m_sensor_z;
	data->button[CELL_PAD_BTN_OFFSET_SENSOR_G]       = pad.m_sensor_g;

	return CELL_OK;
}