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