mirror of https://github.com/RPCS3/rpcs3.git
cellpad: add pclass_profile flags
This commit is contained in:
parent
4e6d95c5b8
commit
e4cb9ef7cd
|
@ -434,7 +434,6 @@ error_code cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> 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 >= config->max_connect)
|
||||
|
@ -446,7 +445,7 @@ error_code cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info)
|
|||
info->device_capability[i] = pads[i]->m_device_capability;
|
||||
info->device_type[i] = pads[i]->m_device_type;
|
||||
info->pclass_type[i] = pads[i]->m_class_type;
|
||||
info->pclass_profile[i] = 0x0;
|
||||
info->pclass_profile[i] = pads[i]->m_class_profile;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
|
@ -479,10 +478,10 @@ error_code cellPadPeriphGetData(u32 port_no, vm::ptr<CellPadPeriphData> data)
|
|||
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 = pad->m_class_type;
|
||||
data->pclass_profile = 0x0;
|
||||
data->pclass_profile = pad->m_class_profile;
|
||||
|
||||
// TODO: support for 'unique' controllers, which goes in offsets 24+ in padData (CELL_PAD_PCLASS_BTN_OFFSET)
|
||||
return cellPadGetData(port_no, data.ptr(&CellPadPeriphData::cellpad_data));
|
||||
}
|
||||
|
||||
|
@ -934,6 +933,7 @@ error_code cellPadLddRegisterController()
|
|||
CELL_PAD_CAPABILITY_PS3_CONFORMITY,
|
||||
CELL_PAD_DEV_TYPE_LDD,
|
||||
CELL_PAD_PCLASS_TYPE_STANDARD,
|
||||
product.pclass_profile,
|
||||
product.vendor_id,
|
||||
product.product_id
|
||||
);
|
||||
|
|
|
@ -34,6 +34,81 @@ enum
|
|||
CELL_PAD_PCLASS_TYPE_NAVIGATION = 0x05,
|
||||
};
|
||||
|
||||
// Profile of a Standard Type Controller
|
||||
// Profile of a Navigation Type Controller
|
||||
// Bits 0 – 31 All 0s
|
||||
|
||||
// Profile of a Guitar Type Controller
|
||||
enum
|
||||
{
|
||||
// Basic
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_FRET_1 = 0x00000001,
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_FRET_2 = 0x00000002,
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_FRET_3 = 0x00000004,
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_FRET_4 = 0x00000008,
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_FRET_5 = 0x00000010,
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_STRUM_UP = 0x00000020,
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_STRUM_DOWN = 0x00000040,
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_WHAMMYBAR = 0x00000080,
|
||||
// All Basic = 0x000000FF
|
||||
|
||||
// Optional
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_FRET_H1 = 0x00000100,
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_FRET_H2 = 0x00000200,
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_FRET_H3 = 0x00000400,
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_FRET_H4 = 0x00000800,
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_FRET_H5 = 0x00001000,
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_5WAY_EFFECT = 0x00002000,
|
||||
CELL_PAD_PCLASS_PROFILE_GUITAR_TILT_SENS = 0x00004000,
|
||||
// All = 0x00007FFF
|
||||
};
|
||||
|
||||
// Profile of a Drum Type Controller
|
||||
enum
|
||||
{
|
||||
CELL_PAD_PCLASS_PROFILE_DRUM_SNARE = 0x00000001,
|
||||
CELL_PAD_PCLASS_PROFILE_DRUM_TOM = 0x00000002,
|
||||
CELL_PAD_PCLASS_PROFILE_DRUM_TOM2 = 0x00000004,
|
||||
CELL_PAD_PCLASS_PROFILE_DRUM_TOM_FLOOR = 0x00000008,
|
||||
CELL_PAD_PCLASS_PROFILE_DRUM_KICK = 0x00000010,
|
||||
CELL_PAD_PCLASS_PROFILE_DRUM_CYM_HiHAT = 0x00000020,
|
||||
CELL_PAD_PCLASS_PROFILE_DRUM_CYM_CRASH = 0x00000040,
|
||||
CELL_PAD_PCLASS_PROFILE_DRUM_CYM_RIDE = 0x00000080,
|
||||
CELL_PAD_PCLASS_PROFILE_DRUM_KICK2 = 0x00000100,
|
||||
// All = 0x000001FF
|
||||
};
|
||||
|
||||
// Profile of a DJ Deck Type Controller
|
||||
enum
|
||||
{
|
||||
CELL_PAD_PCLASS_PROFILE_DJ_MIXER_ATTACK = 0x00000001,
|
||||
CELL_PAD_PCLASS_PROFILE_DJ_MIXER_CROSSFADER = 0x00000002,
|
||||
CELL_PAD_PCLASS_PROFILE_DJ_MIXER_DSP_DIAL = 0x00000004,
|
||||
CELL_PAD_PCLASS_PROFILE_DJ_DECK1_STREAM1 = 0x00000008,
|
||||
CELL_PAD_PCLASS_PROFILE_DJ_DECK1_STREAM2 = 0x00000010,
|
||||
CELL_PAD_PCLASS_PROFILE_DJ_DECK1_STREAM3 = 0x00000020,
|
||||
CELL_PAD_PCLASS_PROFILE_DJ_DECK1_PLATTER = 0x00000040,
|
||||
CELL_PAD_PCLASS_PROFILE_DJ_DECK2_STREAM1 = 0x00000080,
|
||||
CELL_PAD_PCLASS_PROFILE_DJ_DECK2_STREAM2 = 0x00000100,
|
||||
CELL_PAD_PCLASS_PROFILE_DJ_DECK2_STREAM3 = 0x00000200,
|
||||
CELL_PAD_PCLASS_PROFILE_DJ_DECK2_PLATTER = 0x00000400,
|
||||
// All = 0x000007FF
|
||||
};
|
||||
|
||||
// Profile of a Dance Mat Type Controller
|
||||
enum
|
||||
{
|
||||
CELL_PAD_PCLASS_PROFILE_DANCEMAT_CIRCLE = 0x00000001,
|
||||
CELL_PAD_PCLASS_PROFILE_DANCEMAT_CROSS = 0x00000002,
|
||||
CELL_PAD_PCLASS_PROFILE_DANCEMAT_TRIANGLE = 0x00000004,
|
||||
CELL_PAD_PCLASS_PROFILE_DANCEMAT_SQUARE = 0x00000008,
|
||||
CELL_PAD_PCLASS_PROFILE_DANCEMAT_RIGHT = 0x00000010,
|
||||
CELL_PAD_PCLASS_PROFILE_DANCEMAT_LEFT = 0x00000020,
|
||||
CELL_PAD_PCLASS_PROFILE_DANCEMAT_UP = 0x00000040,
|
||||
CELL_PAD_PCLASS_PROFILE_DANCEMAT_DOWN = 0x00000080,
|
||||
// All = 0x000000FF
|
||||
};
|
||||
|
||||
// Length returned in CellPadData struct
|
||||
enum
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "PadHandler.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Input/pad_thread.h"
|
||||
#include "Input/product_info.h"
|
||||
|
||||
cfg_input g_cfg_input;
|
||||
|
||||
|
@ -429,12 +430,23 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr<Pad> pad, const std::string
|
|||
|
||||
std::array<u32, button::button_count> mapping = get_mapped_key_codes(pad_device, profile);
|
||||
|
||||
u32 pclass_profile = 0x0;
|
||||
|
||||
for (const auto product : input::get_products_by_class(profile->device_class_type))
|
||||
{
|
||||
if (product.vendor_id == profile->vendor_id && product.product_id == profile->product_id)
|
||||
{
|
||||
pclass_profile = product.pclass_profile;
|
||||
}
|
||||
}
|
||||
|
||||
pad->Init
|
||||
(
|
||||
CELL_PAD_STATUS_DISCONNECTED,
|
||||
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE,
|
||||
CELL_PAD_DEV_TYPE_STANDARD,
|
||||
profile->device_class_type,
|
||||
pclass_profile,
|
||||
profile->vendor_id,
|
||||
profile->product_id
|
||||
);
|
||||
|
|
|
@ -88,6 +88,68 @@ enum ButtonDataOffset
|
|||
CELL_PAD_BTN_OFFSET_SENSOR_G = 23,
|
||||
};
|
||||
|
||||
enum CellPadPeriphGuitarBtnDataOffset
|
||||
{
|
||||
// Basic
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_FRET_1 = 24,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_FRET_2 = 25,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_FRET_3 = 26,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_FRET_4 = 27,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_FRET_5 = 28,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_STRUM_UP = 29,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_STRUM_DOWN = 30,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_WHAMMYBAR = 31, // 128-255
|
||||
|
||||
// Optional
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_FRET_H1 = 32, // ROCKBAND Stratocaster
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_FRET_H2 = 33,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_FRET_H3 = 34,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_FRET_H4 = 35,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_FRET_H5 = 36,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_5WAY_EFFECT = 37,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_GUITAR_TILT_SENS = 38,
|
||||
};
|
||||
|
||||
enum CellPadPeriphDrumBtnDataOffset
|
||||
{
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DRUM_SNARE = 24,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DRUM_TOM = 25,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DRUM_TOM2 = 26,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DRUM_TOM_FLOOR = 27,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DRUM_KICK = 28,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DRUM_CYM_HiHAT = 29,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DRUM_CYM_CRASH = 30,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DRUM_CYM_RIDE = 31,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DRUM_KICK2 = 32,
|
||||
};
|
||||
|
||||
enum CellPadPeriphDJBtnDataOffset
|
||||
{
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DJ_MIXER_ATTACK = 24,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DJ_MIXER_CROSSFADER = 25,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DJ_MIXER_DSP_DIAL = 26,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DJ_DECK1_STREAM1 = 27,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DJ_DECK1_STREAM2 = 28,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DJ_DECK1_STREAM3 = 29,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DJ_DECK1_PLATTER = 30,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DJ_DECK2_STREAM1 = 31,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DJ_DECK2_STREAM2 = 32,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DJ_DECK2_STREAM3 = 33,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DJ_DECK2_PLATTER = 34,
|
||||
};
|
||||
|
||||
enum CellPadPeriphDanceMatBtnDataOffset
|
||||
{
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DANCEMAT_CIRCLE = 24,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DANCEMAT_CROSS = 25,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DANCEMAT_TRIANGLE = 26,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DANCEMAT_SQUARE = 27,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DANCEMAT_RIGHT = 28,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DANCEMAT_LEFT = 29,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DANCEMAT_UP = 30,
|
||||
CELL_PAD_PCLASS_BTN_OFFSET_DANCEMAT_DOWN = 31,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_PAD_ACTUATOR_MAX = 2,
|
||||
|
@ -180,6 +242,7 @@ struct Pad
|
|||
u32 m_device_capability;
|
||||
u32 m_device_type;
|
||||
u32 m_class_type;
|
||||
u32 m_class_profile;
|
||||
|
||||
u16 m_vendor_id;
|
||||
u16 m_product_id;
|
||||
|
@ -229,12 +292,13 @@ struct Pad
|
|||
bool ldd = false;
|
||||
u8 ldd_data[132] = {};
|
||||
|
||||
void Init(u32 port_status, u32 device_capability, u32 device_type, u32 class_type, u16 vendor_id, u16 product_id)
|
||||
void Init(u32 port_status, u32 device_capability, u32 device_type, u32 class_type, u32 class_profile, u16 vendor_id, u16 product_id)
|
||||
{
|
||||
m_port_status = port_status;
|
||||
m_device_capability = device_capability;
|
||||
m_device_type = device_type;
|
||||
m_class_type = class_type;
|
||||
m_class_profile = class_profile;
|
||||
m_vendor_id = vendor_id;
|
||||
m_product_id = product_id;
|
||||
}
|
||||
|
@ -245,6 +309,7 @@ struct Pad
|
|||
, m_device_capability(device_capability)
|
||||
, m_device_type(device_type)
|
||||
, m_class_type(0)
|
||||
, m_class_profile(0)
|
||||
, m_vendor_id(0)
|
||||
, m_product_id(0)
|
||||
, m_cable_state(0)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#ifdef HAVE_LIBEVDEV
|
||||
|
||||
#include "Input/product_info.h"
|
||||
#include "Emu/Io/pad_config.h"
|
||||
#include "evdev_joystick_handler.h"
|
||||
#include "util/logs.hpp"
|
||||
|
@ -922,12 +923,23 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std
|
|||
return button;
|
||||
};
|
||||
|
||||
u32 pclass_profile = 0x0;
|
||||
|
||||
for (const auto product : input::get_products_by_class(p_profile->device_class_type))
|
||||
{
|
||||
if (product.vendor_id == p_profile->vendor_id && product.product_id == p_profile->product_id)
|
||||
{
|
||||
pclass_profile = product.pclass_profile;
|
||||
}
|
||||
}
|
||||
|
||||
pad->Init
|
||||
(
|
||||
CELL_PAD_STATUS_DISCONNECTED,
|
||||
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE,
|
||||
CELL_PAD_DEV_TYPE_STANDARD,
|
||||
p_profile->device_class_type,
|
||||
pclass_profile,
|
||||
p_profile->vendor_id,
|
||||
p_profile->product_id
|
||||
);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "keyboard_pad_handler.h"
|
||||
#include "Emu/Io/pad_config.h"
|
||||
#include "Input/product_info.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
|
@ -606,13 +607,24 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::
|
|||
return key;
|
||||
};
|
||||
|
||||
//Fixed assign change, default is both sensor and press off
|
||||
u32 pclass_profile = 0x0;
|
||||
|
||||
for (const auto product : input::get_products_by_class(p_profile->device_class_type))
|
||||
{
|
||||
if (product.vendor_id == p_profile->vendor_id && product.product_id == p_profile->product_id)
|
||||
{
|
||||
pclass_profile = product.pclass_profile;
|
||||
}
|
||||
}
|
||||
|
||||
// Fixed assign change, default is both sensor and press off
|
||||
pad->Init
|
||||
(
|
||||
CELL_PAD_STATUS_DISCONNECTED,
|
||||
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE,
|
||||
CELL_PAD_DEV_TYPE_STANDARD,
|
||||
p_profile->device_class_type,
|
||||
pclass_profile,
|
||||
p_profile->vendor_id,
|
||||
p_profile->product_id
|
||||
);
|
||||
|
|
|
@ -24,12 +24,12 @@ namespace input
|
|||
|
||||
enum product_id
|
||||
{
|
||||
red_octane_gh_guitar = 0x0100, // RedOctane Guitar (Guitar Hero)
|
||||
red_octane_gh_drum_kit = 0x0120, // RedOctane Drum Kit (Guitar Hero)
|
||||
dance_dance_revolution_mat = 0x0140, // Dance Dance Revolution Mat
|
||||
dj_hero_turntable = 0x0140, // DJ Hero Turntable
|
||||
harmonix_rockband_guitar = 0x0200, // Harmonix Guitar (Rock Band)
|
||||
harmonix_rockband_drum_kit = 0x0210, // Harmonix Drum Kit (Rock Band)
|
||||
red_octane_gh_guitar = 0x0100, // RedOctane Guitar (Guitar Hero 4 Guitar Controller)
|
||||
red_octane_gh_drum_kit = 0x0120, // RedOctane Drum Kit (Guitar Hero 4 Drum Controller)
|
||||
dance_dance_revolution_mat = 0x0140, // Dance Dance Revolution Dance Mat Controller
|
||||
dj_hero_turntable = 0x0140, // DJ Hero Turntable Controller
|
||||
harmonix_rockband_guitar = 0x0200, // Harmonix Guitar (Rock Band II Guitar Controller)
|
||||
harmonix_rockband_drum_kit = 0x0210, // Harmonix Drum Kit (Rock Band II Drum Controller)
|
||||
playstation_3_controller = 0x0268, // PlayStation 3 Controller
|
||||
};
|
||||
|
||||
|
@ -38,6 +38,7 @@ namespace input
|
|||
product_type type;
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
uint32_t pclass_profile; // See CELL_PAD_PCLASS_PROFILE flags
|
||||
};
|
||||
|
||||
static product_info get_product_info(product_type type)
|
||||
|
@ -47,31 +48,31 @@ namespace input
|
|||
default:
|
||||
case product_type::playstation_3_controller:
|
||||
{
|
||||
return product_info{ type, vendor_id::sony_corp, product_id::playstation_3_controller };
|
||||
return product_info{ type, vendor_id::sony_corp, product_id::playstation_3_controller, 0x0 };
|
||||
}
|
||||
case product_type::dance_dance_revolution_mat:
|
||||
{
|
||||
return product_info{ type, vendor_id::konami_de, product_id::dance_dance_revolution_mat };
|
||||
return product_info{ type, vendor_id::konami_de, product_id::dance_dance_revolution_mat, 0x000000FF };
|
||||
}
|
||||
case product_type::dj_hero_turntable:
|
||||
{
|
||||
return product_info{ type, vendor_id::sony_cea, product_id::dj_hero_turntable };
|
||||
return product_info{ type, vendor_id::sony_cea, product_id::dj_hero_turntable, 0x000007FF };
|
||||
}
|
||||
case product_type::harmonix_rockband_drum_kit:
|
||||
{
|
||||
return product_info{ type, vendor_id::sony_cea, product_id::harmonix_rockband_drum_kit };
|
||||
return product_info{ type, vendor_id::sony_cea, product_id::harmonix_rockband_drum_kit, 0x000000FF };
|
||||
}
|
||||
case product_type::harmonix_rockband_guitar:
|
||||
{
|
||||
return product_info{ type, vendor_id::sony_cea, product_id::harmonix_rockband_guitar };
|
||||
return product_info{ type, vendor_id::sony_cea, product_id::harmonix_rockband_guitar, 0x00007FFF };
|
||||
}
|
||||
case product_type::red_octane_gh_drum_kit:
|
||||
{
|
||||
return product_info{ type, vendor_id::sony_cea, product_id::red_octane_gh_drum_kit };
|
||||
return product_info{ type, vendor_id::sony_cea, product_id::red_octane_gh_drum_kit, 0x000000BB };
|
||||
}
|
||||
case product_type::red_octane_gh_guitar:
|
||||
{
|
||||
return product_info{ type, vendor_id::sony_cea, product_id::red_octane_gh_guitar };
|
||||
return product_info{ type, vendor_id::sony_cea, product_id::red_octane_gh_guitar, 0x000000FF };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue