add directory study
This commit is contained in:
293
study/hardware/Floppy/floppy/FDDIO.C
Normal file
293
study/hardware/Floppy/floppy/FDDIO.C
Normal file
@@ -0,0 +1,293 @@
|
||||
/////////////////////////////////////
|
||||
// Demo of how to access a floppy //
|
||||
// drive without of a BIOS stuff //
|
||||
// //
|
||||
// Program uses DMA data transferr //
|
||||
/////////////////////////////////////
|
||||
|
||||
////////////////////////////////
|
||||
// Compiler Borland C/C++ 3.1 //
|
||||
////////////////////////////////
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define __CPPARGS ...
|
||||
#else
|
||||
#define __CPPARGS
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <conio.h>
|
||||
#include <dos.h>
|
||||
|
||||
#define CYL 0
|
||||
|
||||
typedef struct _DPT_
|
||||
{
|
||||
unsigned char srt_hut;
|
||||
unsigned char dma_hlt;
|
||||
unsigned char motor_w;
|
||||
unsigned char sec_size;
|
||||
unsigned char eot;
|
||||
unsigned char gap_rw;
|
||||
unsigned char dtl;
|
||||
unsigned char gap_f;
|
||||
unsigned char fill_char;
|
||||
unsigned char hst;
|
||||
unsigned char mot_start;
|
||||
} DPT;
|
||||
|
||||
DPT far *get_dpt (void);
|
||||
void fdc_out (unsigned char byte);
|
||||
int fdc_inp (void);
|
||||
void int_wait (void);
|
||||
void dma_init (void far *);
|
||||
void tdelay (int cnt);
|
||||
void interrupt IRQ6 (__CPPARGS);
|
||||
void interrupt (*oldIRQ6) (__CPPARGS);
|
||||
|
||||
char buffer[512];
|
||||
|
||||
static int IRQ=0;
|
||||
|
||||
void main (void)
|
||||
{
|
||||
unsigned i;
|
||||
long l;
|
||||
char status[7], main_status;
|
||||
DPT _far *fdpt;
|
||||
FILE *sect;
|
||||
|
||||
printf ("\n\nWork with Floppy Drive Controller\n");
|
||||
|
||||
oldIRQ6 = _dos_getvect (8+6);
|
||||
_dos_setvect (8+6, IRQ6);
|
||||
|
||||
// We're opening a file in order to store in it
|
||||
// the very first sector of the diskette
|
||||
sect = fopen ("!sector.dat", "wb+");
|
||||
|
||||
// Getting Diskette Parameter Table pointer
|
||||
fdpt = get_dpt();
|
||||
|
||||
// Turning on the motor in the "A:" drive
|
||||
// Enabling interrupts before actual turning on
|
||||
_enable();
|
||||
outp (0x3F2, 0x1C);
|
||||
|
||||
// Waiting while motor speeds up
|
||||
tdelay (18);
|
||||
|
||||
// Displaying contents of the controller state register
|
||||
printf ("Motor is on.\t\t");
|
||||
printf ("State: %02.2X\n", inp(0x3F4));
|
||||
|
||||
// recalibrate
|
||||
fdc_out (7);
|
||||
fdc_out (0);
|
||||
int_wait();
|
||||
|
||||
|
||||
// We need to move drive head to the CYL track
|
||||
|
||||
// "Seek" command
|
||||
fdc_out (0xf);
|
||||
|
||||
// The "Seek" command needs 2 parameters:
|
||||
// a Head/Drive number and a Track number.
|
||||
// Since we're working with "A:" drive and 0 head,
|
||||
// first parameter is 0, second parameter is CYL
|
||||
fdc_out (0);
|
||||
fdc_out (CYL);
|
||||
|
||||
// Displaying contents of the controller state register
|
||||
printf ("\n<<<Seeking>>> \t\t");
|
||||
printf ("State: %02.2X\n", inp(0x3F4));
|
||||
|
||||
// Interrupt notifies us about operation end
|
||||
int_wait();
|
||||
|
||||
// Delay for head positioning
|
||||
tdelay (5);
|
||||
|
||||
// In order to check the result of the "Seek" command
|
||||
// we're sending "Read Interrupt State" command
|
||||
|
||||
// Displaying ST0 register and number of a track after
|
||||
// "Seek" command execution PCN
|
||||
fdc_out (0x8);
|
||||
printf ("Interrupt state:\t");
|
||||
printf (" ST0: %02.2X, \t", fdc_inp());
|
||||
printf ("PCN: %02.2X\n", fdc_inp());
|
||||
|
||||
// For more detailed info of FDC state
|
||||
// we're sending "Read Media/Drive State" command,
|
||||
// displaying ST3 register
|
||||
fdc_out (4);
|
||||
fdc_out (0);
|
||||
printf ("Media/Drive state:\t ST3: %02.2X\n", fdc_inp());
|
||||
|
||||
// Setting speed of data transfer to 500 KB/sec
|
||||
outp (0x3F7, 0);
|
||||
|
||||
// DMA initialization
|
||||
dma_init ((void far *)buffer);
|
||||
|
||||
// "Read Data" command
|
||||
fdc_out (0x66);
|
||||
fdc_out (0x0); // drive 0, head 0
|
||||
|
||||
fdc_out (CYL); // track CYL
|
||||
fdc_out (0); // head 0
|
||||
fdc_out (1); // sector no 1
|
||||
|
||||
// Sending some technical info to FDC.
|
||||
// This info may be obtained form the Diskette Parameter Table.
|
||||
// Parameters are:
|
||||
// - sector size;
|
||||
// - last sector on a track;
|
||||
// - gap length;
|
||||
// - number of bytes to be read/write
|
||||
fdc_out (fdpt->sec_size);
|
||||
fdc_out (fdpt->eot);
|
||||
fdc_out (fdpt->gap_rw);
|
||||
fdc_out (fdpt->dtl);
|
||||
|
||||
// Waiting for interrupt (end of operation)
|
||||
int_wait();
|
||||
|
||||
// Getting and displaying results of
|
||||
// the "Read Data" command
|
||||
printf ("\n<<<Reading a sector>>> \n");
|
||||
printf (" State bytes (ST0,ST1,ST2,C,H,R,N):\n");
|
||||
|
||||
for(i=0; i<7; i++) printf("%02.2X\t", (char) fdc_inp());
|
||||
printf("\n");
|
||||
|
||||
// Saving sector to the file
|
||||
for(i=0; i<512; i++) fputc (buffer[i],sect);
|
||||
fclose (sect);
|
||||
|
||||
// Turning motor off
|
||||
outp (0x3F2, 0xC);
|
||||
lll:
|
||||
_dos_setvect (8+6, oldIRQ6);
|
||||
}
|
||||
|
||||
// Writes a byte to FDC
|
||||
void fdc_out (unsigned char parm)
|
||||
{
|
||||
asm mov dx,3F4h
|
||||
loop_fdc_out:
|
||||
|
||||
asm in al,dx
|
||||
asm test al,80h // Is controller ready?
|
||||
asm jz loop_fdc_out // No, waiting...
|
||||
|
||||
asm inc dx
|
||||
asm mov al, parm // Writing the byte
|
||||
asm out dx, al
|
||||
}
|
||||
|
||||
// Reads a byte from FDC
|
||||
int fdc_inp (void)
|
||||
{
|
||||
asm mov dx,3F4h
|
||||
loop_fdc_inp:
|
||||
asm in al,dx
|
||||
asm test al,80h // Is controller ready?
|
||||
asm jz loop_fdc_inp // No, waiting...
|
||||
|
||||
asm inc dx
|
||||
asm in al, dx // Reading a byte
|
||||
return _AL;
|
||||
}
|
||||
|
||||
// Waits for an interrupt generated by FDC
|
||||
void int_wait (void) {
|
||||
_enable();
|
||||
while (IRQ==0) {};
|
||||
IRQ = 0;
|
||||
}
|
||||
|
||||
void interrupt IRQ6 (__CPPARGS) {
|
||||
IRQ = 1;
|
||||
outportb (0x20, 0x20);
|
||||
}
|
||||
|
||||
// DMA initialization routine
|
||||
void dma_init (void far *buf)
|
||||
{
|
||||
unsigned long f_adr;
|
||||
unsigned sg, of;
|
||||
|
||||
// Computing 24-bit address for the data buffer
|
||||
f_adr = ((unsigned long)FP_SEG(buf) << 4)
|
||||
+ (unsigned long)FP_OFF(buf);
|
||||
|
||||
// Splitting the address into a page number
|
||||
// and an offset
|
||||
sg = (f_adr >> 16) & 0xff;
|
||||
of = f_adr & 0xffff;
|
||||
|
||||
// Disabling ints during DMA programming
|
||||
_disable();
|
||||
asm mov al,46h // FDC read data command
|
||||
|
||||
asm out 12,al // We're working with 16-bit ports.
|
||||
// Next byte sent to 16-bit port is less significiant
|
||||
|
||||
asm out 11,al // DMA mode
|
||||
|
||||
asm mov ax,of // Buffer offset LSB
|
||||
asm out 4,al
|
||||
asm mov al,ah // Buffer offset MSB
|
||||
asm out 4,al
|
||||
|
||||
asm mov ax,sg // Page number
|
||||
asm out 81h,al
|
||||
|
||||
asm mov ax,511 // Data length
|
||||
asm out 5,al
|
||||
asm mov al,ah
|
||||
asm out 5,al
|
||||
|
||||
asm mov al,2 // channel 2 enabled
|
||||
asm out 10,al
|
||||
|
||||
// It's now safe to enable ints
|
||||
_enable();
|
||||
}
|
||||
|
||||
// This routine returns a Diskette Parameter Table address
|
||||
DPT far *get_dpt(void)
|
||||
{
|
||||
void far * far *ptr;
|
||||
|
||||
ptr = (void far * far *)MK_FP(0x0, 0x78);
|
||||
return (DPT far*)(*ptr);
|
||||
}
|
||||
|
||||
// This routine waits for cnt timer ticks.
|
||||
// Timer frequency is 18.2 Hz
|
||||
void tdelay (int cnt)
|
||||
{
|
||||
asm push bx
|
||||
asm push dx
|
||||
asm push si
|
||||
|
||||
asm mov si, cnt
|
||||
asm mov ah, 0
|
||||
asm int 1ah
|
||||
asm mov bx, dx
|
||||
asm add bx, si
|
||||
|
||||
delay_loop:
|
||||
asm int 1ah
|
||||
asm cmp dx, bx
|
||||
asm jne delay_loop
|
||||
|
||||
asm pop si
|
||||
asm pop dx
|
||||
asm pop bx
|
||||
}
|
||||
Reference in New Issue
Block a user