Commit a571f55d authored by Neil Turton's avatar Neil Turton
Browse files

Unused files removed from Trunk

parent e8fae392
; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
;******************************************************************************
;
; ATAPIStuff.s
;
; Author: Mark Watson (EESOX)
;
; Description
; ===========
; This issues the low-level IDE ATAPI commands
;
; Change record
; =============
; 09-Mar-95 16:15 cpartington (Cambridge Systems Design)
; * Start of work on ATAPI_Op to fix data corruption and "Compact disc is
; faulty" errors - rewrite all IDE access code to nearer specification.
; Add special action after IRQ to handle strange behaviour by Panasonic
; CR571B.
; * Tidy up and commenting of existing code.
;
; 14-Mar-95 10:30 cpartington (Cambridge Systems Design)
; * Rewrite of IRQ and DRQ polling following receipt of latest ATAPI
; specfication. MEW assumed Panasonic drive was just buggy and my first
; rewrite followed that assumption code. In fact, Panasonic and Sony
; drives are of different CMD DRQ types (Panasonic is "interrupt DRQ",
; Sony is "accelerated DRQ". The important difference is that "interrupt
; DRQ" provides an IRQ for the DRQ for the CDB. No wonder MEW found he
; needed massive delays to drive the Panasonic without error. Added
; routine WaitForIRQ.
; * Change error handling code in ATAPI_Op to treat drive not ready as disc
; changed. If this isn't done, CDFS does not notice when the drive door is
; open but displays very very slow (and often corrupt) directory viewers.
; * More tidying up following comparison with 1.06 (I was probably given the
; wrong sources to work from - 1.13). Fixed DoMicroDelay to preserve flags
; (as the original, copied from ADFS, did).
;
; 16-Mar-95 14:03 cpartington (Cambridge Systems Design)
; * Rewrite of main data transfer loop so that it copies more data via
; optimised code - MEW's version always copied last 32 bytes a byte at
; a time.
; * Rewrite of ATAPI_Control to call routines rather than branch to them.
; Those routines now simply return VS/VC and ATAPI_Control unlocks the
; IDE registers and returns to its caller.
; * Rewrite ATAPI_Reset so it can be called when a drive locks up. This is
; to cope with the Panasonic which, occasionally, fails to deassert BSY
; when a disc is ejected during a command
; * Removed code corrupting caller's R1 - looks as if it was only ever there
; as debug and all registers are meant to be preserved.
;
; 23-Mar-95 14:51 cpartington (Cambridge Systems Design)
; * Changed ATAPI_LockUnlockIDE to return error returned by lock SWI if
; unable to get lock before timeout.
; * Removed old, pre-1.06 code in ATAPI_LockUnlockIDE. Resisted temptation
; to rewrite current code.
;
; 30-Mar-95 12:20 cpartington (Cambridge Systems Design)
; * Add extra read of alternate status (conditional on fix_cr571b10e_maybe)
; after reading byte count registers as badly-translated fax from
; Panasonic suggests this may work around their cache problem.
; * Add check for IDENTIFY before retrying failed op (conditional on
; fix_slow_when_no_drives).
; * Add 1us delay to WaitForIRQ (conditional on extra_delay_after_irq)
; before returning when BSY is clear after the IRQ has been received (it
; should always be clear after IRQ but some drives misbehave and driver
; has to wait for !BSY). This is not in response to a fault but for
; future-proofing.
; * Spotted a few mini-optimisations but resisted temptation to make them!
; NOTE: some reads of regs are byte, others word - this should be sorted
; out.
;
;*end of change record*
; Routines in thisfile
; ATAPI_Control
; ATAPI_LockUnlockIDE
; ATAPI_Op
; WaitForIRQ
; ATAPI_Reset
; DoMicroDelay
; ONLY EVER USE THE ATAPI_Control function with reason codes.
; NEVER call the functions directly
;------------------------------------------------------------------------------
; ATAPI_Control
;
; on entry:
; r0 - r6 may be used depending on reason code in r8
; r7 -> CDFS control block
; r8 = reason code (IDECONTROL__ ... )
; r12 -> workspace
; r13 -> FD stack
;
; on exit:
; r8 = corrupted (probably not - cpartington)
;
; if OK then
; all regs preserved
; if ERROR then
; r0 = error number
;
;------------------------------------------------------------------------------
ATAPI_Control ROUT
CMP r8,#(ATAPIC_EndOfJumpTable - ATAPIC_StartOfJumpTable) / 4
BHS ATAPIC_UnknownReason
; reason code is valid so try to lock IDE registers
STASH "r0,r14"
MOV r0,#1 ; lock, not unlock
BL ATAPI_LockUnlockIDE
ADDVS sp,sp,#4 ; if error, discard stacked r0...
GRAB "r14",VS ; ...get link
ORRVSS pc,r14,#Overflow_Flag ; and return error (other flags preserved)
; managed to lock IDE registers
GRAB "r0" ; get original r0
MOV r14,pc ; set return address
ADD pc,pc,r8,LSL #2 ; call routine
; valid ops return here
B %F90
ATAPIC_StartOfJumpTable
B ATAPI_Op
B ATAPI_Reset
ATAPIC_EndOfJumpTable
ATAPIC_UnknownReason
;
; Bad reason code
MOV r0,#DRIVERERROR__UNKNOWN_REASON
MOV r1,#0
ORRS pc,r14,#Overflow_Flag
;;;;;;;;;;;;;;;;;
90
; return from ATAPI_Op or ATAPI_Reset
; unlock IDE registers
; original r14 on stack
LDR r14,[sp] ; get original r14
ORRVS r14,r14,#Overflow_Flag ; set V in r14 if error
BICVC r14,r14,#Overflow_Flag ; ...clear it otherwise
STR r14,[sp] ; overwrite stacked r14
STASH "r0" ; save return code
MOV r0,#0 ; unlock, not lock
BL ATAPI_LockUnlockIDE
GRAB "r0,pc",,^ ; return with flags
;------------------------------------------------------------------------------
; ATAPI_Op
;
; on entry:
; r0 = b0 to b7 reserved
; b24 to b25 00 no data, 01 = read, 10=write, 11=reserved
; b26 =0 if Command packet, =1 if identify command
; b27 =0 then use r7 pointer and convert to an IDE
; drive number
; b28 =0 then retry, else don't retry
; b29 to 31 =0 reserved
; r1 = length of control block (must be even value)
; r2 -> control block
; r3 -> start of transfer
; r4 = length of transfer (in bytes)
; r7 -> CDFS control block
; r12 -> workspace
; r13 -> FD stack
;
; on exit:
; if OK then
; all other regs preserved
; if ERROR then
; r0 = internal error number (sense key + flags)
;
;
; COMMENT:
; If TargetError-Unit Attention or MediaChanged flag is set then this
; will do up to 3 retries as well as setting the disc changed flags.
;
;------------------------------------------------------------------------------
ATAPI_Op ROUT
STASH "r0-r10,r14"
[ cdebug
CDebug_StrReg8 "DoOp ",r0,cc
CDebug_StrReg8 ", addr ",r3,cc
CDebug_StrReg8 ", len ",r4,cc
LDRB r6,[r2]
CDebug_StrReg2 ", PCmd ",r6
MOV r1,#12
00
LDRB r0,[r2],#1
CDebug_StrReg2 " ",r0,cc
SUBS r1,r1,#1
BNE %B00
CDebug_NewLine
LDMIA sp,{r0-r2}
]
MOV r6,r0
; work out which drive (0/1) and OR the bit into r6 for reference
TST r6,#ATAPIOP__DONT_USE_R7
BNE AO_GotDrive
BL Extras_ConvertControlBlockToDrive
MOVVS r0,#DRIVERERROR__SELECTION_TIMEOUT
BVS ACOD_ExitError
ORR r6,r6,r0
AO_GotDrive
; Permanent register assignments:
; r6 = r0 on entry + bit 0 = drive 0 or 1
; r7 = length of control block
; r8 -> CDB
; r9 -> start of transfer
; r10 = length of transfer
MOV r7,r1
MOV r8,r2
MOV r9,r3
MOV r10,r4
; poll for !BSY and cause timeout error if it doesn't appear
SWI XOS_ReadMonotonicTime
ADD r5,r0,#TIMEOUT__SELECTION_PHASE ; r5 = time to give up
LDR r1,TBA ; r1 -> IDE
01
LDR r0,[r1,#TASKFILE__R_ALTERNATE_STATUS]
TSTS r0,#STATUSFLAGS__BSY
BEQ %F02 ; branch if !BSY
SWI XOS_ReadMonotonicTime
CMPS r0,r5 ; time to stop?
BLO %B01 ; branch if not
B %F04 ; give up
;;;;;;;;;;;;;;;;;
02
; drive is no longer busy - select it and check status again
; r5 = time to abandon selection
TSTS r6,#1 ; drive?
MOVEQ r2,#DRIVESELECT__ALWAYS + DRIVESELECTBITS__DEVICE0
MOVNE r2,#DRIVESELECT__ALWAYS + DRIVESELECTBITS__DEVICE1
03
STRB r2,[r1,#TASKFILE__W_DRIVE_SELECT]
; wait for other status bits to become valid - 400ns
MOV r0,#1*2 ; 1/2 us units
BL DoMicroDelay
; now check status
LDR r0,[r1,#TASKFILE__R_ALTERNATE_STATUS]
; don't check for DRDY (Panasonic CR571B and Sony CDU50E don't seem to set it)
TSTS r0,#STATUSFLAGS__BSY :OR: STATUSFLAGS__DRQ
BEQ %F05
SWI XOS_ReadMonotonicTime
CMPS r0,r5 ; time to stop?
BLO %B03 ; branch if not
04
; timeout - drive is busy
[ cdebug
LDR r0,[r1,#TASKFILE__R_ALTERNATE_STATUS]
CDebug_StrReg2 " Drive not ready - status ",r0
]
[ reset_on_drive_error
MOV r0,#DRIVERERROR__SELECTION_TIMEOUT
B drive_error
|
LDR r0,[sp] ; get back R0
TSTS r0,#ATAPIOP__DONT_RETRY
MOV r0,#DRIVERERROR__SELECTION_TIMEOUT
BNE ACOD_DiscNotChanged
B ACOD_ExitError
]
;;;;;;;;;;;;;;;;;
05
; drive is ready
; send command to drive via task file registers
LDR r1,TBA
MOV r0,#FEATUREBITS__PIO
STRB r0,[r1,#TASKFILE__W_FEATURES]
; Work out how much data to read/write
MOV r0,#LARGEST_DATA_CHUNK_PLUS_ONE
SUB r0,r0,#2
CMP r10,r0
MOVLT r0,r10
; write this to byte count registers
STRB r0,[r1,#TASKFILE__W_BYTE_COUNT_LOW]
MOV r0,r0,LSR #8
STRB r0,[r1,#TASKFILE__W_BYTE_COUNT_HIGH]
; do a quick read of status register to clear any pending IRQ
; shouldn't be necessary but may get us out of trouble later
LDRB r0,[r1,#TASKFILE__R_STATUS]
TSTS r6,#ATAPIOP__IDENTIFY_DEVICE
MOVEQ r0,#IDE__ATAPI_PACKET_COMMAND
MOVNE r0,#IDE__ATAPI_IDENTIFY_DEVICE
STRB r0,[r1,# TASKFILE__W_COMMAND]
[ cdebug2
CDebug_StrReg2 " IDE command ",r0,cc
LDRB r0,[r8]
CDebug_StrReg2 ", PCmd=",r0
]
; wait 400ns for BSY to become set
MOV r0,#1*2 ; 1/2 us units
BL DoMicroDelay
; need to send CDB to drive so wait for it to be not busy
SWI XOS_ReadMonotonicTime
ADD r5,r0,#TIMEOUT__OTHER ; r5 = time to give up
11
LDR r0,[r1,#TASKFILE__R_ALTERNATE_STATUS]
TSTS r0,#STATUSFLAGS__BSY
BEQ %F12
SWI XOS_ReadMonotonicTime
CMPS r0,r5 ; time to stop?
BLO %B11 ; branch if not
[ cdebug
CDebug_StrReg8 "drive BSY after command, r6=",r6,cc
LDRB r0,[r8]
CDebug_StrReg2 ", PCmd=",r0
]
B %F14
;;;;;;;;;;;;;;;;;
12
; drive no longer busy - wait 400ns and then look for DRQ (if required)
MOV r0,#1*2 ; 1/2 us units
BL DoMicroDelay
; if IDENTIFY, move straight onto waiting for command complete (no CDB)
TSTS r6,#ATAPIOP__IDENTIFY_DEVICE ; identify?
BNE ACOD_WaitForCommandComplete ; branch if IDENTIFY
13
; check if drive is "Interrupt DRQ" type and wait for IRQ if so
; "Accelerated DRQ" drives do not provide an IRQ at this point
AND r0,r6,#1 ; get drive number
ADR r14,DriveFlags
LDRB r0,[r14,r0] ; get flags for this drive
TSTS r0,#DriveFlag_InterruptDRQ
BLNE WaitForIRQ ; (r1,r5->r0,r2,r3,Z)
BNE %F14 ; branch if error
16
; now ready to look for DRQ for CDB
LDR r0,[r1,#TASKFILE__R_ALTERNATE_STATUS]
TSTS r0,#STATUSFLAGS__DRQ
BNE %F15 ; branch if got DRQ
SWI XOS_ReadMonotonicTime
CMPS r0,r5
BLO %B16
[ cdebug
CDebug_StrReg8 "No DRQ (CDB), r6=",r6,cc
LDRB r0,[r8]
CDebug_StrReg2 ", PCmd=",r0
]
14
; drive was busy or failed to assert DRQ
[ cdebug
CDebug_StrReg8 "BSY or no DRQ (CDB) or no IRQ, r6=",r6,cc
LDRB r0,[r8]
CDebug_StrReg2 ", PCmd=",r0
]
MOV r0,#DRIVERERROR__OTHER_TIMEOUT
[ reset_on_drive_error
B drive_error
|
B ACOD_ExitError
]
;;;;;;;;;;;;;;;;;
15
; got DRQ - send command block via data register
MOV r5,r7 ; r5 = length of CDB
LDR r1,TBA ; r1 -> task file registers
ASSERT TASKFILE__W_DATA = 0
MOV r2,r8 ; r2 -> CDB
[ cdebug
TEQS r5,#12
BEQ %F01
CDebug_StrReg8 "CDB wrong size, ",r5
01
]
ACOD_SendLoop
LDRB r3,[r2],#1
LDRB r4,[r2],#1
; RISC PC doesn't like it if you put debugging here - MEW
ORR r3,r3,r4,LSL #8
ORR r3,r3,r3,LSL #16 ; RISC PC uses top, A5000 uses bottom
STR r3,[r1]
SUBS r5,r5,#2
BGT ACOD_SendLoop
; wait 5us (same time as ATA spec says for first sector of a write command)
; to allow BSY to become set.
MOV r0,#5*2 ; 1/2 us units
BL DoMicroDelay
ACOD_WaitForCommandComplete
SWI XOS_ReadMonotonicTime
ADD r5,r0,#512 ; MEW says NEC needs this long
LDR r1,TBA
BL WaitForIRQ ; (r1,r5->r0,r2,r3,Z)
[ cdebug
BEQ %F01
CDebug_StrReg8 "No IRQ for cmd ",r6,cc
LDRB r0,[r8]
CDebug_StrReg2 ", PCmd=",r0
01
]
MOVNE r0,#DRIVERERROR__OTHER_TIMEOUT ; NE => error
[ reset_on_drive_error
BNE drive_error
|
BNE ACOD_ExitError
]
; IRQ appeared and was cleared
LDR r2,[r1,#TASKFILE__R_ALTERNATE_STATUS] ; get updated status
; data transfer requested?
TSTS r6,#2_11:SHL:24
BEQ ACOD_ExitOK ; branch if no data transfer requested
; check that BSY is clear
TSTS r2,#STATUSFLAGS__BSY
BEQ %F64
; drive was busy following the IRQ - it should not be
; It *can't* be safe just to look for (and clear) another IRQ as MEW did
[ cdebug
CDebug_StrReg2 "BSYIRQ ",r2
]
MOV r0,#DRIVERERROR__OTHER_TIMEOUT
[ reset_on_drive_error
B drive_error
|
B ACOD_ExitError
]
64
; BSY is clear - check for error
; r2 = status
TSTS r2,#STATUSFLAGS__CHECK ; error?
LDRNEB r0,[r1,#TASKFILE__R_ERROR] ; yes get error bits
BNE ACOD_ExitError
; any data to be read out of/copied into drive?
TSTS r2,#STATUSFLAGS__DRQ
BEQ ACOD_ExitOK ; branch if no data
; set r5 = how much data drive wants to send/receive
LDR r1,TBA
LDRB r14,[r1,#TASKFILE__R_BYTE_COUNT_LOW]
LDRB r3,[r1,#TASKFILE__R_BYTE_COUNT_HIGH]
ORRS r5,r14,r3,LSL #8
[ cdebug2
CDebug_StrReg4 "bytes in drive=",r5
]
BEQ ACOD_ExitOK ; branch if no data in drive
[ fix_cr571b10e_maybe
; read the alternate status register to try to work around the
; bug in the Panasonic CR571B 1.0e
LDRB r0,[r1,#TASKFILE__R_ALTERNATE_STATUS]
]
; read the data in
LDR r1,TBA
ASSERT TASKFILE__R_DATA = 0
; r0 = temp
; r1 -> task file data register
; r2 =
; r5 = bytes remaining from drive/expected by drive
; r6+ used
MOV r4,r5
; write data out ?
AND r14,r6,#2_11:SHL:24
TEQS r14,#writedata
BEQ AR_WriteDataToDrive
; Make sure that it's not returning more data than we want
; r10 = length of transfer
CMPS r5,r10
MOVGT r5,r10
[ cdebug2
CDebug_StrReg4 "copy ",r5
]
; fall through
ROUT
; Improved data copy routine - MEWs did not copy last 32 bytes in optimised
; loop and this happens on every transfer.
; r1 -> data register
; r4 = bytes in drive
; r5 = bytes to copy into buffer
; r9 -> buffer
; r10 = bytes requested
; if fewer than 32 bytes to copy, do it slowly - the '+2' is in case we
; have to word align the transfer before starting
CMPS r5,#(8*4) + 2
BLT %F20 ; slow copy
; check for odd alignment - fast code can't currently handle this
TSTS r9,#1
BNE %F20 ; slow copy
; word align if necessary for faster copy
TSTS r9,#2 ; half-word aligned
LDRNE r0,[r1] ; align it if so
STRNEB r0,[r9],#1
MOVNE r0,r0,LSR #8
STRNEB r0,[r9],#1
SUBNE r5,r5,#2
; The main loop does 8*4 bytes per iteration.
; We know, by here, that the destination address is word-aligned.
; r1 -> data register
; r4 = bytes in drive
; r5 = bytes to copy into buffer
; r9 -> buffer
; r10 = bytes requested
;
; The following registers are destroyed by this copy
; r0, r14, r2, r3, r4, r6, r7, r8, r10
;
; save registers we must not destroy before starting
STASH "r2,r4,r6,r7,r8,r10"
SUB r5,r5,#8*4 ; number of bytes per loop
10
LDR r0,[r1,#2] ; data in b16..31
LDR r14,[r1] ; data in b0..15
MOV r14,r14,LSL #16 ; move to b16..31 clearing b0..15
ORR r0,r14,r0,LSR #16 ; bring in first 16 bits as b0..15
LDR r2,[r1,#2]
LDR r14,[r1]
MOV r14,r14,LSL #16
ORR r2,r14,r2,LSR #16
LDR r3,[r1,#2]
LDR r14,[r1]
MOV r14,r14,LSL #16
ORR r3,r14,r3,LSR #16
LDR r4,[r1,#2]
LDR r14,[r1]
MOV r14,r14,LSL #16
ORR r4,r14,r4,LSR #16
LDR r6,[r1,#2]
LDR r14,[r1]
MOV r14,r14,LSL #16
ORR r6,r14,r6,LSR #16
LDR r7,[r1,#2]
LDR r14,[r1]
MOV r14,r14,LSL #16
ORR r7,r14,r7,LSR #16