mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-02-09 08:30:39 +00:00
commit
654ff0219c
@ -146,7 +146,7 @@ uint32_t BanditHost::read(uint32_t rgn_start, uint32_t offset, int size)
|
|||||||
if (this->config_addr & BANDIT_CAR_TYPE) { // type 1 configuration command
|
if (this->config_addr & BANDIT_CAR_TYPE) { // type 1 configuration command
|
||||||
LOG_F(
|
LOG_F(
|
||||||
WARNING, "%s: read config cycle type 1 not supported yet %02x:%02x.%x @%02x",
|
WARNING, "%s: read config cycle type 1 not supported yet %02x:%02x.%x @%02x",
|
||||||
this->name.c_str(), BUS_NUM(), DEV_NUM(), FUN_NUM(), offset & 0xFCU
|
this->name.c_str(), BUS_NUM(), DEV_NUM(), FUN_NUM(), REG_NUM() + (offset & 3)
|
||||||
);
|
);
|
||||||
return 0xFFFFFFFFUL; // PCI spec §6.1
|
return 0xFFFFFFFFUL; // PCI spec §6.1
|
||||||
}
|
}
|
||||||
@ -170,7 +170,7 @@ uint32_t BanditHost::read(uint32_t rgn_start, uint32_t offset, int size)
|
|||||||
} else {
|
} else {
|
||||||
LOG_F(
|
LOG_F(
|
||||||
ERROR, "%s err: read attempt from non-existing PCI device ??:%02x.%x @%02x",
|
ERROR, "%s err: read attempt from non-existing PCI device ??:%02x.%x @%02x",
|
||||||
this->name.c_str(), WHAT_BIT_SET(idsel), FUN_NUM(), offset
|
this->name.c_str(), WHAT_BIT_SET(idsel) + 11, FUN_NUM(), REG_NUM() + (offset & 3)
|
||||||
);
|
);
|
||||||
return 0xFFFFFFFFUL; // PCI spec §6.1
|
return 0xFFFFFFFFUL; // PCI spec §6.1
|
||||||
}
|
}
|
||||||
@ -188,9 +188,9 @@ uint32_t BanditHost::read(uint32_t rgn_start, uint32_t offset, int size)
|
|||||||
}
|
}
|
||||||
LOG_F(ERROR, "%s: attempt to read from unmapped PCI I/O space, offset=0x%X",
|
LOG_F(ERROR, "%s: attempt to read from unmapped PCI I/O space, offset=0x%X",
|
||||||
this->name.c_str(), offset);
|
this->name.c_str(), offset);
|
||||||
|
// FIXME: add machine check exception (DEFAULT CATCH!, code=FFF00200)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0xFFFFFFFFUL; // PCI spec §6.1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BanditHost::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size)
|
void BanditHost::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size)
|
||||||
@ -202,7 +202,7 @@ void BanditHost::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int
|
|||||||
if (this->config_addr & BANDIT_CAR_TYPE) { // type 1 configuration command
|
if (this->config_addr & BANDIT_CAR_TYPE) { // type 1 configuration command
|
||||||
LOG_F(
|
LOG_F(
|
||||||
WARNING, "%s: write config cycle type 1 not supported yet %02x:%02x.%x @%02x",
|
WARNING, "%s: write config cycle type 1 not supported yet %02x:%02x.%x @%02x",
|
||||||
this->name.c_str(), BUS_NUM(), DEV_NUM(), FUN_NUM(), offset & 0xFCU
|
this->name.c_str(), BUS_NUM(), DEV_NUM(), FUN_NUM(), REG_NUM() + (offset & 3)
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -231,7 +231,7 @@ void BanditHost::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int
|
|||||||
} else {
|
} else {
|
||||||
LOG_F(
|
LOG_F(
|
||||||
ERROR, "%s err: write attempt to non-existing PCI device ??:%02x.%x @%02x",
|
ERROR, "%s err: write attempt to non-existing PCI device ??:%02x.%x @%02x",
|
||||||
this->name.c_str(), WHAT_BIT_SET(idsel), FUN_NUM(), offset
|
this->name.c_str(), WHAT_BIT_SET(idsel) + 11, FUN_NUM(), REG_NUM() + (offset & 3)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -273,7 +273,7 @@ Bandit::Bandit(int bridge_num, std::string name, int dev_id, int rev)
|
|||||||
mem_ctrl->add_mmio_region(base_addr, 0x01000000, this);
|
mem_ctrl->add_mmio_region(base_addr, 0x01000000, this);
|
||||||
|
|
||||||
// connnect Bandit PCI device
|
// connnect Bandit PCI device
|
||||||
this->my_pci_device = unique_ptr<BanditPciDevice>(
|
this->my_pci_device = unique_ptr<BanditPciDevice>(
|
||||||
new BanditPciDevice(bridge_num, name, dev_id, rev)
|
new BanditPciDevice(bridge_num, name, dev_id, rev)
|
||||||
);
|
);
|
||||||
this->pci_register_device(1, this->my_pci_device.get());
|
this->pci_register_device(1, this->my_pci_device.get());
|
||||||
|
@ -49,10 +49,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
#define BANDIT_CAR_TYPE (1 << 0) // Bandit config address type bit
|
#define BANDIT_CAR_TYPE (1 << 0) // Bandit config address type bit
|
||||||
|
|
||||||
/* Convenient macros for parsing CONFIG_ADDR fields. */
|
/* Convenient macros for parsing CONFIG_ADDR fields. */
|
||||||
#define BUS_NUM() (this->config_addr >> 16) & 0xFFU
|
#define BUS_NUM() ((this->config_addr >> 16) & 0xFFU)
|
||||||
#define DEV_NUM() (this->config_addr >> 11) & 0x1FU
|
#define DEV_NUM() ((this->config_addr >> 11) & 0x1FU)
|
||||||
#define FUN_NUM() (this->config_addr >> 8) & 0x07U
|
#define FUN_NUM() ((this->config_addr >> 8) & 0x07U)
|
||||||
#define REG_NUM() (this->config_addr ) & 0xFCU
|
#define REG_NUM() ((this->config_addr ) & 0xFCU)
|
||||||
|
|
||||||
/** Bandit specific configuration registers. */
|
/** Bandit specific configuration registers. */
|
||||||
enum {
|
enum {
|
||||||
|
@ -100,11 +100,7 @@ void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &
|
|||||||
case PCI_CFG_BAR3:
|
case PCI_CFG_BAR3:
|
||||||
case PCI_CFG_BAR4:
|
case PCI_CFG_BAR4:
|
||||||
case PCI_CFG_BAR5:
|
case PCI_CFG_BAR5:
|
||||||
if (value == 0xFFFFFFFFUL) {
|
this->set_bar_value((reg_offs - 0x10) >> 2, value);
|
||||||
this->do_bar_sizing((reg_offs - 0x10) >> 2);
|
|
||||||
} else {
|
|
||||||
this->set_bar_value((reg_offs - 0x10) >> 2, value);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case PCI_CFG_ROM_BAR:
|
case PCI_CFG_ROM_BAR:
|
||||||
if ((value & this->exp_bar_cfg) == this->exp_bar_cfg) {
|
if ((value & this->exp_bar_cfg) == this->exp_bar_cfg) {
|
||||||
@ -207,23 +203,75 @@ int PCIDevice::attach_exp_rom_image(const std::string img_path)
|
|||||||
|
|
||||||
void PCIDevice::do_bar_sizing(int bar_num)
|
void PCIDevice::do_bar_sizing(int bar_num)
|
||||||
{
|
{
|
||||||
this->bars[bar_num] = this->bars_cfg[bar_num];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCIDevice::set_bar_value(int bar_num, uint32_t value)
|
void PCIDevice::set_bar_value(int bar_num, uint32_t value)
|
||||||
{
|
{
|
||||||
uint32_t bar_cfg = this->bars_cfg[bar_num];
|
uint32_t bar_cfg = this->bars_cfg[bar_num];
|
||||||
if (bar_cfg & 1) {
|
switch (bars_typ[bar_num]) {
|
||||||
this->bars[bar_num] = (value & 0xFFFFFFFCUL) | (bar_cfg & 3);
|
case BAR_Unused:
|
||||||
} else {
|
return;
|
||||||
if (bar_cfg & 6) {
|
|
||||||
ABORT_F("Invalid or unsupported PCI space type: %d", (bar_cfg >> 1) & 3);
|
case BAR_IO_16Bit:
|
||||||
}
|
case BAR_IO_32Bit:
|
||||||
this->bars[bar_num] = (value & 0xFFFFFFF0UL) | (bar_cfg & 0xF);
|
this->bars[bar_num] = (value & bar_cfg & ~3) | (bar_cfg & 3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BAR_MEM_20Bit:
|
||||||
|
case BAR_MEM_32Bit:
|
||||||
|
case BAR_MEM_64Bit:
|
||||||
|
this->bars[bar_num] = (value & bar_cfg & ~0xF) | (bar_cfg & 0xF);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BAR_MEM_64BitHi:
|
||||||
|
this->bars[bar_num] = (value & bar_cfg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value == 0xFFFFFFFFUL) {
|
||||||
|
do_bar_sizing(bar_num);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this->pci_notify_bar_change(bar_num);
|
this->pci_notify_bar_change(bar_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PCIDevice::finish_config_bars()
|
||||||
|
{
|
||||||
|
for (int bar_num = 0; bar_num < 6; bar_num++) {
|
||||||
|
uint32_t bar_cfg = this->bars_cfg[bar_num];
|
||||||
|
if (bar_cfg & 1) {
|
||||||
|
bars_typ[bar_num] = (bar_cfg & 0xffff0000) ? BAR_IO_32Bit : BAR_IO_16Bit;
|
||||||
|
}
|
||||||
|
else if (bar_cfg != 0) {
|
||||||
|
int pci_space_type = (bar_cfg >> 1) & 3;
|
||||||
|
switch (pci_space_type) {
|
||||||
|
case 0:
|
||||||
|
bars_typ[bar_num] = BAR_MEM_32Bit;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
bars_typ[bar_num] = BAR_MEM_20Bit;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (bar_num > 4) {
|
||||||
|
ABORT_F("%s: BAR %d cannot be 64-bit", this->pci_name.c_str(), bar_num);
|
||||||
|
}
|
||||||
|
else if (this->bars_cfg[bar_num+1] == 0) {
|
||||||
|
ABORT_F("%s: 64-bit BAR %d has zero for upper 32 bits", this->pci_name.c_str(), bar_num);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bars_typ[bar_num++] = BAR_MEM_64Bit;
|
||||||
|
bars_typ[bar_num] = BAR_MEM_64BitHi;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
ABORT_F("%s: invalid or unsupported PCI space type %d for BAR %d", this->pci_name.c_str(), pci_space_type, bar_num);
|
||||||
|
break;
|
||||||
|
} // switch pci_space_type
|
||||||
|
} // if BAR_MEM
|
||||||
|
} // for bar_num
|
||||||
|
}
|
||||||
|
|
||||||
void PCIDevice::map_exp_rom_mem()
|
void PCIDevice::map_exp_rom_mem()
|
||||||
{
|
{
|
||||||
uint32_t rom_addr, rom_size;
|
uint32_t rom_addr, rom_size;
|
||||||
|
@ -58,6 +58,16 @@ enum {
|
|||||||
PCI_VENDOR_NVIDIA = 0x10DE,
|
PCI_VENDOR_NVIDIA = 0x10DE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** PCI BAR types */
|
||||||
|
enum PCIBarType {
|
||||||
|
BAR_Unused,
|
||||||
|
BAR_IO_16Bit,
|
||||||
|
BAR_IO_32Bit,
|
||||||
|
BAR_MEM_20Bit, // < 1M
|
||||||
|
BAR_MEM_32Bit,
|
||||||
|
BAR_MEM_64Bit,
|
||||||
|
BAR_MEM_64BitHi,
|
||||||
|
};
|
||||||
|
|
||||||
class PCIDevice : public MMIODevice {
|
class PCIDevice : public MMIODevice {
|
||||||
public:
|
public:
|
||||||
@ -108,6 +118,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
void do_bar_sizing(int bar_num);
|
void do_bar_sizing(int bar_num);
|
||||||
void set_bar_value(int bar_num, uint32_t value);
|
void set_bar_value(int bar_num, uint32_t value);
|
||||||
|
void finish_config_bars();
|
||||||
void map_exp_rom_mem();
|
void map_exp_rom_mem();
|
||||||
|
|
||||||
std::string pci_name; // human-readable device name
|
std::string pci_name; // human-readable device name
|
||||||
@ -132,6 +143,7 @@ protected:
|
|||||||
|
|
||||||
uint32_t bars[6] = { 0 }; // base address registers
|
uint32_t bars[6] = { 0 }; // base address registers
|
||||||
uint32_t bars_cfg[6] = { 0 }; // configuration values for base address registers
|
uint32_t bars_cfg[6] = { 0 }; // configuration values for base address registers
|
||||||
|
PCIBarType bars_typ[6] = { BAR_Unused }; // types for base address registers
|
||||||
|
|
||||||
uint32_t exp_bar_cfg = 0; // expansion ROM configuration
|
uint32_t exp_bar_cfg = 0; // expansion ROM configuration
|
||||||
uint32_t exp_rom_bar = 0; // expansion ROM base address register
|
uint32_t exp_rom_bar = 0; // expansion ROM base address register
|
||||||
|
@ -43,6 +43,7 @@ GrandCentral::GrandCentral() : PCIDevice("mac-io/grandcentral"), InterruptCtrl()
|
|||||||
this->class_rev = 0xFF000002;
|
this->class_rev = 0xFF000002;
|
||||||
this->cache_ln_sz = 8;
|
this->cache_ln_sz = 8;
|
||||||
this->bars_cfg[0] = 0xFFFE0000UL; // declare 128Kb of memory-mapped I/O space
|
this->bars_cfg[0] = 0xFFFE0000UL; // declare 128Kb of memory-mapped I/O space
|
||||||
|
this->finish_config_bars();
|
||||||
|
|
||||||
this->pci_notify_bar_change = [this](int bar_num) {
|
this->pci_notify_bar_change = [this](int bar_num) {
|
||||||
this->notify_bar_change(bar_num);
|
this->notify_bar_change(bar_num);
|
||||||
|
@ -55,6 +55,7 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow"), InterruptCtrl()
|
|||||||
this->cache_ln_sz = 8;
|
this->cache_ln_sz = 8;
|
||||||
this->lat_timer = 0x40;
|
this->lat_timer = 0x40;
|
||||||
this->bars_cfg[0] = 0xFFF80000UL; // declare 512Kb of memory-mapped I/O space
|
this->bars_cfg[0] = 0xFFF80000UL; // declare 512Kb of memory-mapped I/O space
|
||||||
|
this->finish_config_bars();
|
||||||
|
|
||||||
this->pci_notify_bar_change = [this](int bar_num) {
|
this->pci_notify_bar_change = [this](int bar_num) {
|
||||||
this->notify_bar_change(bar_num);
|
this->notify_bar_change(bar_num);
|
||||||
|
@ -37,6 +37,7 @@ OHare::OHare() : PCIDevice("mac-io/ohare"), InterruptCtrl()
|
|||||||
this->class_rev = 0xFF000001;
|
this->class_rev = 0xFF000001;
|
||||||
this->cache_ln_sz = 8;
|
this->cache_ln_sz = 8;
|
||||||
this->bars_cfg[0] = 0xFFF80000UL; // declare 512Kb of memory-mapped I/O space
|
this->bars_cfg[0] = 0xFFF80000UL; // declare 512Kb of memory-mapped I/O space
|
||||||
|
this->finish_config_bars();
|
||||||
|
|
||||||
this->pci_notify_bar_change = [this](int bar_num) {
|
this->pci_notify_bar_change = [this](int bar_num) {
|
||||||
this->notify_bar_change(bar_num);
|
this->notify_bar_change(bar_num);
|
||||||
|
@ -86,6 +86,7 @@ uint32_t MPC106::read(uint32_t rgn_start, uint32_t offset, int size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_F(ERROR, "Attempt to read from unmapped PCI I/O space, offset=0x%X", offset);
|
LOG_F(ERROR, "Attempt to read from unmapped PCI I/O space, offset=0x%X", offset);
|
||||||
|
// FIXME: add machine check exception (DEFAULT CATCH!, code=FFF00200)
|
||||||
} else {
|
} else {
|
||||||
if (offset >= 0x200000) {
|
if (offset >= 0x200000) {
|
||||||
if (this->config_addr & 0x80) // process only if bit E (enable) is set
|
if (this->config_addr & 0x80) // process only if bit E (enable) is set
|
||||||
@ -125,8 +126,8 @@ uint32_t MPC106::pci_read(uint32_t offset, uint32_t size) {
|
|||||||
int reg_offs = (this->config_addr >> 24) & 0xFC;
|
int reg_offs = (this->config_addr >> 24) & 0xFC;
|
||||||
|
|
||||||
if (bus_num) {
|
if (bus_num) {
|
||||||
LOG_F(ERROR, "%s: read attempt from non-local PCI bus, %02x:%02x.%x @%02x",
|
LOG_F(ERROR, "%s: read attempt from non-local PCI bus, %02x:%02x.%x @%02x",
|
||||||
this->name.c_str(), bus_num, dev_num, fun_num, offset & 0xFCU);
|
this->name.c_str(), bus_num, dev_num, fun_num, reg_offs + (offset & 3));
|
||||||
return 0xFFFFFFFFUL; // PCI spec §6.1
|
return 0xFFFFFFFFUL; // PCI spec §6.1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +140,7 @@ uint32_t MPC106::pci_read(uint32_t offset, uint32_t size) {
|
|||||||
return pci_conv_rd_data(result, details);
|
return pci_conv_rd_data(result, details);
|
||||||
} else {
|
} else {
|
||||||
LOG_F(ERROR, "%s: read attempt from non-existing PCI device ??:%02x.%x @%02x",
|
LOG_F(ERROR, "%s: read attempt from non-existing PCI device ??:%02x.%x @%02x",
|
||||||
this->name.c_str(), dev_num, fun_num, offset);
|
this->name.c_str(), dev_num, fun_num, reg_offs + (offset & 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0xFFFFFFFFUL; // PCI spec §6.1
|
return 0xFFFFFFFFUL; // PCI spec §6.1
|
||||||
@ -152,8 +153,8 @@ void MPC106::pci_write(uint32_t offset, uint32_t value, uint32_t size) {
|
|||||||
int reg_offs = (this->config_addr >> 24) & 0xFC;
|
int reg_offs = (this->config_addr >> 24) & 0xFC;
|
||||||
|
|
||||||
if (bus_num) {
|
if (bus_num) {
|
||||||
LOG_F(ERROR, "%s: write attempt to non-local PCI bus, %02x:%02x.%x @%02x",
|
LOG_F(ERROR, "%s: write attempt to non-local PCI bus, %02x:%02x.%x @%02x",
|
||||||
this->name.c_str(), bus_num, dev_num, fun_num, offset & 0xFCU);
|
this->name.c_str(), bus_num, dev_num, fun_num, reg_offs + (offset & 3));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +173,7 @@ void MPC106::pci_write(uint32_t offset, uint32_t value, uint32_t size) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG_F(ERROR, "%s: write attempt to non-existing PCI device ??:%02x.%x @%02x",
|
LOG_F(ERROR, "%s: write attempt to non-existing PCI device ??:%02x.%x @%02x",
|
||||||
this->name.c_str(), dev_num, fun_num, offset);
|
this->name.c_str(), dev_num, fun_num, reg_offs + (offset & 3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ AtiMach64Gx::AtiMach64Gx()
|
|||||||
this->device_id = ATI_MACH64_GX_DEV_ID;
|
this->device_id = ATI_MACH64_GX_DEV_ID;
|
||||||
this->class_rev = (0x030000 << 8) | 3;
|
this->class_rev = (0x030000 << 8) | 3;
|
||||||
this->bars_cfg[0] = 0xFF000000UL; // declare main aperture (16MB)
|
this->bars_cfg[0] = 0xFF000000UL; // declare main aperture (16MB)
|
||||||
|
this->finish_config_bars();
|
||||||
|
|
||||||
this->pci_notify_bar_change = [this](int bar_num) {
|
this->pci_notify_bar_change = [this](int bar_num) {
|
||||||
this->notify_bar_change(bar_num);
|
this->notify_bar_change(bar_num);
|
||||||
|
@ -127,6 +127,7 @@ ATIRage::ATIRage(uint16_t dev_id)
|
|||||||
this->bars_cfg[0] = 0xFF000000UL; // declare main aperture (16MB)
|
this->bars_cfg[0] = 0xFF000000UL; // declare main aperture (16MB)
|
||||||
this->bars_cfg[1] = 0xFFFFFF01UL; // declare I/O region (256 bytes)
|
this->bars_cfg[1] = 0xFFFFFF01UL; // declare I/O region (256 bytes)
|
||||||
this->bars_cfg[2] = 0xFFFFF000UL; // declare register aperture (4KB)
|
this->bars_cfg[2] = 0xFFFFF000UL; // declare register aperture (4KB)
|
||||||
|
this->finish_config_bars();
|
||||||
|
|
||||||
this->pci_notify_bar_change = [this](int bar_num) {
|
this->pci_notify_bar_change = [this](int bar_num) {
|
||||||
this->notify_bar_change(bar_num);
|
this->notify_bar_change(bar_num);
|
||||||
|
@ -62,6 +62,7 @@ ControlVideo::ControlVideo()
|
|||||||
this->bars_cfg[0] = 0xFFFFFFFFUL; // I/O region (4 bytes but it's weird because bit 1 is set)
|
this->bars_cfg[0] = 0xFFFFFFFFUL; // I/O region (4 bytes but it's weird because bit 1 is set)
|
||||||
this->bars_cfg[1] = 0xFFFFF000UL; // base address for the HW registers (4KB)
|
this->bars_cfg[1] = 0xFFFFF000UL; // base address for the HW registers (4KB)
|
||||||
this->bars_cfg[2] = 0xFC000000UL; // base address for the VRAM (64MB)
|
this->bars_cfg[2] = 0xFC000000UL; // base address for the VRAM (64MB)
|
||||||
|
this->finish_config_bars();
|
||||||
|
|
||||||
this->pci_notify_bar_change = [this](int bar_num) {
|
this->pci_notify_bar_change = [this](int bar_num) {
|
||||||
this->notify_bar_change(bar_num);
|
this->notify_bar_change(bar_num);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user