📄 hdd.c
字号:
/* MFM & IDE Hard Disk Device Driver for MMURTL.
This driver does not depend on the data stored
in CMOS RAM for drive geometry. Three routines
determine number of sectors per track,
number of cylinders, and number of heads
by actually trying to seek and/or read them.
This eliminates dependence on system proprietary
CMOS locations.
*/
#define U32 unsigned long
#define S32 long
#define U16 unsigned int
#define S16 int
#define U8 unsigned char
#define S8 char
/* MMURTL OS PROTOTYPES */
extern far AllocExch(U32 *pExchRet);
extern far U32 InitDevDr(U32 dDevNum,
S8 *pDCBs,
U32 nDevices,
U32 dfReplace);
extern far U32 UnMaskIRQ(U32 IRQNum);
extern far U32 MaskIRQ(U32 IRQNum);
extern far U32 SetIRQVector(U32 IRQNum, S8 *pIRQ);
extern far U32 EndOfIRQ(U32 IRQNum);
extern far U32 SendMsg(U32 Exch, U32 msg1, U32 msg2);
extern far U32 ISendMsg(U32 Exch, U32 msg1, U32 msg2);
extern far U32 WaitMsg(U32 Exch, U32 *pMsgRet);
extern far U32 CheckMsg(U32 Exch, U32 *pMsgRet);
extern far U32 Alarm(U32 Exch, U32 count);
extern far U32 KillAlarm(U32 Exch);
extern far U32 Sleep(U32 count);
extern far void MicroDelay(U32 us15count);
extern far void OutByte(U8 Byte, U16 wPort);
extern far void OutWord(U16 Word, U16 wPort);
extern far U8 InByte(U16 wPort);
extern far U16 InWord(U16 wPort);
extern far U8 ReadCMOS(U16 Address);
extern far void CopyData(U8 *pSource, U8 *pDestination, U32 dBytes);
extern far InWords(U32 dPort, U8 *pDataIn, U32 dBytes);
extern far OutWords(U32 dPort, U8 *pDataOut, U32 dBytes);
/* Near External for troubleshooting */
extern long xprintf(char *fmt, ...);
/* LOCAL PROTOTYPES */
void interrupt hdisk_isr(void); /* The HD interrupt function */
U32 hdisk_setup(void);
U32 hd_format_track(U32 dLBA, U32 dnBlocks);
void hd_reset(void);
U32 send_command(U8 parm);
U32 hd_wait (void);
U32 check_busy(void);
U32 hd_seek(U32 dLBA);
U32 hd_recal(U8 drive);
U32 hd_write(U32 dLBA, U32 dnBlocks, U8 *pDataOut);
U32 hd_read(U32 dLBA, U32 dnBlocks, U8 *pDataIn);
U32 hd_status(U8 LastCmd);
U32 setupseek(U32 dLBA, U32 nBlks);
U32 hd_init(U8 drive);
U32 ReadSector(U32 Cylinder, U32 HdSect, U8 *pDataRet);
/* The following 3 calls are required in every MMURTL device driver */
U32 hddev_op(U32 dDevice,
U32 dOpNum,
U32 dLBA,
U32 dnBlocks,
U8 *pData);
U32 hddev_stat(U32 dDevice,
S8 * pStatRet,
U32 dStatusMax,
U32 *pdSatusRet);
U32 hddev_init(U32 dDevNum,
S8 *pInitData,
U32 sdInitData);
/* LOCAL DEFINITIONS */
#define ok 0
/* Error Codes to return */
#define ErcNoMsg 20
#define ErcNotInstalled 504
#define ErcBadBlock 651
#define ErcAddrMark 652
#define ErcBadECC 653
#define ErcSectNotFound 654
#define ErcNoDrive0 655
#define ErcNotSupported 656
#define ErcBadHDC 658
#define ErcBadSeek 659
#define ErcHDCTimeOut 660
#define ErcOverRun 661
#define ErcBadLBA 662
#define ErcInvalidDrive 663
#define ErcBadOp 664
#define ErcBadRecal 665
#define ErcSendHDC 666
#define ErcNotReady 667
#define ErcBadCmd 668
#define ErcNeedsInit 669
#define ErcTooManyBlks 670 /* The controller can only do 128 max */
#define ErcZeroBlks 671 /* 0 Blocks not allowed for this cmd */
#define ErcWriteFault 672 /* WriteFault bit set... bummer */
#define ErcMissHDDInt 675
#define ErcHDDMsgBogus 676
#define ErcHDDIntMsg 677
#define ErcHDDAlarmMsg 678
/* Commands accepted by this HD driver */
#define CmdNull 0
#define CmdRead 1
#define CmdWrite 2
#define CmdVerify 3
#define CmdFmtBlk 4
#define CmdFmtTrk 5
#define CmdSeekTrk 6
#define CmdSetMedia 7 /* Not used unless mountable */
#define CmdResetHdw 8 /* Used to reset controller hardware */
/* CmdReadSect is the only device specific call in the IDE/MFM hard
disk device driver. This allows you to read ONE sector
specified by Cylinder, head and Sector number.
Cylinder is HiWord of dLBA in DeviceOp call,
Head is LoWord of dLBA in DeviceOp call, and
Sector number is LowWord in dnBlocks.
*/
#define CmdReadSect 256 /* only device specific call in HDD */
/* HDC port definitions */
#define HD_PORT 0x1f0
/* When writing to the port+X (where X =):
0 - write data (1F0h - 16 bit)
1 - pre-comp (1F1h)
2 - sector count (1F2h)
3 - sector number (1F3h)
4 - low cyl (1F4h)
5 - high cyl (1F5h)
6 - size/drive/head (1F6h)
7 - command register (1F7h)
When reading from the port+X (where X =):
0 - read data (1F0h - 16 bit)
1 - error register (1F1h)
2 - sector count (1F2h)
3 - sector number (1F3h)
4 - low cyl (1F4h)
5 - high cyl (1F5h)
6 - size/drive/head (1F6h)
7 - status register (1F7h)
*/
#define HD_REG_PORT 0x3f6
/* This is a byte wide write only control port
that allows reset and defines some special
characteristics of the hard drives.
Bit Desc
0 Not used
1 Not used
2 Reset Bit - Set, wait 50us, then Reset
3 Mucho Heads Flag. Set = More than 8 heads
4 Not used
5 Not used
6 Disable retries
7 Disable retries (same as six, either one set)
*/
/* HDC Status Register Bit Masks (1F7h) */
#define BUSY 0x80 /* busy.. can't talk now! */
#define READY 0x40 /* Drive Ready */
#define WRITE_FAULT 0x20 /* Bad news */
#define SEEKOK 0x10 /* Seek Complete */
#define DATA_REQ 0x08 /* Sector buffer needs servicing */
#define CORRECTED 0x04 /* ECC corrected data was read */
#define REV_INDEX 0x02 /* Set once each disk revolution */
#define ERROR 0x01 /* data address mark not found */
/* HDC Error Register Bit Masks (1F1h) */
#define BAD_SECTOR 0x80 /* bad block */
#define BAD_ECC 0x40 /* bad data ecc */
#define BAD_IDMARK 0x10 /* id not found */
#define BAD_CMD 0x04 /* aborted command */
#define BAD_SEEK 0x02 /* trk 0 not found on recalibrate, or bad seek */
#define BAD_ADDRESS 0x01 /* data address mark not found */
/* HDC internal command bytes (HDC_Cmd[7]) */
#define HDC_RECAL 0x10 /* 0001 0000 */
#define HDC_READ 0x20 /* 0010 0000 */
#define HDC_READ_LONG 0x22 /* 0010 0010 */
#define HDC_WRITE 0x30 /* 0011 0000 */
#define HDC_WRITE_LONG 0x32 /* 0011 0010 */
#define HDC_VERIFY 0x40 /* 0100 0000 */
#define HDC_FORMAT 0x50 /* 0101 0000 */
#define HDC_SEEK 0x70 /* 0111 0000 */
#define HDC_DIAG 0x90 /* 1001 0000 */
#define HDC_SET_PARAMS 0x91 /* 1001 0001 */
/* L O C A L D A T A */
U8 hd_Cmd[8]; /* For all 8 command bytes */
U8 fDataReq; /* Flag to indicate is fDataRequest is active */
U8 statbyte; /* From HDC status register last time it was read */
U8 hd_control; /* Current control byte value */
U8 hd_command; /* Current Command */
U8 hd_drive; /* Current Physical Drive, 0 or 1 */
U8 hd_head; /* Calculated from LBA - which head */
U8 hd_nsectors; /* Calculated from LBA - n sectors to read/write */
U8 hd_sector; /* Calculated from LBA - Starting sector */
/* Current type drive 0 & 1 found in CMOS or Set by caller. */
/* Current number of heads, cylinders, and sectors set by caller */
U8 hd0_type;
U8 hd0_heads;
U8 hd0_secpertrk;
U16 hd0_cyls;
U8 hd1_type;
U8 hd1_heads;
U8 hd1_secpertrk;
U16 hd1_cyls;
#define sStatus 64
struct statstruct{
U32 erc;
U32 blocks_done;
U32 BlocksMax;
U8 fNewMedia;
U8 type_now; /* current fdisk_table for drive selected */
U8 resvd0[2]; /* padding for DWord align */
U32 nCyl; /* total physical cylinders */
U32 nHead; /* total heads on device */
U32 nSectors; /* Sectors per track */
U32 nBPS; /* Number of bytes per sect. 32 bytes out to here.*/
U32 LastRecalErc0;
U32 LastSeekErc0;
U8 LastStatByte0;
U8 LastErcByte0;
U8 fIntOnReset; /* Interrupt was received on HDC_RESET */
U8 filler0;
U32 LastRecalErc1;
U32 LastSeekErc1;
U8 LastStatByte1;
U8 LastErcByte1;
U8 ResetStatByte; /* Status Byte immediately after RESET */
U8 filler1;
U32 resvd1[2]; /* out to 64 bytes */
} hdstatus;
struct statstruct HDStatTmp;
struct dcbtype {
S8 Name[12];
S8 sbName;
S8 type;
S16 nBPB;
U32 last_erc;
U32 nBlocks;
S8 *pDevOp;
S8 *pDevInit;
S8 *pDevSt;
U8 fDevReent;
U8 fSingleUser;
S16 wJob;
U32 OS1;
U32 OS2;
U32 OS3;
U32 OS4;
U32 OS5;
U32 OS6;
};
struct dcbtype hdcb[2]; /* two HD device control blocks */
/* Exch and msgs space for HD ISR */
U32 hd_exch;
U32 hd_msg;
U32 hd_msg2;
long HDDInt;
/*======================================================*/
/*=================== START OF CODE ====================*/
/*======================================================*/
/*********************************************************
This is called ONCE to initialize the HD Driver.
*********************************************************/
U32 hdisk_setup(void)
{
U32 erc;
/* first we set up the 2 DCBs in anticipation of calling InitDevDr */
hdcb[0].Name[0] = 'H';
hdcb[0].Name[1] = 'D';
hdcb[0].Name[2] = '0';
hdcb[0].sbName = 3;
hdcb[0].type = 1; /* Random */
hdcb[0].nBPB = 512;
hdcb[0].nBlocks = 524288; /* largest disk handled - 2Gb disks*/
hdcb[0].pDevOp = &hddev_op;
hdcb[0].pDevInit = &hddev_init;
hdcb[0].pDevSt = &hddev_stat;
hdcb[1].Name[0] = 'H';
hdcb[1].Name[1] = 'D';
hdcb[1].Name[2] = '1';
hdcb[1].sbName = 3;
hdcb[1].type = 1; /* Random */
hdcb[1].nBPB = 512;
hdcb[1].nBlocks = 524288; /* largest device handled - 2Gb disks*/
hdcb[1].pDevOp = &hddev_op;
hdcb[1].pDevInit = &hddev_init;
hdcb[1].pDevSt = &hddev_stat;
/* These are defaulted to non zero values to
ensure we don't get a divide by zero during initial calculations
on the first read.
*/
hd0_type = ReadCMOS(0x19);
hd0_heads = 16; /* Max */
hd0_secpertrk = 17; /* most common */
hd0_cyls = 1024; /* Max */
hd1_type = ReadCMOS(0x1A);
hd1_heads = 16;
hd1_secpertrk = 17;
hd1_cyls = 1024;
erc = AllocExch(&hd_exch); /* Exhange for HD Task to use */
SetIRQVector(14, &hdisk_isr);
UnMaskIRQ(14);
/* Documentation lists the fixed disk types at CMOS 11h and 12h,
and also shows them at 19h and 1Ah. We don't actually read them
because they are not dependable. They vary from BIOS to BIOS.
We have to make this sucker work the hard way.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -