USB: close devices before destroying and loading save state and just allocate 64KiB for save states

USBfreezeData itself is currently ~20K so maybe 64K is enough
This commit is contained in:
jackun 2020-11-17 23:32:04 +02:00
parent 44b700a6fd
commit 191ebbcacf
1 changed files with 63 additions and 67 deletions

View File

@ -33,6 +33,7 @@
OHCIState* qemu_ohci = NULL; OHCIState* qemu_ohci = NULL;
USBDevice* usb_device[2] = {NULL}; USBDevice* usb_device[2] = {NULL};
bool configChanged = false; bool configChanged = false;
static bool usb_opened = false;
Config conf; Config conf;
// we'll probably switch our save state system at some point to standardize in // we'll probably switch our save state system at some point to standardize in
@ -90,31 +91,49 @@ void Reset()
ohci_hard_reset(qemu_ohci); ohci_hard_reset(qemu_ohci);
} }
void OpenDevice(int port)
{
//TODO Pass pDsp to open probably so dinput can bind to this HWND
if (usb_device[port] && usb_device[port]->klass.open)
usb_device[port]->klass.open(usb_device[port] /*, pDsp*/);
}
static void CloseDevice(int port)
{
if (usb_device[port] && usb_device[port]->klass.close)
usb_device[port]->klass.close(usb_device[port]);
}
void DestroyDevice(int port)
{
if (qemu_ohci && qemu_ohci->rhport[port].port.dev)
{
qemu_ohci->rhport[port].port.dev->klass.unrealize(qemu_ohci->rhport[port].port.dev);
qemu_ohci->rhport[port].port.dev = nullptr;
}
else if (usb_device[port])
usb_device[port]->klass.unrealize(usb_device[port]);
usb_device[port] = nullptr;
}
void DestroyDevices() void DestroyDevices()
{ {
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
if (qemu_ohci && qemu_ohci->rhport[i].port.dev) CloseDevice(i);
{ DestroyDevice(i);
qemu_ohci->rhport[i].port.dev->klass.unrealize(qemu_ohci->rhport[i].port.dev);
qemu_ohci->rhport[i].port.dev = nullptr;
}
else if (usb_device[i])
usb_device[i]->klass.unrealize(usb_device[i]);
usb_device[i] = nullptr;
} }
} }
USBDevice* CreateDevice(DeviceType index, int port) static USBDevice* CreateDevice(DeviceType index, int port)
{ {
DeviceProxyBase* devProxy;
USBDevice* device = nullptr; USBDevice* device = nullptr;
if (index == DEVTYPE_NONE) if (index == DEVTYPE_NONE)
return nullptr; return nullptr;
devProxy = RegisterDevice::instance().Device(index); DeviceProxyBase* devProxy = RegisterDevice::instance().Device(index);
if (devProxy) if (devProxy)
device = devProxy->CreateDevice(port); device = devProxy->CreateDevice(port);
else else
@ -127,7 +146,7 @@ USBDevice* CreateDevice(DeviceType index, int port)
} }
//TODO re-do sneaky attach //TODO re-do sneaky attach
void USBAttach(int port, USBDevice* dev, bool sneaky = false) static void USBAttach(int port, USBDevice* dev, bool sneaky = false)
{ {
if (!qemu_ohci) if (!qemu_ohci)
return; return;
@ -148,23 +167,19 @@ void USBAttach(int port, USBDevice* dev, bool sneaky = false)
} }
} }
USBDevice* CreateDevice(const std::string& name, int port) static USBDevice* CreateDevice(const std::string& name, int port)
{ {
DeviceProxyBase* devProxy;
USBDevice* device = nullptr; USBDevice* device = nullptr;
if (!name.empty()) if (!name.empty())
{ {
devProxy = RegisterDevice::instance().Device(name); DeviceProxyBase* devProxy = RegisterDevice::instance().Device(name);
if (devProxy) if (devProxy)
device = devProxy->CreateDevice(port); device = devProxy->CreateDevice(port);
else else
Console.WriteLn(Color_Red, "Port %d: Unknown device type", port); Console.WriteLn(Color_Red, "Port %d: Unknown device type", port);
} }
if (!device)
{
}
return device; return device;
} }
@ -178,6 +193,8 @@ void CreateDevices()
{ {
usb_device[i] = CreateDevice(conf.Port[i], i); usb_device[i] = CreateDevice(conf.Port[i], i);
USBAttach(i, usb_device[i]); USBAttach(i, usb_device[i]);
if (usb_opened)
OpenDevice(i);
} }
} }
@ -225,6 +242,7 @@ void USBshutdown()
usbLog = nullptr; usbLog = nullptr;
} }
//#endif //#endif
usb_opened = false;
} }
s32 USBopen(void* pDsp) s32 USBopen(void* pDsp)
@ -274,26 +292,18 @@ s32 USBopen(void* pDsp)
CreateDevices(); //TODO Pass pDsp to init? CreateDevices(); //TODO Pass pDsp to init?
} }
//TODO Pass pDsp to open probably so dinput can bind to this HWND OpenDevice(0 /*, pDsp */);
if (usb_device[0] && usb_device[0]->klass.open) OpenDevice(1 /*, pDsp */);
usb_device[0]->klass.open(usb_device[0] /*, pDsp*/); usb_opened = true;
if (usb_device[1] && usb_device[1]->klass.open)
usb_device[1]->klass.open(usb_device[1] /*, pDsp*/);
return 0; return 0;
} }
void USBclose() void USBclose()
{ {
CloseDevice(0);
if (usb_device[0] && usb_device[0]->klass.close) CloseDevice(1);
usb_device[0]->klass.close(usb_device[0]);
if (usb_device[1] && usb_device[1]->klass.close)
usb_device[1]->klass.close(usb_device[1]);
shared::Uninitialize(); shared::Uninitialize();
usb_opened = false;
} }
u8 USBread8(u32 addr) u8 USBread8(u32 addr)
@ -361,13 +371,16 @@ s32 USBfreeze(int mode, freezeData* data)
s8* ptr = data->data + sizeof(USBfreezeData); s8* ptr = data->data + sizeof(USBfreezeData);
// Load the state of the attached devices // Load the state of the attached devices
if ((long unsigned int)data->size != sizeof(USBfreezeData) + usbd.device[0].size + usbd.device[1].size + 8192) if ((long unsigned int)data->size < sizeof(USBfreezeData) + usbd.device[0].size + usbd.device[1].size + 8192)
return -1; return -1;
//TODO Subsequent save state loadings make USB "stall" for n seconds since previous load //TODO Subsequent save state loadings make USB "stall" for n seconds since previous load
//clocks = usbd.cycles; //clocks = usbd.cycles;
//remaining = usbd.remaining; //remaining = usbd.remaining;
CloseDevice(0);
CloseDevice(1);
for (uint32_t i = 0; i < qemu_ohci->num_ports; i++) for (uint32_t i = 0; i < qemu_ohci->num_ports; i++)
{ {
usbd.t.rhport[i].port.opaque = qemu_ohci; usbd.t.rhport[i].port.opaque = qemu_ohci;
@ -391,18 +404,17 @@ s32 USBfreeze(int mode, freezeData* data)
if (usbd.device[i].index != index) if (usbd.device[i].index != index)
{ {
index = usbd.device[i].index; index = usbd.device[i].index;
USBDevice* dev = qemu_ohci->rhport[i].port.dev; DestroyDevice(i);
qemu_ohci->rhport[i].port.dev = nullptr; conf.Port[i].clear();
if (dev)
{
assert(usb_device[i] == dev);
dev->klass.unrealize(dev);
}
proxy = regInst.Device(index); proxy = regInst.Device(index);
usb_device[i] = CreateDevice(index, i); if (proxy)
USBAttach(i, usb_device[i], index != DEVTYPE_MSD); {
// re-create with saved device type
conf.Port[i] = proxy->TypeName();
usb_device[i] = CreateDevice(index, i);
USBAttach(i, usb_device[i], index != DEVTYPE_MSD);
}
} }
if (proxy && usb_device[i]) /* usb device creation may have failed for some reason */ if (proxy && usb_device[i]) /* usb device creation may have failed for some reason */
@ -446,11 +458,11 @@ s32 USBfreeze(int mode, freezeData* data)
usb_detach(&qemu_ohci->rhport[i].port); usb_detach(&qemu_ohci->rhport[i].port);
usb_attach(&qemu_ohci->rhport[i].port); usb_attach(&qemu_ohci->rhport[i].port);
} }
OpenDevice(i);
} }
else if (!proxy && index != DEVTYPE_NONE) else if (!proxy && index != DEVTYPE_NONE)
{ {
Console.WriteLn(Color_Red, "USB: Port %d: unknown device.\nPlugin is probably too old for this save.\n", 1 + (1 - i)); Console.WriteLn(Color_Red, "USB: Port %d: unknown device.\nPlugin is probably too old for this save.", i);
return -1;
} }
ptr += usbd.device[i].size; ptr += usbd.device[i].size;
} }
@ -493,6 +505,7 @@ s32 USBfreeze(int mode, freezeData* data)
{ {
return -1; return -1;
} }
} }
//TODO straight copying of structs can break cross-platform/cross-compiler save states 'cause padding 'n' stuff //TODO straight copying of structs can break cross-platform/cross-compiler save states 'cause padding 'n' stuff
else if (mode == FREEZE_SAVE) else if (mode == FREEZE_SAVE)
@ -560,24 +573,7 @@ s32 USBfreeze(int mode, freezeData* data)
} }
else if (mode == FREEZE_SIZE) else if (mode == FREEZE_SIZE)
{ {
RegisterDevice& regInst = RegisterDevice::instance(); data->size = 0x10000;
data->size = sizeof(USBfreezeData);
for (int i = 0; i < 2; i++)
{
//TODO check that current created usb device and conf.Port[n] are the same
auto proxy = regInst.Device(conf.Port[i]);
if (proxy)
data->size += proxy->Freeze(FREEZE_SIZE, usb_device[i], nullptr);
}
// PCSX2 queries size before load too, so can't use actual packet length which varies :(
data->size += 8192; // qemu_ohci->usb_packet.actual_length;
if (qemu_ohci->usb_packet.actual_length > 8192)
{
Console.Warning("Saving failed! USB packet is larger than 8K, try again later.\n");
return -1;
}
} }
return 0; return 0;
@ -662,9 +658,9 @@ void USBDoFreezeOut(void* dest)
void USBDoFreezeIn(pxInputStream& infp) void USBDoFreezeIn(pxInputStream& infp)
{ {
freezeData fP = {0, nullptr}; freezeData fP = {(int)infp.Length(), nullptr};
if (USBfreeze(FREEZE_SIZE, &fP) != 0) //if (USBfreeze(FREEZE_SIZE, &fP) != 0)
fP.size = 0; // fP.size = 0;
Console.Indent().WriteLn("Loading USB"); Console.Indent().WriteLn("Loading USB");