BLib.DiskIO - Low-level disk access =================================== File: DiskIO - Update: 1.01 Author: J.G.Harston - Date: 27-Jul-2009 The DiskIO library contains functions for low-level disk access, reading and writing disk sectors directly. There are functions for DFS, ADFS and LVFS single density, double density and hard drive access, depending on the hardware the program is running on. Requirements and dependancies ============================= The library requires a 16-byte global control block with X% holding the address of this block, and Y% holding X% DIV 256. This can easily be set up with DIM ctrl% 15 near the start of the program and X%=ctrl%:Y%=X%DIV256 at the begining of the major program code and at the start of any main program loop. Single/Double density DFS disk access ===================================== err%=FNdisk(addr%,cmd%,drv%,trk%,sec%,num%,den%) FNdisk() makes an 8271 disk access call to read or write data to a floppy disk with 256-byte sectors. If the DFS being called supports it then double density disks can be accessed. addr% is the address to memory to read or write data cmd% is the 8271 command to perform drv% is the drive to use numberd in DFS style 0/2 and 1/3 trk% is the track to start the data transfer sec% is the sector within the track to start the data transfer num% is the number of sectors to transfer, &01 to &FF den% is 1 for single density and 2 for double density if supported FNdisk() returns the 8271 result which will be zero for Ok and non-zero for an error. Reading and writing must be within one track, FNdisk() will not step past the end of a track to the next track as it has no knowledge of what sector numbering has been imposed on the disk. If accessing DFS-type disks sectors are numbered from 0 to 9 and consequently you cannot transfer more than (10 - sector) sectors in one go. Commands -------- &4A Write data 128 bytes &4B Write data &52 Read data 128 bytes &53 Read data &5A &5B Read sector IDs &4E Write deleted data 128 bytes &4F Write deleted data &56 Read data and deleted data 128 bytes &57 Read data and deleted data &5E Verify data and deleted data 128 bytes &5F Verify data and deleted data &63 Format track &64 (EDOS) Write track &65 (EDOS) Read track &69 Seek track &6C Read drive status and reset 'not ready' &75 (Initialise) &76 (EDOS) Force interrupt &7A Write special register, trk%=register, sec%=value &7D Read special register, trk%=register &E0 (1770) Read track &F0 (1770) Write track The most commonly used commands are &4B to write data and &53 to read data. The Initialise and Format commands cannot be called via FNdisk() as they take additional parameters. Results ------- &00 Ok &14 Track 0 not found &08 Clock error &16 Write error &0C ID CRC error &18 Sector not found &0E Data CRC error &1E Drive not present/drive empty &12 Disk write protected &C0+x Command not recognised (1770) FNdisk() always retries if a 'Drive not ready' error is returned. The result will have &20 added to it if a 'Deleted data' command found deleted data. Result &0A is 'Late DMA' which should never be returned on a BBC as it does not have DMA hardware. Some systems extend the range of error numbers to report other states. If there is no DFS present FNdisk() returns &1E, meaning 'Drive not present'. Double density ADFS disk access, LVFS Laser Disk access ======================================================= err%=FNscsi(addr%,cmd%,drv%,sect%,num%) err%=FNlvfs(addr%,cmd%,drv%,sect%,num%) FNscsi() passes an ADFS SCSI command to ADFS to access an ADFS hard drive double-density floppy. FNlfvs() passes an ADFS SCSI command to LVFS to access a VLFS Laser Disk. The commands and results are the same as FNscsi(), other than you cannot write to read-only Laser Disks. addr% is the address to memory to read or write data cmd% is the SCSI command to perform drv% is the drive to use - 0-3 for hard drives, 4-7 for floppies, normally 0 for Laser Disk sect% is the start sector to transfer data num% is the number of sectors to transfer, &0001 to &FFFF FNscsi() and FNlvfs() return the SCSI result code after completing. This will be zero for Ok and non-zero for an error. ADFS floppies use 256-byte sectors, but FNscsi() can also read data from floppies with larger sectors. When doing this, FNscsi() should be called with sector% holding (side*80)+track*16+sector, and sectors must be read or written one at a time. For example: err%=FNscsi(addr%,cmd%,drv%,track*16+sector,1) Commands -------- &00 Test drive ready &01 Seek to track zero &08 Read data &0A Write data &0B Seek to track &1B Park heads; park if num%=0, unpark if num%=1 Results ------- The returned result is &00 if no error occured. If an error occured, bit 6 is clear if a hard drive and set if a floppy drive. There are 63 possible result values, this lists the most usual ones that may occur. &00 Ok &20/&60 Bad SCSI command &02 Drive door open &21/&61 Bad disc address - beyond end of disk &03 Write fault &23/&63 Volume error &06 Track 0 not found &24/&64 Bad arguments &40 Disk write protected &25/&65 Bad drive &08/&48 CRC error &27/&67 Unsupported SCSI command &10/&50 Sector not found &28/&68 Media changed &11 Data CRC error &2F/&6F Abort &12 Address mark not found &30/&70 RAM corrupted &19 Bad track read &3F/&7F Unknown SCSI result Examples -------- The following code would do a simple sector-by-sector backup of a Laser Disk to an ADFS hard drive. Bear in mind it makes no checks for validity and completely overwrites the ADFS drive: DIM ctrl% 31:X%=ctrl%:Y%=X%DIV256 DIM mem% 256*16-1 :REM Copy 16 sectors at a time maxsect%=-1 sect%=0 REPEAT err%=FNlvfs(mem%, 8,0,sect%,16) :REM Read 16 sectors IF err%:PRINT "LVFS error &";~err%:END err%=FNscsi(mem%,10,0,sect%,16) :REM Write 16 sectors IF err%:PRINT "ADFS error &";~err%:END sect%=sect%+16 UNTIL sect%>=maxsect% See also ======== * beebwiki.mdfs.net/OSWORD_62 * beebwiki.mdfs.net/OSWORD_72 * beebwiki.mdfs.net/OSWORD_7F