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