mirror of https://github.com/PCSX2/pcsx2.git
447 lines
9.5 KiB
C
447 lines
9.5 KiB
C
/* USBlinuz
|
|
* Copyright (C) 2002-2004 USBlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include "USB.h"
|
|
|
|
|
|
const unsigned char version = PS2E_USB_VERSION;
|
|
const unsigned char revision = 0;
|
|
const unsigned char build = 4; // increase that with each version
|
|
|
|
static char *libraryName = "USBlinuz Driver";
|
|
|
|
u32 CALLBACK PS2EgetLibType() {
|
|
return PS2E_LT_USB;
|
|
}
|
|
|
|
char* CALLBACK PS2EgetLibName() {
|
|
return libraryName;
|
|
}
|
|
|
|
u32 CALLBACK PS2EgetLibVersion2(u32 type) {
|
|
return (version<<16) | (revision<<8) | build;
|
|
}
|
|
|
|
void __Log(char *fmt, ...) {
|
|
va_list list;
|
|
|
|
if (!conf.Log) return;
|
|
|
|
va_start(list, fmt);
|
|
vfprintf(usbLog, fmt, list);
|
|
va_end(list);
|
|
}
|
|
|
|
s32 CALLBACK USBinit() {
|
|
LoadConfig();
|
|
#ifdef USB_LOG
|
|
usbLog = fopen("logs/usbLog.txt", "w");
|
|
setvbuf(usbLog, NULL, _IONBF, 0);
|
|
USB_LOG("usblinuz plugin version %d,%d\n",revision,build);
|
|
USB_LOG("USBinit\n");
|
|
#endif
|
|
|
|
|
|
usbR = (s8*)malloc(0x10000);
|
|
if (usbR == NULL) {
|
|
SysMessage("Error allocating memory"); return -1;
|
|
}
|
|
memset(usbR, 0, 0x10000);
|
|
ohci = (struct ohci_regs*)usbR;
|
|
ohci->revision = 0x10;
|
|
ohci->roothub.a = 0x2;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CALLBACK USBshutdown() {
|
|
free(usbR);
|
|
#ifdef USB_LOG
|
|
fclose(usbLog);
|
|
#endif
|
|
}
|
|
|
|
s32 CALLBACK USBopen(void *pDsp) {
|
|
#ifdef USB_LOG
|
|
USB_LOG("USBopen\n");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CALLBACK USBclose() {
|
|
}
|
|
|
|
u8 CALLBACK USBread8(u32 addr) {
|
|
u8 hard;
|
|
|
|
switch (addr) {
|
|
default:
|
|
hard = usbRu8(addr);
|
|
#ifdef USB_LOG
|
|
USB_LOG("*Unknown 8bit read at address %lx value %x\n", addr, hard);
|
|
#endif
|
|
return hard;
|
|
}
|
|
|
|
#ifdef USB_LOG
|
|
USB_LOG("*Known 8bit read at address %lx value %x\n", addr, hard);
|
|
#endif
|
|
return hard;
|
|
}
|
|
|
|
u16 CALLBACK USBread16(u32 addr) {
|
|
u16 hard;
|
|
|
|
switch (addr) {
|
|
default:
|
|
hard = usbRu16(addr);
|
|
#ifdef USB_LOG
|
|
USB_LOG("*Unknown 16bit read at address %lx value %x\n", addr, hard);
|
|
#endif
|
|
return hard;
|
|
}
|
|
|
|
#ifdef USB_LOG
|
|
USB_LOG("*Known 16bit read at address %lx value %x\n", addr, hard);
|
|
#endif
|
|
return hard;
|
|
}
|
|
|
|
u32 CALLBACK USBread32(u32 addr) {
|
|
u32 hard;
|
|
int i;
|
|
|
|
if (addr >= 0x1f801654 &&
|
|
addr < 0x1f801690) {
|
|
i = (addr - 0x1f801654) / 4;
|
|
hard = ohci->roothub.portstatus[i];
|
|
#ifdef USB_LOG
|
|
USB_LOG("ohci->roothub.portstatus[%d] read32 %x\n", i, hard);
|
|
#endif
|
|
return hard;
|
|
}
|
|
|
|
switch (addr) {
|
|
#ifdef USB_LOG
|
|
case 0x1f801600:
|
|
hard = ohci->revision;
|
|
USB_LOG("ohci->revision read32 %x\n", hard);
|
|
return hard;
|
|
#endif
|
|
|
|
#ifdef USB_LOG
|
|
case 0x1f801604:
|
|
hard = ohci->control;
|
|
USB_LOG("ohci->control read32 %x\n", hard);
|
|
return hard;
|
|
#endif
|
|
|
|
case 0x1f801608:
|
|
hard = 0;
|
|
#ifdef USB_LOG
|
|
USB_LOG("ohci->cmdstatus read32 %x\n", hard);
|
|
#endif
|
|
return hard;
|
|
|
|
#ifdef USB_LOG
|
|
case 0x1f80160c:
|
|
hard = ohci->intrstatus;
|
|
USB_LOG("ohci->intrstatus read32 %x\n", hard);
|
|
return hard;
|
|
|
|
case 0x1f801610:
|
|
hard = ohci->intrenable;
|
|
USB_LOG("ohci->intrenable read32 %x\n", hard);
|
|
return hard;
|
|
|
|
case 0x1f801648:
|
|
hard = ohci->roothub.a;
|
|
USB_LOG("ohci->roothub.a read32 %x\n", hard);
|
|
return hard;
|
|
|
|
case 0x1f80164C:
|
|
hard = ohci->roothub.b;
|
|
USB_LOG("ohci->roothub.b read32 %x\n", hard);
|
|
return hard;
|
|
|
|
case 0x1f801650:
|
|
hard = ohci->roothub.status;
|
|
USB_LOG("ohci->roothub.status read32 %x\n", hard);
|
|
return hard;
|
|
#endif
|
|
|
|
default:
|
|
hard = usbRu32(addr);
|
|
#ifdef USB_LOG
|
|
USB_LOG("*Unkwnown 32bit read at address %lx: %lx\n", addr, hard);
|
|
#endif
|
|
return hard;
|
|
}
|
|
|
|
#ifdef USB_LOG
|
|
USB_LOG("*Known 32bit read at address %lx: %lx\n", addr, hard);
|
|
#endif
|
|
return hard;
|
|
}
|
|
|
|
void CALLBACK USBwrite8(u32 addr, u8 value) {
|
|
switch (addr) {
|
|
default:
|
|
usbRu8(addr) = value;
|
|
#ifdef USB_LOG
|
|
USB_LOG("*Unknown 8bit write at address %lx value %x\n", addr, value);
|
|
#endif
|
|
return;
|
|
}
|
|
usbRu8(addr) = value;
|
|
#ifdef USB_LOG
|
|
USB_LOG("*Known 8bit write at address %lx value %x\n", addr, value);
|
|
#endif
|
|
}
|
|
|
|
void CALLBACK USBwrite16(u32 addr, u16 value) {
|
|
switch (addr) {
|
|
default:
|
|
usbRu16(addr) = value;
|
|
#ifdef USB_LOG
|
|
USB_LOG("*Unknown 16bit write at address %lx value %x\n", addr, value);
|
|
#endif
|
|
return;
|
|
}
|
|
usbRu16(addr) = value;
|
|
#ifdef USB_LOG
|
|
USB_LOG("*Known 16bit write at address %lx value %x\n", addr, value);
|
|
#endif
|
|
}
|
|
|
|
void CALLBACK USBwrite32(u32 addr, u32 value) {
|
|
int i;
|
|
|
|
if (addr >= 0x1f801654 &&
|
|
addr < 0x1f801690) {
|
|
i = (addr - 0x1f801654) / 4;
|
|
// ohci->roothub.portstatus[i] = value;
|
|
ohci->intrstatus|= OHCI_INTR_SF;
|
|
#ifdef USB_LOG
|
|
USB_LOG("ohci->roothub.portstatus[%d] write32 %x\n", i, value);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
switch (addr) {
|
|
case 0x1f801600: // ohci->revision (read only)
|
|
return;
|
|
case 0x1f801604:
|
|
#ifdef USB_LOG
|
|
USB_LOG("ohci->control write32 %x\n", value);
|
|
#endif
|
|
ohci->control = value;
|
|
if ((ohci->control & OHCI_CTRL_HCFS) == OHCI_USB_OPER) {
|
|
USBirq(PSXCLK / 1000000);
|
|
ohci->roothub.portstatus[0] = 0x1;
|
|
ohci->intrstatus|= OHCI_INTR_RHSC;
|
|
}
|
|
return;
|
|
|
|
case 0x1f80160c:
|
|
#ifdef USB_LOG
|
|
USB_LOG("ohci->intrstatus write32 %x\n", value);
|
|
#endif
|
|
ohci->intrstatus&= ~value;
|
|
return;
|
|
|
|
case 0x1f801610:
|
|
#ifdef USB_LOG
|
|
USB_LOG("ohci->intrenable write32 %x\n", value);
|
|
#endif
|
|
for (i=0; i<32; i++) {
|
|
if (value & (1<<i)) {
|
|
ohci->intrenable|= 1<<i;
|
|
}
|
|
}
|
|
return;
|
|
|
|
case 0x1f801614:
|
|
#ifdef USB_LOG
|
|
USB_LOG("ohci->intrdisable write32 %x\n", value);
|
|
#endif
|
|
for (i=0; i<32; i++) {
|
|
if (value & (1<<i)) {
|
|
ohci->intrenable&= ~(1<<i);
|
|
}
|
|
}
|
|
return;
|
|
|
|
case 0x1f801618:
|
|
ohci->hcca = value;
|
|
hcca = (struct ohci_hcca*)&ram[ohci->hcca];
|
|
ohci->intrstatus|= OHCI_INTR_SF;
|
|
#ifdef USB_LOG
|
|
USB_LOG("ohci->hcca write32 %x\n", value);
|
|
#endif
|
|
return;
|
|
|
|
#ifdef USB_LOG
|
|
case 0x1f801608:
|
|
ohci->cmdstatus = value;
|
|
USB_LOG("ohci->cmdstatus write32 %x\n", value);
|
|
return;
|
|
|
|
case 0x1f801630:
|
|
ohci->donehead = value;
|
|
USB_LOG("ohci->donehead write32 %x\n", value);
|
|
return;
|
|
|
|
case 0x1f801634:
|
|
ohci->fminterval = value;
|
|
USB_LOG("ohci->fminterval write32 %x\n", value);
|
|
return;
|
|
|
|
case 0x1f801640:
|
|
ohci->periodicstart = value;
|
|
USB_LOG("ohci->periodicstart write32 %x\n", value);
|
|
return;
|
|
|
|
case 0x1f801644:
|
|
ohci->lsthresh = value;
|
|
USB_LOG("ohci->lsthresh write32 %x\n", value);
|
|
return;
|
|
|
|
case 0x1f801648:
|
|
ohci->roothub.a = value;
|
|
USB_LOG("ohci->roothub.a write32 %x\n", value);
|
|
return;
|
|
|
|
case 0x1f80164C:
|
|
ohci->roothub.b = value;
|
|
USB_LOG("ohci->roothub.b write32 %x\n", value);
|
|
return;
|
|
|
|
case 0x1f801650:
|
|
ohci->roothub.status = value;
|
|
USB_LOG("ohci->roothub.status write32 %x\n", value);
|
|
return;
|
|
#endif
|
|
default:
|
|
usbRu32(addr) = value;
|
|
#ifdef USB_LOG
|
|
USB_LOG("*Unknown 32bit write at address %lx write %x\n", addr, value);
|
|
#endif
|
|
return;
|
|
}
|
|
usbRu32(addr) = value;
|
|
#ifdef USB_LOG
|
|
USB_LOG("*Known 32bit write at address %lx value %lx\n", addr, value);
|
|
#endif
|
|
}
|
|
|
|
void CALLBACK USBirqCallback(USBcallback callback) {
|
|
USBirq = callback;
|
|
}
|
|
|
|
int CALLBACK _USBirqHandler(void) {
|
|
if ((ohci->control & OHCI_CTRL_HCFS) == OHCI_USB_OPER) {
|
|
USBirq(PSXCLK / 1000000);
|
|
}
|
|
|
|
#ifdef USB_LOG
|
|
// USB_LOG("_USBirqHandler: %x\n", ohci->intrenable);
|
|
#endif
|
|
|
|
if (ohci->fmnumber == 0xffff) {
|
|
ohci->fmnumber = 0;
|
|
ohci->intrstatus|= OHCI_INTR_FNO;
|
|
} else {
|
|
ohci->fmnumber++;
|
|
}
|
|
|
|
if (ohci->intrenable & OHCI_INTR_MIE &&
|
|
ohci->intrenable & OHCI_INTR_SF &&
|
|
ohci->intrstatus & OHCI_INTR_SF) {
|
|
#ifdef USB_LOG
|
|
USB_LOG("_USBirqHandler: SOF\n");
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
if (ohci->intrenable & OHCI_INTR_MIE &&
|
|
ohci->intrenable & OHCI_INTR_FNO &&
|
|
ohci->intrstatus & OHCI_INTR_FNO) {
|
|
#ifdef USB_LOG
|
|
USB_LOG("_USBirqHandler: FNO\n");
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
USBhandler CALLBACK USBirqHandler(void) {
|
|
return (USBhandler)_USBirqHandler;
|
|
}
|
|
|
|
void CALLBACK USBsetRAM(void *mem) {
|
|
ram = mem;
|
|
}
|
|
|
|
// extended funcs
|
|
|
|
char USBfreezeID[] = "USB STv0";
|
|
|
|
typedef struct {
|
|
u8 id[32];
|
|
u8 usbR[0x10000];
|
|
usbStruct usb;
|
|
} USBfreezeData;
|
|
|
|
s32 CALLBACK USBfreeze(int mode, freezeData *data) {
|
|
USBfreezeData *usbd;
|
|
|
|
if (mode == FREEZE_LOAD) {
|
|
usbd = (USBfreezeData*)data->data;
|
|
if (data->size != sizeof(USBfreezeData)) return -1;
|
|
if (strcmp(usbd->id, USBfreezeID)) return -1;
|
|
memcpy(usbR, usbd->usbR, 0x10000);
|
|
memcpy(&usb, &usbd->usb, sizeof(usbStruct));
|
|
} else
|
|
if (mode == FREEZE_SAVE) {
|
|
data->size = sizeof(USBfreezeData);
|
|
data->data = malloc(data->size);
|
|
if (data->data == NULL) return -1;
|
|
usbd = (USBfreezeData*)data->data;
|
|
strcpy(usbd->id, USBfreezeID);
|
|
memcpy(usbd->usbR, usbR, 0x10000);
|
|
memcpy(&usbd->usb, &usb, sizeof(usbStruct));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
s32 CALLBACK USBtest() {
|
|
return 0;
|
|
}
|
|
|