/* Copyright 2008, 2009 Jakub Bednarski This file is part of Minimig Minimig 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 3 of the License, or (at your option) any later version. Minimig 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, see . */ // 2009-11-22 - read/write multiple implemented // 2020-11-14 - AMR: Simplified and combined read / readm + write / writem. AROS IDE now works. #ifdef __GNUC__ #include "AT91SAM7S256.h" #include "stdio.h" #include "string.h" #else #include #include #endif #include "errors.h" #include "hardware.h" #include "fat.h" #include "hdd.h" #include "hdd_internal.h" #include "mmc.h" #include "menu.h" #include "fpga.h" #include "debug.h" #define SWAP(a) ((((a)&0x000000ff)<<24)|(((a)&0x0000ff00)<<8)|(((a)&0x00ff0000)>>8)|(((a)&0xff000000)>>24)) hardfileTYPE *hardfile[2]; // hardfile structure hdfTYPE hdf[2]; // we scan for RDB without mounting the file as a unit, so need a file struct specifically for this task fileTYPE rdbfile; static void SwapBytes(char *c, unsigned int len) { char temp; while(len) { temp = *c; *c=c[1]; c[1]=temp; len-=2; c+=2; } } // RDBChecksum() static void RDBChecksum(unsigned long *p) { unsigned long count=p[1]; unsigned long c2; long result=0; p[2]=0; for(c2=0;c2rdb_ID = 'R'<<24 | 'D' << 16 | 'S' << 8 | 'K'; rdb->rdb_Summedlongs=0x40; rdb->rdb_HostID=0x07; rdb->rdb_BlockBytes=0x200; rdb->rdb_Flags=0x12; // (Disk ID valid, no LUNs after this one) rdb->rdb_BadBlockList=0xffffffff; // We don't provide a bad block list rdb->rdb_PartitionList=1; rdb->rdb_FileSysHeaderList=0xffffffff; rdb->rdb_DriveInit=0xffffffff; rdb->rdb_Reserved1[0]=0xffffffff; rdb->rdb_Reserved1[1]=0xffffffff; rdb->rdb_Reserved1[2]=0xffffffff; rdb->rdb_Reserved1[3]=0xffffffff; rdb->rdb_Reserved1[4]=0xffffffff; rdb->rdb_Reserved1[5]=0xffffffff; rdb->rdb_Cylinders=hdf[unit].cylinders; rdb->rdb_Sectors=hdf[unit].sectors; rdb->rdb_Heads=hdf[unit].heads; rdb->rdb_Interleave=1; rdb->rdb_Park=rdb->rdb_Cylinders; rdb->rdb_WritePreComp=rdb->rdb_Cylinders; rdb->rdb_ReducedWrite=rdb->rdb_Cylinders; rdb->rdb_StepRate=3; rdb->rdb_RDBBlocksLo=0; rdb->rdb_RDBBlocksHi=1; rdb->rdb_LoCylinder=1; rdb->rdb_HiCylinder=rdb->rdb_Cylinders-1; rdb->rdb_CylBlocks=rdb->rdb_Heads * rdb->rdb_Sectors; rdb->rdb_AutoParkSeconds=0; rdb->rdb_HighRDSKBlock=1; strcpy(rdb->rdb_DiskVendor,"Do not "); strcpy(rdb->rdb_DiskProduct, "repartition!"); // swap byte order of strings to be able to "unswap" them after checksum unsigned long *p = (unsigned long*)rdb; for(i=0;i<(8+16)/4;i++) p[40+i] = SWAP(p[40+i]); RDBChecksum((unsigned long *)rdb); // swap byte order of first 0x40 long values for(i=0;i<0x40;i++) p[i] = SWAP(p[i]); break; } case 1: { // Partition hdd_debugf("FAKE: Partition"); struct PartitionBlock *pb=(struct PartitionBlock *)sector_buffer; pb->pb_ID = 'P'<<24 | 'A' << 16 | 'R' << 8 | 'T'; pb->pb_Summedlongs=0x40; pb->pb_HostID=0x07; pb->pb_Next=0xffffffff; pb->pb_Flags=0x1; // bootable pb->pb_DevFlags=0; strcpy(pb->pb_DriveName,unit?"1HD\003":"0HD\003"); // "DH0"/"DH1" BCPL string pb->pb_Environment.de_TableSize=0x10; pb->pb_Environment.de_SizeBlock=0x80; pb->pb_Environment.de_Surfaces=hdf[unit].heads; pb->pb_Environment.de_SectorPerBlock=1; pb->pb_Environment.de_BlocksPerTrack=hdf[unit].sectors; pb->pb_Environment.de_Reserved=2; pb->pb_Environment.de_LowCyl=1; pb->pb_Environment.de_HighCyl=hdf[unit].cylinders-1; pb->pb_Environment.de_NumBuffers=30; pb->pb_Environment.de_MaxTransfer=0xffffff; pb->pb_Environment.de_Mask=0x7ffffffe; pb->pb_Environment.de_DosType=0x444f5301; RDBChecksum((unsigned long *)pb); // swap byte order of first 0x40 entries unsigned long *p = (unsigned long*)pb; for(i=0;i<0x40;i++) p[i] = SWAP(p[i]); break; } default: { break; } } } // IdentifiyDevice() // builds Identify Device struct void IdentifyDevice(unsigned short *pBuffer, unsigned char unit) { char *p, i, x; unsigned long total_sectors = hdf[unit].cylinders * hdf[unit].heads * hdf[unit].sectors; memset(pBuffer, 0, 512); switch(hdf[unit].type) { case HDF_FILE | HDF_SYNTHRDB: case HDF_FILE: pBuffer[0] = 1 << 6; // hard disk pBuffer[1] = hdf[unit].cylinders; // cyl count pBuffer[3] = hdf[unit].heads; // head count pBuffer[6] = hdf[unit].sectors; // sectors per track // FIXME - can get serial no from card itself. memcpy((char*)&pBuffer[10], "iMTSiMiniMHgrafdli e", 20); // serial number - byte swapped memcpy((char*)&pBuffer[23], ".100 ", 8); // firmware version - byte swapped p = (char*)&pBuffer[27]; // FIXME - likewise the model name can be fetched from the card. if (hdf[unit].type & HDF_SYNTHRDB) { memcpy(p, "DON'T ", 40); p += 8; memcpy(p, "REPARTITION! ", 16); } else { memcpy(p, "YAQUBE ", 40); // model name - byte swapped p += 8; if (hardfile[unit]->long_name[0]) { for (i = 0; (x = hardfile[unit]->long_name[i]) && i < 16; i++) // copy file name as model name p[i] = x; } else { memcpy(p, hardfile[unit]->name, 8); // copy file name as model name } } SwapBytes((char*)&pBuffer[27], 40); break; case HDF_CARD: case HDF_CARDPART0: case HDF_CARDPART1: case HDF_CARDPART2: case HDF_CARDPART3: pBuffer[0] = 1 << 6; // hard disk pBuffer[1] = hdf[unit].cylinders; // cyl count pBuffer[3] = hdf[unit].heads; // head count pBuffer[6] = hdf[unit].sectors; // sectors per track // FIXME - can get serial no from card itself. memcpy((char*)&pBuffer[10], "iMTSiMiniMSg0D ", 20); // serial number - byte swapped pBuffer[23]+=hdf[unit].type-HDF_CARD; memcpy((char*)&pBuffer[23], ".100 ", 8); // firmware version - byte swapped p = (char*)&pBuffer[27]; // FIXME - likewise the model name can be fetched from the card. memcpy(p, "YAQUBE ", 40); // model name - byte swapped p += 8; if (hdf[unit].type==HDF_CARD) memcpy(p, "SD/MMC Card", 11); // copy file name as model name else { memcpy(p, "Card Part 1", 11); // copy file name as model name p[10]+=hdf[unit].partition; } SwapBytes((char*)&pBuffer[27], 40); break; } pBuffer[47] = 0x8010; // maximum sectors per block in Read/Write Multiple command pBuffer[53] = 1; pBuffer[54] = hdf[unit].cylinders; pBuffer[55] = hdf[unit].heads; pBuffer[56] = hdf[unit].sectors; pBuffer[57] = (unsigned short)total_sectors; pBuffer[58] = (unsigned short)(total_sectors >> 16); } // chs2lba() unsigned long chs2lba(unsigned short cylinder, unsigned char head, unsigned short sector, unsigned char unit) { return(cylinder * hdf[unit].heads + head) * hdf[unit].sectors + sector - 1; } // WriteTaskFile() void WriteTaskFile(unsigned char error, unsigned char sector_count, unsigned char sector_number, unsigned char cylinder_low, unsigned char cylinder_high, unsigned char drive_head) { EnableFpga(); SPI(CMD_IDE_REGS_WR); // write task file registers command SPI(0x00); SPI(0x00); // dummy SPI(0x00); SPI(0x00); // dummy SPI(0x00); SPI(0x00); // dummy SPI(0x00); SPI(0x00); SPI(error); // error SPI(0x00); SPI(sector_count); // sector count SPI(0x00); SPI(sector_number); // sector number SPI(0x00); SPI(cylinder_low); // cylinder low SPI(0x00); SPI(cylinder_high); // cylinder high SPI(0x00); SPI(drive_head); // drive/head DisableFpga(); } // WriteStatus() void WriteStatus(unsigned char status) { EnableFpga(); SPI(CMD_IDE_STATUS_WR); SPI(status); SPI(0x00); SPI(0x00); SPI(0x00); SPI(0x00); DisableFpga(); } // ATA_Recalibrate() static inline void ATA_Recalibrate(unsigned char* tfr, unsigned char unit) { // Recalibrate 0x10-0x1F (class 3 command: no data) hdd_debugf("IDE%d: Recalibrate", unit); WriteTaskFile(0, 0, 1, 0, 0, tfr[6] & 0xF0); WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ); } // ATA_Diagnostic() static inline void ATA_Diagnostic(unsigned char* tfr) { // Execute Drive Diagnostic (0x90) hdd_debugf("IDE: Drive Diagnostic"); WriteTaskFile(1, 0, 0, 0, 0, 0); WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ); } // ATA_IdentifyDevice() static inline void ATA_IdentifyDevice(unsigned char* tfr, unsigned char unit, unsigned short* id) { int i; // Identify Device (0xec) hdd_debugf("IDE%d: Identify Device", unit); IdentifyDevice(id, unit); WriteTaskFile(0, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]); WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type EnableFpga(); SPI(CMD_IDE_DATA_WR); // write data command SPI(0x00); SPI(0x00); SPI(0x00); SPI(0x00); SPI(0x00); for (i = 0; i < 256; i++) { SPI((unsigned char)id[i]); SPI((unsigned char)(id[i] >> 8)); } DisableFpga(); WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ); } // ATA_Initialize() static inline void ATA_Initialize(unsigned char* tfr, unsigned char unit) { // Initialize Device Parameters (0x91) hdd_debugf("Initialize Device Parameters"); hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]); WriteTaskFile(0, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]); WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ); } // ATA_SetMultipleMode() static inline void ATA_SetMultipleMode(unsigned char* tfr, unsigned char unit) { // Set Multiple Mode (0xc6) hdd_debugf("Set Multiple Mode"); hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]); hdf[unit].sectors_per_block = tfr[2]; WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ); } // ATA_ReadSectors() static inline void ATA_ReadSectors(unsigned char* tfr, unsigned short sector, unsigned short cylinder, unsigned char head, unsigned char unit, unsigned short sector_count, unsigned char multiple) { // Read Sectors (0x20) long lba; int i; int block_count; lba=chs2lba(cylinder, head, sector, unit); hdd_debugf("IDE%d: read %d.%d.%d, %d", unit, cylinder, head, sector, sector_count); while (sector_count) { block_count = multiple ? sector_count : 1; if (multiple && block_count > hdf[unit].sectors_per_block) block_count = hdf[unit].sectors_per_block; WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type while (!(GetFPGAStatus() & CMD_IDECMD)); // wait for empty sector buffer WriteStatus(IDE_STATUS_IRQ); switch(hdf[unit].type) { case HDF_FILE | HDF_SYNTHRDB: case HDF_FILE: if (hdf[unit].file.size) { int blk=block_count; // Deal with FakeRDB and the potential for a read_multiple to cross the boundary into actual data. while(blk && (lba+hdf[unit].offset<0 || ((unit == 0) && (hdf[unit].type == HDF_FILE) && (lba == 0)))) { if ((lba+hdf[unit].offset) < 0) FakeRDB(unit,lba); else // Adjust flags of a real RDB if present. Is this necessary? If it worked before it was accidental due to malformed "if" { HardFileSeek(&hdf[unit], lba + hdf[unit].offset); // read sector into buffer FileRead(&hdf[unit].file, sector_buffer); FileSeek(&hdf[unit].file, 1, SEEK_CUR); // next sector // adjust checksum by the difference between old and new flag value struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)sector_buffer; rdb->rdb_ChkSum = SWAP(SWAP(rdb->rdb_ChkSum) + SWAP(rdb->rdb_Flags) - 0x12); // adjust flags rdb->rdb_Flags=SWAP(0x12); } EnableFpga(); spi8(CMD_IDE_DATA_WR); // write data command spi_n(0x00, 5); spi_block_write(sector_buffer); DisableFpga(); ++lba; --blk; } if(blk) // Any blocks left? { HardFileSeek(&hdf[unit], lba + hdf[unit].offset); FileReadEx(&hdf[unit].file, 0, blk); // NULL enables direct transfer to the FPGA lba+=blk; } } else WriteStatus(IDE_STATUS_RDY|IDE_STATUS_ERR); break; case HDF_CARD: case HDF_CARDPART0: case HDF_CARDPART1: case HDF_CARDPART2: case HDF_CARDPART3: MMC_ReadMultiple(lba+hdf[unit].offset,0,block_count); lba+=block_count; break; } /* Advance CHS address - address of last read remains. */ while(block_count--) { if (sector_count!=1) { if (sector == hdf[unit].sectors) { sector = 1; head++; if (head == hdf[unit].heads) { head = 0; cylinder++; } } else sector++; } --sector_count; } /* Update task file with CHS address */ WriteTaskFile(0, tfr[2], sector, cylinder, (cylinder >> 8), (tfr[6] & 0xF0) | head); } WriteStatus(IDE_STATUS_END); } // ATA_WriteSectors() static inline void ATA_WriteSectors(unsigned char* tfr, unsigned short sector, unsigned short cylinder, unsigned char head, unsigned char unit, unsigned short sector_count, char multiple) { unsigned short i; unsigned short block_count; long lba=chs2lba(cylinder, head, sector, unit); // write sectors WriteStatus(IDE_STATUS_REQ); // pio out (class 2) command type hdd_debugf("IDE%d: write %d.%d.%d, %d", unit, cylinder, head, sector, sector_count); //if (hdf[unit].type>=HDF_CARDPART0) lba+=hdf[unit].offset; if (hdf[unit].file.size) { // File size will be 0 in direct card modes HardFileSeek(&hdf[unit], (lba>-1) ? lba : 0); } while (sector_count) { block_count = multiple ? sector_count : 1; if (multiple && block_count > hdf[unit].sectors_per_block) block_count = hdf[unit].sectors_per_block; while(block_count--) { while (!(GetFPGAStatus() & CMD_IDEDAT)); // wait for full write buffer EnableFpga(); SPI(CMD_IDE_DATA_RD); // read data command SPI(0x00); SPI(0x00); SPI(0x00); SPI(0x00); SPI(0x00); for (i = 0; i < 512; i++) sector_buffer[i] = SPI(0xFF); DisableFpga(); switch(hdf[unit].type) { case HDF_FILE | HDF_SYNTHRDB: case HDF_FILE: if (hdf[unit].file.size && (lba>-1)) { // Don't attempt to write to fake RDB FileWrite(&hdf[unit].file, sector_buffer); FileSeek(&hdf[unit].file, 1, SEEK_CUR); } lba++; break; case HDF_CARD: case HDF_CARDPART0: case HDF_CARDPART1: case HDF_CARDPART2: case HDF_CARDPART3: MMC_Write(lba,sector_buffer); lba++; break; } // decrease sector count if (sector_count!=1) { if (sector == hdf[unit].sectors) { sector = 1; head++; if (head == hdf[unit].heads) { head = 0; cylinder++; } } else { sector++; } } sector_count--; // decrease sector count } WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head); if (sector_count) WriteStatus(IDE_STATUS_IRQ); else WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ); } } // HandleHDD() void HandleHDD(unsigned char c1, unsigned char c2) { unsigned short id[256]; unsigned char tfr[8]; unsigned short i; unsigned short sector; unsigned short cylinder; unsigned char head; unsigned char unit; unsigned short sector_count; if (c1 & CMD_IDECMD) { DISKLED_ON; EnableFpga(); SPI(CMD_IDE_REGS_RD); // read task file registers SPI(0x00); SPI(0x00); SPI(0x00); SPI(0x00); SPI(0x00); for (i = 0; i < 8; i++) { SPI(0); tfr[i] = SPI(0); } DisableFpga(); unit = tfr[6] & 0x10 ? 1 : 0; // master/slave selection if (0) hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]); if (!hardfile[unit]->present) { hdd_debugf("IDE%d: not present", unit); WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ | IDE_STATUS_ERR); DISKLED_OFF; return; } sector = tfr[3]; cylinder = tfr[4] | (tfr[5] << 8); head = tfr[6] & 0x0F; sector_count = tfr[2]; if (sector_count == 0) sector_count = 0x100; if ((tfr[7] & 0xF0) == ACMD_RECALIBRATE) { ATA_Recalibrate(tfr, unit); } else if (tfr[7] == ACMD_DIAGNOSTIC) { ATA_Diagnostic(tfr); } else if (tfr[7] == ACMD_IDENTIFY_DEVICE) { ATA_IdentifyDevice(tfr, unit, id); } else if (tfr[7] == ACMD_INITIALIZE_DEVICE_PARAMETERS) { ATA_Initialize(tfr, unit); } else if (tfr[7] == ACMD_SET_MULTIPLE_MODE) { ATA_SetMultipleMode(tfr, unit); } else if (tfr[7] == ACMD_READ_SECTORS) { ATA_ReadSectors(tfr, sector, cylinder, head, unit, sector_count,0); } else if (tfr[7] == ACMD_READ_MULTIPLE) { ATA_ReadSectors(tfr, sector, cylinder, head, unit, sector_count,1); } else if (tfr[7] == ACMD_WRITE_SECTORS) { ATA_WriteSectors(tfr, sector, cylinder, head, unit, sector_count,0); } else if (tfr[7] == ACMD_WRITE_MULTIPLE) { ATA_WriteSectors(tfr, sector, cylinder, head, unit, sector_count,1); } else { hdd_debugf("Unknown ATA command"); hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]); WriteTaskFile(0x04, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]); WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ | IDE_STATUS_ERR); } DISKLED_OFF; } } // GetHardfileGeometry() // this function comes from WinUAE, should return the same CHS as WinUAE void GetHardfileGeometry(hdfTYPE *pHDF) { unsigned long total=0; unsigned long i, head, cyl, spt; unsigned long sptt[] = { 63, 127, 255, 0 }; unsigned long cyllimit=65535; switch(pHDF->type) { case (HDF_FILE | HDF_SYNTHRDB): if (pHDF->file.size == 0) return; // For WinUAE generated hardfiles we have a fixed sectorspertrack of 32, number of heads and cylinders are variable. // Make a first guess based on 1 head, then refine that guess until the geometry gives a plausible number of // cylinders and also has the correct number of blocks. total = pHDF->file.size / 512; pHDF->sectors = 32; head=1; cyl = total/32; cyllimit-=1; // Need headroom for an RDB while(head<16 && (cyl>cyllimit || (head*cyl*32)!=total)) { ++head; cyl=total/(32*head); } pHDF->heads = head; pHDF->cylinders = cyl+1; // Add a cylinder for the fake RDB. if ((head*cyl*32)==total) // Does the geometry match the size of the underlying hard file? return; // If not, fall back to regular hardfile geometry aproximations... break; case HDF_FILE: if (pHDF->file.size == 0) return; total = pHDF->file.size / 512; break; case HDF_CARD: total = MMC_GetCapacity(); // GetCapacity returns number of blocks, not bytes. break; case HDF_CARDPART0: case HDF_CARDPART1: case HDF_CARDPART2: case HDF_CARDPART3: total = partitions[pHDF->partition].sectors; break; default: break; } for (i = 0; sptt[i] != 0; i++) { spt = sptt[i]; for (head = 4; head <= 16; head++) { cyl = total / (head * spt); if (total <= 1024 * 1024) { if (cyl <= 1023) break; } else { if (cyl < 16383) break; if (cyl < 32767 && head >= 5) break; if (cyl <= cyllimit) // Should there some head constraint here? break; } } if (head <= 16) break; } if(pHDF->type == (HDF_FILE | HDF_SYNTHRDB)) ++cyl; // Add an extra cylinder for the fake RDB pHDF->cylinders = (unsigned short)cyl; pHDF->heads = (unsigned short)head; pHDF->sectors = (unsigned short)spt; } // BuildHardfileIndex() void BuildHardfileIndex(hdfTYPE *pHDF) { // builds index to speed up hard file seek fileTYPE *file = &pHDF->file; unsigned long *index = pHDF->index; unsigned long i; unsigned long j; pHDF->index_size = 16; // indexing size j = 1 << pHDF->index_size; i = pHDF->file.size >> 10; // divided by index table size (1024) while (j < i) { // find greater or equal power of two j <<= 1; pHDF->index_size++; } for (i = 0; i < file->size; i += j) { FileSeek(file, i >> 9, SEEK_SET); // FileSeek seeks in 512-byte sectors *index++ = file->cluster; } } // HardFileSeek() unsigned char HardFileSeek(hdfTYPE *pHDF, unsigned long lba) { if ((pHDF->file.sector ^ lba) & cluster_mask) { // different clusters if ((pHDF->file.sector > lba) || ((pHDF->file.sector ^ lba) & (cluster_mask << (fat32 ? 7 : 8)))) { // 7: 128 FAT32 links per sector, 8: 256 FAT16 links per sector // requested cluster lies before current pointer position or in different FAT sector pHDF->file.cluster = pHDF->index[lba >> (pHDF->index_size - 9)];// minus 9 because lba is in 512-byte sectors pHDF->file.sector = lba & (-1 << (pHDF->index_size - 9)); } } return FileSeek(&pHDF->file, lba, SEEK_SET); } // OpenHardfile() unsigned char OpenHardfile(unsigned char unit) { unsigned long time; char filename[12]; switch(hardfile[unit]->enabled) { case HDF_FILE | HDF_SYNTHRDB: case HDF_FILE: hdf[unit].type=hardfile[unit]->enabled; strncpy(filename, hardfile[unit]->name, 8); strcpy(&filename[8], "HDF"); if (filename[0]) { if (FileOpen(&hdf[unit].file, filename)) { GetHardfileGeometry(&hdf[unit]); hdd_debugf("HARDFILE %d:", unit); hdd_debugf("file: \"%.8s.%.3s\"", hdf[unit].file.name, &hdf[unit].file.name[8]); hdd_debugf("size: %lu (%lu MB)", hdf[unit].file.size, hdf[unit].file.size >> 20); hdd_debugf("CHS: %u.%u.%u", hdf[unit].cylinders, hdf[unit].heads, hdf[unit].sectors); hdd_debugf(" (%lu MB)", ((((unsigned long) hdf[unit].cylinders) * hdf[unit].heads * hdf[unit].sectors) >> 11)); time = GetTimer(0); BuildHardfileIndex(&hdf[unit]); time = GetTimer(0) - time; hdd_debugf("Hardfile indexed in %lu ms", time >> 16); if (hardfile[unit]->enabled & HDF_SYNTHRDB) { hdf[unit].offset=-(hdf[unit].heads*hdf[unit].sectors); } else { hdf[unit].offset=0; } hardfile[unit]->present = 1; return 1; } } break; case HDF_CARD: hdf[unit].type=HDF_CARD; hardfile[unit]->present = 1; hdf[unit].file.size=0; hdf[unit].offset=0; GetHardfileGeometry(&hdf[unit]); return 1; break; case HDF_CARDPART0: case HDF_CARDPART1: case HDF_CARDPART2: case HDF_CARDPART3: hdf[unit].type=hardfile[unit]->enabled; hdf[unit].partition=hdf[unit].type-HDF_CARDPART0; hardfile[unit]->present = 1; hdf[unit].file.size=0; hdf[unit].offset=partitions[hdf[unit].partition].startlba; GetHardfileGeometry(&hdf[unit]); return 1; break; } hardfile[unit]->present = 0; return 0; } // GetHDFFileType() unsigned char GetHDFFileType(char *filename) { if (FileOpen(&rdbfile,filename)) { int i; for(i=0;i<16;++i) { FileRead(&rdbfile,sector_buffer); FileSeek(&rdbfile,512,SEEK_CUR); if (sector_buffer[0]=='R' && sector_buffer[1]=='D' && sector_buffer[2]=='S' && sector_buffer[3]=='K') return(HDF_FILETYPE_RDB); if (sector_buffer[0]=='D' && sector_buffer[1]=='O' && sector_buffer[2]=='S') return(HDF_FILETYPE_DOS); if (sector_buffer[0]=='P' && sector_buffer[1]=='F' && sector_buffer[2]=='S') return(HDF_FILETYPE_DOS); if (sector_buffer[0]=='S' && sector_buffer[1]=='F' && sector_buffer[2]=='S') return(HDF_FILETYPE_DOS); } return(HDF_FILETYPE_UNKNOWN); } return(HDF_FILETYPE_NOTFOUND); }