| 
					
				 | 
			
			
				@@ -5,24 +5,113 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # This is free and unencumbered software released into the public domain. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # See the file COPYING for more details, or visit <http://unlicense.org>. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import math, struct 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import binascii, math, struct 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import itertools as it 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from bitarray import bitarray 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from greaseweazle import error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from greaseweazle.codec.ibm import mfm 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from greaseweazle.track import MasterTrack, RawTrack 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .image import Image 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+class EDSKTrack: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap_presync = 12 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap_4a = 80 # Post-Index 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap_1  = 50 # Post-IAM 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap_2  = 22 # Post-IDAM 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gapbyte = 0x4e 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def __init__(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.time_per_rev = 0.2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.clock = 2e-6 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.bits, self.weak = [], [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def raw_track(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        track = MasterTrack( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            bits = self.bits, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            time_per_rev = self.time_per_rev, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            weak = self.weak) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        track.verify = self 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        track.verify_revs = 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return track 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def _find_sync(self, bits, sync, start): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for offs in bits.itersearch(sync): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if offs >= start: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return offs 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def verify_track(self, flux): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        flux.cue_at_index() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        raw = RawTrack(clock = self.clock, data = flux) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bits, _ = raw.get_all_data() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        weak_iter = it.chain(self.weak, [(self.verify_len+1,1)]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        weak = next(weak_iter) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # Start checking from the IAM sync 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        dump_start = self._find_sync(bits, mfm.iam_sync, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self_start = self._find_sync(self.bits, mfm.iam_sync, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # Include the IAM pre-sync header 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if dump_start is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        dump_start -= self.gap_presync * 16 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self_start -= self.gap_presync * 16 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        while self_start is not None and dump_start is not None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # Find the weak areas immediately before and after the current 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # region to be checked. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            s,n = None,None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            while self_start > weak[0]: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                s,n = weak 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                weak = next(weak_iter) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # If there is a weak area preceding us, move the start point to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # immediately follow the weak area. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if s is not None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                delta = self_start - (s + n + 16) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                self_start -= delta 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                dump_start -= delta 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # Truncate the region at the next weak area, or the last sector. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self_end = max(self_start, min(weak[0], self.verify_len+1)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            dump_end = dump_start + self_end - self_start 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # Extract the corresponding areas from the pristine track and 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # from the dump, and check that they match. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if bits[dump_start:dump_end] != self.bits[self_start:self_end]: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # Find the next A1A1A1 sync pattern 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            dump_start = self._find_sync(bits, mfm.sync, dump_end) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self_start = self._find_sync(self.bits, mfm.sync, self_end) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # Did we verify all regions in the pristine track? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return self_start is None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class EDSK(Image): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     read_only = True 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     default_format = 'ibm.mfm' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    clock = 2e-6 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    time_per_rev = 0.2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def __init__(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.to_track = dict() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # Currently only finds one weak range. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @staticmethod 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def find_weak_ranges(dat, size): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        orig = dat[:size] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        s, e = size, 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for i in range(1, len(dat)//size): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            diff = [x^y for x, y in zip(orig, dat[size*i:size*(i+1)])] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            weak = [idx for idx, val in enumerate(diff) if val != 0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if weak: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                s, e = min(s, weak[0]), max(e, weak[-1]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return [(s,e-s+1)] if s <= e else [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @classmethod 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def from_file(cls, name): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -57,46 +146,91 @@ class EDSK(Image): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             error.check((cyl, head) not in edsk.to_track, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         'EDSK: Track specified twice') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             while True: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                track = mfm.IBM_MFM_Formatted(cyl, head) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                track.clock = cls().clock 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                track.time_per_rev = cls().time_per_rev 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                pos = track.gap_4a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                track.iams = [mfm.IAM(pos*16,(pos+4)*16)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                pos += 4 + track.gap_1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                track = EDSKTrack() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                t = bytes() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # Post-index gap 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                t += mfm.encode(bytes([track.gapbyte] * track.gap_4a)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # IAM 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                t += mfm.encode(bytes(track.gap_presync)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                t += mfm.iam_sync_bytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                t += mfm.encode(bytes([mfm.IBM_MFM.IAM])) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                t += mfm.encode(bytes([track.gapbyte] * track.gap_1)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 secs = dat[o+24:o+24+8*nsecs] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 data_pos = o + 256 # skip track header and sector-info table 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 while secs: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     c, h, r, n, stat1, stat2, actual_length = struct.unpack( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         '<6BH', secs[:8]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     secs = secs[8:] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    pos += track.gap_presync 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    idam = mfm.IDAM(pos*16, (pos+10)*16, 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    c=c, h=h, r=r, n=n) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    pos += 10 + track.gap_2 + track.gap_presync 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     size = 128 << n 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    error.check(size == actual_length, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                'EDSK: Weird sector size (copy protection?)') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    weak = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if size != actual_length: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        error.check(actual_length != 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    and actual_length % size == 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    'EDSK: Weird sector size (GAP protection?)') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        weak = cls().find_weak_ranges( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            dat[data_pos:data_pos+actual_length], size) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # Update CRCs according to status flags 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    icrc, dcrc = 0, 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if stat1 & 0x20: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if stat2 & 0x20: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            dcrc = 0xffff 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            icrc = 0xffff 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        stat1 &= ~0x20 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        stat2 &= ~0x20 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # Update address marks according to status flags 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    imark, dmark = mfm.IBM_MFM.IDAM, mfm.IBM_MFM.DAM 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if stat2 & 0x40: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        dmark = mfm.IBM_MFM.DDAM 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if stat2 & 0x01: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        dmark = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    elif stat1 & 0x01: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        imark = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    stat1 &= ~0x01 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    stat2 &= ~0x41 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     error.check(stat1 == 0 and stat2 == 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                 'EDSK: Mangled sector (copy protection?)') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     sec_data = dat[data_pos:data_pos+size] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    dam = mfm.DAM(pos*16, (pos+4+size+2)*16, 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                  mark=track.DAM, data=sec_data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    track.sectors.append(mfm.Sector(idam, dam)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    pos += 4 + size + 2 + gap_3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    data_pos += size 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    data_pos += actual_length 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # IDAM 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    t += mfm.encode(bytes(track.gap_presync)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    t += mfm.sync_bytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    idam = bytes([0xa1, 0xa1, 0xa1, mfm.IBM_MFM.IDAM, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                  c, h, r, n]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    idam += struct.pack('>H', mfm.crc16.new(idam).crcValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    t += mfm.encode(idam[3:]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    t += mfm.encode(bytes([track.gapbyte] * track.gap_2)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # DAM 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    t += mfm.encode(bytes(track.gap_presync)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    t += mfm.sync_bytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    track.weak += [((s+len(t)//2+4)*16, n*16) for s,n in weak] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    dam = bytes([0xa1, 0xa1, 0xa1, dmark]) + sec_data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    dam += struct.pack('>H', mfm.crc16.new(dam).crcValue^dcrc) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    t += mfm.encode(dam[3:]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    t += mfm.encode(bytes([track.gapbyte] * gap_3)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 # Some EDSK images have bogus GAP3 values. If the track is too 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 # long to comfortably fit in 300rpm at double density, shrink 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 # GAP3 as far as necessary. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 tracklen = int((track.time_per_rev / track.clock) / 16) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                overhang = int(pos - tracklen*0.99) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                overhang = int(len(t)//2 - tracklen*0.99) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 if overhang <= 0: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 new_gap_3 = gap_3 - math.ceil(overhang / nsecs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 error.check(new_gap_3 >= 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             'EDSK: Track %d.%d is too long ' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             '(%d bits @ GAP3=%d; %d bits @ GAP3=0)' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            % (cyl, head, pos*16, gap_3, (pos-gap_3*nsecs)*16)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            % (cyl, head, len(t)*8, gap_3, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                               (len(t)//2-gap_3*nsecs)*16)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 gap_3 = new_gap_3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # Pre-index gap 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            track.verify_len = len(t)*8 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            gap = tracklen - len(t)//2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            t += mfm.encode(bytes([track.gapbyte] * gap)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            track.bits = bitarray(endian='big') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            track.bits.frombytes(mfm.mfm_encode(t)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             edsk.to_track[cyl,head] = track 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             o += tsize 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 |