pcsx2/plugins/USBqemu/USB.cpp

370 lines
7.5 KiB
C++

/* USBqemu
* Copyright (C) 2002-2011 PCSX2 Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "qemu-usb/USBinternal.h"
#ifdef _MSC_VER
# include "svnrev.h"
#endif
const unsigned char version = PS2E_USB_VERSION;
const unsigned char revision = 0;
const unsigned char build = 1; // increase that with each version
// PCSX2 expects ASNI, not unicode, so this MUST always be char...
static char libraryName[256];
OHCIState *qemu_ohci;
Config conf;
HWND gsWindowHandle=NULL;
u8 *ram;
USBcallback _USBirq;
FILE *usbLog;
int64_t usb_frame_time=0;
int64_t usb_bit_time=0;
s64 clocks=0;
s64 remaining=0;
int64_t get_ticks_per_sec()
{
return PSXCLK;
}
void __Log(char *fmt, ...) {
va_list list;
if (!conf.Log) return;
va_start(list, fmt);
vfprintf(usbLog, fmt, list);
va_end(list);
}
static void InitLibraryName()
{
#ifdef USBQEMU_PUBLIC_RELEASE
// Public Release!
// Output a simplified string that's just our name:
strcpy( libraryName, "USBqemu" );
#else
#ifdef SVN_REV_UNKNOWN
// Unknown revision.
// Output a name that includes devbuild status but not
// subversion revision tags:
strcpy( libraryName, "USBqemu"
#ifdef DEBUG_FAST
"-Debug"
#elif defined( PCSX2_DEBUG )
"-Debug/Strict" // strict debugging is slow!
#elif defined( PCSX2_DEVBUILD )
"-Dev"
#else
""
#endif
);
#else
// Use TortoiseSVN's SubWCRev utility's output
// to label the specific revision:
sprintf_s( libraryName, "USBqemu %lld%s"
#ifdef DEBUG_FAST
"-Debug"
#elif defined( PCSX2_DEBUG )
"-Debug/Strict" // strict debugging is slow!
#elif defined( PCSX2_DEVBUILD )
"-Dev"
#else
""
#endif
,SVN_REV,SVN_MODS ? "m" : ""
);
#endif
#endif
}
u32 CALLBACK PS2EgetLibType() {
return PS2E_LT_USB;
}
const char* CALLBACK PS2EgetLibName()
{
InitLibraryName();
return libraryName;
}
u32 CALLBACK PS2EgetLibVersion2(u32 type) {
return (version<<16) | (revision<<8) | build;
}
void USBirq(int cycles)
{
USB_LOG("USBirq.\n");
_USBirq(cycles);
}
s32 CALLBACK USBinit() {
LoadConfig();
if (conf.Log)
{
usbLog = fopen("logs/usbLog.txt", "w");
setvbuf(usbLog, NULL, _IONBF, 0);
USB_LOG("USBqemu plugin version %d,%d\n",revision,build);
USB_LOG("USBinit\n");
}
qemu_ohci = ohci_create(0x1f801600,2);
qemu_ohci->rhport[0].port.dev = usb_keyboard_init();
qemu_ohci->rhport[0].port.ops->attach(&(qemu_ohci->rhport[0].port));
clocks = 0;
remaining = 0;
return 0;
}
void CALLBACK USBshutdown() {
USBDevice* device = qemu_ohci->rhport[0].port.dev;
qemu_ohci->rhport[0].port.ops->detach(&(qemu_ohci->rhport[0].port));
device->info->handle_destroy(qemu_ohci->rhport[0].port.dev);
free(qemu_ohci);
#ifdef _DEBUG
if(usbLog)
fclose(usbLog);
#endif
}
s32 CALLBACK USBopen(void *pDsp) {
USB_LOG("USBopen\n");
HWND hWnd=(HWND)pDsp;
if (!IsWindow (hWnd) && !IsBadReadPtr ((u32*)hWnd, 4))
hWnd = *(HWND*)hWnd;
if (!IsWindow (hWnd))
hWnd = NULL;
else
{
while (GetWindowLong (hWnd, GWL_STYLE) & WS_CHILD)
hWnd = GetParent (hWnd);
}
gsWindowHandle = hWnd;
return 0;
}
void CALLBACK USBclose() {
}
u8 CALLBACK USBread8(u32 addr) {
USB_LOG("* Invalid 8bit read at address %lx\n", addr);
return 0;
}
u16 CALLBACK USBread16(u32 addr) {
USB_LOG("* Invalid 16bit read at address %lx\n", addr);
return 0;
}
u32 CALLBACK USBread32(u32 addr) {
u32 hard;
hard=ohci_mem_read(qemu_ohci,addr - qemu_ohci->mem);
USB_LOG("* Known 32bit read at address %lx: %lx\n", addr, hard);
return hard;
}
void CALLBACK USBwrite8(u32 addr, u8 value) {
USB_LOG("* Invalid 8bit write at address %lx value %x\n", addr, value);
}
void CALLBACK USBwrite16(u32 addr, u16 value) {
USB_LOG("* Invalid 16bit write at address %lx value %x\n", addr, value);
}
void CALLBACK USBwrite32(u32 addr, u32 value) {
USB_LOG("* Known 32bit write at address %lx value %lx\n", addr, value);
ohci_mem_write(qemu_ohci,addr - qemu_ohci->mem, value);
}
void CALLBACK USBirqCallback(USBcallback callback) {
_USBirq = callback;
}
extern u32 bits;
int CALLBACK _USBirqHandler(void)
{
//fprintf(stderr," * USB: IRQ Acknowledged.\n");
//qemu_ohci->intr_status&=~bits;
return 1;
}
USBhandler CALLBACK USBirqHandler(void) {
return (USBhandler)_USBirqHandler;
}
void CALLBACK USBsetRAM(void *mem) {
ram = (u8*)mem;
}
// extended funcs
char USBfreezeID[] = "USBqemu01";
typedef struct {
char freezeID[10];
int cycles;
int remaining;
OHCIState t;
int extraData; // for future expansion with the device state
} USBfreezeData;
s32 CALLBACK USBfreeze(int mode, freezeData *data) {
USBfreezeData usbd;
if (mode == FREEZE_LOAD)
{
if(data->size < sizeof(USBfreezeData))
{
SysMessage("ERROR: Unable to load freeze data! Got %d bytes, expected >= %d.", data->size, sizeof(USBfreezeData));
return -1;
}
usbd = *(USBfreezeData*)data->data;
usbd.freezeID[9] = 0;
usbd.cycles = static_cast<int>(clocks);
usbd.remaining = static_cast<int>(remaining);
if( strcmp(usbd.freezeID, USBfreezeID) != 0)
{
SysMessage("ERROR: Unable to load freeze data! Found ID '%s', expected ID '%s'.", usbd.freezeID, USBfreezeID);
return -1;
}
if (data->size != sizeof(USBfreezeData))
return -1;
for(int i=0; i< qemu_ohci->num_ports; i++)
{
usbd.t.rhport[i].port.opaque = qemu_ohci;
usbd.t.rhport[i].port.ops = qemu_ohci->rhport[i].port.ops;
usbd.t.rhport[i].port.dev = qemu_ohci->rhport[i].port.dev; // pointers
}
*qemu_ohci = usbd.t;
// WARNING: TODO: Load the state of the attached devices!
}
else if (mode == FREEZE_SAVE)
{
data->size = sizeof(USBfreezeData);
data->data = (s8*)malloc(data->size);
if (data->data == NULL)
return -1;
strcpy(usbd.freezeID, USBfreezeID);
usbd.t = *qemu_ohci;
for(int i=0; i< qemu_ohci->num_ports; i++)
{
usbd.t.rhport[i].port.ops = NULL; // pointers
usbd.t.rhport[i].port.opaque = NULL; // pointers
usbd.t.rhport[i].port.dev = NULL; // pointers
}
clocks = usbd.cycles;
remaining = usbd.remaining;
// WARNING: TODO: Save the state of the attached devices!
}
return 0;
}
void CALLBACK USBasync(u32 _cycles)
{
remaining += _cycles;
clocks += remaining;
if(qemu_ohci->eof_timer>0)
{
while(remaining>=qemu_ohci->eof_timer)
{
remaining-=qemu_ohci->eof_timer;
qemu_ohci->eof_timer=0;
ohci_frame_boundary(qemu_ohci);
}
if((remaining>0)&&(qemu_ohci->eof_timer>0))
{
s64 m = qemu_ohci->eof_timer;
if(remaining < m)
m = remaining;
qemu_ohci->eof_timer -= m;
remaining -= m;
}
}
//if(qemu_ohci->eof_timer <= 0)
//{
// ohci_frame_boundary(qemu_ohci);
//}
}
s32 CALLBACK USBtest() {
return 0;
}
void cpu_physical_memory_rw(u32 addr, u8 *buf,
int len, int is_write)
{
if(is_write)
memcpy(&(ram[addr]),buf,len);
else
memcpy(buf,&(ram[addr]),len);
}
s64 get_clock()
{
return clocks;
}
void *qemu_mallocz(uint32_t size)
{
void *m=malloc(size);
if(!m) return NULL;
memset(m,0,size);
return m;
}