/* SetCPU V1.60 by Dave Haynie, April 13, 1990 Released to the Public Domain MISC.C MODULE This module is responsible for managing ROM image patchs. */ #include "setcpu.h" /* ====================================================================== */ /* This replaces the Lattice "stricmp()" function, plus it's a better form for my needs here. */ LONG striequ(s1,s2) char *s1,*s2; { LONG aok = FALSE; while (*s1 && *s2 && (aok = (*s1++ & 0xdf) == (*s2++ & 0xdf))); return (LONG) (!*s1 && !*s2 && aok); } LONG strniequ(s1,s2,n) char *s1,*s2; unsigned n; { LONG aok = FALSE; while (n-- && *s1 && *s2 && (aok = (*s1++ & 0xdf) == (*s2++ & 0xdf))); return aok; } /* ====================================================================== */ /* The device I/O functions. */ /* This routine turns off the motor. */ void MotorOff(req) struct IOStdReq *req; { req->io_Length = 0L; req->io_Command = TD_MOTOR; (void)DoIO((struct IORequest *)req); } /* This function fills the buffer "buf" with the contents of the given sector number. Returns 0 if there's no error. */ BYTE ReadBuf(buf,sect,req) char *buf; LONG sect; struct IOStdReq *req; { req->io_Length = 512L; req->io_Data = (APTR) buf; req->io_Command = CMD_READ; req->io_Offset = (512L * sect); (void)DoIO((struct IORequest *)req); return req->io_Error; } /* This function takes in a DOS name, and returns either the trackdisk.device unit that it corresponds to, or -1L. */ LONG CheckTDDev(name) char *name; { char *devname; struct DosLibrary *dl; struct RootNode *dr; struct DosInfo *di; struct DeviceNode *dev; struct FileSysStartupMsg *start; struct DosEnvec *env; dl = (struct DosLibrary *)OpenLibrary("dos.library",0L); dr = (struct RootNode *)dl->dl_Root; di = (struct DosInfo *)BADDR(dr->rn_Info); dev = (struct DeviceNode *)BADDR(di->di_DevInfo); CloseLibrary((struct Library *)dl); /* Next we find the device */ if (name[strlen(name)-1] == ':') name[strlen(name)-1] = '\0'; for (; dev != NULL; dev = (struct DeviceNode *)BADDR(dev->dn_Next)) { if (dev->dn_Type != DLT_DEVICE) continue; devname = (char *)BADDR(dev->dn_Name); if (strniequ(name,devname+1,(unsigned)devname[0])) break; } /* Is it a valid trackdisk.device? */ if (!dev) return -1L; if (!(start = (struct FileSysStartupMsg *)BADDR(dev->dn_Startup))) return -1L; env = (struct DosEnvec *)BADDR(start->fssm_Environ); if (env->de_BlocksPerTrack != 11L || env->de_LowCyl != 0L) return -1L; devname = (char *)BADDR(start->fssm_Device); if (!strniequ(devname+1,"trackdisk.device",16)) return -1L; return start->fssm_Unit; } /* ====================================================================== */ /* The patch manager stuff. */ /* The "JSR address" opcode used for my patches. */ #define JSR_OPCODE 0x4eb9 /* These are for some string patches */ static char DiskS[] = "SALV to recover it! "; /* These are the V1.3 patches */ struct pitem PL_345[] = { { PT_KEYBOARD,0,0x2528a, 0L, NULL }, /* Keyboard... */ { PT_STRING, 0,0x3fe19, 20L, (UWORD *)DiskS }, /* "DiskDoctor" name */ { PT_END, 0, 0, 0L, NULL } }; struct pitem PL_33180[] = { { PT_KEYBOARD,0,0x2572a, 0L, NULL }, /* Keyboard... */ { PT_STRING, 0,0x3fe11, 20L, (UWORD *)DiskS }, /* "DiskDoctor" name */ { PT_END, 0, 0, 0L, NULL } }; /* This is main system patch list. */ struct patch SystemPatch[] = { { &SystemPatch[1], &PL_345[0],34,5 }, { NULL, &PL_33180[0],33,180 } }; /* This is a pointer to the base of the last applied patch, for making patch links. The structure of any applied allocated patch, such as a JSR patch, is a link pointer, the actual patch size, and then the patch code. This lets any version of SetCPU remove allocated patches from any other version, providing it can locate the tag. */ struct MemChunk *lastpatch = NULL; /* This routine applys the patch */ LONG AddPatch(rom,lst,tag) ULONG rom; struct patch *lst; struct systag *tag; { UWORD *kickver = (UWORD *)(0x100000C - ( * (ULONG *) 0xFFFFEC )); UWORD *addr, *base; struct pitem *item; struct MemChunk *chunk; LONG any = FALSE; while (lst) { if (lst->Version == kickver[0] && lst->Revision == kickver[1]) { for (item = &lst->list[0]; item->Type != PT_END; ++item) { any = TRUE; switch (item->Type) { case PT_IGNORE : break; case PT_STRING : MemCopy(item->Code,(char *)(rom+item->Offset),item->Length); ++tag->patches; break; case PT_JSR : chunk = (struct MemChunk *)AllocMem(item->Length+14L,0L); chunk->mc_Next = lastpatch; lastpatch = chunk; chunk->mc_Bytes = item->Length+14L; addr = (UWORD *)(((ULONG)chunk)+8L); base = (UWORD *)(rom+item->Offset); MemCopy(base,addr,6L); base[0] = (UWORD)JSR_OPCODE; base[1] = (UWORD)(((ULONG)addr)>>16L); base[2] = (UWORD)(((ULONG)addr)&0x0ffff); MemCopy(item->Code,&addr[3],item->Length); ++tag->patches; break; } } } lst = lst->next; } return any; }