Logo Search packages:      
Sourcecode: pcsxr version File versions  Download package

sio.c

/***************************************************************************
 *   Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX 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 02111-1307 USA.           *
 ***************************************************************************/

/*
* SIO functions.
*/

#include "sio.h"
#include <sys/stat.h>

// Status Flags
#define TX_RDY          0x0001
#define RX_RDY          0x0002
#define TX_EMPTY  0x0004
#define PARITY_ERR      0x0008
#define RX_OVERRUN      0x0010
#define FRAMING_ERR     0x0020
#define SYNC_DETECT     0x0040
#define DSR             0x0080
#define CTS             0x0100
#define IRQ             0x0200

// Control Flags
#define TX_PERM         0x0001
#define DTR             0x0002
#define RX_PERM         0x0004
#define BREAK           0x0008
#define RESET_ERR 0x0010
#define RTS             0x0020
#define SIO_RESET 0x0040

// *** FOR WORKS ON PADS AND MEMORY CARDS *****

static unsigned char buf[256];
unsigned char cardh[4] = { 0x00, 0x00, 0x5a, 0x5d };

// Transfer Ready and the Buffer is Empty
// static unsigned short StatReg = 0x002b;
static unsigned short StatReg = TX_RDY | TX_EMPTY;
static unsigned short ModeReg;
static unsigned short CtrlReg;
static unsigned short BaudReg;

static unsigned int bufcount;
static unsigned int parp;
static unsigned int mcdst, rdwr;
static unsigned char adrH, adrL;
static unsigned int padst;

char Mcd1Data[MCD_SIZE], Mcd2Data[MCD_SIZE];

// clk cycle byte
// 4us * 8bits = (PSXCLK / 1000000) * 32; (linuzappz)
// TODO: add SioModePrescaler and BaudReg
static inline void SIO_INT() {
      if (!Config.Sio) {
            psxRegs.interrupt |= 0x80;
            psxRegs.intCycle[7 + 1] = 400;
            psxRegs.intCycle[7] = psxRegs.cycle;
      }
}

void sioWrite8(unsigned char value) {
#ifdef PAD_LOG
      PAD_LOG("sio write8 %x\n", value);
#endif
      switch (padst) {
            case 1: SIO_INT();
                  if ((value & 0x40) == 0x40) {
                        padst = 2; parp = 1;
                        if (!Config.UseNet) {
                              switch (CtrlReg & 0x2002) {
                                    case 0x0002:
                                          buf[parp] = PAD1_poll(value);
                                          break;
                                    case 0x2002:
                                          buf[parp] = PAD2_poll(value);
                                          break;
                              }
                        }/* else {
//                            SysPrintf("%x: %x, %x, %x, %x\n", CtrlReg&0x2002, buf[2], buf[3], buf[4], buf[5]);
                        }*/

                        if (!(buf[parp] & 0x0f)) {
                              bufcount = 2 + 32;
                        } else {
                              bufcount = 2 + (buf[parp] & 0x0f) * 2;
                        }
                        if (buf[parp] == 0x41) {
                              switch (value) {
                                    case 0x43:
                                          buf[1] = 0x43;
                                          break;
                                    case 0x45:
                                          buf[1] = 0xf3;
                                          break;
                              }
                        }
                  }
                  else padst = 0;
                  return;
            case 2:
                  parp++;
/*                if (buf[1] == 0x45) {
                        buf[parp] = 0;
                        SIO_INT();
                        return;
                  }*/
                  if (!Config.UseNet) {
                        switch (CtrlReg & 0x2002) {
                              case 0x0002: buf[parp] = PAD1_poll(value); break;
                              case 0x2002: buf[parp] = PAD2_poll(value); break;
                        }
                  }

                  if (parp == bufcount) { padst = 0; return; }
                  SIO_INT();
                  return;
      }

      switch (mcdst) {
            case 1:
                  SIO_INT();
                  if (rdwr) { parp++; return; }
                  parp = 1;
                  switch (value) {
                        case 0x52: rdwr = 1; break;
                        case 0x57: rdwr = 2; break;
                        default: mcdst = 0;
                  }
                  return;
            case 2: // address H
                  SIO_INT();
                  adrH = value;
                  *buf = 0;
                  parp = 0;
                  bufcount = 1;
                  mcdst = 3;
                  return;
            case 3: // address L
                  SIO_INT();
                  adrL = value;
                  *buf = adrH;
                  parp = 0;
                  bufcount = 1;
                  mcdst = 4;
                  return;
            case 4:
                  SIO_INT();
                  parp = 0;
                  switch (rdwr) {
                        case 1: // read
                              buf[0] = 0x5c;
                              buf[1] = 0x5d;
                              buf[2] = adrH;
                              buf[3] = adrL;
                              switch (CtrlReg & 0x2002) {
                                    case 0x0002:
                                          memcpy(&buf[4], Mcd1Data + (adrL | (adrH << 8)) * 128, 128);
                                          break;
                                    case 0x2002:
                                          memcpy(&buf[4], Mcd2Data + (adrL | (adrH << 8)) * 128, 128);
                                          break;
                              }
                              {
                              char xor = 0;
                              int i;
                              for (i = 2; i < 128 + 4; i++)
                                    xor ^= buf[i];
                              buf[132] = xor;
                              }
                              buf[133] = 0x47;
                              bufcount = 133;
                              break;
                        case 2: // write
                              buf[0] = adrL;
                              buf[1] = value;
                              buf[129] = 0x5c;
                              buf[130] = 0x5d;
                              buf[131] = 0x47;
                              bufcount = 131;
                              break;
                  }
                  mcdst = 5;
                  return;
            case 5:
                  parp++;
                  if (rdwr == 2) {
                        if (parp < 128) buf[parp + 1] = value;
                  }
                  SIO_INT();
                  return;
      }

      switch (value) {
            case 0x01: // start pad
                  StatReg |= RX_RDY;            // Transfer is Ready

                  if (!Config.UseNet) {
                        switch (CtrlReg & 0x2002) {
                              case 0x0002: buf[0] = PAD1_startPoll(1); break;
                              case 0x2002: buf[0] = PAD2_startPoll(2); break;
                        }
                  } else {
                        if ((CtrlReg & 0x2002) == 0x0002) {
                              int i, j;

                              PAD1_startPoll(1);
                              buf[0] = 0;
                              buf[1] = PAD1_poll(0x42);
                              if (!(buf[1] & 0x0f)) {
                                    bufcount = 32;
                              } else {
                                    bufcount = (buf[1] & 0x0f) * 2;
                              }
                              buf[2] = PAD1_poll(0);
                              i = 3;
                              j = bufcount;
                              while (j--) {
                                    buf[i++] = PAD1_poll(0);
                              }
                              bufcount+= 3;

                              if (NET_sendPadData(buf, bufcount) == -1)
                                    netError();

                              if (NET_recvPadData(buf, 1) == -1)
                                    netError();
                              if (NET_recvPadData(buf + 128, 2) == -1)
                                    netError();
                        } else {
                              memcpy(buf, buf + 128, 32);
                        }
                  }

                  bufcount = 2;
                  parp = 0;
                  padst = 1;
                  SIO_INT();
                  return;
            case 0x81: // start memcard
                  StatReg |= RX_RDY;
                  memcpy(buf, cardh, 4);
                  parp = 0;
                  bufcount = 3;
                  mcdst = 1;
                  rdwr = 0;
                  SIO_INT();
                  return;
      }
}

void sioWriteStat16(unsigned short value) {
}

void sioWriteMode16(unsigned short value) {
      ModeReg = value;
}

void sioWriteCtrl16(unsigned short value) {
      CtrlReg = value & ~RESET_ERR;
      if (value & RESET_ERR) StatReg &= ~IRQ;
      if ((CtrlReg & SIO_RESET) || (!CtrlReg)) {
            padst = 0; mcdst = 0; parp = 0;
            StatReg = TX_RDY | TX_EMPTY;
            psxRegs.interrupt &= ~0x80;
      }
}

void sioWriteBaud16(unsigned short value) {
      BaudReg = value;
}

unsigned char sioRead8() {
      unsigned char ret = 0;

      if ((StatReg & RX_RDY)/* && (CtrlReg & RX_PERM)*/) {
//          StatReg &= ~RX_OVERRUN;
            ret = buf[parp];
            if (parp == bufcount) {
                  StatReg &= ~RX_RDY;           // Receive is not Ready now
                  if (mcdst == 5) {
                        mcdst = 0;
                        if (rdwr == 2) {
                              switch (CtrlReg & 0x2002) {
                                    case 0x0002:
                                          memcpy(Mcd1Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
                                          SaveMcd(Config.Mcd1, Mcd1Data, (adrL | (adrH << 8)) * 128, 128);
                                          break;
                                    case 0x2002:
                                          memcpy(Mcd2Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
                                          SaveMcd(Config.Mcd2, Mcd2Data, (adrL | (adrH << 8)) * 128, 128);
                                          break;
                              }
                        }
                  }
                  if (padst == 2) padst = 0;
                  if (mcdst == 1) {
                        mcdst = 2;
                        StatReg|= RX_RDY;
                  }
            }
      }

#ifdef PAD_LOG
      PAD_LOG("sio read8 ;ret = %x\n", ret);
#endif
      return ret;
}

unsigned short sioReadStat16() {
      return StatReg;
}

unsigned short sioReadMode16() {
      return ModeReg;
}

unsigned short sioReadCtrl16() {
      return CtrlReg;
}

unsigned short sioReadBaud16() {
      return BaudReg;
}

void netError() {
      ClosePlugins();
      SysMessage(_("Connection closed!\n"));

      CdromId[0] = '\0';
      CdromLabel[0] = '\0';

      SysRunGui();
}

void sioInterrupt() {
#ifdef PAD_LOG
      PAD_LOG("Sio Interrupt (CP0.Status = %x)\n", psxRegs.CP0.n.Status);
#endif
//    SysPrintf("Sio Interrupt\n");
      StatReg |= IRQ;
      psxHu32ref(0x1070) |= SWAPu32(0x80);
}

void LoadMcd(int mcd, char *str) {
      FILE *f;
      char *data = NULL;

      if (mcd == 1) data = Mcd1Data;
      if (mcd == 2) data = Mcd2Data;

      if (*str == 0) {
            sprintf(str, "memcards/card%d.mcd", mcd);
            SysPrintf(_("No memory card value was specified - creating a default card %s\n"), str);
      }
      f = fopen(str, "rb");
      if (f == NULL) {
            SysPrintf(_("The memory card %s doesn't exist - creating it\n"), str);
            CreateMcd(str);
            f = fopen(str, "rb");
            if (f != NULL) {
                  struct stat buf;

                  if (stat(str, &buf) != -1) {
                        if (buf.st_size == MCD_SIZE + 64)
                              fseek(f, 64, SEEK_SET);
                        else if(buf.st_size == MCD_SIZE + 3904)
                              fseek(f, 3904, SEEK_SET);
                  }
                  fread(data, 1, MCD_SIZE, f);
                  fclose(f);
            }
            else
                  SysMessage(_("Memory card %s failed to load!\n"), str);
      }
      else {
            struct stat buf;
            SysPrintf(_("Loading memory card %s\n"), str);
            if (stat(str, &buf) != -1) {
                  if (buf.st_size == MCD_SIZE + 64)
                        fseek(f, 64, SEEK_SET);
                  else if(buf.st_size == MCD_SIZE + 3904)
                        fseek(f, 3904, SEEK_SET);
            }
            fread(data, 1, MCD_SIZE, f);
            fclose(f);
      }
}

void LoadMcds(char *mcd1, char *mcd2) {
      LoadMcd(1, mcd1);
      LoadMcd(2, mcd2);
}

void SaveMcd(char *mcd, char *data, uint32_t adr, int size) {
      FILE *f;

      f = fopen(mcd, "r+b");
      if (f != NULL) {
            struct stat buf;

            if (stat(mcd, &buf) != -1) {
                  if (buf.st_size == MCD_SIZE + 64)
                        fseek(f, adr + 64, SEEK_SET);
                  else if (buf.st_size == MCD_SIZE + 3904)
                        fseek(f, adr + 3904, SEEK_SET);
                  else
                        fseek(f, adr, SEEK_SET);
            } else
                  fseek(f, adr, SEEK_SET);

            fwrite(data + adr, 1, size, f);
            fclose(f);
            return;
      }

#if 0
      // try to create it again if we can't open it
      f = fopen(mcd, "wb");
      if (f != NULL) {
            fwrite(data, 1, MCD_SIZE, f);
            fclose(f);
      }
#endif

      ConvertMcd(mcd, data);
}

void CreateMcd(char *mcd) {
      FILE *f;
      struct stat buf;
      int s = MCD_SIZE;
      int i = 0, j;

      f = fopen(mcd, "wb");
      if (f == NULL)
            return;

      if (stat(mcd, &buf) != -1) {
            if ((buf.st_size == MCD_SIZE + 3904) || strstr(mcd, ".gme")) {
                  s = s + 3904;
                  fputc('1', f);
                  s--;
                  fputc('2', f);
                  s--;
                  fputc('3', f);
                  s--;
                  fputc('-', f);
                  s--;
                  fputc('4', f);
                  s--;
                  fputc('5', f);
                  s--;
                  fputc('6', f);
                  s--;
                  fputc('-', f);
                  s--;
                  fputc('S', f);
                  s--;
                  fputc('T', f);
                  s--;
                  fputc('D', f);
                  s--;
                  for (i = 0; i < 7; i++) {
                        fputc(0, f);
                        s--;
                  }
                  fputc(1, f);
                  s--;
                  fputc(0, f);
                  s--;
                  fputc(1, f);
                  s--;
                  fputc('M', f);
                  s--;
                  fputc('Q', f);
                  s--;
                  for (i = 0; i < 14; i++) {
                        fputc(0xa0, f);
                        s--;
                  }
                  fputc(0, f);
                  s--;
                  fputc(0xff, f);
                  while (s-- > (MCD_SIZE + 1))
                        fputc(0, f);
            } else if ((buf.st_size == MCD_SIZE + 64) || strstr(mcd, ".mem") || strstr(mcd, ".vgs")) {
                  s = s + 64;
                  fputc('V', f);
                  s--;
                  fputc('g', f);
                  s--;
                  fputc('s', f);
                  s--;
                  fputc('M', f);
                  s--;
                  for (i = 0; i < 3; i++) {
                        fputc(1, f);
                        s--;
                        fputc(0, f);
                        s--;
                        fputc(0, f);
                        s--;
                        fputc(0, f);
                        s--;
                  }
                  fputc(0, f);
                  s--;
                  fputc(2, f);
                  while (s-- > (MCD_SIZE + 1))
                        fputc(0, f);
            }
      }
      fputc('M', f);
      s--;
      fputc('C', f);
      s--;
      while (s-- > (MCD_SIZE - 127))
            fputc(0, f);
      fputc(0xe, f);
      s--;

      for (i = 0; i < 15; i++) { // 15 blocks
            fputc(0xa0, f);
            s--;
            fputc(0x00, f);
            s--;
            fputc(0x00, f);
            s--;
            fputc(0x00, f);
            s--;
            fputc(0x00, f);
            s--;
            fputc(0x00, f);
            s--;
            fputc(0x00, f);
            s--;
            fputc(0x00, f);
            s--;
            fputc(0xff, f);
            s--;
            fputc(0xff, f);
            s--;
            for (j = 0; j < 117; j++) {
                  fputc(0x00, f);
                  s--;
            }
            fputc(0xa0, f);
            s--;
      }

      for (i = 0; i < 20; i++) {
            fputc(0xff, f);
            s--;
            fputc(0xff, f);
            s--;
            fputc(0xff, f);
            s--;
            fputc(0xff, f);
            s--;
            fputc(0x00, f);
            s--;
            fputc(0x00, f);
            s--;
            fputc(0x00, f);
            s--;
            fputc(0x00, f);
            s--;
            fputc(0xff, f);
            s--;
            fputc(0xff, f);
            s--;
            for (j = 0; j < 118; j++) {
                  fputc(0x00, f);
                  s--;
            }
      }

      while ((s--) >= 0)
            fputc(0, f);

      fclose(f);
}

void ConvertMcd(char *mcd, char *data) {
      FILE *f;
      int i = 0;
      int s = MCD_SIZE;

      if (strstr(mcd, ".gme")) {
            f = fopen(mcd, "wb");
            if (f != NULL) {
                  fwrite(data - 3904, 1, MCD_SIZE + 3904, f);
                  fclose(f);
            }
            f = fopen(mcd, "r+");
            s = s + 3904;
            fputc('1', f); s--;
            fputc('2', f); s--;
            fputc('3', f); s--;
            fputc('-', f); s--;
            fputc('4', f); s--;
            fputc('5', f); s--;
            fputc('6', f); s--;
            fputc('-', f); s--;
            fputc('S', f); s--;
            fputc('T', f); s--;
            fputc('D', f); s--;
            for (i = 0; i < 7; i++) {
                  fputc(0, f); s--;
            }
            fputc(1, f); s--;
            fputc(0, f); s--;
            fputc(1, f); s--;
            fputc('M', f); s--;
            fputc('Q', f); s--;
            for(i=0;i<14;i++) {
                  fputc(0xa0, f); s--;
            }
            fputc(0, f); s--;
            fputc(0xff, f);
            while (s-- > (MCD_SIZE+1)) fputc(0, f);
            fclose(f);
      } else if(strstr(mcd, ".mem") || strstr(mcd,".vgs")) {
            f = fopen(mcd, "wb");
            if (f != NULL) {
                  fwrite(data-64, 1, MCD_SIZE+64, f);
                  fclose(f);
            }
            f = fopen(mcd, "r+");
            s = s + 64;
            fputc('V', f); s--;
            fputc('g', f); s--;
            fputc('s', f); s--;
            fputc('M', f); s--;
            for(i=0;i<3;i++) {
                  fputc(1, f); s--;
                  fputc(0, f); s--;
                  fputc(0, f); s--;
                  fputc(0, f); s--;
            }
            fputc(0, f); s--;
            fputc(2, f);
            while (s-- > (MCD_SIZE+1)) fputc(0, f);
            fclose(f);
      } else {
            f = fopen(mcd, "wb");
            if (f != NULL) {
                  fwrite(data, 1, MCD_SIZE, f);
                  fclose(f);
            }
      }
}

void GetMcdBlockInfo(int mcd, int block, McdBlock *Info) {
      unsigned char *data = NULL, *ptr, *str, *sstr;
      unsigned short clut[16];
      unsigned short c;
      int i, x;

      memset(Info, 0, sizeof(McdBlock));

      if (mcd == 1) data = Mcd1Data;
      if (mcd == 2) data = Mcd2Data;

      ptr = data + block * 8192 + 2;

      Info->IconCount = *ptr & 0x3;

      ptr += 2;

      x = 0;

      str = Info->Title;
      sstr = Info->sTitle;

      for (i = 0; i < 48; i++) {
            c = *(ptr) << 8;
            c |= *(ptr + 1);
            if (!c) break;

            // Convert ASCII characters to half-width
            if (c >= 0x8281 && c <= 0x829A)
                  c = (c - 0x8281) + 'a';
            else if (c >= 0x824F && c <= 0x827A)
                  c = (c - 0x824F) + '0';
            else if (c == 0x8140) c = ' ';
            else if (c == 0x8143) c = ',';
            else if (c == 0x8144) c = '.';
            else if (c == 0x8146) c = ':';
            else if (c == 0x8147) c = ';';
            else if (c == 0x8148) c = '?';
            else if (c == 0x8149) c = '!';
            else if (c == 0x815E) c = '/';
            else if (c == 0x8168) c = '"';
            else if (c == 0x8169) c = '(';
            else if (c == 0x816A) c = ')';
            else if (c == 0x816D) c = '[';
            else if (c == 0x816E) c = ']';
            else if (c == 0x817C) c = '-';
            else {
                  str[i] = ' ';
                  sstr[x++] = *ptr++; sstr[x++] = *ptr++;
                  continue;
            }

            str[i] = sstr[x++] = c;
            ptr += 2;
      }

      trim(str);
      trim(sstr);

      ptr = data + block * 8192 + 0x60; // icon palette data

      for (i = 0; i < 16; i++) {
            clut[i] = *((unsigned short *)ptr);
            ptr += 2;
      }

      for (i = 0; i < Info->IconCount; i++) {
            short *icon = &Info->Icon[i * 16 * 16];

            ptr = data + block * 8192 + 128 + 128 * i; // icon data

            for (x = 0; x < 16 * 16; x++) {
                  icon[x++] = clut[*ptr & 0xf];
                  icon[x] = clut[*ptr >> 4];
                  ptr++;
            }
      }

      ptr = data + block * 128;

      Info->Flags = *ptr;

      ptr += 0xa;
      strncpy(Info->ID, ptr, 12);
      ptr += 12;
      strncpy(Info->Name, ptr, 16);
}

int sioFreeze(gzFile f, int Mode) {
      gzfreeze(buf, sizeof(buf));
      gzfreeze(&StatReg, sizeof(StatReg));
      gzfreeze(&ModeReg, sizeof(ModeReg));
      gzfreeze(&CtrlReg, sizeof(CtrlReg));
      gzfreeze(&BaudReg, sizeof(BaudReg));
      gzfreeze(&bufcount, sizeof(bufcount));
      gzfreeze(&parp, sizeof(parp));
      gzfreeze(&mcdst, sizeof(mcdst));
      gzfreeze(&rdwr, sizeof(rdwr));
      gzfreeze(&adrH, sizeof(adrH));
      gzfreeze(&adrL, sizeof(adrL));
      gzfreeze(&padst, sizeof(padst));

      return 0;
}

Generated by  Doxygen 1.6.0   Back to index