based on hw tests busreq is affected by reset. Remove old hack too
[picodrive.git] / pico / cart.c
index ad15ab9..8614a16 100644 (file)
 #include "../unzip/unzip_stream.h"\r
 \r
 \r
-static char *rom_exts[] = { "bin", "gen", "smd", "iso" };\r
+static const char *rom_exts[] = { "bin", "gen", "smd", "iso", "sms", "gg", "sg" };\r
 \r
 void (*PicoCartUnloadHook)(void) = NULL;\r
 \r
 void (*PicoCartLoadProgressCB)(int percent) = NULL;\r
-void (*PicoCDLoadProgressCB)(int percent) = NULL; // handled in Pico/cd/cd_file.c\r
+void (*PicoCDLoadProgressCB)(const char *fname, int percent) = NULL; // handled in Pico/cd/cd_file.c\r
 \r
 static void PicoCartDetect(void);\r
 \r
@@ -71,18 +71,31 @@ static int uncompress2(void *dest, int destLen, void *source, int sourceLen)
     return inflateEnd(&stream);\r
 }\r
 \r
+static const char *get_ext(const char *path)\r
+{\r
+  const char *ext;\r
+  if (strlen(path) < 4)\r
+    return ""; // no ext\r
+\r
+  // allow 2 or 3 char extensions for now\r
+  ext = path + strlen(path) - 2;\r
+  if (ext[-1] != '.') ext--;\r
+  if (ext[-1] != '.')\r
+    return "";\r
+  return ext;\r
+}\r
+\r
 pm_file *pm_open(const char *path)\r
 {\r
   pm_file *file = NULL;\r
   const char *ext;\r
   FILE *f;\r
 \r
-  if (path == NULL) return NULL;\r
-\r
-  if (strlen(path) < 5) ext = NULL; // no ext\r
-  else ext = path + strlen(path) - 3;\r
+  if (path == NULL)\r
+    return NULL;\r
 \r
-  if (ext && strcasecmp(ext, "zip") == 0)\r
+  ext = get_ext(path);\r
+  if (strcasecmp(ext, "zip") == 0)\r
   {\r
     struct zipent *zipentry;\r
     gzFile gzf = NULL;\r
@@ -90,18 +103,19 @@ pm_file *pm_open(const char *path)
     int i;\r
 \r
     zipfile = openzip(path);\r
-\r
     if (zipfile != NULL)\r
     {\r
       /* search for suitable file (right extension or large enough file) */\r
       while ((zipentry = readzip(zipfile)) != NULL)\r
       {\r
-        if (zipentry->uncompressed_size >= 128*1024) goto found_rom_zip;\r
-        if (strlen(zipentry->name) < 5) continue;\r
+        ext = get_ext(zipentry->name);\r
+\r
+        if (zipentry->uncompressed_size >= 32*1024)\r
+          goto found_rom_zip;\r
 \r
-        ext = zipentry->name+strlen(zipentry->name)-3;\r
         for (i = 0; i < sizeof(rom_exts)/sizeof(rom_exts[0]); i++)\r
-          if (strcasecmp(ext, rom_exts[i]) == 0) goto found_rom_zip;\r
+          if (strcasecmp(ext, rom_exts[i]) == 0)\r
+            goto found_rom_zip;\r
       }\r
 \r
       /* zipfile given, but nothing found suitable for us inside */\r
@@ -112,12 +126,13 @@ found_rom_zip:
       gzf = zip2gz(zipfile, zipentry);\r
       if (gzf == NULL)  goto zip_failed;\r
 \r
-      file = malloc(sizeof(*file));\r
+      file = calloc(1, sizeof(*file));\r
       if (file == NULL) goto zip_failed;\r
       file->file  = zipfile;\r
       file->param = gzf;\r
       file->size  = zipentry->uncompressed_size;\r
       file->type  = PMT_ZIP;\r
+      strncpy(file->ext, ext, sizeof(file->ext) - 1);\r
       return file;\r
 \r
 zip_failed:\r
@@ -129,7 +144,7 @@ zip_failed:
       return NULL;\r
     }\r
   }\r
-  else if (ext && strcasecmp(ext, "cso") == 0)\r
+  else if (strcasecmp(ext, "cso") == 0)\r
   {\r
     cso_struct *cso = NULL, *tmp = NULL;\r
     int size;\r
@@ -176,7 +191,7 @@ zip_failed:
     cso->fpos_in = ftell(f);\r
     cso->fpos_out = 0;\r
     cso->block_in_buff = -1;\r
-    file = malloc(sizeof(*file));\r
+    file = calloc(1, sizeof(*file));\r
     if (file == NULL) goto cso_failed;\r
     file->file  = f;\r
     file->param = cso;\r
@@ -194,7 +209,7 @@ cso_failed:
   f = fopen(path, "rb");\r
   if (f == NULL) return NULL;\r
 \r
-  file = malloc(sizeof(*file));\r
+  file = calloc(1, sizeof(*file));\r
   if (file == NULL) {\r
     fclose(f);\r
     return NULL;\r
@@ -204,6 +219,7 @@ cso_failed:
   file->param = NULL;\r
   file->size  = ftell(f);\r
   file->type  = PMT_UNCOMPRESSED;\r
+  strncpy(file->ext, ext, sizeof(file->ext) - 1);\r
   fseek(f, 0, SEEK_SET);\r
 \r
 #ifndef __EPOC32__ // makes things worse on Symbian\r
@@ -418,37 +434,51 @@ static unsigned char *cd_realloc(void *old, int filesize)
   return rom;\r
 }\r
 \r
-static unsigned char *PicoCartAlloc(int filesize)\r
+static unsigned char *PicoCartAlloc(int filesize, int is_sms)\r
 {\r
   int alloc_size;\r
   unsigned char *rom;\r
 \r
-  if (PicoAHW & PAHW_MCD) return cd_realloc(NULL, filesize);\r
+  if (PicoAHW & PAHW_MCD)\r
+    return cd_realloc(NULL, filesize);\r
+\r
+  if (is_sms) {\r
+    // make size power of 2 for easier banking handling\r
+    int s = 0, tmp = filesize;\r
+    while ((tmp >>= 1) != 0)\r
+      s++;\r
+    if (filesize > (1 << s))\r
+      s++;\r
+    alloc_size = 1 << s;\r
+  }\r
+  else {\r
+    // align to 512K for memhandlers\r
+    alloc_size = (filesize + 0x7ffff) & ~0x7ffff;\r
+  }\r
 \r
-  alloc_size=filesize+0x7ffff;\r
-  if((filesize&0x3fff)==0x200) alloc_size-=0x200;\r
-  alloc_size&=~0x7ffff; // use alloc size of multiples of 512K, so that memhandlers could be set up more efficiently\r
-  if((filesize&0x3fff)==0x200) alloc_size+=0x200;\r
-  else if(alloc_size-filesize < 4) alloc_size+=4; // padding for out-of-bound exec protection\r
+  if (alloc_size - filesize < 4)\r
+    alloc_size += 4; // padding for out-of-bound exec protection\r
 \r
   // Allocate space for the rom plus padding\r
-  rom=(unsigned char *)malloc(alloc_size);\r
-  if(rom) memset(rom+alloc_size-0x80000,0,0x80000);\r
+  rom = calloc(alloc_size, 1);\r
   return rom;\r
 }\r
 \r
-int PicoCartLoad(pm_file *f,unsigned char **prom,unsigned int *psize)\r
+int PicoCartLoad(pm_file *f,unsigned char **prom,unsigned int *psize,int is_sms)\r
 {\r
-  unsigned char *rom=NULL; int size, bytes_read;\r
-  if (f==NULL) return 1;\r
+  unsigned char *rom;\r
+  int size, bytes_read;\r
+\r
+  if (f == NULL)\r
+    return 1;\r
 \r
-  size=f->size;\r
+  size = f->size;\r
   if (size <= 0) return 1;\r
-  size=(size+3)&~3; // Round up to a multiple of 4\r
+  size = (size+3)&~3; // Round up to a multiple of 4\r
 \r
   // Allocate space for the rom plus padding\r
-  rom=PicoCartAlloc(size);\r
-  if (rom==NULL) {\r
+  rom = PicoCartAlloc(size, is_sms);\r
+  if (rom == NULL) {\r
     elprintf(EL_STATUS, "out of memory (wanted %i)", size);\r
     return 2;\r
   }\r
@@ -478,22 +508,35 @@ int PicoCartLoad(pm_file *f,unsigned char **prom,unsigned int *psize)
     return 3;\r
   }\r
 \r
-  // maybe we are loading MegaCD BIOS?\r
-  if (!(PicoAHW & PAHW_MCD) && size == 0x20000 && (!strncmp((char *)rom+0x124, "BOOT", 4) ||\r
-       !strncmp((char *)rom+0x128, "BOOT", 4))) {\r
-    PicoAHW |= PAHW_MCD;\r
-    rom = cd_realloc(rom, size);\r
-  }\r
+  if (!is_sms)\r
+  {\r
+    // maybe we are loading MegaCD BIOS?\r
+    if (!(PicoAHW & PAHW_MCD) && size == 0x20000 && (!strncmp((char *)rom+0x124, "BOOT", 4) ||\r
+         !strncmp((char *)rom+0x128, "BOOT", 4))) {\r
+      PicoAHW |= PAHW_MCD;\r
+      rom = cd_realloc(rom, size);\r
+    }\r
 \r
-  // Check for SMD:\r
-  if (size >= 0x4200 && (size&0x3fff)==0x200 &&\r
-      ((rom[0x2280] == 'S' && rom[0x280] == 'E') || (rom[0x280] == 'S' && rom[0x2281] == 'E'))) {\r
-    DecodeSmd(rom,size); size-=0x200; // Decode and byteswap SMD\r
+    // Check for SMD:\r
+    if (size >= 0x4200 && (size&0x3fff) == 0x200 &&\r
+        ((rom[0x2280] == 'S' && rom[0x280] == 'E') || (rom[0x280] == 'S' && rom[0x2281] == 'E'))) {\r
+      elprintf(EL_STATUS, "SMD format detected.");\r
+      DecodeSmd(rom,size); size-=0x200; // Decode and byteswap SMD\r
+    }\r
+    else Byteswap(rom,size); // Just byteswap\r
+  }\r
+  else\r
+  {\r
+    if (size >= 0x4200 && (size&0x3fff) == 0x200) {\r
+      elprintf(EL_STATUS, "SMD format detected.");\r
+      // at least here it's not interleaved\r
+      size -= 0x200;\r
+      memmove(rom, rom + 0x200, size);\r
+    }\r
   }\r
-  else Byteswap(rom,size); // Just byteswap\r
 \r
-  if (prom)  *prom=rom;\r
-  if (psize) *psize=size;\r
+  if (prom)  *prom = rom;\r
+  if (psize) *psize = size;\r
 \r
   return 0;\r
 }\r
@@ -520,7 +563,7 @@ int PicoCartInsert(unsigned char *rom,unsigned int romsize)
     PicoCartUnloadHook = NULL;\r
   }\r
 \r
-  PicoAHW &= PAHW_MCD;\r
+  PicoAHW &= PAHW_MCD|PAHW_SMS;\r
 \r
   PicoMemResetHooks();\r
   PicoDmaHook = NULL;\r
@@ -531,7 +574,7 @@ int PicoCartInsert(unsigned char *rom,unsigned int romsize)
 \r
   PicoMemReset();\r
 \r
-  if (!(PicoAHW & PAHW_MCD))\r
+  if (!(PicoAHW & (PAHW_MCD|PAHW_SMS)))\r
     PicoCartDetect();\r
 \r
   // setup correct memory map for loaded ROM\r
@@ -543,15 +586,25 @@ int PicoCartInsert(unsigned char *rom,unsigned int romsize)
     case PAHW_SVP:  PicoMemSetup(); break;\r
     case PAHW_MCD:  PicoMemSetupCD(); break;\r
     case PAHW_PICO: PicoMemSetupPico(); break;\r
+    case PAHW_SMS:  PicoMemSetupMS(); break;\r
   }\r
   PicoMemReset();\r
 \r
-  PicoPower();\r
+  if (PicoAHW & PAHW_SMS)\r
+    PicoPowerMS();\r
+  else\r
+    PicoPower();\r
+\r
   return 0;\r
 }\r
 \r
 void PicoCartUnload(void)\r
 {\r
+  if (PicoCartUnloadHook != NULL) {\r
+    PicoCartUnloadHook();\r
+    PicoCartUnloadHook = NULL;\r
+  }\r
+\r
   if (Pico.rom != NULL) {\r
     SekFinishIdleDet();\r
     free(Pico.rom);\r
@@ -698,7 +751,8 @@ static void PicoCartDetect(void)
   else if ((name_cmp("ROBOCOP 3") == 0 && Pico.romsize == 0x200000) ||\r
     (rom_strcmp(0x160, "FLICKY") == 0 && Pico.romsize >= 0x200000)  ||\r
     (name_cmp(" SHOVE IT!") == 0 && Pico.romsize >= 0x200000) ||\r
-    (name_cmp("MS PACMAN") == 0 && Pico.romsize >= 0x200000)) // bad dump?\r
+    (name_cmp("MS PACMAN") == 0 && Pico.romsize >= 0x200000) || // bad dump?\r
+    (name_cmp("ALIEN 3") == 0 && Pico.romsize == 0x200000))\r
   {\r
     carthw_12in1_startup();\r
   }\r