|
|
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.4 ! root 9: char HDC_rcsid[] = "Hatari $Id: hdc.c,v 1.6 2004/04/23 15:33:58 thothy Exp $";
1.1 root 10:
11: #include "main.h"
12: #include "debug.h"
1.1.1.3 root 13: #include "configuration.h"
1.1 root 14: #include "fdc.h"
15: #include "hdc.h"
16: #include "floppy.h"
17: #include "ikbd.h"
18: #include "m68000.h"
19: #include "memorySnapShot.h"
20: #include "mfp.h"
21: #include "misc.h"
22: #include "psg.h"
23: #include "stMemory.h"
24: #include "debugui.h"
25:
26: /*
27: ACSI emulation:
28: ACSI commands are six byte-packets sent to the
29: hard drive controller (which is on the HD unit, not in the ST)
30:
31: While the hard drive is busy, DRQ is high, polling the DRQ during
32: operation interrupts the current operation. The DRQ status can
33: be polled non-destructively in GPIP.
34:
35: (For simplicity, the operation is finished immediatly,
36: this is a potential bug, but I doubt it is significant,
37: we just appear to have a very fast hard drive.)
38:
39: The ACSI command set is a subset of the SCSI standard.
40: (for details, see the X3T9.2 SCSI draft documents
41: from 1985, for an example of writing ACSI commands,
42: see the TOS DMA boot code)
43: */
44:
45: /* #define DISALLOW_HDC_WRITE */
46: /* #define HDC_VERBOSE */ /* display operations */
47: /* #define HDC_REALLY_VERBOSE */ /* display command packets */
48:
49: /* HDC globals */
50: HDCOMMAND HDCCommand;
51: FILE *hd_image_file = NULL;
52: int nPartitions = 0;
53: short int HDCSectorCount;
54:
55: /*
1.1.1.4 ! root 56: FDC registers used:
! 57: - FDCSectorCountRegister
! 58: - DiscControllerStatus_ff8604rd
! 59: - DMAModeControl_ff8606wr
1.1 root 60: */
61:
62:
63: /* Our dummy INQUIRY response data */
1.1.1.4 ! root 64: static unsigned char inquiry_bytes[] =
1.1 root 65: {
66: 0, /* device type 0 = direct access device */
67: 0, /* device type qualifier (nonremovable) */
68: 1, /* ANSI version */
69: 0, /* reserved */
70: 26, /* length of the following data */
71: ' ', ' ', ' ', /* Vendor specific data */
72: 'H','a','t','a','r','i',' ','E', /* Vendor */
73: 'm','u','l','a','t','e','d',' ', /* Model */
74: ' ',' ',' ',' ', /* Revision */
75: 0,0,0,0,0,0,0,0,0,0 /* ?? */
76: };
77:
78: /*---------------------------------------------------------------------*/
79: /*
80: Return the file offset of the sector specified in the current
81: ACSI command block.
82: */
1.1.1.4 ! root 83: static unsigned long HDC_GetOffset(void)
! 84: {
1.1 root 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: */
1.1.1.4 ! root 100: static void HDC_Seek(void)
1.1 root 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: */
1.1.1.4 ! root 115: static void HDC_Inquiry(void)
1.1 root 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: */
1.1.1.4 ! root 131: static void HDC_WriteSector(void)
1.1 root 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: */
1.1.1.4 ! root 152: static void HDC_ReadSector(void)
1.1 root 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: */
1.1.1.4 ! root 274: static void HDC_GetInfo(void)
1.1 root 275: {
276: long offset;
277: unsigned char hdinfo[64];
278: int i;
1.1.1.2 root 279: #ifdef HDC_VERBOSE
280: unsigned long size;
281: #endif
1.1 root 282:
283: nPartitions = 0;
284: if(hd_image_file == NULL) return;
285: offset = ftell(hd_image_file);
286:
287: fseek(hd_image_file, 0x1C2, 0);
288: fread(hdinfo, 64, 1, hd_image_file);
289:
290: #ifdef HDC_VERBOSE
291: size = (((unsigned long) hdinfo[0] << 24)
292: | ((unsigned long) hdinfo[1] << 16)
293: | ((unsigned long) hdinfo[2] << 8)
294: | ((unsigned long) hdinfo[3]));
295:
296: fprintf(stderr, "Total disk size %li Mb\n", size>>11);
297: fprintf(stderr, "Partition 0 exists?: %s\n", (hdinfo[4] != 0)?"Yes":"No");
298: fprintf(stderr, "Partition 1 exists?: %s\n", (hdinfo[4+12] != 0)?"Yes":"No");
299: fprintf(stderr, "Partition 2 exists?: %s\n", (hdinfo[4+24] != 0)?"Yes":"No");
300: fprintf(stderr, "Partition 3 exists?: %s\n", (hdinfo[4+36] != 0)?"Yes":"No");
301: #endif
302:
303: for(i=0;i<4;i++)
304: if(hdinfo[4 + 12*i]) nPartitions++;
305:
306: fseek(hd_image_file, offset, 0);
307: }
308:
309: /*---------------------------------------------------------------------*/
310: /*
311: Open the disk image file, set partitions.
312: */
313: BOOL HDC_Init(char *filename)
314: {
315: if( (hd_image_file = fopen(filename, "r+")) == NULL)
316: return( FALSE );
317:
318: HDC_GetInfo();
319: if(!nPartitions)
320: {
321: fclose( hd_image_file );
322: hd_image_file = NULL;
1.1.1.3 root 323: ConfigureParams.HardDisc.bUseHardDiscImage = FALSE;
1.1 root 324: return( FALSE );
325: }
326: /* set number of partitions */
327: ConfigureParams.HardDisc.nDriveList += nPartitions;
328:
1.1.1.3 root 329: ConfigureParams.HardDisc.bUseHardDiscImage = TRUE;
330:
1.1 root 331: return( TRUE );
332: }
1.1.1.3 root 333:
1.1 root 334: /*---------------------------------------------------------------------*/
335: /*
336: HDC_UnInit - close image file
337:
338: */
1.1.1.4 ! root 339: void HDC_UnInit(void)
1.1 root 340: {
341: if(!(ACSI_EMU_ON)) return;
342: fclose(hd_image_file);
343: hd_image_file = NULL;
344: nPartitions = 0;
1.1.1.3 root 345: ConfigureParams.HardDisc.bUseHardDiscImage = FALSE;
1.1 root 346: }
347:
348: /*---------------------------------------------------------------------*/
349: /*
350: Process HDC command packets, called when bytes are
351: written to $FFFF8606 and the HDC (not the FDC) is selected.
352: */
1.1.1.4 ! root 353: void HDC_WriteCommandPacket(void)
1.1 root 354: {
355:
356: /* check status byte */
357: if(((DMAModeControl_ff8606wr & 0x0018) != 8)) return;
358:
359: /* is HDC emulation enabled? */
360: if(!(ACSI_EMU_ON)) return;
361:
362: /* command byte sent, store it. */
363: HDCCommand.command[HDCCommand.byteCount++] = (DiscControllerWord_ff8604wr&0xFF);
364:
365: /* have we recived a complete 6-byte packet yet? */
366: if(HDCCommand.byteCount >= 6){
367:
368: #ifdef HDC_REALLY_VERBOSE
369: HDC_DebugCommandPacket(stderr);
370: #endif
371:
372: /* If it's aimed for our drive, emulate it! */
373: if((HD_CONTROLLER(HDCCommand)) == 0)
374: {
375: if(HD_DRIVENUM(HDCCommand) == 0) HDC_EmulateCommandPacket();
376: }
377: else
378: {
379: FDC_SetDMAStatus(FALSE);
380: FDC_AcknowledgeInterrupt();
381: HDCCommand.returnCode = HD_STATUS_NODRIVE;
382: FDCSectorCountRegister = 0;
383: FDC_AcknowledgeInterrupt();
384: }
385:
386: HDCCommand.byteCount = 0;
387: }
388: }
389:
390:
391:
392:
393:
394:
395:
396:
397:
398:
399:
400:
401:
402:
403:
404:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.