📄 fdd.c
字号:
/* Floppy Disk Device Driver for MMURTL */
/*
MMURTL Operating System Source Code
Copyright 1991,1992,1993, Richard A. Burgess
ALL RIGHTS RESERVED
Version x0.8
*/
#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 SpawnTask(S8 *pEntry,
U32 dPriority,
U32 fDebug,
S8 *pStack,
U32 fOSCode);
extern far U32 AllocExch(U32 *pExchRet);
extern far U32 InitDevDr(U32 dDevNum,
S8 *pDCBs,
U32 nDevices,
U32 dfReplace);
extern far DmaSetUp(S8 *pPhyMem,
U32 sdMem, /* size */
U32 dChannel, /* channel 2 floppy */
U32 dType, /* 0=Verfify, 1=IN, 2=OUT */
U32 dMode); /* FDC uses 1 (single cycle) */
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, S8 *pMsgRet);
extern far U32 CheckMsg(U32 Exch, S8 *pMsgRet);
extern far U32 GetTimerTick(U32 *pTickRet);
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);
/* THE FLOPPY INTERRUPT FUNCTION PROTOTYPE */
void interrupt fdisk_isr(void);
/* PROTOTYPE FOR Floppy motor control task and associated stuff */
extern void FDMotorTask(void);
void fdmotor_task(void);
void fd_select(U32 drive);
void fd_motoroff(U32 drive);
/* THE REST OF THE PROTOTYPES */
U32 fdisk_setup(void);
U32 RdWrtVerf(U32 op);
U32 format_track(void);
U32 Set_Media(U32 drive, U32 type);
U32 FDC_reset(void);
U8 cmos_type (U8 drive_nr);
U32 send_fdc(U8 parm);
U8 GetParm(U8 index);
U32 wait_int (void);
U32 seek(void);
U32 recal(void);
U32 read_data(U8 *pDataRet);
U32 results(U32 expect);
void purge_fdc (void);
void wait_for_head(void);
U32 med_change(void);
U32 get_fdc_status(void);
/* The following 3 calls are required in every MMURTL device driver */
U32 dev_op(U32 dDevice,
U32 dOpNum,
U32 dLBA,
U32 dnBlocks,
S8 *pData);
U32 dev_stat(U32 dDevice,
S8 * pStatRet,
U32 dStatusMax,
U32 *pdSatusRet);
U32 dev_init(U32 dDevNum,
S8 *pInitData,
U32 sdInitData);
/* Near External for troubleshooting */
extern long xprintf(char *fmt, ...);
/* LOCAL DEFINITIONS */
#define ok 0
#define TRUE 1
#define FALSE 0
#define RATE_500 0x00
#define RATE_300 0x01
#define RATE_250 0x02
#define RATE_1000 0x03
#define INT_FLAG 0x80
/* Error Codes to return */
#define ErcNotInstalled 504
#define ErcAddrMark 602
#define ErcReadOnly 603
#define ErcSectNotFound 604
#define ErcNewMedia 605
#define ErcNotMounted 606
#define ErcCRC 607
#define ErcBadFDC 608
#define ErcBadSeek 609
#define ErcFDCTimeOut 610
#define ErcOverRun 611
#define ErcBadLBA 612
#define ErcDriveType 613
#define ErcBadOp 614
#define ErcBadRecal 615
#define ErcSendFDC 616
#define ErcResults 617
#define ErcBadCmd 618
#define ErcReadyLine 619
/* Commands accepted by driver */
#define CmdNull 0
#define CmdRead 1
#define CmdWrite 2
#define CmdVerify 3
#define CmdFmtBlk 4
#define CmdFmtTrk 5
#define CmdSeekTrk 6
/* FDC port definitions */
#define DOR_PORT 0x3f2
#define MSR_PORT 0x3f4
#define DATA_PORT 0x3f5
#define DIR_PORT 0x3f7
#define DRR_PORT 0x3f7
/* FDC Return Status bit definitions */
#define BUSY 0x10 /* was BIT4 */
#define DSKCHANGE_BIT 0x80
#define BIT7 0x80
#define BIT6 0x40
#define BIT5 0x20
#define BIT4 0x10
#define BIT3 0x08
#define BIT2 0x04
#define BIT1 0x02
#define BIT0 0x01
#define RQM 0x80
#define DIO 0x40
/* FDC commands */
#define FDC_READ 0xe6
#define FDC_WRITE 0xc5
#define FDC_FORMAT 0x4d
/* FDC DOR register bits */
#define FD_MOTOR0 0x10
#define FD_MOTOR1 0x20
#define FD_INTS 0x08
#define FD_RESET 0x04
#define FD_DRV1SEL 0x01
#define FD_MOTMASK 0xf0 /* mask to see motor bits */
/* L O C A L C O N S T A N T S */
/* The drive table contains parameters for each disk
type. The values are:
0 - FDC SPECIFY Command byte 1
1 - FDC SPECIFY Command byte 2
2 - Unused
3 - Bytes per Sector (coded 0=128, 1=256, 2=512, 3=1024);
4 - number of sectors per track (Last sector)
5 - Intersector Gap Size
6 - Data Length (FFh = 512)
7 - GAP 3 for Format Command
8 - Fill Byte for Format command
9 - Head settle time in milliseconds
10 - Motor start time in milliseconds/10 (mult value by 10 to use)
11 - max cylinder index (number of cyls - 1)
12 - Xfer rate Command
13 - Unused
14 - Double Step Flag (e.g., 360K in a 1.2Mb drive)
15 - Unused
*/
U8 fdisk_table[5][16]= {
/* 0 = NO DRIVE - first two params set to allow FDC_reset */
{0x0af,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
/* 1 = 360 kb drive */
{0x0af, 2, 0, 2, 9, 0x2a, -1, 0x50, 0x0f6, 15, 8, 39, RATE_250, 0, 0, 0},
/* 2 = 1.2 mb drive */
{0xaf, 2, 0, 2, 15, 0x1b, -1, 0x54, 0x0f6, 15, 8, 79, RATE_500, 0, 0, 0},
/* 3 = 720 type drive */
{0x0af, 2, 0, 2, 9, 0x2a, -1, 0x50, 0x0f6, 15, 8, 79, RATE_250, 0, 0, 0},
/* 4 = 1.44 mb drive */
{0xaf, 2, 0, 2, 18, 0x1b, -1, 0x6c, 0x0f6, 15, 8, 79, RATE_500, 0, 0, 0},
};
U32 MotorStk[75];
U32 MotorStkTop;
U8 fd_fdc_command;
U8 fd_drive;
U8 fd_nr_sectors;
U8 fd_head;
U8 fd_sector;
U8 fd_track;
U8 seek_status;
U8 fwrite;
S8 *fd_pData;
/* current fdisk_table[x] for drive 0 & 1 */
U8 type0
U8 type1
/* Record for 64 byte status and init record */
#define sStatus 64
struct statstruct{
U32 erc;
U32 blocks_done;
U32 BlocksMax;
U8 fNewMedia;
U8 type_now; /* current fdisk_table for drive selected */
U8 resvd1[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 */
U8 params[16]; /* begin device specific fields */
U8 STATUS[8]; /* status returned from FDC (for user status) */
U32 resvd3;
U32 resvd4; /* 64 bytes total */
} fdstatus;
struct statstruct FDStatTmp;
U8 FDC_STATUS[8]; /* status returned from FDC */
U8 LAST_TRACK[3]; /* last track number */
struct dcbtype {
S8 Name[12];
S8 sbName;
S8 type;
S16 nBPB;
U32 last_erc;
U32 nBlocks;
S8 *pDevOp;
S8 *pDevInit;
S8 *pDevSt;
S8 fDevReent;
S8 fSingleUser;
S16 wJob;
U32 OS1;
U32 OS2;
U32 OS3;
U32 OS4;
U32 OS5;
U32 OS6;
};
struct dcbtype fdcb[2]; /* two floppy device control blcocks */
/* Exch, msgs space, and vars for FD Motor task */
U8 dor_crnt; /* last value sent to DOR port */
U8 motor0_want; /* desired motor0 state, TRUE = want ON */
U8 motor1_want; /* desired motor1 state, TRUE = want ON */
U32 fd_tick; /* Set to tick everytime we select a floppy */
U32 fd_newtick; /* used to check tick time */
/* Exch and msgs space for FD ISR */
U32 fd_exch;
U32 fd_msg[2];
U32 rgSectorMax[10] = {0, 720, 2400, 1440, 2880,
0, 0, 0, 0, 0}; /* set max sectors */
U8 sectbuf[518]; /* sector buffer for DMA */
/*======================================================*/
/*=================== START OF CODE ====================*/
/*======================================================*/
void enable_ints(void)
{
;
#asm
STI
#endasm
}
void disable_ints(void)
{
;
#asm
CLI
#endasm
}
/********************************************************************
This small function becomes a thread (task) just to control the motor.
The floppy motors are controlled serarately from the rest
of the floppy drive electronics. A single port controls both
floppies. After a floppy is used you don't want to shut it right
off or you can forget about any dreams of decent throughput.
This wakes up every 3 seconds and checks to see if there was
any floppy activity in the past 3 seconds. If not, we shut off
the motor(s).
**********************************************************************/
void fdmotor_task(void)
{
enable_ints();
MotorLoop:
Sleep(300); /* 3 seconds */
GetTimerTick(&fd_newtick);
if ((fd_newtick - fd_tick) > 300) { /* not used in last 3 seconds */
if ((!motor0_want) && (dor_crnt & FD_MOTOR0)) { /* They want 0 off */
disable_ints();
dor_crnt &= ~FD_MOTOR0;
OutByte( dor_crnt, DOR_PORT);
enable_ints();
}
if ((!motor1_want) && (dor_crnt & FD_MOTOR1)) { /* They want 1 off */
disable_ints();
dor_crnt &= ~FD_MOTOR1;
OutByte( dor_crnt, DOR_PORT);
enable_ints();
}
}
goto MotorLoop;
}
/*******************************************
Set desired motor status flags and drive
select bit. If drive select bit has changed
this sends the current DOR value to select
the correct drive. If the motor bit we wanted
isn't on, we will also send the command.
We DO NOT mess with the other motor bit.
*******************************************/
void fd_select(U32 drive)
{
U8 fsend;
U8 fdelay;
GetTimerTick(&fd_tick); /* update last time selected */
fsend = FALSE;
fdelay = FALSE;
if (drive) { /* drive 1 */
if (!(dor_crnt & 0x01)) {
fsend = TRUE;
dor_crnt |= 0x01; /* select 1 */
}
if (!(dor_crnt & FD_MOTOR1)) {
fsend = TRUE;
fdelay = TRUE;
dor_crnt |= FD_MOTOR1; /* motor 1 on */
}
}
else {
if (dor_crnt & 0x01) {
fsend = TRUE;
dor_crnt &= 0xFE; /* select 0 (turn 1 off) */
}
if (!(dor_crnt & FD_MOTOR0)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -