home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 181_01 / disk1_c.lst < prev    next >
File List  |  1986-01-09  |  11KB  |  416 lines

  1. Reprinted from: Micro/Systems Journal, Volume 1. No. 2. May/June 1985  
  2. Article Title: "C & Godbout Disk-1 Controller"
  3. Author: Edward Heyman
  4. -----------------------------------------------------------------
  5. Copy of back issue may be obtained for $4.50 (foreign $6) from:
  6. Subscriptions are: $20/yr & $35/2yrs ; published bi-monthly
  7. Micro/Systems Journal
  8. Box 1192
  9. Mountainside NJ 07092
  10. -----------------------------------------------------------------
  11. Copyright 1986
  12. Micro/Systems Journal, Box 1192, Mountainside NJ 07092
  13. This software is released into the public domain for
  14.  non-commercial use only.
  15. -----------------------------------------------------------------
  16.  
  17.  
  18.                 LISTING    1
  19.  
  20. /* reads the 8272 status port untill the chip is ready for a command    */
  21. /* byte, must be done before each command byte is sent to the 8272    */
  22.  
  23. int    cmdstat()        
  24. {
  25.     char    c;
  26.     
  27.     while ( (c = inp(fdcstat)) < 0x80);
  28.     return(TRUE);
  29. }
  30.     
  31.  
  32.  
  33.  
  34.  
  35.                 LISTING    2
  36.  
  37. /*     print value of 8272 status register 0's bits            */
  38.  
  39. st0(byte)
  40. char    byte;
  41. {
  42. char    drive,hd,nr,ec,se,ic;
  43.     
  44.     drive = byte & 3;            /* drive number            */
  45.     hd   = (byte >> 2) & 1;        /* head address ie; 0 or 1    */
  46.     nr   = (byte >> 3) & 1;        /* not ready if 1        */
  47.     ec   = (byte >> 4) & 1;        /* equipment check        */
  48.     se   = (byte >> 5) & 1;        /* seek end            */
  49.     ic   = (byte >> 6) & 3;        /* interrupt code, does not    */
  50.     /* work as per 8272 data sheet for read and write commands     */
  51.     /* since Godbout did not implement the terminal count line    */
  52.     printf("\n ST0>  %s %u %s %u %s %u %s %u %s %u %s %u \n",
  53.     "drive = ",drive,
  54.     " head = ",hd," nr = ",nr," ec = ",ec," se = ",se," ic = ",ic);
  55. }/* st0 */
  56.  
  57.  
  58.  
  59.  
  60.  
  61.                 LISTING    3
  62.  
  63. /*         prompt for and return drive number            */
  64. /*   drive may be entered as 'a','b','A','B','0' or '1'            */
  65.  
  66. char    getdrive()
  67. {
  68.     char    drive;
  69.  
  70.     printf("\nEnter drive designation ");
  71.     do
  72.     {
  73.       drive = getchar();
  74.       if( (drive == 'A') || (drive == 'B') )
  75.     drive -= 'A';
  76.       else if( (drive == 'a') || (drive == 'b') )
  77.          drive -= 'a';
  78.        else if( (drive == '0') || (drive == '1') )
  79.               drive -= '0';
  80.         else
  81.         {
  82.           putchar('\b');
  83.           putchar(' ');
  84.           putchar('\b');
  85.         }
  86.     }
  87.     while(drive != 0 && drive != 1);
  88.     return(drive);
  89. } /*getdrive*/
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97.                    LISTING 4
  98.  
  99. /*                 RECAL.C                         */
  100. /*    program for testing routines recal() and senseintstat()        */
  101.  
  102. #include bdscio.h
  103. #include cdisk.h
  104.  
  105. main()
  106. {   
  107.     char    drive;
  108.     int        temp;
  109.     
  110.     while(TRUE) {
  111.         drive = getdrive();
  112.         printf("\n drive = %u  \n",drive);
  113.         recal(drive);
  114.         }/*while*/
  115. }/*main*/
  116.  
  117. senseintstat(bytes)
  118. char bytes[];
  119. /*        reads and returns the 8272 status register 0        */
  120. /*        and the current cylinder number                */
  121. {
  122.     cmdstat();            /* wait till ready for command byte    */
  123.     outp(fdcdata,c_rsts);    /* send command byte            */
  124.     resultstat();        /* wait till ready for result byte    */
  125.     bytes[0] = inp(fdcdata);    /* get status register 0         */
  126.     st0(bytes[0]);        /* print Status Register 0        */
  127.     resultstat();        /* wait till ready for result byte    */
  128.     bytes[1] = inp(fdcdata);    /* get cylinder number             */
  129.     printf("\ncylinder = %u\n",bytes[1]);
  130. }/* senseint stat */
  131.  
  132.  
  133. int    recal(drive)
  134. char    drive;
  135. /*    move the head to cylinder zero, return TRUE if successful    */
  136. /*    print error message if unsuccessful                */
  137. {
  138. int    k;            /* try counter                */
  139. char    bytes[8];        /* array to hold results        */
  140.  
  141. for(k=0; k < 3; K++)
  142. {
  143.     cmdstat();            /* wait till ready for command byte    */
  144.     outp(fdcdata,c_reca);    /* send command byte            */
  145.     cmdstat();            /* wait till ready for command byte    */
  146.     outp(fdcdata,drive);    /* end of 8272 recalibrate command phase*/
  147.     intstat();            /* wait till execution phase complete    */
  148.     senseintstat(bytes);    /* check if recal ok             */
  149.     /*     check for satisfactory completion and at cylinder 0    */
  150.     if( ((bytes[0] & no_err) == 0x00 ) && (bytes[1] == 0)) return(TRUE);
  151. }/* or */
  152. printf("\nRecal error drive %c ",drive+'A');
  153. if ( (bytes[0] & ds_err) != drive ) printf("incorrect drive select\n");
  154. if ( (bytes[0] & nr_err) != 0 ) printf("not ready\n");
  155. if ( (bytes[0] & eq_err) != 0 ) printf("equipment error\n");
  156. return(FALSE);
  157. }/* recal */
  158.  
  159.  
  160.  
  161.  
  162.  
  163.                 LISTING 5
  164.  
  165. /*                 CDISK.H                 */
  166.  
  167. #define TRUE    1
  168. #define FALSE    0
  169.  
  170. /* the following sets the conditional compile in setdma() so that the    */
  171. /* tpa(transient program area is in page 0 for CPM 2.2 and page 1 for    */
  172. /* CPM 3. If you are using with CPM 2.2 or a non-banked CPM 3 set to    */
  173. /* FALSE                                */
  174. #define CPM3    TRUE
  175.  
  176. /*             DISK1 PORTS                    */
  177. #define    fdport    0xc0        /* base address of disk controller    */
  178. #define    fdcstat    fdport        /* 8272 status port            */
  179. #define    fdcdata    fdport + 1    /* 8272 command and results data port    */
  180. #define    fdma    fdport + 2    /* Disk1 DMA port (write)        */
  181. #define    ints    fdport + 2    /* Disk1 interrupt status port (read)    */
  182.  
  183. /*             8272 COMMAND CODES                */
  184. #define    c_rtk    0x02        /* read a track                */
  185. #define    c_spec    0x03        /* specify                */
  186. #define    c_dsts    0x04        /* sense drive status            */
  187. #define    c_wrat    0x05        /* write data                */
  188. #define    c_rdat    0x06        /* read data                */
  189. #define    c_reca    0x07        /* recalibrate                */
  190. #define    c_rsts    0x08        /* sense interrupt status        */
  191. #define c_rdid    0x0A        /* read ID                */
  192. #define    c_form    0x0D        /* format                */
  193. #define    c_seek    0x0F        /* seek                    */
  194.         
  195.             8272 ERROR MASKS
  196. #define ds_err    0x03        /* incorrect disk select        */
  197. #define nr_err     0x08        /* not ready error            */
  198. #define eq_err    0x10        /* equipment error            */
  199. #define no_err    0xc0        /* no error                */
  200.  
  201. /*             GLOBAL VARIABLES                */
  202. /*     globals have the form variable[drive] where drive is 0..3    */
  203.  
  204. char    mt[4];        /* two side operation = 1, one side = 0        */
  205. char    mfm[4];        /* double density = 1, single density = 0    */ 
  206. char    sk[4];        /* skip (not used) always 0            */
  207. char    bps[4];        /* bytes per sector 0,1,2,3 for Godbout format    */
  208. char    eot[4];        /* final sector number of track            */
  209. char    gpl[4];        /* gap length                    */
  210. char    dtl[4];        /* data length                    */
  211.  
  212. int    x,y;        /* cursor coordinates used by iolib.c        */
  213.  
  214.  
  215.  
  216.  
  217.  
  218.  
  219.                 LISTING    6
  220.  
  221. /* Getresult() routine reads the results from a read,write,format or     */
  222. /* readid command returns TRUE for a good read or write            */
  223.  
  224. int    getresult(bytes)
  225. char    bytes[];
  226. {
  227.   int    k;            /* byte counter                */
  228.     
  229.   for (k = 0 ; k < 7 ; ) {
  230.     resultstat();        /* wait till ready for result byte    */
  231.     bytes[k++] = inp(fdcdata);  /* read result byte            */
  232.     }
  233.   return((bytes[1] == 0x80));    /* return TRUE if end of cylinder    */
  234. }/* getresult */
  235.  
  236.  
  237.  
  238.  
  239.  
  240.                 LISTING    7
  241.  
  242. /*         DENSITY.C                         */
  243. /* program to return number of sides, density and format of a disk    */
  244.  
  245. #include bdscio.h
  246. #include cdisk.h
  247.  
  248. main(argc,argv)
  249. char    **argv;
  250. {   
  251.   char  cyl,hds,drive;
  252.   char  bytes[8];    
  253.   int      i;
  254.   
  255.   printf("\ndensity version 1.3\n");
  256.   drive = getdrive();            /* request drive        */
  257.   hds= 0;                /* select head 0        */
  258.   cyl = 2;                /* select cylinder 2        */
  259.   dseek(drive,cyl);            /* position head        */
  260.   getmt(drive);                /* find number of sides        */
  261.   readid(drive,hds,bytes);        /* find density and format    */
  262.   printf("\ndrive %c is ",(drive+'A'));
  263.     if (mt[drive]) printf("Double Sided, ");
  264.     else printf("Single sided, ");
  265.     switch (n[drive]) {
  266.     case 0    : printf("Single density with 128 Byte sectors\n");
  267.           break;
  268.     case 1    : printf("Double density with 256 Byte sectors\n");
  269.           break;
  270.     case 2    : printf("Double density with 512 Byte sectors\n");
  271.           break;
  272.     case 3    : printf("Double density with 1024 Byte sectors\n");
  273.     } /* switch */
  274. } /* density */
  275.     
  276.  
  277.  
  278.  
  279.  
  280.                 LISTING    8
  281. /*        segment of setparam() code                */
  282.     
  283.     else         /* double density */
  284.     switch (n[drive]) {
  285.         case 1    : gpl[drive] = 0x0e;    /* gap length        */
  286.               eot[drive] = 0x1a;    /* last sector on track    */
  287.               dtl[drive] = 0xff;    /* no meaning in dd    */
  288.           break;
  289.         case 2    : gpl[drive] = 0x1b;    /* gap length        */
  290.               eot[drive] = 0x0f;    /* last sector on track    */
  291.               dtl[drive] = 0xff;    /* no meaning in dd    */
  292.           break;
  293.         case 3    : gpl[drive] = 0x35;    /* gap length        */
  294.               eot[drive] = 0x08;    /* last sector on track    */
  295.               dtl[drive] = 0xff;    /* no meaning in dd    */
  296.           break;
  297.         } /* case */
  298. }/* setparam */ 
  299.  
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308.                 LISTING    9 
  309.  
  310. /*             Setrscmd() fills the 9 byte read command array        */
  311.  
  312. setrscmd(rdcmd,drive,cyl,sector,sectors,hds)
  313. char    rdcmd[],drive,cyl,sector,sectors,hds;
  314. {
  315.     rdcmd[0] = (mfm[drive]<<6) | (sk[drive]<< 5) | c_rdat;
  316.     rdcmd[1] = (hds << 2) | drive;    /* head and drive data        */
  317.     rdcmd[2] = cyl;            /* cylinder number        */
  318.     rdcmd[3] = hds;            /* head                */
  319.     rdcmd[4] = sector;            /* first sector to read        */
  320.     rdcmd[5] = n[drive];        /* disk format            */
  321.     rdcmd[6] = sector + sectors - 1;    /* last sector to read        */
  322.     rdcmd[7] = gpl[drive];        /* gap length            */
  323.     rdcmd[8] = dtl[drive];
  324. }/* setrscmd */
  325.  
  326.  
  327.  
  328.  
  329.  
  330.                 LISTING    10
  331.  
  332. /* perform a read operation either sector or cylinder. Must have set up    */
  333. /* the rdcmd[] array before calling this function. Returns TRUE if read */
  334. /* was successful FALSE if an error occured.                */
  335.  
  336. int    dread(rdcmd,bytes)
  337. char    rdcmd[];        /* array contaning the read command    */
  338. char    bytes[];        /* array to recieve the results        */
  339. {
  340.     int    j;            /* byte counter                */
  341.     
  342.     for (j = 0; j < 9;j++)    /* send 9 bytes                */
  343.         {
  344.         cmdstat();        /* wait till ready for command byte    */
  345.         outp(fdcdata,rdcmd[j]); /* send read command byte        */
  346.         }
  347.     intstat();            /* wait till end of execution phase    */
  348.     if(getresult(bytes)) return(TRUE);
  349.     else {
  350.     printf("\nread error drive %c head %u ",
  351.         ( (bytes[0]&3)+'A' ),( (bytes[0]>>2) & 1) );
  352.     geterror(bytes);
  353.     return(FALSE);
  354.     }
  355. }/* dread */
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374.                 LISTING    11
  375.  
  376. /* Geterror() prints  an error message for an incorrect read or write     */
  377. /* command, detailing the error. Must call getresults(bytes) first.    */
  378.         
  379. int    geterror(bytes)
  380. char    bytes[];        /* array containg the results bytes    */
  381. {
  382. if (( bytes[0] & 8) != 0) printf("not ready \n");
  383. if (( bytes[1] & 0x7f) != 0) {
  384.     if ((( bytes[1] & 1) != 0) && (( bytes[2] & 1) == 0))
  385.             printf("missing ID address mark\n");
  386.     if (( bytes[1] & 2 ) != 0 ) printf("write protected\n");
  387.     if (( bytes[1] & 4) != 0) printf("no data transfered \n");
  388.     if ((( bytes[1] & 0x20) != 0) && ((bytes[2] & 0x20) == 0))
  389.         printf("crc error in ID field\n");
  390.     }
  391. if (( bytes[2] != 0)) {
  392.     if (( bytes[2] & 1) != 0) printf("missing data address mark\n");
  393.     if (( bytes[2] & 0x20) != 0) printf("crc error in  data field\n");
  394.     if (( bytes[2] & 0x10) != 0) printf("wrong cylinder\n");
  395.     }
  396. return(TRUE);
  397. }/* geterror */
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.                 LISTING    12
  405.  
  406. /* Segment of setform() command that sets up format command sequence     */
  407. /* to be read by the controller    as it formats each sector.        */
  408.  
  409. for(sector=1,k = 0; sector<=eot[drive]; sector++) {/* do for each sector*/
  410.     buffer[k++] = cyl;                /* cylinder    */
  411.     buffer[k++] = hds;                /* head (side)    */
  412.     buffer[k++] = sector;                /* sector    */
  413.     buffer[k++] = n[drive];                /* format    */
  414.     }/* for */
  415. }/* setformat */
  416.