Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
RiscOS
S
Sources
H
HWSupport
CD
ATAPI
Commits
a571f55d
Commit
a571f55d
authored
Dec 16, 1996
by
Neil Turton
Browse files
Unused files removed from Trunk
parent
e8fae392
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
0 additions
and
1254 deletions
+0
-1254
s/ATAPIstuff
s/ATAPIstuff
+0
-1254
No files found.
s/ATAPIstuff
deleted
100644 → 0
View file @
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