home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
listings
/
v_06_07
/
v6n7019a.txt
< prev
next >
Wrap
Text File
|
1989-09-28
|
14KB
|
486 lines
/* floppydr - floppy "doctor" program: low-low-level access to FDC */
#include <conio.h>
#include <dos.h>
#include <bios.h>
#include <stdio.h>
#include <ctype.h>
#define UBYTE unsigned char
#define flop_cmd(dr, motflag, moton, c, r, n, b) \
{ drive_sel(dr, motflag, moton); \
fdc_cmd(c, r, n, b); \
results(c[0], r);}
#define out_dor(cmd) outp(0x3F2, cmd)
#define in_stat() (inp(0x03f4))
#define out_dat(d) outp(0x3f5,d)
#define in_dat() (inp(0x3f5))
/* notes for Turbo-C: use outportb() and inportb() */
UBYTE buffer[1024];
char get_menu_choice();
UBYTE peekbyte(unsigned, unsigned);
long start_tmo(void);
#define READ_DATA 6
#define READ_DELETED_DATA 0xC
#define WRITE_DATA 5
#define WRITE_DELETED_DATA 9
#define READ_TRACK 2
#define READ_ID 0xA
#define FORMAT_TRACK 0xD
#define RECALIBRATE 7
#define SENSE_INTR_STATUS 8
#define SPECIFY 3
#define SENSE_DRIVE_STATUS 4
#define SEEK 0xF
typedef struct {
unsigned int ncmd;
unsigned int nres;
char ctype; /* N, I, R, or W,
for "no DMA", "Interrupt", "Read", "Write") */
} CMD_INFO;
CMD_INFO cmdt[16] = {
{0, 0, ' '}, /* 0x00 */
{0, 0, ' '}, /* 0x01 */
{9, 7, 'R'}, /* 0x02 read track */
{3, 0, 'N'}, /* 0x03 specify */
{2, 1, 'N'}, /* 0x04 sense drive status */
{9, 7, 'W'}, /* 0x05 write data */
{9, 7, 'R'}, /* 0x06 read data */
{2, 0, 'I'}, /* 0x07 recalibrate */
{1, 2, 'N'}, /* 0x08 sense interrupt status */
{9, 7, 'W'}, /* 0x09 write deleted data */
{2, 7, 'N'}, /* 0x0a read id */
{0, 0, ' '}, /* 0x0b */
{9, 7, 'R'}, /* 0x0c read deleted data */
{6, 7, 'W'}, /* 0x0d format track */
{0, 0, ' '}, /* 0x0e */
{3, 0, 'I'}, /* 0x0f seek */
};
#define NDPARM 12
struct DPARM {
UBYTE spec1; /* 0 specify byte 1 */
UBYTE spec2; /* 1 specify byte 2 */
UBYTE mot_off_wt; /* 2 meaningless */
UBYTE nrec; /* 3 number of bytes code */
UBYTE eot; /* 4 end-of-track */
UBYTE gpl; /* 5 gap length */
UBYTE dtl; /* 6 data length (if N = 0) */
UBYTE fgpl; /* 7 gpl for format */
UBYTE fd; /* 8 fill byte for format */
UBYTE hdsttl; /* 9 head settle time (milliseconds) */
UBYTE mot_start; /* 10 motor start time (1/8 seconds) */
UBYTE mt_mfm_sk; /* 11 bits: 0x80 = MT, 0x40 = MFM,
0x20 = SK */
} dparm = {0xcf, 0x02, 0x25, 0x02, 0x12, 0x2A,
0xFF, 0x50, 0xF6, 0x01, 0x04, 0xE0};
static char *dparmmsg[] = {
"0 - specify byte 1 (bits 0-3 = HUT, 4-7 = SRT) ",
"1 - specify byte 2 (bit 1-7 = HLT, 0 = 'no dma')",
"2 - meaningless (was motor start time)",
"3 - N: number of bytes code (2=512)",
"4 - EOT: end-of-track",
"5 - GPL: gap length",
"6 - DTL:data length (if N = 0)",
"7 - gpl for format",
"8 - fill byte for format",
"9 - head settle time (milliseconds) (not used)",
"10 - motor start time (1/8 seconds) (not used)",
"11 - bits: 0x80 = MT, 0x40 = MFM, 0x20 = SK"};
int main()
{
UBYTE unit = 0;
UBYTE track = 0;
UBYTE head = 0;
UBYTE sector = 1;
UBYTE nsector = 9;
UBYTE cd[9], rs[7], c, hdsds;
int nbyte, i, j;
printf("\n\nfloppy doctor program\n\n");
out_dor(0); /* reset card */
out_dor(0xC); /* select drive 0, allow ints & DMA */
while (1)
{
c = get_menu_choice();
switch (c)
{
case '0':
printf(" Enter Drive number:");
getnum("%d", &unit);
cd[0] = SENSE_DRIVE_STATUS;
cd[1] = (hdsds = unit + (head << 2));
flop_cmd(unit, 0, 0, cd, rs, 0, buffer);
break;
case '1':
cd[0] = SPECIFY;
cd[1] = dparm.spec1;
cd[2] = dparm.spec2;
flop_cmd(unit, 0, 0, cd, rs, 0, buffer);
break;
case '2':
cd[0] = RECALIBRATE;
cd[1] = unit;
flop_cmd(unit, 1, 200, cd, rs, 0, buffer);
break;
case '3':
printf(" Enter cylinder (track) number: ");
getnum("%d", &track);
cd[0] = SEEK;
cd[1] = hdsds;
cd[2] = track;
drive_sel();
flop_cmd(unit, 1, 200, cd, rs, 0, buffer);
break;
case '4':
printf(" Enter Head number:");
getnum("%d", &head);
hdsds = (hdsds & 0x3) | head;
break;
case '5':
cd[0] = READ_DATA + dparm.mt_mfm_sk;
goto read_write;
case '6':
cd[0] = WRITE_DATA + (dparm.mt_mfm_sk & 0xC0);
read_write:
printf(" Enter sector number: ");
getnum("%d", §or);
nbyte = 128 << dparm.nrec;
cd[1] = hdsds;
cd[2] = track;
cd[3] = head;
cd[4] = sector;
cd[5] = dparm.nrec;
cd[6] = dparm.eot;
cd[7] = dparm.gpl;
cd[8] = dparm.dtl;
flop_cmd(unit, 1, 200, cd, rs, nbyte, buffer);
if ((cd[0] & 0x0f) == READ_DATA) {
puts("");
dump_buf(nbyte, buffer);
}
break;
case '7':
for (i = 0; i < nsector; i++)
buffer[i * 4 + 2] = i;
cd[0] = FORMAT_TRACK + (dparm.mt_mfm_sk & 0x40);
cd[1] = hdsds;
cd[2] = dparm.nrec;
cd[3] = nsector;
cd[4] = dparm.fgpl; /* gap length for format */
cd[5] = dparm.fd; /* fill byte for format */
fdc_cmd(unit, 1, 200, cd, rs, nsector * 4, buffer);
break;
case '8':
printf("Enter number of times to read ids: ");
getnum("%d", &j);
drive_sel(unit, 1, 200);
cd[0] = READ_ID + (dparm.mt_mfm_sk & 0x40);
cd[1] = hdsds;
for (i = 0; i < j; i++) {
fdc_cmd(cd, rs, 0, buffer);
buffer[i * 4 + 0] = rs[3];
buffer[i * 4 + 1] = rs[4];
buffer[i * 4 + 2] = rs[5];
buffer[i * 4 + 3] = rs[6];
}
results(cd[0], rs); /* of the last command */
for (i = 0; i < j; i++)
printf("c = %d, h = %d, r = %d, n = %d\n",
buffer[i * 4 + 0], buffer[i * 4 + 1],
buffer[i * 4 + 2], buffer[i * 4 + 3]);
puts("Enter a key when ready");
getch();
puts("");
break;
case 'R':
dparm_rpt_chg();
break;
case 'X':
exit(0);
break;
default:
printf("\nIllegal command.\n");
}
}
}
char get_menu_choice()
{
char inp[80];
puts("");
puts("Menu:");
puts(" 0 - Drive #");
puts(" 1 - Specify (Step rate, Head unload, etc.)");
puts(" 2 - Recalibrate");
puts(" 3 - Seek (cylinder (track) number");
puts(" 4 - Head (surface)");
puts(" 5 - Read sector");
puts(" 6 - Write sector");
puts(" 7 - Format a track");
puts(" 8 - Read IDs");
puts(" R - Report and change the DPARM table");
puts(" X - Exit program");
puts("\n");
printf("Command: ");
gets(inp);
puts("");
return (isalpha(inp[0]) ? toupper(inp[0]) : inp[0]);
}
int dparm_rpt_chg()
{
int i, pi;
unsigned int nv;
UBYTE *a = &dparm.spec1;
for (i = 0; i < NDPARM; i++)
printf("(0x%02x) ", a[i]), puts(dparmmsg[i]);
puts("");
printf("Which to change (enter -1 if none to change): ");
getnum("%d", &pi);
if ((pi < 0) || (pi >= NDPARM))
return;
printf("dparm[%d] = %02x, new value: ", pi, a[pi]);
getnum("%x", &nv);
a[pi] = nv;
}
int fdc_cmd(UBYTE cmds[], UBYTE results[], int nbyte, UBYTE buffer[])
{ /* fdc_cmd */
int i, ccode, s;
ccode = cmds[0] & 0xF;
if (cmdt[ccode].ctype == 'R')
set_dma_up(buffer, 0, nbyte); /* set up DMA to read */
else if (cmdt[ccode].ctype == 'W')
set_dma_up(buffer, 1, nbyte); /* set up DMA to write */
set_for_int();
for (i = 0; i < cmdt[ccode].ncmd; i++) {
s = out_fdccmd(cmds[i]);
if (s)
printf("fdc_cmd: Error from out_fdccmd = %d\n", s);
}
if (cmdt[ccode].ctype == 'I') {
if (s = wait_for_int())
printf("fdc_cmd: Error from wait_for_int = %d\n", s);
s = out_fdccmd(SENSE_INTR_STATUS);
if (s)
printf("fdc_cmd: Error "
"during sense_intr_stat from out_fdccmd = %d\n", s);
in_fdcres(results++); /* from sense_intr_status */
in_fdcres(results);
}
else {
if (cmdt[ccode].ctype != 'N') {
if (s = wait_for_int())
printf("fdc_cmd: Error from wait_for_int = %d\n", s);
}
for (i = 0; i < cmdt[ccode].nres; i++) {
s = in_fdcres(results++);
if (s)
printf("fdc_cmd: Error from in_fdcres = %d\n", s);
}
}
} /* fdc_cmd */
int results(UBYTE cmd, UBYTE res[])
{
int i;
printf("\nresults :");
for (i=0; i < (cmdt[cmd & 0xf].nres); i++)
printf("%02x ", res[i]);
printf("\n");
}
int dump_buf(int n, UBYTE buf[])
{ /* dump_buf */
int i, j;
for (i = 0; i < n; i++) {
if ((i & 0xF) == 0)
printf("%4x: ", i);
else if ((i & 0x7) == 0)
printf(" |");
printf(" %02x", buf[i]);
if ((i & 0xF) == 15) {
printf(" |");
for (j = i - 15; j <= i; j++)
if (isprint(buf[j]))
putchar(buf[j]);
else
putchar('.');
printf("|\n");
if ((i & 0xFF) == 0xFF) {
printf("hit any key to continue");
getch();
puts("");
}
}
}
}
int set_motor_tmo(int count)
{
pokebyte(0x40, 0x40, &count); /* set motor_count for BIOS */
}
int getnum(char *fmt, int *num)
{
char s[80];
gets(s);
sscanf(s, fmt, num);
}
int out_fdccmd(UBYTE byte)
{
long st;
st = start_tmo();
while ((in_stat() & 0xC0) != 0x80)
if (check_tmo(st, 18))
return 1;
out_dat(byte);
return 0;
}
int in_fdcres(UBYTE *byte)
{
long st;
st = start_tmo();
while ((in_stat() & 0xC0) != 0xC0) {
if (check_tmo(st, 18))
return 2;
}
*byte = in_dat();
return 0;
}
int set_for_int()
{ /* set_for_int */
UBYTE seek_status;
seek_status = 0;
pokebyte(0x40, 0x3E, seek_status);
} /* set_for_int */
int wait_for_int()
{ /* wait_for_int */
UBYTE seek_status;
long t1;
t1 = start_tmo();
do {
if (check_tmo(t1, 18))
return 3;
seek_status = peekbyte(0x40, 0x3E);
}
while (seek_status == 0);
return 0;
} /* wait_for_int */
#define DMACH2AD 0x04
#define DMACH2WC 0x05
#define DMACLRFF 0x0C
#define DMAMODE 0x0B
#define DMAWAMRB 0x0A /* WRITE A MASK REGISTER BIT */
#define PAGEREG 0x81
/* cmd = 0 for read, 1 for write */
int set_dma_up(char *ptr, int cmd, int count)
{ /* set_dma_up */
unsigned long paddr, test;
UBYTE lobyte, hibyte, hinybl;
struct SREGS seg;
segread(&seg);
paddr = (seg.ds * 0x10L) + (unsigned) ptr;
lobyte = (char) (paddr & 0xFF);
hibyte = (char) ((paddr >> 8) & 0xFF);
hinybl = (char) ((paddr >> 16) & 0xF);
test = (paddr & 0xFFFFL) + (unsigned) count;
if (test & 0xFFFF0000L) {
printf("paddr - attempt for dma to cross 64K boundary\n");
printf("paddr = 0x%08lx: %01x %02x %02x\n",
paddr, hinybl, hibyte, lobyte);
exit(0);
}
_disable(); /* for Turbo-C: disable(); */
outp(DMACLRFF, 0); /* clear byte ptr flip/flop */
if (cmd == 0)
outp(DMAMODE, 0x46);
else
outp(DMAMODE, 0x4A);
outp(DMACH2AD, lobyte);
outp(DMACH2AD, hibyte);
outp(PAGEREG, hinybl);
count--; /* required for dma chip */
lobyte = (char) (count & 0xFF);
hibyte = (char) ((count >> 8) & 0xFF);
outp(DMACH2WC, lobyte);
outp(DMACH2WC, hibyte);
_enable(); /* for Turbo-C: enable(); */
outp(DMAWAMRB, 2); /* clear bit for ch 2, enabling transfer */
} /* set_dma_up */
int drive_sel(int unit, int motor, int timeout)
{
if (motor)
set_motor_tmo(timeout);
out_dor(0xC+unit+(motor?(0x10<<unit):0));
}
/*******************************************************************/
long start_tmo()
{
long t;
_bios_timeofday(_TIME_GETCLOCK, &t);
/* for Turbo-C: t = biostime(0, t); */
return t;
}
int check_tmo(long startt, int tmoticks)
{
long t;
_bios_timeofday(_TIME_GETCLOCK, &t);
/* for Turbo-C: t = biostime(0, t); */
if (t > startt + tmoticks)
return 1;
else
return 0;
}
#pragma check_pointer(off) /* required here to let these work */
pokebyte(unsigned seg, unsigned off, UBYTE dbyte)
{
UBYTE far *sp;
FP_SEG(sp) = seg; FP_OFF(sp) = off;
/* for Turbo-C: sp = MK_FP(seg, off); */
*sp = dbyte;
}
UBYTE peekbyte(unsigned seg, unsigned off)
{
UBYTE far *sp;
FP_SEG(sp) = seg; FP_OFF(sp) = off;
/* for Turbo-C: sp = MK_FP(seg, off); */
return *sp;
}