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 >
Text File  |  1989-09-28  |  14KB  |  486 lines

  1. /* floppydr - floppy "doctor" program: low-low-level access to FDC */
  2. #include <conio.h>
  3. #include <dos.h>
  4. #include <bios.h>
  5. #include <stdio.h>
  6. #include <ctype.h>
  7.  
  8. #define UBYTE unsigned char
  9.  
  10. #define flop_cmd(dr, motflag, moton, c, r, n, b) \
  11.     { drive_sel(dr, motflag, moton); \
  12.     fdc_cmd(c, r, n, b); \
  13.     results(c[0], r);}
  14.  
  15. #define out_dor(cmd) outp(0x3F2, cmd)
  16. #define in_stat() (inp(0x03f4))
  17. #define out_dat(d) outp(0x3f5,d)
  18. #define in_dat() (inp(0x3f5))
  19.     /* notes for Turbo-C:  use outportb() and inportb() */
  20.  
  21. UBYTE buffer[1024];
  22. char get_menu_choice();
  23. UBYTE peekbyte(unsigned, unsigned);
  24. long start_tmo(void);
  25.  
  26. #define READ_DATA 6
  27. #define READ_DELETED_DATA 0xC
  28. #define WRITE_DATA 5
  29. #define WRITE_DELETED_DATA 9
  30. #define READ_TRACK 2
  31. #define READ_ID 0xA
  32. #define FORMAT_TRACK 0xD
  33. #define RECALIBRATE 7
  34. #define SENSE_INTR_STATUS 8
  35. #define SPECIFY 3
  36. #define SENSE_DRIVE_STATUS 4
  37. #define SEEK 0xF
  38.  
  39. typedef struct {
  40.     unsigned int ncmd;
  41.     unsigned int nres;
  42.     char ctype;         /* N, I, R, or W,
  43.                     for "no DMA", "Interrupt", "Read", "Write") */
  44.     } CMD_INFO;
  45.  
  46. CMD_INFO cmdt[16] = {
  47.     {0, 0, ' '}, /* 0x00 */
  48.     {0, 0, ' '}, /* 0x01 */
  49.     {9, 7, 'R'}, /* 0x02 read track */
  50.     {3, 0, 'N'}, /* 0x03 specify */
  51.     {2, 1, 'N'}, /* 0x04 sense drive status */
  52.     {9, 7, 'W'}, /* 0x05 write data */
  53.     {9, 7, 'R'}, /* 0x06 read data */
  54.     {2, 0, 'I'}, /* 0x07 recalibrate */
  55.     {1, 2, 'N'}, /* 0x08 sense interrupt status */
  56.     {9, 7, 'W'}, /* 0x09 write deleted data */
  57.     {2, 7, 'N'}, /* 0x0a read id */
  58.     {0, 0, ' '}, /* 0x0b */
  59.     {9, 7, 'R'}, /* 0x0c read deleted data */
  60.     {6, 7, 'W'}, /* 0x0d format track */
  61.     {0, 0, ' '}, /* 0x0e */
  62.     {3, 0, 'I'}, /* 0x0f seek */
  63.     };
  64.  
  65. #define NDPARM 12
  66. struct DPARM {
  67.     UBYTE spec1;        /* 0 specify byte 1 */
  68.     UBYTE spec2;        /* 1 specify byte 2 */
  69.     UBYTE mot_off_wt;   /* 2 meaningless */
  70.     UBYTE nrec;         /* 3 number of bytes code */
  71.     UBYTE eot;          /* 4 end-of-track */
  72.     UBYTE gpl;          /* 5 gap length */
  73.     UBYTE dtl;          /* 6 data length (if N = 0) */
  74.     UBYTE fgpl;         /* 7 gpl for format */
  75.     UBYTE fd;           /* 8 fill byte for format */
  76.     UBYTE hdsttl;       /* 9 head settle time (milliseconds) */
  77.     UBYTE mot_start;    /* 10 motor start time (1/8 seconds) */
  78.     UBYTE mt_mfm_sk;    /* 11 bits: 0x80 = MT, 0x40 = MFM,
  79.                             0x20 = SK */
  80.     } dparm = {0xcf, 0x02, 0x25, 0x02, 0x12, 0x2A, 
  81.         0xFF, 0x50, 0xF6, 0x01, 0x04, 0xE0};
  82.  
  83. static char *dparmmsg[] = {
  84.     "0 - specify byte 1 (bits 0-3 = HUT, 4-7 = SRT)  ", 
  85.     "1 - specify byte 2 (bit 1-7 = HLT, 0 = 'no dma')", 
  86.     "2 - meaningless (was motor start time)", 
  87.     "3 - N: number of bytes code (2=512)", 
  88.     "4 - EOT: end-of-track", 
  89.     "5 - GPL: gap length", 
  90.     "6 - DTL:data length (if N = 0)", 
  91.     "7 - gpl for format", 
  92.     "8 - fill byte for format", 
  93.     "9 - head settle time (milliseconds) (not used)", 
  94.     "10 - motor start time (1/8 seconds) (not used)", 
  95.     "11 - bits: 0x80 = MT, 0x40 = MFM, 0x20 = SK"};
  96.  
  97. int main()
  98.     {
  99.     UBYTE unit = 0;
  100.     UBYTE track = 0;
  101.     UBYTE head = 0;
  102.     UBYTE sector = 1;
  103.     UBYTE nsector = 9;
  104.  
  105.     UBYTE cd[9], rs[7], c, hdsds;
  106.     int nbyte, i, j;
  107.  
  108.     printf("\n\nfloppy doctor program\n\n");
  109.     out_dor(0);         /* reset card */
  110.     out_dor(0xC);       /* select drive 0, allow ints & DMA */
  111.  
  112.     while (1)
  113.         {
  114.         c = get_menu_choice();
  115.         switch (c)
  116.             {
  117.         case '0':
  118.             printf("  Enter Drive number:");
  119.             getnum("%d", &unit);
  120.             cd[0] = SENSE_DRIVE_STATUS;
  121.             cd[1] = (hdsds = unit + (head << 2));
  122.             flop_cmd(unit, 0, 0, cd, rs, 0, buffer);
  123.             break;
  124.         case '1':
  125.             cd[0] = SPECIFY;
  126.             cd[1] = dparm.spec1;
  127.             cd[2] = dparm.spec2;
  128.             flop_cmd(unit, 0, 0, cd, rs, 0, buffer);
  129.             break;
  130.         case '2':
  131.             cd[0] = RECALIBRATE;
  132.             cd[1] = unit;
  133.             flop_cmd(unit, 1, 200, cd, rs, 0, buffer);
  134.             break;
  135.         case '3':
  136.             printf("  Enter cylinder (track) number: ");
  137.             getnum("%d", &track);
  138.             cd[0] = SEEK;
  139.             cd[1] = hdsds;
  140.             cd[2] = track;
  141.             drive_sel();
  142.             flop_cmd(unit, 1, 200, cd, rs, 0, buffer);
  143.             break;
  144.         case '4':
  145.             printf("  Enter Head number:");
  146.             getnum("%d", &head);
  147.             hdsds = (hdsds & 0x3) | head;
  148.             break;
  149.         case '5':
  150.             cd[0] = READ_DATA + dparm.mt_mfm_sk;
  151.             goto read_write;
  152.         case '6':
  153.             cd[0] = WRITE_DATA + (dparm.mt_mfm_sk & 0xC0);
  154. read_write:
  155.             printf("  Enter sector number: ");
  156.             getnum("%d", §or);
  157.             nbyte = 128 << dparm.nrec;
  158.             cd[1] = hdsds;
  159.             cd[2] = track;
  160.             cd[3] = head;
  161.             cd[4] = sector;
  162.             cd[5] = dparm.nrec;
  163.             cd[6] = dparm.eot;
  164.             cd[7] = dparm.gpl;
  165.             cd[8] = dparm.dtl;
  166.             flop_cmd(unit, 1, 200, cd, rs, nbyte, buffer);
  167.             if ((cd[0] & 0x0f) == READ_DATA) {
  168.                 puts("");
  169.                 dump_buf(nbyte, buffer);
  170.                 }
  171.             break;
  172.         case '7':
  173.             for (i = 0;  i < nsector;  i++)
  174.                 buffer[i * 4 + 2] = i;
  175.             cd[0] = FORMAT_TRACK + (dparm.mt_mfm_sk & 0x40);
  176.             cd[1] = hdsds;
  177.             cd[2] = dparm.nrec;
  178.             cd[3] = nsector;
  179.             cd[4] = dparm.fgpl; /* gap length for format */
  180.             cd[5] = dparm.fd;   /* fill byte for format */
  181.             fdc_cmd(unit, 1, 200, cd, rs, nsector * 4, buffer);
  182.             break;
  183.         case '8':
  184.             printf("Enter number of times to read ids: ");
  185.             getnum("%d", &j);
  186.             drive_sel(unit, 1, 200);
  187.             cd[0] = READ_ID + (dparm.mt_mfm_sk & 0x40);
  188.             cd[1] = hdsds;
  189.             for (i = 0;  i < j;  i++) {
  190.                 fdc_cmd(cd, rs, 0, buffer);
  191.                 buffer[i * 4 + 0] = rs[3];
  192.                 buffer[i * 4 + 1] = rs[4];
  193.                 buffer[i * 4 + 2] = rs[5];
  194.                 buffer[i * 4 + 3] = rs[6];
  195.                 }
  196.             results(cd[0], rs);     /* of the last command */
  197.             for (i = 0;  i < j;  i++)
  198.                 printf("c = %d, h = %d, r = %d, n = %d\n",
  199.                     buffer[i * 4 + 0], buffer[i * 4 + 1],
  200.                     buffer[i * 4 + 2], buffer[i * 4 + 3]);
  201.             puts("Enter a key when ready");
  202.             getch();
  203.             puts("");
  204.             break;
  205.         case 'R':
  206.             dparm_rpt_chg();
  207.             break;
  208.         case 'X':
  209.             exit(0);
  210.             break;
  211.         default:
  212.             printf("\nIllegal command.\n");
  213.             }
  214.         }
  215.     }
  216.  
  217. char get_menu_choice()
  218.     {
  219.     char inp[80];
  220.  
  221.     puts("");
  222.     puts("Menu:");
  223.     puts("     0 - Drive #");
  224.     puts("     1 - Specify (Step rate, Head unload, etc.)");
  225.     puts("     2 - Recalibrate");
  226.     puts("     3 - Seek (cylinder (track) number");
  227.     puts("     4 - Head (surface)");
  228.     puts("     5 - Read sector");
  229.     puts("     6 - Write sector");
  230.     puts("     7 - Format a track");
  231.     puts("     8 - Read IDs");
  232.     puts("     R - Report and change the DPARM table");
  233.     puts("     X - Exit program");
  234.     puts("\n");
  235.     printf("Command:  ");
  236.     gets(inp);
  237.     puts("");
  238.     return (isalpha(inp[0]) ? toupper(inp[0]) : inp[0]);
  239.     }
  240.  
  241. int dparm_rpt_chg()
  242.     {
  243.     int i, pi;
  244.     unsigned int nv;
  245.     UBYTE *a = &dparm.spec1;
  246.  
  247.     for (i = 0;  i < NDPARM;  i++)
  248.         printf("(0x%02x)  ", a[i]),  puts(dparmmsg[i]);
  249.     puts("");
  250.     printf("Which to change (enter -1 if none to change): ");
  251.     getnum("%d", &pi);
  252.     if ((pi < 0) || (pi >= NDPARM))
  253.         return;
  254.     printf("dparm[%d] = %02x, new value:  ", pi, a[pi]);
  255.     getnum("%x", &nv);
  256.     a[pi] = nv;
  257.     }
  258.  
  259. int fdc_cmd(UBYTE cmds[], UBYTE results[], int nbyte, UBYTE buffer[])
  260.     {                       /* fdc_cmd */
  261.     int i, ccode, s;
  262.  
  263.     ccode = cmds[0] & 0xF;
  264.     if (cmdt[ccode].ctype == 'R')
  265.         set_dma_up(buffer, 0, nbyte);   /* set up DMA to read */
  266.     else if (cmdt[ccode].ctype == 'W')
  267.         set_dma_up(buffer, 1, nbyte);   /* set up DMA to write */
  268.     set_for_int();
  269.     for (i = 0;  i < cmdt[ccode].ncmd;  i++) {
  270.         s = out_fdccmd(cmds[i]);
  271.         if (s)
  272.             printf("fdc_cmd: Error from out_fdccmd = %d\n", s);
  273.         }
  274.     if (cmdt[ccode].ctype == 'I') {
  275.         if (s = wait_for_int())
  276.             printf("fdc_cmd: Error from wait_for_int = %d\n", s);
  277.         s = out_fdccmd(SENSE_INTR_STATUS);
  278.         if (s)
  279.             printf("fdc_cmd: Error "
  280.                 "during sense_intr_stat from out_fdccmd = %d\n", s);
  281.         in_fdcres(results++);   /* from sense_intr_status */
  282.         in_fdcres(results);
  283.         }
  284.     else {
  285.         if (cmdt[ccode].ctype != 'N') {
  286.             if (s = wait_for_int())
  287.                 printf("fdc_cmd: Error from wait_for_int = %d\n", s);
  288.             }
  289.         for (i = 0;  i < cmdt[ccode].nres;  i++) {
  290.             s = in_fdcres(results++);
  291.             if (s)
  292.                 printf("fdc_cmd: Error from in_fdcres = %d\n", s);
  293.             }
  294.         }
  295.     }                               /* fdc_cmd */
  296.  
  297. int results(UBYTE cmd, UBYTE res[])
  298.     {
  299.     int i;
  300.  
  301.     printf("\nresults :");
  302.     for (i=0; i < (cmdt[cmd & 0xf].nres); i++)
  303.         printf("%02x ", res[i]);
  304.     printf("\n");
  305.     }
  306.  
  307. int dump_buf(int n, UBYTE buf[])
  308.     {                           /* dump_buf */
  309.     int i, j;
  310.  
  311.     for (i = 0;  i < n;  i++) {
  312.         if ((i & 0xF) == 0)
  313.             printf("%4x:  ", i);
  314.         else if ((i & 0x7) == 0)
  315.             printf(" |");
  316.         printf(" %02x", buf[i]);
  317.         if ((i & 0xF) == 15) {
  318.             printf("  |");
  319.             for (j = i - 15;  j <= i;  j++)
  320.                 if (isprint(buf[j]))
  321.                     putchar(buf[j]);
  322.                 else
  323.                     putchar('.');
  324.             printf("|\n");
  325.             if ((i & 0xFF) == 0xFF) {
  326.                 printf("hit any key to continue");
  327.                 getch();
  328.                 puts("");
  329.                 }
  330.             }
  331.         }
  332.     }
  333.  
  334. int set_motor_tmo(int count)
  335.     {
  336.     pokebyte(0x40, 0x40, &count);   /* set motor_count for BIOS */
  337.     }
  338.  
  339. int getnum(char *fmt, int *num)
  340.     {
  341.     char s[80];
  342.  
  343.     gets(s);
  344.     sscanf(s, fmt, num);
  345.     }
  346.  
  347. int out_fdccmd(UBYTE byte)
  348.     {
  349.     long st;
  350.  
  351.     st = start_tmo();
  352.     while ((in_stat() & 0xC0) != 0x80)
  353.         if (check_tmo(st, 18))
  354.             return 1;
  355.     out_dat(byte);
  356.     return 0;
  357.     }
  358.  
  359. int in_fdcres(UBYTE *byte)
  360.     {
  361.     long st;
  362.  
  363.     st = start_tmo();
  364.     while ((in_stat() & 0xC0) != 0xC0) {
  365.         if (check_tmo(st, 18))
  366.             return 2;
  367.         }
  368.     *byte = in_dat();
  369.     return 0;
  370.     }
  371.  
  372. int set_for_int()
  373.     {                   /* set_for_int */
  374.     UBYTE seek_status;
  375.  
  376.     seek_status = 0;
  377.     pokebyte(0x40, 0x3E, seek_status);
  378.     }                   /* set_for_int */
  379.  
  380. int wait_for_int()
  381.     {                   /* wait_for_int */
  382.     UBYTE seek_status;
  383.     long t1;
  384.  
  385.     t1 = start_tmo();
  386.     do  {
  387.         if (check_tmo(t1, 18))
  388.             return 3;
  389.         seek_status = peekbyte(0x40, 0x3E);
  390.         }
  391.     while (seek_status == 0);
  392.     return 0;
  393.     }                   /* wait_for_int */
  394.  
  395. #define DMACH2AD    0x04
  396. #define DMACH2WC    0x05
  397. #define DMACLRFF    0x0C
  398. #define DMAMODE     0x0B
  399. #define DMAWAMRB    0x0A        /* WRITE A MASK REGISTER BIT */
  400. #define PAGEREG     0x81
  401.                            /* cmd = 0 for read, 1 for write */
  402. int set_dma_up(char *ptr, int cmd, int count)
  403.     {                   /* set_dma_up */
  404.     unsigned long paddr, test;
  405.     UBYTE lobyte, hibyte, hinybl;
  406.     struct SREGS seg;
  407.  
  408.     segread(&seg);
  409.  
  410.     paddr = (seg.ds * 0x10L) + (unsigned) ptr;
  411.     lobyte = (char) (paddr & 0xFF);
  412.     hibyte = (char) ((paddr >> 8) & 0xFF);
  413.     hinybl = (char) ((paddr >> 16) & 0xF);
  414.     test = (paddr & 0xFFFFL) + (unsigned) count;
  415.     if (test & 0xFFFF0000L) {
  416.         printf("paddr - attempt for dma to cross 64K boundary\n");
  417.         printf("paddr = 0x%08lx: %01x %02x %02x\n",
  418.             paddr, hinybl, hibyte, lobyte);
  419.         exit(0);
  420.         }
  421.     _disable();     /* for Turbo-C: disable(); */
  422.     outp(DMACLRFF, 0);  /* clear byte ptr flip/flop */
  423.     if (cmd == 0)
  424.         outp(DMAMODE, 0x46);
  425.     else 
  426.         outp(DMAMODE, 0x4A);
  427.     outp(DMACH2AD, lobyte);
  428.     outp(DMACH2AD, hibyte);
  429.     outp(PAGEREG, hinybl);
  430.     count--;            /* required for dma chip */
  431.     lobyte = (char) (count & 0xFF);
  432.     hibyte = (char) ((count >> 8) & 0xFF);
  433.     outp(DMACH2WC, lobyte);
  434.     outp(DMACH2WC, hibyte);
  435.     _enable();      /* for Turbo-C: enable(); */
  436.     outp(DMAWAMRB, 2);  /* clear bit for ch 2, enabling transfer */
  437.     }                   /* set_dma_up */
  438.  
  439. int drive_sel(int unit, int motor, int timeout)
  440.     {
  441.     if (motor)
  442.         set_motor_tmo(timeout);
  443.     out_dor(0xC+unit+(motor?(0x10<<unit):0));
  444.     }
  445.  
  446. /*******************************************************************/
  447. long start_tmo()
  448.     {
  449.     long t;
  450.  
  451.     _bios_timeofday(_TIME_GETCLOCK, &t);
  452.             /* for Turbo-C: t = biostime(0, t); */
  453.     return t;
  454.     }
  455.  
  456. int check_tmo(long startt, int tmoticks)
  457.     {
  458.     long t;
  459.  
  460.     _bios_timeofday(_TIME_GETCLOCK, &t);
  461.             /* for Turbo-C: t = biostime(0, t); */
  462.     if (t > startt + tmoticks)
  463.         return 1;
  464.     else
  465.         return 0;
  466.     }
  467.  
  468. #pragma check_pointer(off)    /* required here to let these work */
  469. pokebyte(unsigned seg, unsigned off, UBYTE dbyte)
  470.     {
  471.     UBYTE far *sp;
  472.  
  473.     FP_SEG(sp) = seg;       FP_OFF(sp) = off;
  474.          /* for Turbo-C:  sp = MK_FP(seg, off); */
  475.     *sp = dbyte;
  476.     }
  477.  
  478. UBYTE peekbyte(unsigned seg, unsigned off)
  479.     {
  480.     UBYTE far *sp;
  481.  
  482.     FP_SEG(sp) = seg;       FP_OFF(sp) = off;
  483.         /* for Turbo-C:  sp = MK_FP(seg, off); */
  484.     return *sp;
  485.     }
  486.