|
|
1.1 ! root 1: /* ! 2: Hatari ! 3: ! 4: Low-level hard drive emulation ! 5: ! 6: */ ! 7: ! 8: #include "main.h" ! 9: #include "debug.h" ! 10: #include "decode.h" ! 11: #include "dialog.h" ! 12: #include "fdc.h" ! 13: #include "hdc.h" ! 14: #include "floppy.h" ! 15: #include "ikbd.h" ! 16: #include "m68000.h" ! 17: #include "memorySnapShot.h" ! 18: #include "mfp.h" ! 19: #include "misc.h" ! 20: #include "psg.h" ! 21: #include "stMemory.h" ! 22: #include "debugui.h" ! 23: ! 24: /* ! 25: ACSI emulation: ! 26: ACSI commands are six byte-packets sent to the ! 27: hard drive controller (which is on the HD unit, not in the ST) ! 28: ! 29: While the hard drive is busy, DRQ is high, polling the DRQ during ! 30: operation interrupts the current operation. The DRQ status can ! 31: be polled non-destructively in GPIP. ! 32: ! 33: (For simplicity, the operation is finished immediatly, ! 34: this is a potential bug, but I doubt it is significant, ! 35: we just appear to have a very fast hard drive.) ! 36: ! 37: The ACSI command set is a subset of the SCSI standard. ! 38: (for details, see the X3T9.2 SCSI draft documents ! 39: from 1985, for an example of writing ACSI commands, ! 40: see the TOS DMA boot code) ! 41: */ ! 42: ! 43: /* #define DISALLOW_HDC_WRITE */ ! 44: /* #define HDC_VERBOSE */ /* display operations */ ! 45: /* #define HDC_REALLY_VERBOSE */ /* display command packets */ ! 46: ! 47: /* HDC globals */ ! 48: HDCOMMAND HDCCommand; ! 49: FILE *hd_image_file = NULL; ! 50: int nPartitions = 0; ! 51: short int HDCSectorCount; ! 52: ! 53: /* ! 54: FDC registers used ! 55: */ ! 56: extern short int HDCSectorCount; ! 57: extern short int FDCSectorCountRegister; ! 58: ! 59: extern unsigned short int DiscControllerStatus_ff8604rd; /* 0xff8604 (read) */ ! 60: extern unsigned short int DiscControllerWord_ff8604wr; /* 0xff8604 (write) */ ! 61: extern unsigned short int DMAStatus_ff8606rd; /* 0xff8606 (read) */ ! 62: extern unsigned short int DMAModeControl_ff8606wr,DMAModeControl_ff8606wr_prev; /* 0xff8606 (write,store prev for 'toggle' checks) */ ! 63: ! 64: /* Our dummy INQUIRY response data */ ! 65: unsigned char inquiry_bytes[] = ! 66: { ! 67: 0, /* device type 0 = direct access device */ ! 68: 0, /* device type qualifier (nonremovable) */ ! 69: 1, /* ANSI version */ ! 70: 0, /* reserved */ ! 71: 26, /* length of the following data */ ! 72: ' ', ' ', ' ', /* Vendor specific data */ ! 73: 'H','a','t','a','r','i',' ','E', /* Vendor */ ! 74: 'm','u','l','a','t','e','d',' ', /* Model */ ! 75: ' ',' ',' ',' ', /* Revision */ ! 76: 0,0,0,0,0,0,0,0,0,0 /* ?? */ ! 77: }; ! 78: ! 79: /*---------------------------------------------------------------------*/ ! 80: /* ! 81: Return the file offset of the sector specified in the current ! 82: ACSI command block. ! 83: */ ! 84: unsigned long HDC_GetOffset(){ ! 85: unsigned long offset; ! 86: ! 87: /* construct the logical block adress */ ! 88: offset = ((HD_LBA_MSB(HDCCommand) << 16) ! 89: | (HD_LBA_MID(HDCCommand) << 8) ! 90: | (HD_LBA_LSB(HDCCommand))) ; ! 91: ! 92: /* return value in bytes */ ! 93: return(offset * 512); ! 94: } ! 95: ! 96: /*---------------------------------------------------------------------*/ ! 97: /* ! 98: Seek - move to a sector ! 99: */ ! 100: void HDC_Seek() ! 101: { ! 102: ! 103: fseek(hd_image_file, HDC_GetOffset(),0); ! 104: ! 105: FDC_SetDMAStatus(FALSE); /* no DMA error */ ! 106: FDC_AcknowledgeInterrupt(); ! 107: HDCCommand.returnCode = HD_STATUS_OK; ! 108: FDCSectorCountRegister = 0; ! 109: } ! 110: ! 111: /*---------------------------------------------------------------------*/ ! 112: /* ! 113: Inquiry - return some disk information ! 114: */ ! 115: void HDC_Inquiry() ! 116: { ! 117: inquiry_bytes[4] = HD_SECTORCOUNT(HDCCommand) - 8; ! 118: memcpy( (char *)((unsigned long)STRam+FDC_ReadDMAAddress()), inquiry_bytes, ! 119: HD_SECTORCOUNT(HDCCommand)); ! 120: ! 121: FDC_SetDMAStatus(FALSE); /* no DMA error */ ! 122: FDC_AcknowledgeInterrupt(); ! 123: HDCCommand.returnCode = HD_STATUS_OK; ! 124: FDCSectorCountRegister = 0; ! 125: } ! 126: ! 127: /*---------------------------------------------------------------------*/ ! 128: /* ! 129: Write a sector off our disk - (seek implied) ! 130: */ ! 131: void HDC_WriteSector() ! 132: { ! 133: /* seek to the position */ ! 134: fseek(hd_image_file, HDC_GetOffset(),0); ! 135: ! 136: /* write -if allowed */ ! 137: #ifndef DISALLOW_HDC_WRITE ! 138: fwrite((char *)((unsigned long)STRam+FDC_ReadDMAAddress()), ! 139: 512*HD_SECTORCOUNT(HDCCommand), 1, hd_image_file); ! 140: #endif ! 141: ! 142: FDC_SetDMAStatus(FALSE); /* no DMA error */ ! 143: FDC_AcknowledgeInterrupt(); ! 144: HDCCommand.returnCode = HD_STATUS_OK; ! 145: FDCSectorCountRegister = 0; ! 146: } ! 147: ! 148: /*---------------------------------------------------------------------*/ ! 149: /* ! 150: Read a sector off our disk - (implied seek) ! 151: */ ! 152: void HDC_ReadSector() ! 153: { ! 154: /* seek to the position */ ! 155: fseek(hd_image_file, HDC_GetOffset(),0); ! 156: ! 157: #ifdef HDC_VERBOSE ! 158: fprintf(stderr,"Reading %i sectors from 0x%lx to addr:%lx\n", HD_SECTORCOUNT(HDCCommand), HDC_GetOffset() ,FDC_ReadDMAAddress()); ! 159: #endif ! 160: ! 161: fread((char *)((unsigned long)STRam+FDC_ReadDMAAddress()), ! 162: 512*HD_SECTORCOUNT(HDCCommand), 1, hd_image_file); ! 163: ! 164: FDC_SetDMAStatus(FALSE); /* no DMA error */ ! 165: FDC_AcknowledgeInterrupt(); ! 166: HDCCommand.returnCode = HD_STATUS_OK; ! 167: FDCSectorCountRegister = 0; ! 168: } ! 169: ! 170: /*---------------------------------------------------------------------*/ ! 171: /* ! 172: Emulation routine for HDC command packets. ! 173: */ ! 174: void HDC_EmulateCommandPacket() ! 175: { ! 176: ! 177: switch(HD_OPCODE(HDCCommand)){ ! 178: ! 179: case HD_READ_SECTOR: ! 180: HDC_ReadSector(); ! 181: break; ! 182: case HD_WRITE_SECTOR: ! 183: HDC_WriteSector(); ! 184: break; ! 185: ! 186: case HD_INQUIRY: ! 187: #ifdef HDC_VERBOSE ! 188: fprintf(stderr,"Inquiry made.\n"); ! 189: #endif ! 190: HDC_Inquiry(); ! 191: break; ! 192: ! 193: case HD_SEEK: ! 194: HDC_Seek(); ! 195: break; ! 196: ! 197: case HD_SHIP: ! 198: HDCCommand.returnCode = 0xFF; ! 199: FDC_AcknowledgeInterrupt(); ! 200: break; ! 201: ! 202: /* as of yet unsupported commands */ ! 203: case HD_VERIFY_TRACK: ! 204: case HD_FORMAT_TRACK: ! 205: case HD_CORRECTION: ! 206: case HD_MODESENSE: ! 207: case HD_REQ_SENSE: ! 208: ! 209: default: ! 210: HDCCommand.returnCode = HD_STATUS_OPCODE; ! 211: FDC_AcknowledgeInterrupt(); ! 212: break; ! 213: } ! 214: } ! 215: ! 216: /*---------------------------------------------------------------------*/ ! 217: /* ! 218: Debug routine for HDC command packets. ! 219: */ ! 220: void HDC_DebugCommandPacket(FILE *hdlogFile) ! 221: { ! 222: switch(HD_OPCODE(HDCCommand)){ ! 223: case HD_VERIFY_TRACK: ! 224: fprintf(hdlogFile, "OpCode: VERIFY TRACK\n"); ! 225: break; ! 226: case HD_FORMAT_TRACK: ! 227: fprintf(hdlogFile, "OpCode: FORMAT TRACK\n"); ! 228: break; ! 229: case HD_READ_SECTOR: ! 230: fprintf(hdlogFile, "OpCode: READ SECTOR(S)\n"); ! 231: break; ! 232: case HD_WRITE_SECTOR: ! 233: fprintf(hdlogFile, "OpCode: WRITE SECTOR(S)\n"); ! 234: break; ! 235: case HD_INQUIRY: ! 236: fprintf(hdlogFile, "OpCode: INQUIRY\n"); ! 237: break; ! 238: case HD_SEEK: ! 239: fprintf(hdlogFile, "OpCode: SEEK\n"); ! 240: break; ! 241: case HD_CORRECTION: ! 242: fprintf(hdlogFile, "OpCode: CORRECTION\n"); ! 243: break; ! 244: case HD_MODESENSE: ! 245: fprintf(hdlogFile, "OpCode: MODESENSE\n"); ! 246: break; ! 247: ! 248: case HD_SHIP: ! 249: fprintf(hdlogFile, "OpCode: SHIP\n"); ! 250: break; ! 251: ! 252: case HD_REQ_SENSE: ! 253: fprintf(hdlogFile, "OpCode: MODESENSE\n"); ! 254: break; ! 255: ! 256: default: ! 257: fprintf(hdlogFile, "Unknown OpCode!! Value = %x\n", HD_OPCODE(HDCCommand)); ! 258: break; ! 259: } ! 260: fprintf(hdlogFile, "Controller: %i\n", HD_CONTROLLER(HDCCommand)); ! 261: fprintf(hdlogFile, "Drive: %i\n", HD_DRIVENUM(HDCCommand)); ! 262: fprintf(hdlogFile, "LBA: %lx\n", HDC_GetOffset()); ! 263: ! 264: fprintf(hdlogFile, "Sector count: %x\n", HD_SECTORCOUNT(HDCCommand)); ! 265: fprintf(hdlogFile, "HDC sector count: %x\n", HDCSectorCount); ! 266: fprintf(hdlogFile, "FDC sector count: %x\n", FDCSectorCountRegister); ! 267: fprintf(hdlogFile, "Control byte: %x\n", HD_CONTROL(HDCCommand)); ! 268: } ! 269: ! 270: /*---------------------------------------------------------------------*/ ! 271: /* ! 272: Print data about the hard drive image ! 273: */ ! 274: void HDC_GetInfo() ! 275: { ! 276: long offset; ! 277: unsigned char hdinfo[64]; ! 278: unsigned long size; ! 279: int i; ! 280: ! 281: nPartitions = 0; ! 282: if(hd_image_file == NULL) return; ! 283: offset = ftell(hd_image_file); ! 284: ! 285: fseek(hd_image_file, 0x1C2, 0); ! 286: fread(hdinfo, 64, 1, hd_image_file); ! 287: ! 288: #ifdef HDC_VERBOSE ! 289: size = (((unsigned long) hdinfo[0] << 24) ! 290: | ((unsigned long) hdinfo[1] << 16) ! 291: | ((unsigned long) hdinfo[2] << 8) ! 292: | ((unsigned long) hdinfo[3])); ! 293: ! 294: fprintf(stderr, "Total disk size %li Mb\n", size>>11); ! 295: fprintf(stderr, "Partition 0 exists?: %s\n", (hdinfo[4] != 0)?"Yes":"No"); ! 296: fprintf(stderr, "Partition 1 exists?: %s\n", (hdinfo[4+12] != 0)?"Yes":"No"); ! 297: fprintf(stderr, "Partition 2 exists?: %s\n", (hdinfo[4+24] != 0)?"Yes":"No"); ! 298: fprintf(stderr, "Partition 3 exists?: %s\n", (hdinfo[4+36] != 0)?"Yes":"No"); ! 299: #endif ! 300: ! 301: for(i=0;i<4;i++) ! 302: if(hdinfo[4 + 12*i]) nPartitions++; ! 303: ! 304: fseek(hd_image_file, offset, 0); ! 305: } ! 306: ! 307: /*---------------------------------------------------------------------*/ ! 308: /* ! 309: Open the disk image file, set partitions. ! 310: */ ! 311: BOOL HDC_Init(char *filename) ! 312: { ! 313: if( (hd_image_file = fopen(filename, "r+")) == NULL) ! 314: return( FALSE ); ! 315: ! 316: HDC_GetInfo(); ! 317: if(!nPartitions) ! 318: { ! 319: fclose( hd_image_file ); ! 320: hd_image_file = NULL; ! 321: return( FALSE ); ! 322: } ! 323: /* set number of partitions */ ! 324: ConfigureParams.HardDisc.nDriveList += nPartitions; ! 325: ! 326: return( TRUE ); ! 327: } ! 328: /*---------------------------------------------------------------------*/ ! 329: /* ! 330: HDC_UnInit - close image file ! 331: ! 332: */ ! 333: void HDC_UnInit() ! 334: { ! 335: if(!(ACSI_EMU_ON)) return; ! 336: fclose(hd_image_file); ! 337: hd_image_file = NULL; ! 338: nPartitions = 0; ! 339: } ! 340: ! 341: /*---------------------------------------------------------------------*/ ! 342: /* ! 343: Process HDC command packets, called when bytes are ! 344: written to $FFFF8606 and the HDC (not the FDC) is selected. ! 345: */ ! 346: void HDC_WriteCommandPacket() ! 347: { ! 348: ! 349: /* check status byte */ ! 350: if(((DMAModeControl_ff8606wr & 0x0018) != 8)) return; ! 351: ! 352: /* is HDC emulation enabled? */ ! 353: if(!(ACSI_EMU_ON)) return; ! 354: ! 355: /* command byte sent, store it. */ ! 356: HDCCommand.command[HDCCommand.byteCount++] = (DiscControllerWord_ff8604wr&0xFF); ! 357: ! 358: /* have we recived a complete 6-byte packet yet? */ ! 359: if(HDCCommand.byteCount >= 6){ ! 360: ! 361: #ifdef HDC_REALLY_VERBOSE ! 362: HDC_DebugCommandPacket(stderr); ! 363: #endif ! 364: ! 365: /* If it's aimed for our drive, emulate it! */ ! 366: if((HD_CONTROLLER(HDCCommand)) == 0) ! 367: { ! 368: if(HD_DRIVENUM(HDCCommand) == 0) HDC_EmulateCommandPacket(); ! 369: } ! 370: else ! 371: { ! 372: FDC_SetDMAStatus(FALSE); ! 373: FDC_AcknowledgeInterrupt(); ! 374: HDCCommand.returnCode = HD_STATUS_NODRIVE; ! 375: FDCSectorCountRegister = 0; ! 376: FDC_AcknowledgeInterrupt(); ! 377: } ! 378: ! 379: HDCCommand.byteCount = 0; ! 380: } ! 381: } ! 382: ! 383: ! 384: ! 385: ! 386: ! 387: ! 388: ! 389: ! 390: ! 391: ! 392: ! 393: ! 394: ! 395: ! 396: ! 397:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.