home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 354.lha / MSH_v1.5 / src / devio.c < prev    next >
C/C++ Source or Header  |  1990-03-12  |  48KB  |  1,892 lines

  1. /*-
  2.  * $Id: devio.c,v 1.4 90/02/10 21:42:17 Rhialto Exp $
  3.  * $Log:    devio.c,v $
  4.  * Revision 1.4  90/02/10  21:42:17  Rhialto
  5.  * Small changes
  6.  * 
  7.  * Revision 1.3  90/01/27  20:36:04  Rhialto
  8.  * Variable #sectors/track!
  9.  *
  10.  * Revision 1.2  90/01/23  00:41:39  Rhialto
  11.  * Remove C version of DecodeTrack.
  12.  *
  13.  * Revision 1.1  89/12/17  20:04:11  Rhialto
  14.  *
  15.  * DEVIO.C
  16.  *
  17.  * The messydisk.device code that does the real work.
  18.  *
  19.  * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
  20.  * not be used or copied without a licence.
  21. -*/
  22.  
  23. #include "dev.h"
  24. #include "device.h"
  25.  
  26. /*#undef DEBUG            /**/
  27. #ifdef DEBUG
  28. #   define    debug(x)  dbprintf x
  29. #else
  30. #   define    debug(x)
  31. #endif
  32.  
  33. struct DiskResource *DRResource;/* Argh! A global variable! */
  34. void *CiaBResource;        /* And yet another! */
  35.  
  36. void        Internal_Update();
  37. word        DataCRC();
  38. word        CalculateGapLength();
  39.  
  40. /*-
  41.  *  The high clock bit in this table is still 0, but it could become
  42.  *  a 1 if the two adjecent data bits are both 0.
  43.  *  In fact, that is the principle of MFM clock bits: make sure that no
  44.  *  two 1 bits are adjecent, but not too many (more than 3) 0 bits either.
  45.  *  So, 0 c 0 -> 0 1 0        (where c is a clock bit to be determined)
  46.  *    0 c 1 -> 0 0 1
  47.  *    1 c 0 -> 1 0 0
  48.  *    1 c 1 -> 1 0 1
  49.  *  The sync pattern, $4489, is %0100 0100 1000 1001
  50.  *                  ~ ~  ~ ~  ~ ~  ~ ~ -> %1010 0001 -> $A1
  51.  *  also follows the rules, but won't be formed by encoding $A1...
  52.  *  Since the bytes are written high bit first, the unknown clock bit
  53.  *  (for encoded nybbles 0-7, high bit 0) will become a 1 if the preceding
  54.  *  byte was even (with low bit 0).
  55.  *  So, the clock bit is the NOR of the two data bits.
  56. -*/
  57.  
  58. byte        MfmEncode[16] = {
  59.     0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
  60.     0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55
  61. };
  62.  
  63. #define SYNC    0x4489
  64. #define TLEN    12500        /* In BYTES */
  65. #define RLEN    (TLEN+1324) /* 1 sector extra */
  66. #define WLEN    (TLEN+20)   /* 20 bytes more than the theoretical track size */
  67.  
  68. #define INDEXGAP    60  /* All these values are in WORDS */
  69.  
  70. #define IDGAP2        12  /* Sector header: 22 words */
  71. #define IDSYNC         3
  72. #define IDMARK         1
  73. #define IDDATA         4
  74. #define IDCRC         2
  75. #define IDLEN        (IDGAP2+IDSYNC+IDMARK+IDDATA+IDCRC)
  76.  
  77. #define DATAGAP1    22  /* Sector itself: 552 words */
  78. #define DATAGAP2    12
  79. #define DATASYNC     3
  80. #define DATAMARK     1
  81. #define DATACRC      2
  82. #define DATAGAP3_9    78  /* for 9 or less sectors/track */
  83. #define DATAGAP3_10    40  /* for 10 sectors/track */
  84. #define DATALEN     (DATAGAP1+DATAGAP2+DATASYNC+DATAMARK+MS_BPS+DATACRC)
  85.  
  86. #define BLOCKLEN    (IDLEN+DATALEN)     /* Total: 574 words */
  87.  
  88. #define TAILGAP     50
  89.  
  90. /* INDENT OFF */
  91. #asm
  92.  
  93. ; Some hardware data:
  94.  
  95. SYNC        equ $4489
  96. TLEN        equ 12500    ; 2 miscrosecs/bit, 200 ms/track -> 100000 bits
  97. WLEN        equ TLEN+20
  98.  
  99. ;;;;
  100. ;
  101. ;   The following lengths are all in unencoded bytes (or encoded words)
  102.  
  103. INDEXGAP    equ 60
  104.  
  105. IDGAP2        equ 12
  106. IDSYNC        equ  3
  107. IDMARK        equ  1
  108. IDDATA        equ  4
  109. IDCRC        equ  2
  110.  
  111. DATAGAP1    equ 22
  112. DATAGAP2    equ 12
  113. DATASYNC    equ  3
  114. DATAMARK    equ  1
  115. DATACRC     equ  2
  116.  
  117. custom        equ $DFF000
  118.  
  119. Dsklen        equ $24
  120. Intena        equ $9a     ; Interrupt enable  register (write)
  121. Intreq        equ $9c     ; Interrupt request register (write)
  122.  
  123. ; Flags in DSKLEN:
  124.  
  125. dskdmaoff    equ $4000
  126.  
  127. ; Flags in INTENA/INTREQ:
  128.  
  129. intf_setclr    equ 1<<15
  130. intf_dskblk    equ 1<<1
  131.  
  132. ; CIA interrupt control register bits/flags:
  133.  
  134. ciaicrf_flg    equ    1<<4     ; flg interrupt (disk index)
  135.  
  136. ; some cia.resource library functions
  137.  
  138.         public    _LVOSignal
  139.         public    _LVOAbleICR
  140.         public    _LVOSetICR
  141.  
  142. _SafeEnableICR: move.l    _CiaBResource,a6
  143.         move.b    4+1(sp),d0
  144.         jsr    _LVOSetICR(a6)      ; clear pending interrupt
  145.         move.b    4+1(sp),d0
  146.         or.b    #$80,d0         ; then enable it
  147.         jsr    _LVOAbleICR(a6)
  148.         rts
  149. ;;;;
  150. ;
  151. ;   Disk index interrupt code.
  152. ;   is_Data (A1) is the value to stuff into the DSKLEN register.
  153. ;   A0 points to the custom chips already.
  154. ;   It then enables the disk block interrupt and disables the
  155. ;   index interrupt.
  156.  
  157. _IndexIntCode:
  158. ;     movem.l A2-A4/D2-D7,-(sp)
  159.     move.w    #dskdmaoff,Dsklen(a0)
  160.     move.w    a1,Dsklen(a0)
  161.     move.w    a1,Dsklen(a0)       ; this enables the DMA
  162.     move.w    #intf_setclr|intf_dskblk,Intena(a0)
  163.     move.l    _CiaBResource,a6
  164.     move.b    #ciaicrf_flg,d0
  165.     jsr    _LVOAbleICR(a6)     ; disable index interrupt
  166. ;     movem.l (sp)+,A2-A4/D2-D7
  167.     rts
  168. ;;;;
  169. ;
  170. ;   Disk DMA finished interrupt code.
  171. ;   (a1) is the task to Signal, 4(a1) is the signal mask to use.
  172. ;   Disables the disk block finished interrupt.
  173.  
  174. _DskBlkIntCode:
  175.     move.w    #dskdmaoff,Dsklen(a0)   ; disable disk DMA
  176.     move.w    #intf_dskblk,Intena(a0) ; disable the interrupt
  177.     move.w    #intf_dskblk,Intreq(a0) ; clear 'diskblock finished' flag
  178.     move.l    4(a1),d0            ; signal mask
  179.     move.l    (a1),a1             ; task to signal
  180.     jsr    _LVOSignal(a6)
  181.     rts
  182.  
  183. #endasm
  184.  
  185. #define DSKDMAEN    (1<<15)
  186. #define DSKWRITE    (1<<14)
  187.  
  188. void IndexIntCode(), DskBlkIntCode();
  189.  
  190. /* INDENT ON */
  191.  
  192. int
  193. HardwareIO(dev, unit, dskwrite)
  194. DEV           *dev;
  195. register UNIT  *unit;
  196. int        dskwrite;
  197. {
  198.     struct {
  199.     struct Task *task;
  200.     ulong signal;
  201.     } tasksig;
  202.  
  203.     debug(("Disk buffer is at %lx\n", dev->md_Rawbuffer));
  204.  
  205.     tasksig.task = FindTask(NULL);
  206.     tasksig.signal = 1L << unit->mu_DmaSignal;
  207.  
  208.     unit->mu_DRUnit.dru_Index.is_Data = (APTR) ((WLEN >> 1)|DSKDMAEN| dskwrite);
  209.     unit->mu_DRUnit.dru_DiscBlock.is_Data = (APTR) &tasksig;
  210.  
  211.     /* Clear signal bit */
  212.     SetSignal(0L, tasksig.signal);
  213.  
  214.     /* Allocate drive and install index and block interrupts */
  215.     GetDrive(&unit->mu_DRUnit);
  216.  
  217.     /* Select correct drive and side */
  218.     ciab.ciaprb = 0xff & ~CIAF_DSKMOTOR;    /* See hardware manual p229 */
  219.     ciab.ciaprb = 0xff & ~CIAF_DSKMOTOR
  220.                & ~(CIAF_DSKSEL0 << unit->mu_UnitNr)
  221.                & ~(unit->mu_CurrentSide << CIAB_DSKSIDE);
  222.  
  223.     /* Set up disk parameters */
  224.  
  225. /*
  226.  * This is the adkcon setup: MFM mode, wordsync, no MSBsync, fast mode.
  227.  * The precomp is 0 nanoseconds for the outer half of the disk, 120 for
  228.  * the rest.
  229.  */
  230.     {
  231.     register word adk;
  232.  
  233.     custom.adkcon = ADKF_PRECOMP1|ADKF_PRECOMP0|ADKF_MSBSYNC;
  234.  
  235.     adk = ADKF_SETCLR|ADKF_MFMPREC|ADKF_FAST|ADKF_WORDSYNC;
  236.  
  237.     /* Are we on the inner half ? */
  238.     if (unit->mu_CurrentTrack > unit->mu_NumCyls >> 1) {
  239.         adk |= ADKF_PRECOMP0;
  240.     }
  241.     custom.adkcon = adk;
  242.     }
  243.  
  244.     /* Set up disk buffer address */
  245.     custom.dskpt = (APTR) dev->md_Rawbuffer;
  246.  
  247.     /* Enable disk DMA */
  248.     custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_DISK;
  249.  
  250.     if (dskwrite) {
  251.     /* Enable disk index interrupt to start the whole thing. */
  252.     SafeEnableICR((int) CIAICRF_FLG);
  253.     } else {
  254.     /* Set the sync word */
  255.     custom.dsksync = SYNC;
  256.  
  257.     /* Do the same as the disk index interrupt would */
  258.     custom.dsklen = DSKDMAOFF;
  259.     custom.dsklen = (RLEN >> 1) | DSKDMAEN;
  260.     custom.dsklen = (RLEN >> 1) | DSKDMAEN;
  261.  
  262.     custom.intena = INTF_SETCLR | INTF_DSKBLK;
  263.     }
  264.  
  265.     Wait(tasksig.signal);
  266.  
  267.     FreeDrive();
  268. }
  269.  
  270. #if 0
  271. #define ID_ADDRESS_MARK     0xFE
  272. #define MFM_ID            0x5554
  273. #define DATA_ADDRESS_MARK   0xFB
  274. #define MFM_DATA        0x5545
  275.  
  276. /* INDENT OFF
  277. byte
  278. DecodeByte(mfmdecode, mfm)
  279. byte *mfmdecode;
  280. word mfm;
  281. {
  282.     return mfmdecode[(byte)mfm & 0x7F] |
  283.        mfmdecode[(byte)(mfm >> 8) & 0x7F] << 4;
  284. } */
  285.  
  286. #asm
  287. mfmdecode   set     4
  288. mfm        set     8
  289.  
  290. _DecodeByte:
  291.     move.l    mfmdecode(sp),a0
  292.     move.b    mfm(sp),d1      ; high nybble
  293.     and.w    #$7f,d1     ; strip clock bit (and garbage)
  294.     move.b    (a0,d1.w),d0    ; decode 4 data bits
  295.     lsl.b    #4,d0        ; make room for the rest
  296.  
  297.     move.b    mfm+1(sp),d1    ; low nybble
  298.     and.b    #$7f,d1     ; strip clock bit again
  299.     or.b    (a0,d1.w),d0    ; insert 4 decoded bits
  300.  
  301.     rts
  302.  
  303. #endasm
  304.  
  305. /* INDENT ON */
  306. byte DecodeByte();
  307.  
  308. int
  309. DecodeTrack(dev, unit)
  310. DEV           *dev;
  311. UNIT           *unit;
  312. {
  313.     register word  *rawbuf = (word *)dev->md_Rawbuffer; /*  a2 */
  314.     byte       *rawend = (byte *)rawbuf + RLEN - (MS_BPS+2)*sizeof(word);
  315.     byte       *trackbuf = unit->mu_TrackBuffer;
  316.     register byte  *decode = dev->md_MfmDecode;     /*  a3 */
  317.     word       *oldcrc = unit->mu_CrcBuffer;
  318.     register byte  *secptr;                /*  a4 */
  319.     long        sector;
  320.     word        numsecs;
  321.     register long   numbytes;                /*  d3 */
  322.     word        maxsec;
  323.  
  324. #define Len    ((byte *)rawbuf - dev->md_Rawbuffer)
  325.     maxsec = 0;
  326.  
  327.     for (numsecs = 0; numsecs < MS_SPT_MAX; numsecs++) {
  328.     /*
  329.      *  First try to find a sector id.
  330.      */
  331. find_id:
  332.     while (*rawbuf != SYNC) {
  333.         if (++rawbuf >= rawend) {
  334.         debug(("id start, EOT %4x\n", Len));
  335.         goto end;
  336.         }
  337.     }
  338.     while (*rawbuf == SYNC) {
  339.         rawbuf++;
  340.     }
  341.     if (*rawbuf++ != MFM_ID) {
  342.         debug(("No ID (%4x), %4x\n", rawbuf[-1], Len));
  343.         goto find_id;
  344.     }
  345.  
  346.     sector = DecodeByte(decode, *rawbuf++);
  347.     if (sector != unit->mu_CurrentTrack) {
  348.         debug(("Track error?? %d\n", (int)sector));
  349.         goto find_id;
  350.     }
  351.     sector = DecodeByte(decode, *rawbuf++);
  352.     if (sector != unit->mu_CurrentSide) {
  353.         debug(("Side error?? %d\n", (int)sector));
  354.         goto find_id;
  355.     }
  356.     if (rawbuf >= rawend) {
  357.         debug(("id end, EOT %4x\n", Len));
  358.         goto end;
  359.     }
  360.     sector = DecodeByte(decode, *rawbuf++);
  361.     debug(("#%2d %4x, ", (int)sector, Len-0xC));
  362.     if (sector > MS_SPT_MAX) {
  363.         debug(("Bogus sector number) "));
  364.         goto find_id;
  365.     }
  366.     if (sector > maxsec)
  367.         maxsec = sector;
  368.     sector--;        /* Normalize sector number */
  369.  
  370.     /*
  371.      *  Then find the data block.
  372.      */
  373. find_data:
  374.     while (*rawbuf != SYNC) {
  375.         if (++rawbuf >= rawend) {
  376.         debug(("data start, EOT %4x\n", Len));
  377.         return 0; /* TDERR_TooFewSecs; */
  378.         }
  379.     }
  380.     while (*rawbuf == SYNC) {
  381.         rawbuf++;
  382.     }
  383.     if (*rawbuf++ != MFM_DATA) {
  384.         debug(("No Data (%4x), %4x\n", rawbuf[-1], Len));
  385.         goto find_id;
  386.     }
  387.     debug(("%4x, ", Len-8));
  388.  
  389.     if (rawbuf >= rawend) {
  390.         debug(("short data, EOT %4x\n", Len));
  391.         goto end;
  392.     }
  393.     secptr = trackbuf + MS_BPS * sector;
  394.     for (numbytes = 0; numbytes < MS_BPS; numbytes++) {
  395.         *secptr++ = DecodeByte(decode, *rawbuf++);
  396.     }
  397.     debug(("%4x\n", Len));
  398.     oldcrc[sector]    = DecodeByte(decode, *rawbuf++) << 8;
  399.     oldcrc[sector] |= DecodeByte(decode, *rawbuf++);
  400.     unit->mu_SectorStatus[sector] = unit->mu_InitSectorStatus;
  401.     }
  402.  
  403. end:
  404.     if (numsecs == 0)
  405.     return TDERR_TooFewSecs;
  406.  
  407. #ifndef READONLY
  408.     /*
  409.      * If we read the very first track, we adjust our notion about the
  410.      * number of sectors on each track. This is the only track we can
  411.      * accurately find if this number is unknown. Let's hope that the first
  412.      * user of this disk starts reading it here.
  413.      */
  414.     if (unit->mu_CurrentTrack == 0 && unit->mu_CurrentSide == 0) {
  415.     unit->mu_SectorsPerTrack = maxsec;
  416.     }
  417.     unit->mu_CurrentSectors = maxsec;
  418.     debug(("%d sectors\n", unit->mu_SectorsPerTrack));
  419. #endif
  420.  
  421.     return 0;
  422.  
  423. #undef Len
  424. }
  425. #else    /* Use assembly */
  426.  
  427. int
  428. DecodeTrack(dev, unit)
  429. DEV           *dev;
  430. UNIT           *unit;
  431. {
  432.     register word  *rawbuf = (word *)dev->md_Rawbuffer; /*  a2 */
  433.     byte       *rawend = (byte *)rawbuf + RLEN - (MS_BPS+2)*sizeof(word);
  434.     byte       *trackbuf = unit->mu_TrackBuffer;
  435.     register byte  *decode = dev->md_MfmDecode;     /*  a3 */
  436.     word       *oldcrc = unit->mu_CrcBuffer;
  437.     register byte  *secptr;                /*  a4 */
  438.     long        sector;
  439.     word        numsecs;
  440.     register long   numbytes;                /*  d3 */
  441.     word        maxsec;
  442.  
  443. #asm
  444.  
  445. MFM_ID        equ     $5554
  446. MFM_DATA    equ     $5545
  447.  
  448. rawbuf        equr    a2
  449. decode        equr    a3
  450. secptr        equr    a4
  451. numbytes    equr    d3
  452.  
  453. rawend        set     -4
  454. trackbuf    set     -8
  455. oldcrc        set     -12
  456. sector        set     -16
  457. numsecs     set     -18
  458. maxsec        set     -20
  459.  
  460.     move.w    #0,numsecs(a5)      ; no sectors found yet
  461.     move.w    #0,maxsec(a5)       ; and no highest sector number
  462.  
  463. ;;;;    First we will try to find a sector id.
  464. find_id:
  465.     cmp    #SYNC,(rawbuf)+
  466.     beq.s    fid_gotsync
  467.     cmpa.l    rawend(a5),rawbuf
  468.     blt    find_id
  469.     bra    return            ; We ran off the end of the buffer.
  470.  
  471. fid_gotsync:                ; Skip the other syncs.
  472.     cmp.w    #SYNC,(rawbuf)
  473.     bne    fid_endsync
  474.     lea    2(rawbuf),rawbuf
  475.     bra    fid_gotsync
  476.  
  477. fid_endsync:
  478.     cmp.w    #MFM_ID,(rawbuf)+
  479.     bne    find_id
  480.  
  481.     bsr    DecodeByte        ; track #
  482.     bsr    DecodeByte        ; side #
  483.     moveq.l #0,d0            ; clear high part
  484.     bsr    DecodeByte        ; sector #
  485.     cmp.w    #MS_SPT_MAX,d0        ; sector number too large?
  486.     bgt    find_id
  487.     cmp.w    maxsec(a5),d0       ; what is the highest sector number?
  488.     ble    nomax
  489.     move.w    d0,maxsec(a5)       ; record the highest sector number
  490. nomax:
  491.     subq.w    #1,d0            ; normalize sector number
  492.     move.l    d0,sector(a5)
  493.  
  494. find_data:                ; Then find the data block.
  495.     cmp    #SYNC,(rawbuf)+
  496.     beq.s    fda_gotsync
  497.     cmpa.l    rawend(a5),rawbuf
  498.     blt    find_data
  499.     bra    return            ; we ran off the end of the buffer.
  500.  
  501. fda_gotsync:                ; skip the other syncs.
  502.     cmp.w    #SYNC,(rawbuf)
  503.     bne    fda_endsync
  504.     lea    2(rawbuf),rawbuf
  505.     bra    fda_gotsync
  506.  
  507. fda_endsync:
  508.     cmp.w    #MFM_DATA,(rawbuf)+ ; do we really have a data block?
  509.     bne    find_id
  510.  
  511.     cmpa.l    rawend(a5),rawbuf   ; will we still be inside the mfm data?
  512.     bge    return
  513.  
  514.     move.l    sector(a5),d0       ; calculate the location to
  515.     moveq.l #LOG2_MS_BPS,d1     ;  store this sector.
  516.     asl.l    d1,d0
  517.     move.l    trackbuf(a5),secptr
  518.     add.l    d0,secptr
  519.  
  520.     move.w    #MS_BPS-1,numbytes
  521. data_copy:
  522.     bsr    DecodeByte
  523.     move.b    d0,(secptr)+
  524.     dbra    numbytes,data_copy
  525.  
  526.     move.l    sector(a5),d3       ; get pointer to crc location
  527.     add.l    d3,d3            ; 2 bytes of crc per sector
  528.     move.l    oldcrc(a5),a0
  529.     add.l    d3,a0
  530.  
  531.     bsr    DecodeByte        ; get high byte
  532.     move.b    d0,(a0)+
  533.     bsr    DecodeByte        ; and low byte of crc
  534.     move.b    d0,(a0)+
  535.  
  536. #endasm
  537.     unit->mu_SectorStatus[sector] = unit->mu_InitSectorStatus;
  538. #asm
  539.     addq.w    #1,numsecs(a5)
  540.     cmp.w    #MS_SPT_MAX,numsecs(a5)
  541.     blt    find_id
  542. return:
  543. #endasm
  544.  
  545.     if (numsecs == 0)
  546.     return TDERR_TooFewSecs;
  547.  
  548. #ifndef READONLY
  549.     /*
  550.      * If we read the very first track, we adjust our notion about the
  551.      * number of sectors on each track. This is the only track we can
  552.      * accurately find if this number is unknown. Let's hope that the first
  553.      * user of this disk starts reading it here.
  554.      */
  555.     if (unit->mu_CurrentTrack == 0 && unit->mu_CurrentSide == 0) {
  556.     unit->mu_SectorsPerTrack = maxsec;
  557.     }
  558.     unit->mu_CurrentSectors = maxsec;
  559.     debug(("%d sectors\n", unit->mu_SectorsPerTrack));
  560. #endif
  561.  
  562.     return 0;
  563.  
  564. }
  565.  
  566. #asm
  567. ;;;;
  568. ;
  569. ;   Decode a single MFM word to a byte.
  570. ;   Auto-increments the rawbuffer pointer.
  571.  
  572. DecodeByte:
  573.     move.b    (rawbuf)+,d1    ; high nybble
  574.     and.w    #$7f,d1     ; strip clock bit (and garbage)
  575.     move.b    (decode,d1.w),d0; decode 4 data bits
  576.     lsl.b    #4,d0        ; make room for the rest
  577.  
  578.     move.b    (rawbuf)+,d1    ; low nybble
  579.     and.b    #$7f,d1     ; strip clock bit again
  580.     or.b    (decode,d1.w),d0; insert 4 decoded bits
  581.  
  582.     rts
  583.  
  584. #endasm
  585. #endif    /* using assembly */
  586.  
  587. /*
  588.  * Initialize the ibm mfm decoding table
  589.  */
  590.  
  591. void
  592. InitDecoding(decode)
  593. register byte  *decode;
  594. {
  595.     register int    i;
  596.  
  597.     i = 0;
  598.     do {
  599.     decode[i] = 0xff;
  600.     } while (++i < 128);
  601.  
  602.     i = 0;
  603.     do {
  604.     decode[MfmEncode[i]] = i;
  605.     } while (++i < 0x10);
  606. }
  607.  
  608. #ifdef notdef
  609. long
  610. MyDoIO(req)
  611. register struct IORequest *req;
  612. {
  613.     req->io_Flags |= IOF_QUICK;
  614.     BeginIO(req);
  615.     return WaitIO(req);
  616. }
  617. #endif
  618.  
  619. /*
  620.  * Switch the drive motor on. Return previous state. Don't use this when
  621.  * you have allocated the disk via GetDrive().
  622.  */
  623.  
  624. int
  625. TDMotorOn(tdreq)
  626. register struct IOExtTD *tdreq;
  627. {
  628.     debug(("TDMotorOn "));
  629.     tdreq->iotd_Req.io_Command = TD_MOTOR;
  630.     tdreq->iotd_Req.io_Length = 1;
  631.     DoIO(tdreq);
  632.     debug(("was %ld\n", tdreq->iotd_Req.io_Actual));
  633.  
  634.     return tdreq->iotd_Req.io_Actual;
  635. }
  636.  
  637. /*
  638.  * Get the number of cylinders the drive is capable of using.
  639.  */
  640.  
  641. int
  642. TDGetNumCyls(tdreq)
  643. register struct IOExtTD *tdreq;
  644. {
  645.     tdreq->iotd_Req.io_Command = TD_GETNUMTRACKS;
  646.     DoIO(tdreq);
  647.  
  648.     return tdreq->iotd_Req.io_Actual / NUMHEADS;
  649. }
  650.  
  651. /*
  652.  * Seek the drive to the indicated cylinder. Use the trackdisk.device for
  653.  * ease. Don't use this when you have allocated the disk via GetDrive().
  654.  */
  655.  
  656. int
  657. TDSeek(unit, ioreq, cylinder)
  658. UNIT           *unit;
  659. struct IOStdReq *ioreq;
  660. int        cylinder;
  661. {
  662.     register struct IOExtTD *tdreq = unit->mu_DiskIOReq;
  663.  
  664.     debug(("TDSeek %d\n", cylinder));
  665.  
  666.     tdreq->iotd_Req.io_Command = TD_SEEK;
  667.     tdreq->iotd_Req.io_Offset = cylinder * (TD_SECTOR * NUMSECS * NUMHEADS);
  668.     if ((ioreq->io_Flags & IOMDF_40TRACKS) && (unit->mu_NumCyls == 80))
  669.     tdreq->iotd_Req.io_Offset *= 2;
  670.     DoIO(tdreq);
  671.  
  672.     return tdreq->iotd_Req.io_Error;
  673. }
  674.  
  675. void           *
  676. GetDrive(drunit)
  677. register struct DiskResourceUnit *drunit;
  678. {
  679.     register void  *LastDriver;
  680.  
  681.     debug(("GetDrive: "));
  682.     for (;;) {
  683.     drunit->dru_Message.mn_Node.ln_Type = NT_MESSAGE;
  684.     LastDriver = GetUnit(drunit);
  685.  
  686.     debug(("LastDriver %08lx\n", LastDriver));
  687.     if (LastDriver) {
  688.         return LastDriver;
  689.     } else {
  690.         while (drunit->dru_Message.mn_Node.ln_Type != NT_REPLYMSG)
  691.         Wait(1L << drunit->dru_Message.mn_ReplyPort->mp_SigBit);
  692.         Remove(drunit);
  693.         debug(("GetDrive: Retry\n"));
  694.     }
  695.     }
  696. }
  697.  
  698. void
  699. FreeDrive()
  700. {
  701.     GiveUnit();
  702. }
  703.  
  704. int
  705. GetTrack(ioreq, side, track)
  706. struct IOStdReq *ioreq;
  707. int        side;
  708. int        track;
  709. {
  710.     register int    i;
  711.     DEV        *dev;
  712.     register UNIT  *unit;
  713.  
  714.     debug(("GetTrack %d %d\n", track, side));
  715.     dev = (DEV *) ioreq->io_Device;
  716.     unit = (UNIT *) ioreq->io_Unit;
  717.  
  718.     if (track != unit->mu_CurrentTrack || side != unit->mu_CurrentSide) {
  719. #ifndef READONLY
  720.     Internal_Update(ioreq, unit);
  721. #endif
  722.     for (i = MS_SPT_MAX-1; i >= 0; i--) {
  723.         unit->mu_SectorStatus[i] = TDERR_NoSecHdr;
  724.     }
  725.  
  726.     TDMotorOn(unit->mu_DiskIOReq);
  727.     if (TDSeek(unit, ioreq, track)) {
  728.         debug(("Seek error\n"));
  729.         return ioreq->io_Error = IOERR_BADLENGTH;
  730.     }
  731.     unit->mu_CurrentTrack = track;
  732.     unit->mu_CurrentSide = side;
  733.     ObtainSemaphore(&dev->md_HardwareUse);
  734.     HardwareIO(dev, unit, 0);
  735.     i = DecodeTrack(dev, unit);
  736.     ReleaseSemaphore(&dev->md_HardwareUse);
  737.     debug(("DecodeTrack returns %d\n", i));
  738.  
  739.     if (i != 0) {
  740.         unit->mu_CurrentTrack = -1;
  741.         return i;
  742.     }
  743.     }
  744.  
  745.     return 0;
  746. }
  747.  
  748. /*
  749.  * Test if it is changed
  750.  */
  751.  
  752. int
  753. CheckChanged(ioreq, unit)
  754. struct IOExtTD *ioreq;
  755. register UNIT  *unit;
  756. {
  757.     register struct IOExtTD *tdreq;
  758.  
  759.     if ((ioreq->iotd_Req.io_Command & TDF_EXTCOM) &&
  760.     ioreq->iotd_Count < unit->mu_ChangeNum) {
  761. diskchanged:
  762.     ioreq->iotd_Req.io_Error = TDERR_DiskChanged;
  763. error:
  764.     return 1;
  765.     }
  766.     return 0;
  767. }
  768.  
  769. /*
  770.  * Test if we can read or write the disk. Is it inserted and writable?
  771.  */
  772.  
  773. int
  774. CheckRequest(ioreq, unit)
  775. struct IOExtTD *ioreq;
  776. register UNIT  *unit;
  777. {
  778.     register struct IOExtTD *tdreq;
  779.  
  780.     if ((ioreq->iotd_Req.io_Command & TDF_EXTCOM) &&
  781.     ioreq->iotd_Count < unit->mu_ChangeNum) {
  782. diskchanged:
  783.     ioreq->iotd_Req.io_Error = TDERR_DiskChanged;
  784. error:
  785.     return 1;
  786.     }
  787.     /*
  788.      * if (ioreq->iotd_Req.io_Offset + ioreq->iotd_Req.io_Length >
  789.      * (unit->mu_NumCyls * MS_NSIDES * MS_SPT * MS_BPS)) {
  790.      * ioreq->iotd_Req.io_Error = IOERR_BADLENGTH; goto error; }
  791.      */
  792.  
  793.     tdreq = unit->mu_DiskIOReq;
  794.  
  795.     if (unit->mu_DiskState == STATEF_UNKNOWN) {
  796.     tdreq->iotd_Req.io_Command = TD_PROTSTATUS;
  797.     DoIO(tdreq);
  798.     if (tdreq->iotd_Req.io_Error == 0) {
  799.         if (tdreq->iotd_Req.io_Actual == 0) {
  800.         unit->mu_DiskState = STATEF_PRESENT | STATEF_WRITABLE;
  801.         } else
  802.         unit->mu_DiskState = STATEF_PRESENT;
  803.     } else
  804.         unit->mu_DiskState = 0;
  805.     }
  806.     if (!(unit->mu_DiskState & STATEF_PRESENT))
  807.     goto diskchanged;
  808.  
  809.     /*
  810.      * Check _WRITE, _UPDATE, _FORMAT
  811.      */
  812.     if (STRIP(ioreq->iotd_Req.io_Command) != CMD_READ) {
  813.     if (!(unit->mu_DiskState & STATEF_WRITABLE)) {
  814.         ioreq->iotd_Req.io_Error = TDERR_WriteProt;
  815.         goto error;
  816.     }
  817.     }
  818.     return 0;
  819. }
  820.  
  821.  
  822. /*
  823.  * Read zero or more sectors from the disk and copy them into the user's
  824.  * buffer.
  825.  */
  826.  
  827. void
  828. CMD_Read(ioreq, unit)
  829. register struct IOExtTD *ioreq;
  830. register UNIT  *unit;
  831. {
  832.     int         side;
  833.     int         cylinder;
  834.     int         sector;
  835.     byte       *userbuf;
  836.     long        length;
  837.     long        offset;
  838.     byte       *diskbuf;
  839.     int         retrycount;
  840.  
  841.     debug(("CMD_Read "));
  842.     userbuf = (byte *) ioreq->iotd_Req.io_Data;
  843.     length = ioreq->iotd_Req.io_Length / MS_BPS;    /* Sector count */
  844.     offset = ioreq->iotd_Req.io_Offset / MS_BPS;    /* Sector number */
  845.     debug(("userbuf %08lx off %ld len %ld ", userbuf, offset, length));
  846.  
  847.     cylinder = offset / unit->mu_SectorsPerTrack;
  848.     side = cylinder % MS_NSIDES;
  849.     cylinder /= MS_NSIDES;
  850.     sector = offset % unit->mu_SectorsPerTrack;       /* 0..8 or 9 */
  851.     debug(("Tr=%d Si=%d Se=%d\n", cylinder, side, sector));
  852.  
  853.     ioreq->iotd_Req.io_Actual = 0;
  854.  
  855.     if (length <= 0 || CheckRequest(ioreq, unit))
  856.     goto end;
  857.  
  858.     retrycount = 0;
  859.     diskbuf = unit->mu_TrackBuffer + MS_BPS * sector;
  860. gettrack:
  861.     GetTrack(ioreq, side, cylinder);
  862.  
  863.     for (;;) {
  864.     /*
  865.      * Have we ever checked this CRC?
  866.      */
  867.     if (unit->mu_SectorStatus[sector] == CRC_UNCHECKED) {
  868.         /*
  869.          * Do it now. If it mismatches, remember that for later.
  870.          */
  871.         if (unit->mu_CrcBuffer[sector] != DataCRC(diskbuf)) {
  872.         debug(("%d: %04x, now %04x\n", sector, unit->mu_CrcBuffer[sector], DataCRC(diskbuf)));
  873.         unit->mu_SectorStatus[sector] = TDERR_BadSecSum;
  874.         } else
  875.         unit->mu_SectorStatus[sector] = TDERR_NoError;
  876.     }
  877.     if (unit->mu_SectorStatus[sector] > TDERR_NoError) {
  878.         if (++retrycount < 3) {
  879.         unit->mu_CurrentTrack = -1;
  880.         goto gettrack;
  881.         }
  882.         ioreq->iotd_Req.io_Error = unit->mu_SectorStatus[sector];
  883.         goto end;        /* Don't use this sector anymore... */
  884.     }
  885.     retrycount = 0;
  886.     CopyMem(diskbuf, userbuf, (long) MS_BPS);
  887.     ioreq->iotd_Req.io_Actual += MS_BPS;
  888.     if (--length <= 0)
  889.         break;
  890.     userbuf += MS_BPS;
  891.     diskbuf += MS_BPS;
  892.     if (++sector >= unit->mu_SectorsPerTrack) {
  893.         sector = 0;
  894.         diskbuf = unit->mu_TrackBuffer;
  895.         if (++side >= MS_NSIDES) {
  896.         side = 0;
  897.         if (++cylinder >= unit->mu_NumCyls) {
  898.             /* ioreq->iotd_Req.io_Error = IOERR_BADLENGTH; */
  899.             goto end;
  900.         }
  901.         }
  902.         GetTrack(ioreq, side, cylinder);
  903.     }
  904.     }
  905.  
  906. end:
  907.     TermIO(ioreq);
  908. }
  909.  
  910. #ifdef READONLY
  911.  
  912. void
  913. CMD_Write(ioreq, unit)
  914. register struct IOExtTD *ioreq;
  915. UNIT           *unit;
  916. {
  917.     ioreq->iotd_Req.io_Error = TDERR_NotSpecified;
  918.     TermIO(ioreq);
  919. }
  920.  
  921. void
  922. TD_Format(ioreq, unit)
  923. register struct IOExtTD *ioreq;
  924. UNIT           *unit;
  925. {
  926.     ioreq->iotd_Req.io_Error = TDERR_NotSpecified;
  927.     TermIO(ioreq);
  928. }
  929.  
  930. #endif
  931.  
  932. void
  933. CMD_Reset(ioreq, unit)
  934. struct IOExtTD *ioreq;
  935. UNIT           *unit;
  936. {
  937.     unit->mu_CurrentSide = -1;
  938.     unit->mu_TrackChanged = 0;
  939.     TermIO(ioreq);
  940. }
  941.  
  942. void
  943. CMD_Update(ioreq, unit)
  944. struct IOExtTD *ioreq;
  945. register UNIT  *unit;
  946. {
  947. #ifndef READONLY
  948.     if (unit->mu_TrackChanged && !CheckRequest(ioreq, unit))
  949.     Internal_Update(ioreq, unit);
  950. #endif
  951.     TermIO(ioreq);
  952. }
  953.  
  954. void
  955. CMD_Clear(ioreq, unit)
  956. struct IOExtTD *ioreq;
  957. UNIT           *unit;
  958. {
  959.     if (!CheckChanged(ioreq, unit)) {
  960.     unit->mu_CurrentSide = -1;
  961.     unit->mu_TrackChanged = 0;
  962.     }
  963.     TermIO(ioreq);
  964. }
  965.  
  966. void
  967. TD_Seek(ioreq, unit)
  968. struct IOExtTD *ioreq;
  969. UNIT           *unit;
  970. {
  971.     if (!CheckChanged(ioreq, unit)) {
  972.     word        cylinder;
  973.  
  974.     cylinder = (ioreq->iotd_Req.io_Offset / unit->mu_SectorsPerTrack) /
  975.             (MS_BPS * MS_NSIDES);
  976.     TDSeek(unit, ioreq, cylinder);
  977.     }
  978.     TermIO(ioreq);
  979. }
  980.  
  981. /*
  982.  * Ask the trackdisk.device for the answer, but keep a local copy.
  983.  */
  984.  
  985. void
  986. TD_Changenum(ioreq, unit)
  987. struct IOExtTD *ioreq;
  988. UNIT           *unit;
  989. {
  990.     register struct IOStdReq *req;
  991.  
  992.     req = &unit->mu_DiskIOReq->iotd_Req;
  993.     req->io_Command = TD_CHANGENUM;
  994.     DoIO(req);
  995.  
  996.     unit->mu_ChangeNum = req->io_Actual;
  997.     ioreq->iotd_Req.io_Actual = req->io_Actual;
  998.     TermIO(ioreq);
  999. }
  1000.  
  1001. int
  1002. DevInit(dev)
  1003. register DEV   *dev;
  1004. {
  1005.     if (!(DRResource = OpenResource(DISKNAME)))
  1006.     goto abort;
  1007.  
  1008.     if (!(CiaBResource = OpenResource(CIABNAME)))
  1009.     goto abort;
  1010.  
  1011. #ifndef READONLY
  1012.     if (!InitWrite(dev))
  1013.     goto abort;
  1014. #endif
  1015.  
  1016.     InitDecoding(dev->md_MfmDecode);
  1017.     InitSemaphore(&dev->md_HardwareUse);
  1018.     return 1;            /* Initializing succeeded */
  1019.  
  1020. abort:
  1021.     return DevCloseDown(dev);
  1022. }
  1023.  
  1024. int
  1025. DevCloseDown(dev)
  1026. DEV           *dev;
  1027. {
  1028. #ifndef READONLY
  1029.     FreeBuffer(dev);
  1030. #endif
  1031.     return 0;            /* Now unitialized */
  1032. }
  1033.  
  1034. #ifndef READONLY
  1035. /*
  1036.  * Calculate the length between the sectors, given the length of the track
  1037.  * and the number of sectors that must fit on it.
  1038.  * The proper formula would be
  1039.  * (((TLEN/2) - INDEXGAP - TAILGAP) / unit->mu_SectorsPerTrack) - BLOCKLEN;
  1040.  */
  1041.  
  1042. word
  1043. CalculateGapLength(sectors)
  1044. int        sectors;
  1045. {
  1046.     return (sectors == 10) ? DATAGAP3_10 : DATAGAP3_9;
  1047. }
  1048. #endif
  1049.  
  1050. UNIT           *
  1051. UnitInit(dev, UnitNr)
  1052. DEV           *dev;
  1053. ulong        UnitNr;
  1054. {
  1055.     register UNIT  *unit;
  1056.     struct Task    *task;
  1057.     struct IOStdReq *dcr;
  1058.     struct IOExtTD *tdreq;
  1059.  
  1060.     unit = AllocMem((long) sizeof (UNIT), MEMF_PUBLIC | MEMF_CLEAR);
  1061.     if (unit == NULL)
  1062.     return NULL;
  1063.  
  1064.     if (!(tdreq = CreateExtIO(&unit->mu_DiskReplyPort, (long) sizeof (*tdreq)))) {
  1065.     goto abort;
  1066.     }
  1067.     unit->mu_DiskIOReq = tdreq;
  1068.     if (OpenDevice(TD_NAME, UnitNr, tdreq, TDF_ALLOW_NON_3_5)) {
  1069.     tdreq->iotd_Req.io_Device = NULL;
  1070.     goto abort;
  1071.     }
  1072.     dcr = (void *) CreateExtIO(&unit->mu_DiskReplyPort, (long) sizeof (*dcr));
  1073.     if (dcr) {
  1074.     unit->mu_DiskChangeReq = dcr;
  1075.     unit->mu_DiskChangeInt.is_Node.ln_Pri = 32;
  1076.     unit->mu_DiskChangeInt.is_Data = (APTR) unit;
  1077.     unit->mu_DiskChangeInt.is_Code = DiskChangeHandler;
  1078.     /* Clone IO request part */
  1079.     dcr->io_Device = tdreq->iotd_Req.io_Device;
  1080.     dcr->io_Unit = tdreq->iotd_Req.io_Unit;
  1081.     dcr->io_Command = TD_ADDCHANGEINT;
  1082.     dcr->io_Data = (void *) &unit->mu_DiskChangeInt;
  1083.     SendIO(dcr);
  1084.     }
  1085.     NewList(&unit->mu_ChangeIntList);
  1086.  
  1087.     unit->mu_NumCyls = TDGetNumCyls(tdreq);
  1088.     unit->mu_UnitNr = UnitNr;
  1089.     unit->mu_DiskState = STATEF_UNKNOWN;
  1090.     unit->mu_TrackChanged = 0;
  1091.     unit->mu_CurrentSide = -1;
  1092.     unit->mu_InitSectorStatus = CRC_UNCHECKED;
  1093.     unit->mu_SectorsPerTrack = MS_SPT;
  1094.  
  1095.     unit->mu_DRUnit.dru_Message.mn_ReplyPort = &unit->mu_DiskReplyPort;
  1096.     unit->mu_DRUnit.dru_Index.is_Node.ln_Pri = 32; /* high pri for index int */
  1097.     unit->mu_DRUnit.dru_Index.is_Code = IndexIntCode;
  1098.     unit->mu_DRUnit.dru_DiscBlock.is_Code = DskBlkIntCode;
  1099.  
  1100.     /*
  1101.      * Now create the Unit task. Remember that it won't start running
  1102.      * since we are Forbid()den. But just to be sure, we Forbid() again.
  1103.      */
  1104.     Forbid();
  1105.     task = CreateTask(DevName, TASKPRI, UnitTask, TASKSTACK);
  1106.     task->tc_UserData = (APTR) unit;
  1107.  
  1108.     unit->mu_Port.mp_Flags = PA_IGNORE;
  1109.     unit->mu_Port.mp_SigTask = task;
  1110.     NewList(&unit->mu_Port.mp_MsgList);
  1111.  
  1112.     unit->mu_DiskReplyPort.mp_Flags = PA_IGNORE;
  1113.     unit->mu_DiskReplyPort.mp_SigTask = task;
  1114.     NewList(&unit->mu_DiskReplyPort.mp_MsgList);
  1115.     Permit();
  1116.  
  1117.     return unit;
  1118.  
  1119. abort:
  1120.     UnitCloseDown(NULL, dev, unit);
  1121.     return NULL;
  1122. }
  1123.  
  1124. int
  1125. UnitCloseDown(ioreq, dev, unit)
  1126. struct IOExtTD *ioreq;
  1127. DEV           *dev;
  1128. register UNIT  *unit;
  1129. {
  1130. #ifndef READONLY
  1131.     if (ioreq && unit->mu_TrackChanged)
  1132.     Internal_Update(ioreq, unit);
  1133. #endif
  1134.  
  1135.     /*
  1136.      * Get rid of the Unit's task. We know this is safe because the unit
  1137.      * has an open count of zero, so it is 'guaranteed' not in use.
  1138.      */
  1139.  
  1140.     if (unit->mu_Port.mp_SigTask) {
  1141. #ifdef DEBUG
  1142.     extern struct SignalSemaphore PortUse;
  1143.  
  1144.     /*
  1145.      * Make sure that the unit task does not get removed when it has
  1146.      * the semaphore.
  1147.      */
  1148.     ObtainSemaphore(&PortUse);
  1149. #endif
  1150.     RemTask(unit->mu_Port.mp_SigTask);
  1151. #ifdef DEBUG
  1152.     ReleaseSemaphore(&PortUse);
  1153. #endif
  1154.     }
  1155.     if (unit->mu_DiskChangeReq) {
  1156. #if 0                /* V1.2 and V1.3 have a broken
  1157.                  * TD_REMCHANGEINT */
  1158.     register struct IOExtTD *req = unit->mu_DiskIOReq;
  1159.  
  1160.     req->iotd_Req.io_Command = TD_REMCHANGEINT;
  1161.     req->iotd_Req.io_Data = (void *) unit->mu_DiskChangeReq;
  1162.     DoIO(req);
  1163.     WaitIO(unit->mu_DiskChangeReq);
  1164. #else
  1165.     Disable();
  1166.     Remove(unit->mu_DiskChangeReq);
  1167.     Enable();
  1168. #endif
  1169.     DeleteExtIO(unit->mu_DiskChangeReq);
  1170.     unit->mu_DiskChangeReq = NULL;
  1171.     }
  1172.     if (unit->mu_DiskIOReq) {
  1173.     if (unit->mu_DiskIOReq->iotd_Req.io_Device)
  1174.         CloseDevice(unit->mu_DiskIOReq);
  1175.     DeleteExtIO(unit->mu_DiskIOReq);
  1176.     unit->mu_DiskIOReq = NULL;
  1177.     }
  1178.     FreeMem(unit, (long) sizeof (UNIT));
  1179.  
  1180.     return 0;            /* Now unitialized */
  1181. }
  1182.  
  1183. /*
  1184.  * Create missing bindings
  1185.  */
  1186. /* INDENT OFF */
  1187.  
  1188. #asm
  1189.  
  1190. lib_vectsize    equ    6
  1191. lib_base    equ    -lib_vectsize
  1192.  
  1193. _RVOAllocUnit    equ    lib_base-(0*lib_vectsize)
  1194. _RVOFreeUnit    equ    lib_base-(1*lib_vectsize)
  1195. _RVOGetUnit    equ    lib_base-(2*lib_vectsize)
  1196. _RVOGiveUnit    equ    lib_base-(3*lib_vectsize)
  1197. _RVOGetUnitID    equ    lib_base-(4*lib_vectsize)
  1198.  
  1199. ;_AllocUnit:
  1200. ;        move.l    _DRResource,a6
  1201. ;        move.l    4(sp),d0
  1202. ;        jmp    _RVOAllocUnit(a6)
  1203. ;_FreeUnit:
  1204. ;        move.l    _DRResource,a6
  1205. ;        move.l    4(sp),d0
  1206. ;        jmp    _RVOFreeUnit(a6)
  1207. _GetUnit:
  1208.         move.l    _DRResource,a6
  1209.         move.l    4(sp),a1
  1210.         jmp    _RVOGetUnit(a6)
  1211. ;_GetUnitID:
  1212. ;        move.l    _DRResource,a6
  1213. ;        move.l    4(sp),d0
  1214. ;        jmp    _RVOGetUnitID(a6)
  1215. _GiveUnit:
  1216.         move.l    _DRResource,a6
  1217.         jmp    _RVOGiveUnit(a6)
  1218.  
  1219. #endasm
  1220. /* INDENT ON */
  1221.  
  1222. /*
  1223.  * We handle disk change interrupts internally, since the io request is
  1224.  * held by the device. Since SoftInts caused by the trackdisk.device are
  1225.  * broadcast to our clients, our own softint must have the highest
  1226.  * priority possible.
  1227.  *
  1228.  * TD_Addchangeint is an IMMEDIATE command, so no exclusive use of the list
  1229.  * is acquired (nor released). The list is accessed by (software)
  1230.  * interrupt code.
  1231.  */
  1232.  
  1233. void
  1234. TD_Addchangeint(ioreq)
  1235. register struct IOStdReq *ioreq;
  1236. {
  1237.     register UNIT  *unit;
  1238.  
  1239.     unit = (UNIT *) ioreq->io_Unit;
  1240.     Disable();
  1241.     AddTail(&unit->mu_ChangeIntList, ioreq);
  1242.     Enable();
  1243.     ioreq->io_Flags &= ~IOF_QUICK;    /* So we call ReplyMsg instead of
  1244.                      * TermIO */
  1245.     /* Note no TermIO */
  1246. }
  1247.  
  1248. void
  1249. TD_Remchangeint(ioreq)
  1250. register struct IOStdReq *ioreq;
  1251. {
  1252.     register struct IOStdReq *intreq;
  1253.  
  1254.     intreq = (struct IOStdReq *) ioreq->io_Data;
  1255.     Disable();
  1256.     Remove(intreq);
  1257.     Enable();
  1258.     ReplyMsg(&intreq->io_Message);      /* Quick bit always cleared */
  1259.     ioreq->io_Error = 0;
  1260.     TermIO(ioreq);
  1261. }
  1262.  
  1263. void
  1264. DiskChangeHandler()
  1265. {
  1266.     auto UNIT       *unit;
  1267.     register struct IOStdReq *ioreq;
  1268.     register struct IOStdReq *next;
  1269. /* INDENT OFF */
  1270. #asm
  1271.     movem.l d2-d7/a2-a4,-(sp)
  1272.     move.l  a1,-4(a5)        ;unit
  1273. #endasm
  1274.     /* INDENT ON */
  1275.     unit->mu_DiskState = STATEF_UNKNOWN;
  1276.     unit->mu_ChangeNum++;
  1277.     unit->mu_SectorsPerTrack = MS_SPT;
  1278.     for (ioreq = (struct IOStdReq *) unit->mu_ChangeIntList.mlh_Head;
  1279.      next = (struct IOStdReq *) ioreq->io_Message.mn_Node.ln_Succ;
  1280.      ioreq = next) {
  1281.     Cause((struct Interrupt *) ioreq->io_Data);
  1282.     }
  1283. /* INDENT OFF */
  1284. #asm
  1285.     movem.l (sp)+,d2-d7/a2-a4
  1286. #endasm
  1287.     /* INDENT ON */
  1288. }
  1289.  
  1290. #ifndef READONLY
  1291.  
  1292. /*
  1293.  * Parts of the following code were written by Werner Guenther.
  1294.  * Used with permission.
  1295.  */
  1296.  
  1297. /* mu_TrackChanged is a flag. When a sector has changed it changes to 1 */
  1298.  
  1299. /*
  1300.  * InitWrite() has to be called once at startup. It allocates the space
  1301.  * for one raw track, and writes the low level stuff between sectors
  1302.  * (gaps, syncs etc.)
  1303.  */
  1304.  
  1305. int
  1306. InitWrite(dev)
  1307. DEV           *dev;
  1308. {
  1309.     if ((dev->md_Rawbuffer =
  1310.         AllocMem((long)RLEN+2, MEMF_CHIP | MEMF_PUBLIC)) == 0)
  1311.     return 0;
  1312.  
  1313.     return 1;
  1314. }
  1315.  
  1316. /*
  1317.  * FreeBuffer has to be called when msh: closes down, it just frees the
  1318.  * memory InitWrite has allocated
  1319.  */
  1320.  
  1321. void
  1322. FreeBuffer(dev)
  1323. DEV           *dev;
  1324. {
  1325.     if (dev->md_Rawbuffer) {    /* OIS */
  1326.     FreeMem(dev->md_Rawbuffer, (long) RLEN + 2);
  1327.     }
  1328. }
  1329.  
  1330. /*
  1331.  * This routine doesn't write to the disk, but updates the TrackBuffer to
  1332.  * respect the new sector. We have to be sure the TrackBuffer is filled
  1333.  * with the current Track. As GetSTS calls Internal_Update if the track
  1334.  * changes we don't have to bother about actually writing any data to the
  1335.  * disk. GetSTS has to be changed in the following way:
  1336.  *
  1337.  * if (track != mu_CurrentTrack || side != mu_CurrentSide) { Internal_Update(); for
  1338.  * (i = 0; i < MS_SPT; i++) ..... etc.
  1339.  */
  1340.  
  1341. void
  1342. CMD_Write(ioreq, unit)
  1343. register struct IOExtTD *ioreq;
  1344. UNIT           *unit;
  1345. {
  1346.     int         side;
  1347.     int         cylinder;
  1348.     int         sector;
  1349.     byte       *userbuf;
  1350.     long        length;
  1351.     long        offset;
  1352.     word        spt;
  1353.  
  1354.     debug(("CMD_Write "));
  1355.     userbuf = (byte *) ioreq->iotd_Req.io_Data;
  1356.     length = ioreq->iotd_Req.io_Length / MS_BPS;    /* Sector count */
  1357.     offset = ioreq->iotd_Req.io_Offset / MS_BPS;    /* Sector number */
  1358.     debug(("userbuf %08lx off %ld len %ld ", userbuf, offset, length));
  1359.  
  1360.     spt = unit->mu_SectorsPerTrack;
  1361.     cylinder = offset / spt;
  1362.     side = cylinder % MS_NSIDES;
  1363.     cylinder /= MS_NSIDES;
  1364.     sector = offset % spt;
  1365.     debug(("T=%d Si=%d Se=%d\n", cylinder, side, sector));
  1366.  
  1367.     ioreq->iotd_Req.io_Actual = 0;
  1368.  
  1369.     if (length <= 0 || CheckRequest(ioreq, unit))
  1370.     goto end;
  1371.  
  1372.     GetTrack(ioreq, side, cylinder);
  1373.     for (;;) {
  1374.     CopyMem(userbuf, unit->mu_TrackBuffer + MS_BPS * sector, (long) MS_BPS);
  1375.     unit->mu_TrackChanged = 1;
  1376.     unit->mu_SectorStatus[sector] = CRC_CHANGED;
  1377.  
  1378.     ioreq->iotd_Req.io_Actual += MS_BPS;
  1379.     if (--length <= 0)
  1380.         break;
  1381.     userbuf += MS_BPS;
  1382.     /*
  1383.      * Get next sequential sector/side/track
  1384.      */
  1385.     if (++sector >= spt) {
  1386.         sector = 0;
  1387.         if (++side >= MS_NSIDES) {
  1388.         side = 0;
  1389.         if (++cylinder >= unit->mu_NumCyls)
  1390.             goto end;
  1391.         }
  1392.         GetTrack(ioreq, side, cylinder);
  1393.     }
  1394.     }
  1395.  
  1396.     if (length)
  1397.     ioreq->iotd_Req.io_Error = TDERR_NotSpecified;
  1398.  
  1399. end:
  1400.     TermIO(ioreq);
  1401. }
  1402.  
  1403. /*
  1404.  * This is called by your GetSTS() routine if the Track has changed. It
  1405.  * writes the changes back to the disk (a whole track at a time). It has
  1406.  * to be called if your device gets a CLOSE instruction too.
  1407.  */
  1408.  
  1409. void
  1410. Internal_Update(ioreq, unit)
  1411. struct IOExtTD *ioreq;
  1412. register UNIT  *unit;
  1413. {
  1414.     debug(("Internal_Update "));
  1415.     /* did we have a changed sector at all     */
  1416.     if (unit->mu_TrackChanged != 0) {
  1417.     debug(("needs to write "));
  1418.  
  1419.     if (unit->mu_SectorsPerTrack > unit->mu_CurrentSectors)
  1420.         unit->mu_CurrentSectors = unit->mu_SectorsPerTrack;
  1421.  
  1422.     /*
  1423.      * Only recalculate the CRC on changed sectors. This way, a
  1424.      * sector with a bad CRC won't suddenly be ``repaired''.
  1425.      */
  1426.     {
  1427.         register int i;
  1428.  
  1429.         for (i = unit->mu_CurrentSectors - 1; i >= 0; i--) {
  1430.         if (unit->mu_SectorStatus[i] == CRC_CHANGED) {
  1431.             unit->mu_CrcBuffer[i] = DataCRC(unit->mu_TrackBuffer + i * MS_BPS);
  1432.             debug(("%d: %04x\n", i, unit->mu_CrcBuffer[i]));
  1433.         }
  1434.         }
  1435.     }
  1436.     {
  1437.         DEV        *dev;
  1438.         register struct IOExtTD *tdreq;
  1439.         word        SectorGap;
  1440.  
  1441.         dev = (DEV *) ioreq->iotd_Req.io_Device;
  1442.         tdreq = unit->mu_DiskIOReq;
  1443.         SectorGap = CalculateGapLength(unit->mu_CurrentSectors);
  1444.  
  1445.         ObtainSemaphore(&dev->md_HardwareUse);
  1446.         EncodeTrack(unit->mu_TrackBuffer, dev->md_Rawbuffer,
  1447.             unit->mu_CrcBuffer,
  1448.             unit->mu_CurrentTrack, unit->mu_CurrentSide,
  1449.             SectorGap, unit->mu_CurrentSectors);
  1450.  
  1451.         TDMotorOn(tdreq);
  1452.         if (TDSeek(unit, ioreq, unit->mu_CurrentTrack)) {
  1453.         debug(("Seek error\n"));
  1454.         ioreq->iotd_Req.io_Error = TDERR_SeekError;
  1455.         goto end;
  1456.         }
  1457.         HardwareIO(dev, unit, DSKWRITE);
  1458.  
  1459.         ReleaseSemaphore(&dev->md_HardwareUse);
  1460.         unit->mu_TrackChanged = 0;
  1461.     }
  1462.     }
  1463. end:
  1464.     debug(("done\n"));
  1465. }
  1466.  
  1467. /*
  1468.  * TD_Format writes one or more whole tracks without reading them first.
  1469.  */
  1470.  
  1471. void
  1472. TD_Format(ioreq, unit)
  1473. register struct IOExtTD *ioreq;
  1474. UNIT           *unit;
  1475. {
  1476.     register struct IOExtTD *tdreq = unit->mu_DiskIOReq;
  1477.     DEV        *dev;
  1478.     short        side;
  1479.     int         cylinder;
  1480.     byte       *userbuf;
  1481.     int         length;
  1482.     word        spt;
  1483.     word        gaplen;
  1484.  
  1485.     debug(("CMD_Format "));
  1486.  
  1487.     if (CheckRequest(ioreq, unit))
  1488.     goto end;
  1489.  
  1490.     userbuf = (byte *) ioreq->iotd_Req.io_Data;
  1491.     length = ioreq->iotd_Req.io_Length / MS_BPS;        /* Sector count */
  1492.     cylinder = ioreq->iotd_Req.io_Offset / MS_BPS;        /* Sector number */
  1493.     /*
  1494.      * Now try to guess the number of sectors the user wants per track.
  1495.      * 40 sectors is the first ambuiguous length.
  1496.      */
  1497.     if (length < 40) {
  1498.     if (length > 0) {
  1499.         for (spt = 8; spt <= MS_SPT_MAX; spt++) {
  1500.         if ((length % spt) == 0)
  1501.             goto found_spt;
  1502.         }
  1503.     }
  1504.     /*
  1505.      * Not 8, 16, 24, 32, 9, 18, 27, 36, 10, 20, or 30? That is an error.
  1506.      */
  1507.     ioreq->iotd_Req.io_Error = IOERR_BADLENGTH;
  1508.     goto end;
  1509.     } else  /* assume previous number */
  1510.     spt = unit->mu_SectorsPerTrack;
  1511.  
  1512. found_spt:
  1513.     gaplen = CalculateGapLength(spt);
  1514.  
  1515.     /*
  1516.      * Assume the whole disk will have this layout.
  1517.      */
  1518.     unit->mu_SectorsPerTrack = spt;
  1519.  
  1520.     length /= spt;
  1521.     cylinder /= spt;
  1522.  
  1523.     side = cylinder % MS_NSIDES;
  1524.     cylinder /= MS_NSIDES;
  1525.     debug(("userbuf %08lx cylinder %d len %d\n", userbuf, cylinder, length));
  1526.  
  1527.     ioreq->iotd_Req.io_Actual = 0;
  1528.  
  1529.     /*
  1530.      * Write out the current track if we are not going to overwrite it.
  1531.      * After the format operation, the buffer is invalidated.
  1532.      */
  1533.     if (cylinder <= unit->mu_CurrentTrack &&
  1534.     unit->mu_CurrentTrack < cylinder + length)
  1535.     Internal_Update(ioreq, unit);
  1536.  
  1537.     dev = (DEV *) ioreq->iotd_Req.io_Device;
  1538.  
  1539.     while (length > 0) {
  1540.     {
  1541.         register int i;
  1542.  
  1543.         for (i = spt - 1; i >= 0; i--) {
  1544.         unit->mu_CrcBuffer[i] = DataCRC(userbuf + i * MS_BPS);
  1545.         debug(("%d: %04x\n", i, unit->mu_CrcBuffer[i]));
  1546.         }
  1547.     }
  1548.     ObtainSemaphore(&dev->md_HardwareUse);
  1549.     EncodeTrack(userbuf, dev->md_Rawbuffer, unit->mu_CrcBuffer,
  1550.             cylinder, side,
  1551.             gaplen, spt);
  1552.  
  1553.     TDMotorOn(tdreq);
  1554.     if (TDSeek(unit, ioreq, cylinder)) {
  1555.         debug(("Seek error\n"));
  1556.         ioreq->iotd_Req.io_Error = IOERR_BADLENGTH;
  1557.         break;
  1558.     }
  1559.     unit->mu_CurrentSide = side;
  1560.     HardwareIO(dev, unit, DSKWRITE);
  1561.  
  1562.     ReleaseSemaphore(&dev->md_HardwareUse);
  1563.  
  1564.     length--;
  1565.     userbuf += MS_BPS * spt;
  1566.     ioreq->iotd_Req.io_Actual += MS_BPS * spt;
  1567.  
  1568.     if (++side >= MS_NSIDES) {
  1569.         side = 0;
  1570.         if (++cylinder >= unit->mu_NumCyls)
  1571.         goto end;
  1572.     }
  1573.     }
  1574. end:
  1575.     unit->mu_CurrentSide = -1;
  1576.     TermIO(ioreq);
  1577. }
  1578. /* INDENT OFF */
  1579.  
  1580. #asm
  1581.  
  1582. ; we need a buffer for the Sector-ID field to calculate its checksum
  1583. ;SectorHeader:
  1584. ;     dc.b     0           ; track
  1585. ;     dc.b     0           ; side
  1586. ;     dc.b     0           ; sector
  1587. ;     dc.b     2           ; length (2=512 bytes)
  1588. ;     dc.w     0           ; CRC
  1589.  
  1590.     public _EncodeTrack
  1591.  
  1592. ;   EncodeTrack(TrackBuffer, Rawbuffer, Crcs, Track, Side, GapLen, NumSecs)
  1593. ;        4         4        4     2      2       2       2
  1594.  
  1595. _EncodeTrack:
  1596.     movem.l d2-d7/a2-a6,-(sp)  ; save registers
  1597.  
  1598. fp    set    (4*(6+5))+4        ; 4 for return address
  1599. trackbf set    0
  1600. rawbf    set    4
  1601. crcs    set    8
  1602. track    set    12
  1603. side    set    14
  1604. gaplen    set    16
  1605. numsecs set    18
  1606.  
  1607. ; a0    ptr in encoded data (also putmfmbyte)
  1608. ; a2    ptr to mfm encoding table (putmfmbyte)
  1609. ; a3    ptr to data to be crc'd (HeaderCRC)
  1610. ; a4    ptr to table with calculated CRC's
  1611. ; a5    ptr to unencoded data
  1612.  
  1613. ; d0    byte to be encoded (putmfmbyte)
  1614. ; d1    trashed by putmfmbyte
  1615. ; d3    used by putmfmbyte
  1616. ; d5    sector number
  1617. ; d6    general counter of byte spans
  1618. ; d7    sector countdown
  1619.  
  1620.     sub.w    #2,fp+gaplen(sp)   ; gap length between sectors
  1621.     move.l    fp+rawbf(sp),a0    ; pointer to mfmencoded buffer
  1622.     move.l    fp+crcs(sp),a4     ; pointer to precalculated CRCs
  1623.     move.l    fp+trackbf(sp),a5  ; pointer to unencoded data
  1624.     lea    _MfmEncode,a2       ; pointer to MFM lookup table
  1625.  
  1626.     move.w    #$9254,d0       ; a track starts with a gap
  1627.     moveq    #INDEXGAP-1,d6       ; (60 * $4e)
  1628. ingl    move.w    d0,(a0)+           ; mfmencoded = $9254
  1629.     dbf    d6,ingl
  1630.  
  1631.     lea    -6(sp),sp          ; Reserve room for SectorHeader
  1632. fp    set    fp+6
  1633.     move.w    fp+numsecs(sp),d7  ; number of sectors to encode
  1634.     subq.w    #1,d7           ; minus 1 for dbra
  1635.     moveq    #0,d5           ; start with first sector
  1636.  
  1637. secloop:
  1638.     move.w    #$aaaa,d0       ; a sector starts with a gap containing
  1639.     moveq    #IDGAP2-1,d6       ; 12 * 0 (mfm = $aaaa)
  1640. id2gl    move.w    d0,(a0)+
  1641.     dbf    d6,id2gl
  1642.  
  1643.     move.w    #SYNC,d0       ; The ID field begins here, starting
  1644.     move.w    d0,(a0)+           ; with 3 syncs (3 * $a1) with a missing
  1645.     move.w    d0,(a0)+           ; clock bit
  1646.     move.w    d0,(a0)+
  1647.  
  1648.     move.w    #$5554,(a0)+       ; ID-Address mark ($fe)
  1649.  
  1650.     move.l    sp,a3           ; pointer to Sector-ID buffer
  1651.  
  1652.     moveq    #$5554&1,d3       ; preload d3 for the putmfmbyte routine
  1653.     move.b    fp+track+1(sp),0(a3)  ; insert current track number
  1654.     move.b    fp+side+1(sp),1(a3)   ; side number
  1655.     addq.w    #1,d5           ; sectors start with 1 instead of 0
  1656.     move.b    d5,2(a3)           ; sector number
  1657.     move.b    #MS_BPScode,3(a3)  ; sector length 512 bytes
  1658.     bsr    HeaderCRC       ; calculate checksum
  1659.     move.w    d0,IDDATA(a3)      ; put it past the data
  1660.  
  1661.     moveq    #IDDATA+IDCRC-1,d6 ; 6 bytes Sector-ID
  1662. sidl    move.b    (a3)+,d0           ; get one byte
  1663.     bsr    putmfmbyte       ; encode it
  1664.     dbf    d6,sidl        ; end of buffer ?
  1665.  
  1666.     moveq    #$4e,d0        ; recalculate the MFM value of the
  1667.     bsr    putmfmbyte       ; first gap byte
  1668.  
  1669.     moveq    #DATAGAP1-1-1,d6   ; GAP consisting of
  1670.     move.w    #$9254,d0       ; 22 * $4e
  1671. dg1l    move.w    d0,(a0)+
  1672.     dbf    d6,dg1l
  1673.  
  1674.     moveq    #DATAGAP2-1,d6       ; GAP consisting of
  1675.     move.w    #$aaaa,d0       ; 12 * 0 (mfm = $aaaa)
  1676. dg2l    move.w    d0,(a0)+
  1677.     dbf    d6,dg2l
  1678.  
  1679.     move.w    #SYNC,d0       ; Sector data
  1680.     move.w    d0,(a0)+           ; starts with 3 syncs
  1681.     move.w    d0,(a0)+
  1682.     move.w    d0,(a0)+
  1683.  
  1684.     move.w    #$5545,(a0)+       ; Data Address Mark ($fb)
  1685.  
  1686.     moveq    #$5545&1,d3       ; preload d3
  1687.     move    #MS_BPS-1,d6       ; a sector has 512 bytes
  1688. dblockl move.b    (a5)+,d0           ; get one byte from the buffer
  1689.     bsr    putmfmbyte       ; encode it
  1690.     dbf    d6,dblockl       ; end of sector ?
  1691.  
  1692.     move.b    (a4)+,d0           ; get first byte of CRC
  1693.     bsr    putmfmbyte       ; encode it
  1694.     move.b    (a4)+,d0           ; get second byte
  1695.     bsr    putmfmbyte       ; encode it
  1696.  
  1697.     moveq    #$4e,d0        ; recalculate the MFM value of the
  1698.     bsr    putmfmbyte       ; first gap byte -> -1 in following loop
  1699.  
  1700. ;    moveq    #DATAGAP3-1-1,d6   ; sector ends with a gap
  1701.     move.w    fp+gaplen(sp),d6   ; sector ends with a gap, -1 for dbf
  1702.     move.w    #$9254,d0       ; 80 * $4e
  1703. dg3l    move.w    d0,(a0)+
  1704.     dbf    d6,dg3l
  1705.  
  1706.     dbf    d7,secloop       ; next sector. d5 has been incremented
  1707.  
  1708.     lea    6(sp),sp           ; Free room for SectorHeader
  1709. fp    set    fp-6
  1710.  
  1711.     move.l    fp+rawbf(sp),d6    ; pointer to mfmencoded buffer
  1712.     add.l    #WLEN,d6       ; end of encoded buffer
  1713.     move.l    a0,d0           ; (I really want to   sub.l a0,d6 )
  1714.     sub.l    d0,d6           ; length of the remains
  1715.     lsr.l    #1,d6           ; turn into words
  1716.  
  1717.     move.w    #$9254,d0       ; Fill the end of the track with $4e
  1718. endgl    move.w    d0,(a0)+           ; $9254 mfm encoded
  1719.     dbf    d6,endgl
  1720.  
  1721.     movem.l (sp)+,d2-d7/a2-a6
  1722.     rts
  1723.  
  1724. ; putmfmbyte encodes one byte (in D0) into MSDOS MFM format to the location
  1725. ; pointed by A0. D3 has to be preserved between calls !
  1726. ; A2 must contain the pointer to the encoding table.
  1727. ; Destroys D0, D1. Updates A0 and D3. Requires A0, D0, D3.
  1728.  
  1729. putmfmbyte
  1730.     moveq    #16-4,d1
  1731.     lsl.l    d1,d0        ; split the byte into two nibbles
  1732.     lsr.w    d1,d0        ; low nibble is in bits 0..15
  1733.                 ; high nibble in bits 16..31
  1734.     swap    d0        ; process high nibble first
  1735.     and.w    #$0f,d0     ; mask out unwanted bits
  1736.     move.b    0(a2,d0.w),d1   ; get mfmencoded nibble from table
  1737.     btst    #6,d1        ; we now have to work out if
  1738.     bne.s    1$        ; the high bit of the unencoded data
  1739.     btst    #0,d3        ; byte and the low bit of the last
  1740.     bne.s    1$        ; encoded data are both 0. if this is the
  1741.     bset    #7,d1        ; case the first clock bit has to be '1'
  1742. 1$    move.b    d1,(a0)+        ; write high (encoded) nibble
  1743.     swap    d0        ; process low nibble
  1744.     move.b    0(a2,d0.w),d3   ; ....same as above
  1745.     btst    #6,d3
  1746.     bne.s    2$
  1747.     btst    #0,d1
  1748.     bne.s    2$
  1749.     bset    #7,d3
  1750. 2$    move.b    d3,(a0)+
  1751.     rts
  1752.  
  1753. #endasm
  1754. #endif                /* READONLY */
  1755. #asm
  1756.  
  1757. ; The CRC is computed not only over the actual data, but including
  1758. ; the SYNC mark (3 * $a1) and the 'ID/DATA - Address Mark' ($fe/$fb).
  1759. ; As we don't read or encode these fields into our buffers, we have to
  1760. ; preload the registers containing the CRC with the values they would have
  1761. ; after stepping over these fields.
  1762. ;
  1763. ; How CRCs "really" work:
  1764. ;
  1765. ; First, you should regard a bitstring as a series of coefficients of
  1766. ; polymomials. We calculate with these polynomials in modulo-2
  1767. ; arithmetic, in which both add and subtract are done the same as
  1768. ; exclusive-or. Now, we modify our data (a very long polynomial) in
  1769. ; such a way that it becomes divisible by the CCITT-standard 16-bit
  1770. ;         16   12   5
  1771. ; polynomial:    x  + x    + x + 1, represented by $11021. The easiest
  1772. ; way to do this would be to multiply (using proper arithmetic) our
  1773. ; datablock with $11021. So we have:
  1774. ;   data * $11021         =
  1775. ;   data * ($10000 + $1021)      =
  1776. ;   data * $10000 + data * $1021
  1777. ; The left part of this is simple: Just add two 0 bytes. But then
  1778. ; the right part (data $1021) remains difficult and even could have
  1779. ; a carry into the left part. The solution is to use a modified
  1780. ; multiplication, which has a result that is not correct, but with
  1781. ; a difference of any multiple of $11021. We then only need to keep
  1782. ; the 16 least significant bits of the result.
  1783. ;
  1784. ; The following algorithm does this for us:
  1785. ;
  1786. ;   unsigned char *data, c, crclo, crchi;
  1787. ;   while (not done) {
  1788. ;    c = *data++ + crchi;
  1789. ;    crchi = (@ c) >> 8 + crclo;
  1790. ;    crclo = @ c;
  1791. ;   }
  1792. ;
  1793. ; Remember, + is done with EOR, the @ operator is in two tables (high
  1794. ; and low byte separately), which is calculated as
  1795. ;
  1796. ;      $1021 * (c & $F0)
  1797. ;  xor $1021 * (c & $0F)
  1798. ;  xor $1021 * (c >> 4)         (* is regular multiplication)
  1799. ;
  1800. ;
  1801. ; Anyway, the end result is the same as the remainder of the division of
  1802. ; the data by $11021. I am afraid I need to study theory a bit more...
  1803.  
  1804.  
  1805. ; This is the entry to calculate the checksum for the sector-id field
  1806. ; requires:  a3 = pointer to the unencoded data
  1807. ; returns:   d0 = CRC
  1808.  
  1809. HeaderCRC:
  1810.     movem.l  d1-d3/a3-a5,-(sp) ; save registers
  1811.     move.w     #$b2,d0       ; preload registers
  1812.     moveq     #$30,d1       ; (CRC for $a1,$a1,$a1,$fb)
  1813.     moveq     #3,d3           ; calculate checksum for 4 bytes
  1814.     bra.s     getCRC        ; (=track,side,sector,sectorlength)
  1815.  
  1816. ; This is the entry to calculate the checksum for the data field
  1817. ; requires:  a3 = pointer to the unencoded data
  1818. ; returns:   d0 = CRC
  1819.  
  1820. DataCRC:
  1821.     movem.l  d1-d3/a3-a5,-(sp) ; save registers
  1822.     bra.s    DataCRC1
  1823.  
  1824. ; C entry point for DataCRC(byte *data)
  1825.  
  1826. _DataCRC:
  1827.     movem.l d1-d3/a3-a5,-(sp) ; save registers
  1828. fp    set    (4*(3+3))+4
  1829. data    set    0
  1830.     move.l    fp+data(sp),a3    ; get parameter
  1831. DataCRC1:
  1832.     move.w     #$e2,d0       ; preload the CRC registers
  1833.     move.w     #$95,d1       ; (CRC for $a1,$a1,$a1,$fe)
  1834.     move.w     #MS_BPS-1,d3       ; a sector 512 bytes
  1835.  
  1836. getCRC    lea     CRCTable1,a4
  1837.     lea     CRCTable2,a5
  1838.     moveq     #0,d2
  1839.  
  1840. 1$    move.b     (a3)+,d2
  1841.     eor.b     d0,d2
  1842.     move.b     0(a4,d2.w),d0
  1843.     eor.b     d1,d0
  1844.     move.b     0(a5,d2.w),d1
  1845.     dbf     d3,1$
  1846.  
  1847.     lsl.w     #8,d0
  1848.     move.b     d1,d0
  1849.     movem.l  (sp)+,d1-d3/a3-a5
  1850.     rts
  1851.  
  1852.  
  1853. CRCTable1:
  1854.     dc.b $00,$10,$20,$30,$40,$50,$60,$70,$81,$91,$a1,$b1,$c1,$d1,$e1,$f1
  1855.     dc.b $12,$02,$32,$22,$52,$42,$72,$62,$93,$83,$b3,$a3,$d3,$c3,$f3,$e3
  1856.     dc.b $24,$34,$04,$14,$64,$74,$44,$54,$a5,$b5,$85,$95,$e5,$f5,$c5,$d5
  1857.     dc.b $36,$26,$16,$06,$76,$66,$56,$46,$b7,$a7,$97,$87,$f7,$e7,$d7,$c7
  1858.     dc.b $48,$58,$68,$78,$08,$18,$28,$38,$c9,$d9,$e9,$f9,$89,$99,$a9,$b9
  1859.     dc.b $5a,$4a,$7a,$6a,$1a,$0a,$3a,$2a,$db,$cb,$fb,$eb,$9b,$8b,$bb,$ab
  1860.     dc.b $6c,$7c,$4c,$5c,$2c,$3c,$0c,$1c,$ed,$fd,$cd,$dd,$ad,$bd,$8d,$9d
  1861.     dc.b $7e,$6e,$5e,$4e,$3e,$2e,$1e,$0e,$ff,$ef,$df,$cf,$bf,$af,$9f,$8f
  1862.     dc.b $91,$81,$b1,$a1,$d1,$c1,$f1,$e1,$10,$00,$30,$20,$50,$40,$70,$60
  1863.     dc.b $83,$93,$a3,$b3,$c3,$d3,$e3,$f3,$02,$12,$22,$32,$42,$52,$62,$72
  1864.     dc.b $b5,$a5,$95,$85,$f5,$e5,$d5,$c5,$34,$24,$14,$04,$74,$64,$54,$44
  1865.     dc.b $a7,$b7,$87,$97,$e7,$f7,$c7,$d7,$26,$36,$06,$16,$66,$76,$46,$56
  1866.     dc.b $d9,$c9,$f9,$e9,$99,$89,$b9,$a9,$58,$48,$78,$68,$18,$08,$38,$28
  1867.     dc.b $cb,$db,$eb,$fb,$8b,$9b,$ab,$bb,$4a,$5a,$6a,$7a,$0a,$1a,$2a,$3a
  1868.     dc.b $fd,$ed,$dd,$cd,$bd,$ad,$9d,$8d,$7c,$6c,$5c,$4c,$3c,$2c,$1c,$0c
  1869.     dc.b $ef,$ff,$cf,$df,$af,$bf,$8f,$9f,$6e,$7e,$4e,$5e,$2e,$3e,$0e,$1e
  1870.  
  1871. CRCTable2:
  1872.     dc.b $00,$21,$42,$63,$84,$a5,$c6,$e7,$08,$29,$4a,$6b,$8c,$ad,$ce,$ef
  1873.     dc.b $31,$10,$73,$52,$b5,$94,$f7,$d6,$39,$18,$7b,$5a,$bd,$9c,$ff,$de
  1874.     dc.b $62,$43,$20,$01,$e6,$c7,$a4,$85,$6a,$4b,$28,$09,$ee,$cf,$ac,$8d
  1875.     dc.b $53,$72,$11,$30,$d7,$f6,$95,$b4,$5b,$7a,$19,$38,$df,$fe,$9d,$bc
  1876.     dc.b $c4,$e5,$86,$a7,$40,$61,$02,$23,$cc,$ed,$8e,$af,$48,$69,$0a,$2b
  1877.     dc.b $f5,$d4,$b7,$96,$71,$50,$33,$12,$fd,$dc,$bf,$9e,$79,$58,$3b,$1a
  1878.     dc.b $a6,$87,$e4,$c5,$22,$03,$60,$41,$ae,$8f,$ec,$cd,$2a,$0b,$68,$49
  1879.     dc.b $97,$b6,$d5,$f4,$13,$32,$51,$70,$9f,$be,$dd,$fc,$1b,$3a,$59,$78
  1880.     dc.b $88,$a9,$ca,$eb,$0c,$2d,$4e,$6f,$80,$a1,$c2,$e3,$04,$25,$46,$67
  1881.     dc.b $b9,$98,$fb,$da,$3d,$1c,$7f,$5e,$b1,$90,$f3,$d2,$35,$14,$77,$56
  1882.     dc.b $ea,$cb,$a8,$89,$6e,$4f,$2c,$0d,$e2,$c3,$a0,$81,$66,$47,$24,$05
  1883.     dc.b $db,$fa,$99,$b8,$5f,$7e,$1d,$3c,$d3,$f2,$91,$b0,$57,$76,$15,$34
  1884.     dc.b $4c,$6d,$0e,$2f,$c8,$e9,$8a,$ab,$44,$65,$06,$27,$c0,$e1,$82,$a3
  1885.     dc.b $7d,$5c,$3f,$1e,$f9,$d8,$bb,$9a,$75,$54,$37,$16,$f1,$d0,$b3,$92
  1886.     dc.b $2e,$0f,$6c,$4d,$aa,$8b,$e8,$c9,$26,$07,$64,$45,$a2,$83,$e0,$c1
  1887.     dc.b $1f,$3e,$5d,$7c,$9b,$ba,$d9,$f8,$17,$36,$55,$74,$93,$b2,$d1,$f0
  1888.  
  1889. #endasm
  1890.  
  1891. /* INDENT ON */
  1892.