
;Module init
;-----------
;Entry:
; R10 - pointer to initialisation parameters
; R11 - instantiation number
; R12 - pointer to private word

.Entry_init
 STMFD   R13!, {R1-R11, R14}

 LDR     R10, [R12]
 TEQ     R10, #0
 BNE     _already_running

 MOV     R0, #Module_Claim
 MOV     R3, #VARS.size
 SWI     XOS_Module			;claim some memory
 LDMVSFD R13!, {R1-R11, PC}
 STR     R2, [R12]			;update our private word
 MOV     R9, R12			;R9=private word pointer
 MOV     R12, R2

 MOV     R0, #0				;clear VARS
 ._L1
   STR     R0, [R2], #4
   SUBS    R3, R3, #4
 BNE     _L1

 STR     R12, [R12, #0]			;pointer to itself

 ADD     R10, R12, #VARS.drive_info	;setup drive_info table
 MOV     R3, #7				;8 discs
 ._L2
   ADR     R1, Dismount_text
   ADD     R2, R10, R3, LSL #Drive_struct
   ADD     R2, R2, #Drive.dismount	;*Dismount
   MOV     R5, #LEN("-HDFFS-Dismount ")
   ._L2b
     LDRB    R0, [R1], #1
     STRB    R0, [R2], #1
     SUBS    R5, R5, #1
   BNE     _L2b
   SUBS    R3, R3, #1
 BPL     _L2

 ADR     R0, Set_filetype
 SWI     XOS_CLI
 ADR     R0, Set_alias
 SWI     XOS_CLI
 BL      Register_Resources
 LDMVSFD R13!, {R1-R11, PC}

 ._already_running
 ADR     R0, FS_Create_Block		;FileCore descriptor block
 ADR     R1, 0				;Base of this module
 MOV     R2, R9				;our private word pointer
 MOV     R3, #3<<8			;no. of HD-1
 ORR     R3, R3, #4<<16			;default drive
 MOV     R4, #32*1024			;size of directory cache
 MOV     R5, #0 ;32			;no. of 1024 byte buffers, if we
					;..support background transfers
 MOV     R6, #&02020202			;HD map sizes
 SWI     XFileCore_Create		;PRM2-228
 LDMVSFD R13!, {R1-R11, PC}
 STR     R0, [R12, #VARS.filecore_private]	;point private word at our data block
 STR     R1, [R12, #VARS.disc_op_complete]

 MOV     R0, #our_FileSystem_number
 ADR     R1, free_handler
 MOV     R2, R12
 SWI     XFree_Register			;register with Free
LDMFD    R13!, {R1-R11, PC}




.Entry_kill
 STMFD   R13!, {R1, R14}
 LDR     R12, [R12, #0]

 TEQ     R12, #0
 BEQ     _eek_no_vars

 MOV     R1, #7
 ._L1
   MOV     R0, R1
   BL      internal_eject
   SUBS    R1, R1, #1
 BPL     _L1

 LDR     R0, [R12, #VARS.wimp_taskhandle]
 TEQ     R0, #0				;is the filer running?
 LDRNE   R1, WIMP_Task			;yes, close it down
 SWINE   XWimp_CloseDown		;PRM3-172

 MOV     R0, #our_FileSystem_number
 ADR     R1, free_handler
 MOV     R2, R12
 SWI     XFree_DeRegister		;register with Free

 MOV     R0, #Module_Free
 MOV     R2, R12
 SWI     XOS_Module			;free data block if we have one

 ._eek_no_vars
 BL      Deregister_Resources

 MOV     R0, #Module_Delete		;Kill FileCore%HDFFS
 ADR     R1, HDFFS_Full_Title
 SWI     XOS_Module			;PRM1-235
LDMFD   R13!, {R1, PC}




.free_handler
 CMP     R0, #4
 ADDLS   PC, PC, R0, LSL #2
 LDMFD   R13!, {PC}
 LDMFD   R13!, {PC}			;entry 0
 B       _free_device_name		;entry 1
 B       _free_space			;entry 2
 B       _free_compare			;entry 3
 B       _free_space64			;entry 4

;Entry:
; R2 - pointer buffer to fill
; R3 - pointer to device ID byte
;
;Exit:
; R0 - length of filled buffer, including terminator

 ._free_device_name
 ADD     R14, R12, #VARS.free_stack		;our temp stack
 STMFD   R14!, {R1-R3}

 LDRB    R0, [R3]
 SUB     R0, R0, #ASC("0")
 ADD     R1, R12, #VARS.drive_info + Drive.name
 ADD     R1, R1, R0, LSL #Drive_struct		;R1=pointer to disc name
 MOV     R0, R2
 ._L1
   LDRB    R3, [R1], #1
   STRB    R3, [R2], #1
   TEQ     R3, #0
 BNE     _L1

 SUB     R0, R2, R0				;R0=length of string
 LDMFD   R14, {R1-R3}
 LDMFD   R13!, {PC}


;Entry:
; R2 - pointer buffer to fill
; R3 - pointer to device ID byte
;
;Exit:
; [R2, #0] = size of device (0 if unchanged)
; [R2, #4] = free space
; [R2, #8] = used space

 ._free_space
 ADD     R14, R12, #VARS.free_stack		;our temp stack
 STMFD   R14!, {R0-R2, R8, R13}
 MOV     R13, R14

 MOV     R8, R2					;R8=buffer for result
 MOV     R1, R13
 BL      build_discname				;pointer to "HDFFS::<discname>"
 MOV     R0, #49				;Read free space
 SWI     XOS_FSControl				;PRM2-134
 STR     R0, [R8, #4]				;Free space
 SUB     R2, R2, R0				;R2=rough used space
 STR     R1, [R8, #8]				;Used space
 MOV     R2, #0					;disc size hasn't changed
 STR     R2, [R8, #0]				;Disc size
 LDMFD   R13, {R0-R2, R8, R13}
 LDMFD   R13!, {PC}


 ._free_compare
 CMP     R2, R2
 LDMFD   R13!, {PC}


;Entry:
; R2 - pointer buffer to fill
; R3 - pointer to device ID byte
;
;Exit:
; R0=0
; [R2, #0] = size of device Low (0 if unchanged)
; [R2, #4] = size of device High
; [R2, #8] = free space Low
; [R2, #12] = free space High
; [R2, #16] = used space Low
; [R2, #20] = used space High

 ._free_space64
 ADD     R14, R12, #VARS.free_stack		;our temp stack
 STMFD   R14!, {R1-R4, R8, R13}
 MOV     R13, R14

 MOV     R8, R2					;R8=buffer for result
 MOV     R1, R13
 BL      build_discname				;pointer to "HDFFS::<discname>"
 MOV     R0, #55				;Read free space
 SWI     XOS_FSControl				;PRM2-134
 MOVVS   R0, #0
 MOVVS   R1, #0
 MOVVS   R2, #0
 MOVVS   R3, #0
 MOVVS   R4, #0
 STR     R3, [R8, #0]				;Disc size Low
 STR     R4, [R8, #4]				;Disc size High
 STR     R0, [R8, #8]				;Free space Low
 STR     R1, [R8, #12]				;Free space High
 SUBS    R3, R3, R0				;R3=rough used space Low
 SBC     R4, R4, R1				;R4=rough used space High
 STR     R3, [R8, #16]				;Used space Low
 STR     R4, [R8, #20]				;Used space High
 SUBS    R0, R0, R0				;clear V and set R0=0
 LDMFD   R13, {R1-R4, R8, R13}
 LDMFD   R13!, {PC}




;build_discname
;--------------
;builds the full discname.  ie HDFFS::HardDisc1

;Entry:
; R1 - buffer pointer
; R3 - pointer to <discname>
;Exit:
; R0, R2, R3 - corrupt
; R1 - pointer to "HDFFS::<discname><00>"

.build_discname
 MOV     R2, R3
 ._L1					;find end of discname
   LDRB    R0, [R3], #1
   CMP     R0, #32
 BHI     _L1
 SUB     R3, R3, #1

;Entry:
; R2 - start of string
; R3 - end of string
.build_discname_from_icon
 MOV     R0, #0
 STRB    R0, [R1, #-1]!
 ._L2					;copy discname
   LDRB    R0, [R3, #-1]!
   STRB    R0, [R1, #-1]!
   CMP     R3, R2
 BNE     _L2

 ADR     R3, FS_Path			;prepend "HDFFS::"
 ._L3
   LDRB    R0, [R3, #-1]!
   TEQ     R0, #0
   STRNEB  R0, [R1, #-1]!
 BNE     _L3
MOV     PC, R14




;Entry_service
;-------------
;Respond to Service_StartFiler
;
;Entry:
; R0 - Filer's task handle
; R1 - reason code

 ._service_table
 DCD 0				;set R1 to service no.
 DCD Entry_service + 4		;entry for services
 DCD Service_Reset		;27
 DCD Service_StartFiler		;4B
 DCD Service_ResourceFSStarting	;60
 DCD 0

 DCD _service_table
.Entry_service
 MOV     R0, R0				;magic word for RO4+
 STR     R14, [R13, #-4]!
 LDR     R12, [R12, #0]

 TEQ     R1, #Service_Reset
 BEQ     _service_reset

 TEQ     R1, #Service_ResourceFSStarting
 BEQ     _load_resources

 TEQ     R1, #Service_StartFiler	;PRM2-500
 LDRNE   PC, [R13], #4

 LDR     R14, [R12, #VARS.wimp_taskhandle]	;is our filer running?
 TEQ     R14, #0
 ADREQ   R0, our_Desktop_HDFFSFiler	;NO, ptr to *command
 MOVEQ   R1, #0				;|+  claim call
LDR    PC, [R13], #4

 ._service_reset
 BL      WIMP_closedown
LDR    PC, [R13], #4

 ._load_resources
 BL      Register_Resources
LDR    PC, [R13], #4




.Register_Resources
 STMFD   R13!, {R14}
 ADR     R0, our_resources
 SWI     XResourceFS_RegisterFiles

 ADR     R0, IconSprites
 SWI     XOS_CLI 
LDMFD   R13!, {PC}



.Deregister_Resources
 STMFD   R13!, {R14}
 ADR     R0, our_resources
 SWI     XResourceFS_DeregisterFiles
LDMFD   R13!, {PC}




;*Desktop_HDFFSFiler
;-------------------
;Start the ADFFS filer
;
;Entry:
; R0  - pointer to command tail
; R1  - no. of parameters
; R12 - point to module private word

.Desktop_HDFFSFiler
 STR     R14, [R13, #-4]!

 MOV     R2, R0
 ADR     R1, HDFFS_Title
 MOV     R0, #Module_Enter		;start the filer
 SWI     XOS_Module			;PRM1-233
LDR     PC, [R13], #4




;*HDFFS
;-----
;Select the HDFFS File System

.Entry_HDFFS
 STMFD   R13!, {R1, R14}

 MOV     R0, #FSControl_SelectFS	;Select HDFFS file system
 ADR     R1, HDFFS_Name
 SWI     XOS_FSControl			;PRM2-80
LDMFD    R13!, {R1, PC}




;*HDFEject
;---------
;Dismounts a drive and removes its Filer icon

.Entry_Eject
 STMFD   R13!, {R1-R5, R10-R11, R14}
 LDR     R12, [R12, #0]

 MOV     R1, R0				;command tail
 MOV     R2, #7				;range is 0-7
 MOV     R0, #10 OR (1<<29)		;assume base 10 number
 SWI     XOS_ReadUnsigned		;read the value PRM1-460
 LDMVSFD R13!, {R1-R5, R10-R11, PC}	;exit on error
 MOV     R11, R2			;R11=drive #

.internal_eject_P1
 ADD     R1, R12, #VARS.drive_info
 ADD     R10, R1, R11, LSL #Drive_struct
 MOV     R0, #0
 LDR     R1, [R10, #Drive.size]
 TEQ     R1, #0
 LDMEQFD R13!, {R1-R5, R10-R11, PC}

 ADD     R0, R10, #Drive.dismount
 SWI     XOS_CLI			;*DISMOUNT

 LDR     R0, [R10, #Drive.icon_handle]
 TEQ     R0, #0
 BLNE    Remove_Icon			;remove the filer icon

 SUBS    R0, R0, R0			;clear V
 STR     R0, [R10, #Drive.icon_handle]
 STR     R0, [R10, #Drive.size]
LDMFD   R13!, {R1-R5, R10-R11, PC}




;internal_eject
;--------------
;internal call to peform *HDFEject

;Entry:
; R0 - drive number (0-7)
; R12 - pointer to VARS

;Exit:
; R0 - corrupt

.internal_eject
 STMFD   R13!, {R1-R5, R10-R11, R14}

 MOV     R11, R0
 B       internal_eject_P1




;internal_dismount
;-----------------
;intenal call to perform *HDFDismount

;Entry:
; R0 - drive number (0-7)
; R12 - pointer to VARS

.internal_dismount
 STMFD   R13!, {R1-R2, R14}
 ADD     R2, R12, #VARS.drive_info
 ADD     R2, R2, R0, LSL #Drive_struct

 LDR     R1, [R2, #Drive.size]
 TEQ     R1, #0
 ADDNE   R0, R2, #Drive.dismount
 SWINE   XOS_CLI			;*DISMOUNT
LDMFD   R13!, {R1-R2, PC}




;*HDFOPEN
;--------
;mount drive and open a Filer window

.Entry_MountOpen
 STMFD   R13!, {R14}
 BL      Entry_Mount
 BLVC    Open_Filer
LDMFD   R13!, {PC}




;*HDFMOUNT
;---------
;mount a drive

; Exit:
; R0 - drive # used

.Entry_Mount
 STMFD   R13!, {R1-R5, R9-R11, R14}
 LDR     R12, [R12, #0]
 MOV     R10, R0			;R10=filename
 MOV     R11, #4			;assume drive 4

 CMP     R1, #1				;two parameters?
 BEQ     _mount_file			;NO

 MOV     R0, #10 OR (1<<29)		;assume base 10 number
 MOV     R1, R10			;command tail
 MOV     R2, #7				;range is 0-7
 SWI     XOS_ReadUnsigned		;read the value PRM1-460
 LDMVSFD R13!, {R1-R5, R9-R11, PC}		;exit on error
 MOV     R11, R2			;R11=drive #
 MOV     R10, R1

 ._mount_file
 ADD     R9, R12, #VARS.drive_info
 ADD     R9, R9, R11, LSL #Drive_struct	;R5=pointer to Drive struct

 MOV     R0, R11			;drive #
 BL      internal_eject			;dismount current drive if required

 MOV     R1, R10
 MOV     R0, #17			;get file info
 SWI     XOS_File			;PRM2-46
 TEQ     R0, #1				;did we find a file?
 MOVNE   R0, #19			;NO, generate an error message
 MOVNE   R2, #0
 SWINE   XOS_File
 LDMVSFD R13!, {R1-R5, R9-R11, PC}	;exit on error
 STR     R4, [R9, #Drive.size]

 MOV     R0, #37			;Canonicalise path
 MOV     R1, R10			;filename we were passed
 ADD     R2, R9, #Drive.hdf_filename	;track the file we just opened
 MOV     R3, #0
 MOV     R4, #0
 MOV     R5, #Drive.hdf_filename_end - Drive.hdf_filename	;size of buffer
 SWI     XOS_FSControl
 LDMVSFD R13!, {R1-R5, R9-R11, PC}	;exit on error

.Entry_Mount_P1
 STR     R13, [R9, #Drive.media_changed]

 MOV     R0, R11			;take a copy of the disc name
 BL      construct_wimp_message
 ADD     R1, R12, #VARS.wimp_message
 LDR     R2, [R12, #VARS.wimp_taskhandle]	;add validation to create
 ORR     R0, R0, R2, LSL #8			;a drive icon
 STR     R0, [R1, #User_Message.your_ref]	;set ref to drive #

 ADD     R1, R1, #User_Message.directory + LEN("HDFFS::")
 ADD     R2, R9, #Drive.name
 ._L1
   LDRB    R0, [R1], #1
   STRB    R0, [R2], #1
   TEQ     R0, #ASC(".")
 BNE     _L1
 MOV     R0, #0
 STRB    R0, [R2, #-1]			;terminate the disc name

 BL      Send_Add_Icon_Message

 SUBS    R1, R1, R1			;clear V
 MOV     R0, R11			;drive #
LDMFD   R13!, {R1-R5, R9-R11, PC}




;Readd_Icon
;----------
;re-adds the Filer icon for the drive

;Entry:
; R0 - drive #

.Readd_Icon
 STMFD   R13!, {R1-R5, R9-R11, R14}
 MOV     R11, R0
 ADD     R9, R12, #VARS.drive_info
 ADD     R9, R9, R11, LSL #Drive_struct	;R5=pointer to Drive struct
 B       Entry_Mount_P1




.Entry_SWI
 STMFD   R13!, {R8, R14}
 LDR     R12, [R12, #0]
 LDR     R8, [R12, #VARS.filecore_private]	;R8=FileCore private word

 CMP     R11, #8
 ADDLS   PC, PC, R11, LSL #2
LDMFD   R13!, {R8, PC}
#set XHDFFS_Remount = our_SWI_chunk + &20000 + 8
 B       _HDFFS_DiscOp		;SWI 0
 B       _HDFFS_MiscOp		;SWI 1
 B       _HDFFS_Drives		;SWI 2
 B       _HDFFS_FreeSpace	;SWI 3
 B       _HDFFS_DescribeDisc	;SWI 4
 B       _HDFFS_SectorDiscOp	;SWI 5
 B       _HDFFS_IDEDeviceInfo	;SWI 6
 B       _HDFFS_ControllerType	;SWI 7
 B       _HDFFS_Remount		;SWI 8
; B       _HDFFS_DiscOp64	;SWI x


._HDFFS_DiscOp
 SWI     XFileCore_DiscOp
LDMFD    R13!, {R8, PC}


._HDFFS_MiscOp
 SWI     XFileCore_MiscOp
LDMFD    R13!, {R8, PC}


._HDFFS_Drives
 SWI     XFileCore_Drives
LDMFD    R13!, {R8, PC}


._HDFFS_FreeSpace
 SWI     XFileCore_FreeSpace
LDMFD    R13!, {R8, PC}


._HDFFS_DescribeDisc
 SWI     XFileCore_DescribeDisc
LDMFD    R13!, {R8, PC}


._HDFFS_SectorDiscOp
 SWI     XFileCore_SectorDiscOp
LDMFD    R13!, {R8, PC}


._HDFFS_Remount
 CMP     R0, #8				;is drive # below 8?
 LDMHSFD R13!, {R8, PC}			;NO

 LDR     R8, [R12, #VARS.wimp_taskhandle]	;add validation to create
 ORR     R14, R0, R8, LSL #8			;a drive icon
 ADD     R8, R12, #VARS.wimp_message
 STR     R14, [R8, #User_Message.your_ref]	;set ref to drive #

 ADD     R8, R12, #VARS.drive_info
 ADD     R8, R8, R0, LSL #Drive_struct
 LDR     R14, [R8, #Drive.icon_handle]
 TEQ     R14, #0				;is it mounted?
 LDMEQFD R13!, {R8, PC}			;NO

 STMFD   R13!, {R0-R1}
 LDR     R1, [R8, #Drive.size]
 BL      internal_eject			;dismount
 STR     R1, [R8, #Drive.size]
 LDMFD   R13!, {R0-R1}
 BL      Readd_Icon
 SUBS    R0, R0, R0			;clear V
LDMFD    R13!, {R8, PC}



;._HDFFS_DiscOp64
; SWI     XFileCore_DiscOp64
;LDMFD    R13!, {R8, PC}



;Entry:
; R0 = 0	- legacy ID
; R1 = ID
;
;Exit:
; R0 - preserved
; R1 - 2 (ATAPI)
; R2 - drive #
; R3 - pointer to IDENTIFY response

._HDFFS_IDEDeviceInfo
 TEQ     R0, #0			;device info by legacy ID?
 LDMHIFD R13!, {R8, PC}

 ADD     R8, R12, #VARS.drive_info
 ADD     R8, R8, R1, LSL #Drive_struct
 LDR     R2, [R8, #Drive.size]
 CMP     R2, #0			;is the drive mounted?
 MOVEQ   R1, #0			;no device
 LDMEQFD R13!, {R8, PC}		;exit with R1=0 R3=0

 ADD     R3, R12, #VARS.IDENTIFY_response
 MOV     R14, #512		;clear IDENTIFY response block
 ._L1
   STR     R0, [R3], #4
   SUBS    R14, R14, #4
 BNE     _L1
 SUB     R3, R3, #512

 MOV     R14, #1 << 7		;drive is removable
 STRB    R14, [R3, #0]
 MOV     R14, #1 << (9-8)	;drive supports LBA
 STRB    R14, [R3, #49*2 + 1]
 MOV     R14, #1 << (10-8)	;drive supports 48bit LBA
 STRB    R14, [R3, #83*2 + 1]

 MOV     R2, R2, LSR #9		;R2=size in 512 byte LBA
 STR     R2, [R3, #100*2]
 MOV     R14, #0
 STRB    R14, [R3, #102*2]

 ADR     R0, HDF_image		;drive model
 ADD     R8, R3, #27*2
 MOV     R2, #LEN("HDF image")
 ._L2
   LDRB    R14, [R0], #1
   STRB    R14, [R8], #1
   SUBS    R2, R2, #1
 BNE     _L2

 MOV     R2, R1			;drive ID
 MOV     R1, #2			;ATAPI
 MOV     R0, #0
LDMFD    R13!, {R8, PC}


._HDFFS_ControllerType
 CMP     R0, #7
 MOVHI   R0, #0			;Disc not present
 LDMHIFD R13!, {R8, PC}

 ADD     R8, R12, #VARS.drive_info
 ADD     R8, R8, R0, LSL #Drive_struct
 LDR     R0, [R8, #Drive.size]
 CMP     R0, #0			;is the drive mounted?
 MOVHI   R0, #4			;Yes, use IDE as the controller type
LDMFD    R13!, {R8, PC}




;Exit_bad_parameters
;-------------------
;Exit from DiscOp/MiscOp with "Bad parameters" error

.Exit_bad_parameters
 MOV     R0, #HD_error_Bad_parameters
 ADD     R13, R13, #4			;drop R0 from stack
 ORR     R1, R1, #1<<31
 ADDS    R1, R1, R1			;set V
LDMFD   R13!, {R1-R11, PC}		;NO




;MiscOp Entry
;------------
;Entry:
; R0  - reason
; R1  - drive
; R8  - pointer to FileCore instance private word
; R12 - Module private word

.Entry_MiscOp
 CMP     R1, #7				;sanity check
 MOVHI   PC, R14
 STMFD   R13!, {R0-R11, R14}

 LDR     R12, [R12, #0]
 ADD     R11, R12, #VARS.drive_info
 MOV     R7, R1				;R7=drive #
 ADD     R11, R11, R1, LSL #Drive_struct

 CMP     R0, #6
 ADDLS   PC, PC, R0, LSL #2
 B       Exit_bad_parameters
 B       _MiscOp_0_Mount		;MiscOp 0
 B       _MiscOp_1_PollChanged		;MiscOp 1
 B       Exit_bad_parameters		;MiscOp 2
 B       Exit_bad_parameters		;MiscOp 3
 B       _MiscOp_4_Poll_period		;MiscOp 4
 LDMFD   R13!, {R0-R11, PC}		;MiscOp 5
 B       Exit_bad_parameters		;MiscOp 6

;Exit:
; EQ - drive doesn't exist
; NE - drive exists

._MiscOp_check_drive
 STMFD   R13!, {R0}
 LDR     R0, [R11, #Drive.size]
 TEQ     R0, #0				;does the disc exist?
 LDMFD   R13!, {R0}
 LDMEQFD R13!, {R0-R11, PC}		;drive doesn't exist
 MOV     PC, R14



._MiscOp_4_Poll_period
 MOV     R5, #100			;100cs poll period
 ADR     R6, MiscOp_media_type		; |+  media type string
 ADD     R1, R13, #5*4
 STMIA   R1, {R5, R6}
LDMFD   R13!, {R0-R11, PC}




;MiscOp 0
;--------
;Entry:
; R1  - drive
; R2  - disc address to read
; R3  - pointer to buffer
; R4  - length to read into buffer
; R5  - pointer to disc record to fill in (not required for HD)
; R7  - drive
; R8  - pointer to FileCore instance private word
; R11 - pointer to Drive struct
; R12 - pointer to VARS

._MiscOp_0_Mount
 BL      _MiscOp_check_drive

 LDR     R1, FS_Create_Block
 TST     R1, #Sector_Aligned		;are we using sector addressing?
 BICEQ   R2, R2, #%111<<29		;NO, clear the drive from the address
 MOV     R1, #1
 B       DiscOp_1_Read_Sector






;MiscOp 1
;--------
;Entry:
; R1  - drive
; R2  - sequence no.
; R7  - drive
; R8  - pointer to FileCore instance private word
; R11 - pointer to Drive structure
; R12 - pointer to VARS
;
;Exit:
; R2 = sequence no.
; R3 = result flag -       11-31 reserved
;                  +----------10 ready works
;                  |+--------- 9 density sensing works
;                  ||+-------- 8 disc in drive is high density
;                  |||+------- 7 changed works
;                  ||||+------ 6 empty works
;                  |||||+----- 5 drive is 40 track
;                  ||||||+---- 4 ready
;                  |||||||+--- 3 empty
;                  ||||||||+-- 2 changed
;                  |||||||||+- 1 maybe changed
;                  ||||||||||+ 0 not changed
;                  |||||||||||

._MiscOp_1_PollChanged
 BL      _MiscOp_check_drive

 MOV     R3,     #%10010010000		;PRM2-244
 LDR     R0, [R11, #Drive.media_changed]
 TEQ     R0, #0
 ORRNE   R3, R3, #%00000000010		;media may have changed
 ORREQ   R3, R3, #%00000000001		;not changed
 MOVNE   R0, #0
 STRNE   R0, [R11, #Drive.media_changed]
 STR     R3, [R13, #3*4]
LDMFD   R13!, {R0-R11, PC}




;Entry:
; R1  - bits 0 - 3 reason code
;     -      4 - 7 option bits
; R2  - disc address, top 3 bits drive
; R3  - pointer to buffer
; R4  - length in bytes
; R5  - pointer to alternative disc record
; R6  - pointer to defect list?
; R8  - pointer to FileCore instance private word
; R12 - Module private word

.Entry_DiscOp
 STMFD   R13!, {R0-R11, R14}
 LDR     R12, [R12, #0]
 MOV     R7, R2, LSR #29		;R7=drive #
 BIC     R2, R2, #%111<<29		;clear drive from address
 AND     R9, R1, #%1111			;R9=reason code

 ADD     R11, R12, #VARS.drive_info
 ADD     R11, R11, R7, LSL #Drive_struct
 LDR     R0, [R11, #Drive.size]
 TEQ     R0, #0				;does the disc exist?
 LDMEQFD R13!, {R0-R11, PC}		;NO, fail silently

 CMP     R9, #9
 ADDLO   PC, PC, R9, LSL #2
 B       Exit_bad_parameters
 B       DiscOp_0_Verify
 B       DiscOp_1_Read_Sector
 B       DiscOp_2_Write_Sector
 B       DiscOp_3_Read_Track
 B       DiscOp_4_Write_Track
 B       DiscOp_5_Seek
 B       DiscOp_6_Restore
 B       DiscOp_7_StepIn
 B       DiscOp_8_StepOut
 B       DiscOp_9_Read_Sector_Cached



.DiscOp_0_Verify
.DiscOp_3_Read_Track
.DiscOp_4_Write_Track
.DiscOp_5_Seek
.DiscOp_6_Restore
.DiscOp_7_StepIn
.DiscOp_8_StepOut
 LDMFD   R13!, {R0-R11, PC}



.DiscOp_2_Write_Sector
 TEQ     R4, #0
 LDMEQFD R13!, {R0-R11, PC}
 MOV     R5, #1				;R5=OS_GBPB to write
 B       handle_read_write



;DiscOp 1
;--------
;Entry:
; R1  - bits 0 - 3 reason code
;            4 - 7 option bits
; R2  - disc address
; R3  - pointer to buffer
; R4  - length in bytes
; R5  - pointer to disc record
; R7  - drive #
; R8  - pointer to FileCore instance private word
; R11 - pointer to Drive struct
; R12 - pointer to VARS

;Exit:
; R0  - error if applicable
; R4  - bytes remaining on error, zero if successful

.DiscOp_9_Read_Sector_Cached
.DiscOp_1_Read_Sector
 TEQ     R4, #0
 LDMEQFD R13!, {R0-R11, PC}
 MOV     R5, #3				;R5=OS_GBPB to read

.handle_read_write
 STMFD   R13!, {R0-R1}
 MOV     R0, #&C8			;open with read/write access
 ADD     R1, R11, #Drive.hdf_filename	;filename
 SWI     XOS_Find
 TEQ     R0, #0				;did it fail?
 STR     R0, [R11, #Drive.filehandle]
 LDMFD   R13!, {R0-R1}
 BEQ     _read_write_fault

 TST     R1, #ScatterList_Op		;is it a scatterlist
 MOVNE   R10, R3			;YES, R10=scatterlist
 ADDEQ   R10, R12, #VARS.local_scatterlist	;NO, build one
 MOVEQ   R6, #0
 MOVEQ   R9, #0
 STMEQIA R10, {R3, R4, R6, R9}
 MOV     R9, R4				;R9=foreground cap
 ._L1
   LDMIA   R10, {R3, R4}		;read the address and length
   CMN     R3, #Scatter_List_End	;if <= -65536 the scatter list looped
   TEQCS   R4, #0			;...and R4=0
   ADDEQ   R10, R10, R3			;...go back to the start of the list
   LDMEQIA R10, {R3, R4}		;...and load the next pair
   TEQ     R4, #0			;are we at the end of the list?
   BEQ     _scatterList_exit		;YES
   TST     R1, #Background_Op		;are we running a background transfer?
   BNE     _P1				;YES, skip foreground limit check
   CMP     R4, R9
   MOVHI   R4, R9			;cap transfer to foreground limit

   ._P1					;R3=address, R4=size
   MOV     R6, R4			;R6=bytes we're going to read
   BL      read_write
   SUB     R6, R6, R4			;R6=bytes actually read
   TEQ     R4, #0			;did it complete?
   STMNEIA R10, {R3, R4}		;NO
   STMEQIA R10!, {R3, R4}		;YES, go to next
   TEQ     R0, #0			;did an error occur?
   STRNE   R0, [R13]			;YES
   BNE     _scatterList_exit

   SUBS    R9, R9, R6			;reduce foreground cap
   TSTEQ   R1, #Background_Op		;are we performing a background transfer?
 BNE      _L1				;NO

 ._scatterList_exit
 TST     R1, #Background_Op		;are we running a background transfer?
 BEQ     _not_background_op		;NO

 BL      Find_ScatterList_Start		;YES, find start of scatterlist
 MOV     R0, #0
 STR     R0, [R14, #-4]			;clear process active bit PRM2-604
 STR     R12, [R13, #-4]!
 LDR     R12, [R12, #VARS.filecore_private]	;notify FileCore transfer is complete
 MOV     R14, PC
 LDR     PC, [R12, #VARS.disc_op_complete]
 LDR     R12, [R13], #4

 ._not_background_op
 MOV     R0, #0
 LDR     R1, [R11, #Drive.filehandle]
 SWI     XOS_Find			;close the file
 SUBS    R0, R0, R0			;clear V

 STR     R4, [R13, #4*4]		;set return R4
 ._exit
 LDR     R0, [R13], #4
 TEQ     R0, #0				;did an error occur?
 MOVNE   R1, #1<<31			;YES
 ADDNE   R1, R1, R1			; |+ set V
LDMFD   R13!, {R1-R11, PC}

; R5=1 - write error
; R5=3 - read error
._read_write_fault
 TEQ     R5, #1
 MOVEQ   R0, #7				;write fault
 MOVNE   R0, #&18			;no data address mark
 STR     R0, [R13, #0]
B       _exit




;Find_ScatterList_Start
;----------------------
;Returns the address of the first entry in a scatterlist
;
;Entry:
; R3 = scatterlist pointer
;
;Exit:
; R14 - pointer to start of scatterlist

.Find_ScatterList_Start
 STMFD   R13!, {R2-R4, R14}

 ._L1					;find the start of the scatter list
   LDMIA   R3!, {R2, R4}
   CMN     R2, #Scatter_List_End	;if address <= -65536
   TEQCS   R4, #0			;.. and length 0
 BNE     _L1				;.. we've hit the end

 ADD     R3, R3, R2
 SUB     R14, R3, #8			;R14 is now start of list
LDMFD   R13!, {R2-R4, PC}





;Entry:
; R2 - disc address (sector aligned)
; R3 - buffer
; R4 - length to read
; R5 - OS_GBPB command to use (1=write 3=read)
; R7 - drive #
; R11 - pointer to Drive struct
; R12 - private area
;
;Exit:
; R0 - error if applicable
; R2 - updated disc address
; R3 - updated buffer address
; R4 - bytes remaining

.read_write
 TEQ     R4, #0
 MOVEQ   PC, R14
 STMFD   R13!, {R1, R10, R14}

 LDR     R0, [R11, #Drive.size]
 CMP     R2, R0					;is the address within the disc extent?
 MOVHS   R0, #HD_error_Bad_parameters
 BHS     _disc_error				;NO
 ADD     R10, R2, R4				;check the final address
 CMP     R10, R0
 SUBHI   R4, R0, R2				;YES, cap to end

 LDR     R1, [R11, #Drive.filehandle]
 MOV     R0, R4
 MOV     R4, R2					;address
 MOV     R2, R3					;buffer
 MOV     R3, R0					;size
 MOV     R0, R5
 SWI     XOS_GBPB
 MOV     R10, R3
 MOV     R3, R2					;R3=updated buffer address
 MOV     R2, R4					;R2=updated disc address
 MOV     R4, R10				;R4=bytes not transferred
 MOVVS   R0, #HD_error_Disc_error
 BVS     _disc_error
 MOV     R0, #0
LDMFD   R13!, {R1, R10, PC}

 ._disc_error					;PRM2-600
 CMP     R0, #&FF				;FileCore errors?
 ORRHI   R0, R0, #1<<30				;R0 is pointer to error block
 LDMHSFD R13!, {R1, R10, PC}			;YES, exit with error in R0

 LDR     R10, FS_Create_Block			;build error code into R0
 TST     R10, #New_Style_Errors			;is ADFS using new style errors?
 MOVEQ   R0, R0, LSL #24			;NO, error no
 ORREQ   R0, R0, #1<<31				; |  set error flag
 ORREQ   R0, R0, R2, LSR #8			; |  disc byte address/256
 ORREQ   R0, R0, R7, LSL #21			; |+ drive no
 STRNEB  R0, [R12, #VARS.new_style_error_block + 1]	; |   store error code
 STRNE   R3, [R12, #VARS.new_style_error_block + 4]	; |   disc address
 ADDNE   R0, R12, #VARS.new_style_error_block
 ORRNE   R0, R0, #1				; |+  set error flag
LDMFD   R13!, {R1, R10, PC}
