📄 fl_drver.c
字号:
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright Peter Van Oudenaren , 1993
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* fl_drver.c - Generic floppy disk driver routines.
Routines in this file are generic routines to control an NEC765 class
floppy disk controller in AT mode. The routines should be independent
of executive environment and of the system hosting the 765 controller.
Public routines:
These routines are pointed to by the RTFS bdevsw table.
floppy_ioctl - IO control function. Does nothing
floppy_open - Drive open routine. Initializes the controller and
establishes interrupt vector if open count is zero.
Increments the open count.
floppy_close - Decreases the open count. If the open count goes
to zero it releases interrupts.
floppy_io - Performs reads/writes on the drives
This routine is public but is not in the device table. You may call it
directly.
fl_format -
The rest of the routines are internal to the driver.
fl_claim - Claims the controller for a drive. Establishes
the media type if need be and sets the data rate
so the disk may be read/written.
fl_establish_media - Determines the media type of the floppy disk in
the drive by varying the data rate and attempting to
read the sector ID off of the disk. Also seeks the
head to clear the disk changed line.
fl_sense_interrupt - Requests sense (staust registers) from the floppy
after reset,recal and seek
fl_read_id - Reads sector IDs from a floppy. Used by establish
media
fl_seek - Seeks the head.
fl_recalibrate - Seeks the head to track 0 and resets chips internal
head position counter
fl_specify - Specify head load/unload times and seek step rate
fl_controller_init - Clears internal floppy tables, establishes interrupts
and resets the 765 chip.
fl_reset_controller - Called by fl_controller_init. Issues a reset to
the chip.
fl_motor_on - Turns the floppy motor on and starts a daemon to
shut it off.
fl_motor_off - The daemon calls this to shut off the floppy motor
fl_command_phase - Sends command phase values to the chip. Called by
higher level routines like fl_read_id, fl_io etc.
fl_results_phase - Reads results phase values from the chip. Called by
higher level routines like fl_read_id, fl_io etc.
fl_ready - Determines what data transfer state the floppy
controller's state machine is in. TO, FROM or
none.
fl_change_line - Called by floppy_io to check the drive's change
line to see if the floppy disk has been removed.
If the drive has been removed we call establish
media to clear it. We should probaly add a call
back mechanism here to alert the user to replace the
disk and possibly to give the file system a
chance to recover.
fl_cp_parms - Copy parameters from the parameter table to the
_floppy structure.
fl_dma_chk - Takes an address and returns the number of blocks
that may be transferd to that address before a
dma segment wrap occurs.
fl_dma_init - Sets up the dma controller for a to or from memory
transfer from/to the floppy controller
fl_read_data - Reads a byte from the 765 data register
fl_read_drr - Reads a byte from the 765 data rate register
fl_read_msr - Reads a byte from the 765 master status register
fl_write_data - Writes a byte to the 765 data register
fl_write_dor - Writes a byte to the 765 digital output register
fl_write_drr - Writes a byte to the 765 data rate register
fl_report_error - Converts floppy errors to strings and prints them
fl_waitdma - Waits for dma to complete and checks status
fl_waitint - Waits for a floppy disk interrupt. Or tiomes out
*/
#include <pcdisk.h>
/*#include <stdio.h> */
#if USE_FLOPPY
#include <dos.h>
#include <conio.h>
#include <ctype.h>
#if (defined(ERTFS_SA))
void hook_floppy_interrupt(int irq);
void ks_clear_floppy_signal(void);
void ks_invoke_floppy_interrupt(int controller_no);
#define OS_FLOPPY_SIGNAL_BIND(X)
#define OS_FLOPPY_SIGNAL_CLEAR(X) ks_clear_floppy_signal()
#endif
byte os_floppy_type(int driveno);
#if (USE_DMA)
#ifdef PME
/* for pmiSetBaseAddr(), etc */
//#include "pme.h"
//#include "cpmi.h"
#endif
#if (N_FLOPPY_UNITS > 2)
#error Reduce N_FLOPPY_UNITS in PCCONF.H. Floppy driver supports up to 2 drives.
#endif
#if !defined(PME)
extern unsigned char _dma_buffer[512];
extern DMAPTYPE dma_buffer;
DMAPTYPE alloc_dma_buffer(void)
{
return((DMAPTYPE) &_dma_buffer[0]);
}
#endif // PME
static void far_copybuf(DMAPTYPE to, DMAPTYPE from, int size)
{
while (size--)
*to++ = *from++;
}
//DM: added
#if defined(PME)
#define DMA_BUF_SECTS 18
#define LO_BUF_SIZE (DMA_BUF_SECTS*512)
/* USER: The absolute address below is the start of the DMA buffer used when
running under pmEasy. Set it to an unused location in real memory.
Ensure the buffer is not split across 64K boundary (size is LO_BUF_SIZE).
This buffer is necessary because the DMA controller can not write to
the user buffer in extended memory. It can only write to mem below 1MB. */
#define LO_BUF_SEG 0x9000
word lo_buf_sel = 0;
byte far *lo_buf_prot; // needed by us for copying results to/from user's buffer
byte far *lo_buf_real; // needed by DMA controller to initiate read/write
#endif
#endif /* USE_DMA */
#if (!USE_DMA)
int polled_read(byte KS_FAR *buffer, word n, byte cmd);
int polled_write(byte KS_FAR *buffer, word n, byte cmd);
#endif
/* Shadow of the digital output register. We write to this each time we
write to the dig. output reg. */
extern byte shadow_dig_out;
extern int shut_mo_off_in;
extern _FL_DEVPARMS fl_devparms[7];
/* Current selected floppy for use by fl_claim.
Note: We use the following confusing convention:
0 = None selected
1 = Drive one selected
2 = Drive two selected
This is confusing because usually driveno == 0, 1 for the first two drives */
/* Open function. This is pointed to by the bdevsw[] table */
extern int fl_controller_open_count;
extern int selected_floppy;
extern _FLOPPY floppy[N_FLOPPY_UNITS];
static BOOLEAN change_checked[N_FLOPPY_UNITS];
BOOLEAN floppy_open(void);
BOOLEAN floppy_io(int driveno, dword l_sector, void KS_FAR *in_buffer, word count, BOOLEAN reading);
BOOLEAN floppy_format(int driveno, int drivesize, int interleave);
static BOOLEAN fl_controller_init(void);
static BOOLEAN fl_reset_controller(void);
static BOOLEAN fl_claim(int driveno);
BOOLEAN fl_establish_media(int driveno);
static BOOLEAN fl_sense_interrupt(COMMAND_BLOCK *p);
static BOOLEAN fl_read_id(int driveno, COMMAND_BLOCK *p);
static BOOLEAN fl_seek(int driveno, word cyl, word head);
static BOOLEAN fl_recalibrate(int driveno);
static BOOLEAN fl_specify(int driveno);
void fl_motor_off(void);
static void fl_motor_on(int driveno);
static BOOLEAN fl_command_phase(COMMAND_BLOCK *p);
static BOOLEAN fl_results_phase(COMMAND_BLOCK *p);
static int fl_ready(void);
BOOLEAN fl_change_line(int driveno);
static void fl_cp_parms(int driveno, int parmindex);
static BOOLEAN fl_waitint(int ticks);
static BOOLEAN fl_report_error(int error, BOOLEAN return_me);
#if (USE_DMA)
static BOOLEAN fl_waitdma(int ticks);
static BOOLEAN fl_dma_init(DMAPTYPE in_address, word length, BOOLEAN reading);
//DM: added conditional to comment out if !PME
#if !defined(PME)
static word fl_dma_chk(DMAPTYPE in_address);
#endif
#endif
static void fl_write_drr(byte value);
static byte fl_read_drr(void);
static void fl_write_dor(byte value);
static void fl_write_data(byte value);
static byte fl_read_data(void);
static byte fl_read_msr(void);
/* floppy_isr() - Implementation specific ISR routines.
*
* This routine is the IBM-PC specific interupt service routine. It
* calls ide_interrupt(controller_number), the platform independent
* portion of the interrupt routine, and then clears the PIC
*
*/
void KS_FAR floppy_isr(int controller_no) /*__fn__*/
{
/* Signal interrupt complete */
ks_invoke_floppy_interrupt(controller_no);
}
BOOLEAN _floppy_open(void);
BOOLEAN floppy_open(void) /*__fn__*/
{
int i;
for (i = 0; i < 3; i++)
if (_floppy_open())
return(TRUE);
return(FALSE);
}
BOOLEAN _floppy_open(void) /*__fn__*/
{
#if (USE_DMA)
//DM: added:
#if defined(PME)
#ifdef FM
lo_buf_prot = (byte *) (LO_BUF_SEG << 4);
lo_buf_real = (byte *) (LO_BUF_SEG << 4); // is actually linear address, not far pointer
#else
if (lo_buf_sel == 0)
{
if (pmiAllocLD(1, &lo_buf_sel) != 0)
return(FALSE); /* error: insuff descr */
pmiSetBaseAddr(lo_buf_sel, (dword)LO_BUF_SEG << 4);
pmiSetLimit(lo_buf_sel, (dword)LO_BUF_SIZE - 1);
pmiSetRights(lo_buf_sel, wData, 0);
lo_buf_prot = (byte far *)MK_FP(lo_buf_sel,0);
lo_buf_real = (byte far *)MK_FP(LO_BUF_SEG,0);
}
#endif
//DM: (end of added)
#else //DM: added #else -- real mode case
/* Make sure we have a dma buffer in real memory. if not fail */
if (!dma_buffer)
dma_buffer = alloc_dma_buffer();
if (!dma_buffer)
return(FALSE);
#endif //DM: added #endif
#endif
/* Initialize the controller */
if (!fl_controller_open_count)
{
if (!fl_controller_init())
return(FALSE);
}
fl_controller_open_count += 1;
return(TRUE);
}
/* floppy_down() - Note that the floppy disk either not installed or
* not formatted. Sets the media type to NONE.
*
*
*/
void floppy_down(int driveno) /*__fn__*/
{
floppy[driveno].media_type = (byte) DT_NONE;
selected_floppy = 0;
}
/* Check if a floppy disk is installed. */
BOOLEAN floppy_installed(int driveno) /*__fn__*/
{
if (fl_claim(driveno))
return(TRUE);
else
floppy_down(driveno);
return(FALSE);
}
/* floppy_io - Floppy disk read write routine (in bdevsw[] table.)
*
* Summary:
*
* BOOLEAN floppy_io(driveno, l_sector, in_buffer, count, reading)
*
*
* Inputs:
* word driveno - 0 or 1 = a: b:
* dword l_sector - absolute sector to read/write
* void *in_buffer - address of data buffer
* word count - sectors to transfer
* BOOLEAN reading - TRUE if a read FALSE if a write
*
* Returns:
* TRUE on success else FALSE.
*
* This routine performs read and writes from to the floppy disk. It calculates
* head:sector:track from the physical sector number, then it reads/write of
* track or count, whichever is less. If more data needs to be transfered it
* adjusts the current sector number, recalculates head:sector:track and repeats
* the IO procedure. This occurs until the process is completed.
*
* Note: On a PC AT the dma controller is a 16 BIT device. A 4 bit bank
* switch register is used to address the lower 1 MEG. A segment
* wrap occurs when a transfer spans two banks. When this routine
* senses this condition it breaks the request into two or
* more operations so the wrap does not occur.
*
* Note: This routine is basically portable except for the the DMA wrap
* calculation. Also in protected mode 386/486 systems a double
* buffering scheme needs to be added since we can only dma to the
* first 1 meg. This double buffer logic will be identical to the
* logic used for double buffering in the DMA segment wrap situation,
* the only exception being the transfer should be larger than 1.
*
*/
BOOLEAN _floppy_io(DDRIVE *pdr, dword l_sector, void KS_FAR *in_buffer, word count, BOOLEAN reading);
BOOLEAN floppy_io(int driveno, dword l_sector, void KS_FAR *in_buffer, word count, BOOLEAN reading) /*__fn__*/
{
int i;
DDRIVE *pdr;
pdr = pc_drno_to_drive_struct(driveno);
if (pdr)
{
for (i = 0; i < 3; i++)
if(_floppy_io(pdr, l_sector, in_buffer, count, reading))
return(TRUE);
}
return(FALSE);
}
BOOLEAN _floppy_io(DDRIVE *pdr, dword l_sector, void KS_FAR *in_buffer, word count, BOOLEAN reading) /*__fn__*/
{
COMMAND_BLOCK b;
word cyl;
word head;
word sec;
word final_sec;
word final_cyl;
word final_head;
word utemp;
word sector;
word nleft_track;
word n_todo;
byte KS_FAR *buffer = (byte KS_FAR *) in_buffer;
int unit_number;
#if (!USE_DMA)
int i;
int ready;
#else
#if !defined(PME) //DM: added this conditional around use_dma_buff
BOOLEAN use_dma_buff;
#endif
#endif
unit_number = pdr->logical_unit_number;
if (!count) /* Must have a count */
return(FALSE);
/* Establish media if the drive is different from before */
/* fl_claim has its own error reporting */
if (!fl_claim(unit_number))
return(FALSE);
sector = (word) l_sector;
/* cylinder == sector / sectors/cylinder */
cyl = (word) (sector/floppy[unit_number].sectors_per_cyl);
utemp = (word) (sector%floppy[unit_number].sectors_per_cyl);
head = (word) (utemp/floppy[unit_number].sectors_per_track);
sec = (word) (utemp%floppy[unit_number].sectors_per_track);
nleft_track = (word) (floppy[unit_number].sectors_per_track - sec);
if (count > nleft_track)
n_todo = nleft_track;
else
n_todo = count;
while (count)
{
if (fl_change_line(unit_number))
{
/* establish media. It has a hack in here to clear change line */
/* establish media has its own error reporting */
if (!fl_establish_media(unit_number))
return(FALSE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -