;[x] 18/12/2023. добавление/допиливание API CD-ROM (ATAPI)
;██████████████████████████████████████████████████████████████████████████
;CD ROM DRIVE DRIVER
;---------------------------------------------------------------
;Rev	Date	   Name	Description
;---------------------------------------------------------------
;	02-08-2001 DNS	Initial this module
;---------------------------------------------------------------
;========================================================

;!TODO ;!TODO ;!TODO ;!TODO ;!TODO ;!TODO ;!TODO ;!TODO ;!TODO ;!TODO ;!TODO ;!TODO 
;
;	[ ] установка параметра максимального размера для чтения через DRV_SET_PAR
;
;----------------------------------------------------------------------------------
MAX_ATAPI_SEC_SIZE			EQU	4096/2
PACKET_SIZE				EQU	12	; !FIXIT брать из IDENTIFY PACKET DEVICE
RAM_ATAPI_PK 				EQU	SYS_PAGE.SHARED_BUFFER_32b
RAM_ATAPI_RW_CMD			EQU	SYS_PAGE.SHARED_BUFFER_32b+16
MAX_DATA_PACKET_FOR_REQUEST_SENSE	EQU	254

	ASSERT ((PACKET_SIZE % 4) = 0), "PACKET_SIZE must be an even number"

;[]================================================================[#51]
;!FIXIT сделать настоящий ресет
CD_5x_RESET:	LD	C,IDE.Device.ATAPI
		CALL	SELECT_DRIVE
		RET	C
		LD	B,50
.loop:		PUSH	BC
		LD	HL,ATAPI_CMD_PACKET.NOP
		LD	DE,0	; маркер того, что не нужно читать с устройства в ОЗУ
		CALL	EXEC_PACKET_COMMAND
		;!FIXIT ;[ ] sector size. сделать реинит HDD_INIT_TABLE
		POP	BC
		RET	NC
		;
		CALL	CD_CHECK_MEDIA_CHANGED
		RET	C
		;
		EI 
		HALT 
		DJNZ  .loop
		RET 
;[]================================================================[#51]


;[]================================================================[#58]
;Function: Get Current Media Parameters
;	A - Disk
;Return:
;	H - Heads
;	L - Sectors per cylinder
;      DE - Cylinders
;      IX - Capacity sector in bytes
;	B - Flags: MASTER/SLAVE, LBA/CHS
; [ ]	A - HDD_INIT_TABLE.RemovableMedia
CD_5x_GETMED:	LD	C,IDE.Device.ATAPI
		CALL	SELECT_DRIVE
		RET	C
		;
		IN	A,(SLOT3)
		EX	AF,AF'
		 LD	A,SYS_PAGE
		 OUT	(SLOT3),A
		 ;
		 ; [ ] sector size. media changed
		  CALL	CD_CHECK_MEDIA_CHANGED
		  JR	NC,.get_data
		  ;
		;   CP	BIOS.Error.ATAPI.UnitAttention
		;   JR	NZ,.get_data
		  ;
		  LD	A,(IY + IDE.HDD_INIT_TABLE.RemovableMedia)
		  AND	%1111'1101
		  LD	(IY + IDE.HDD_INIT_TABLE.RemovableMedia),A
		  ;
.get_data:	 ;
		 ; LD	L,(IY+IDE.HDD_INIT_TABLE.SectorsPerTrack)
		 ; LD	H,(IY+IDE.HDD_INIT_TABLE.HeadsNumber)
		 ; LD	E,(IY+IDE.HDD_INIT_TABLE.CylinderNumberLow)
		 ; LD	D,(IY+IDE.HDD_INIT_TABLE.CylinderNumberHigh)
		 LD	A,(IY+IDE.HDD_INIT_TABLE.RemovableMedia)
		 LD	B,(IY+IDE.HDD_INIT_TABLE.DRV_Flags)
		 LD	L,(IY+IDE.HDD_INIT_TABLE.SectorSize)			;[ ] sector size
		 LD	H,(IY+IDE.HDD_INIT_TABLE.SectorSize + 1)		;[ ] sector size
		 EX	DE,HL
		 LD	XL,E
		 LD	XH,D
		 ;
		 LD	HL,0
		 LD	D,H
		 LD	E,H
		EX	AF,AF'
		OUT	(SLOT3),A
		EX	AF,AF
		RET 
;[]================================================================[#58]

;!TODO
; atapi.pdf стр. 24 запись/чтение могут быть максимальными блоками в несколько заходов
;[]================================================================[#55]
;Function: Read	Sectors
;	A - Disk
;   HL:IX - Sector
;      DE - Address
;	B - Sector counter
;Return:
;   HL:IX - Sector + Sector counter
;      DE - Address + (Sector counter *	Size sector)
;READ SECTOR(S)
CD_5x_READ:
	EX	AF,AF'
	 IN	A,(SLOT3)
	EX	AF,AF'
;[]================================================================[#52]
;Function: Long	Read Sectors
;	A - Disk
;   HL:IX - Sector
;      DE - Address
;	B - Sector counter
;	A'- Memory Page Number
;Return:
;   HL:IX - Sector + Sector counter
;      DE - Address + (Sector counter *	Size sector)
;LONG READ SECTOR(S)
CD_5x_LONG_READ:
		AND	A
		;
		PUSH	IY
		SAFE_PORTY_2
		PUSH	BC
		PUSH	IX
		PUSH	HL
		;
		 EX	AF,AF'
		  AND	A	;read
		 EX	AF,AF'
		CALL	RW_ATAPI_SECTORs
		; [ ] sector size. media changed
		 JP	HDD_5x_LONG_READ.shared
		;  JP	NC,HDD_5x_LONG_READ.shared
		;  CP	BIOS.Error.UnitAttention
		;  JR	Z,CD_MEDIA_CHANGED_ERROR
		;  SCF
;[]================================================================[#52]
; INPUT:
;	A - Disk
;   HL:IX - Sector
;      DE - Address
;	B - Sector counter
;	A'- Memory Page Number
;	CF'=1 - write, CF'=0 - read
;
; OUTPUT:
;	
RW_ATAPI_SECTORs:
		LD	C,IDE.Device.ATAPI
		CALL	SELECT_DRIVE
		RET	C
		;
		EXX
		 LD	C,SLOT3
		 IN	B,(C)
		 PUSH	BC
		 LD	A,SYS_PAGE
		 OUT	(C),A
		 ; [ ] media change
		  LD	A,(IY + IDE.HDD_INIT_TABLE.RemovableMedia)
		  AND	%0000'0010
		  JR	NZ,.error_media
		 ;
		 LD	HL,ATAPI_CMD_PACKET.READ
		 EX	AF,AF'
		  JR	NC,.read_cmd
		  LD	HL,ATAPI_CMD_PACKET.WRITE
.read_cmd:	 EX	AF,AF'	 
		 LD	DE,RAM_ATAPI_RW_CMD
		 LD	BC,PACKET_SIZE
		 LDIR
		EXX
		;
		LD	A,H
		LD	H,L
		LD	L,A
		LD	(RAM_ATAPI_RW_CMD + ATAPI_PACKET.SECTOR+0),HL
		LD	A,XH
		LD	(RAM_ATAPI_RW_CMD + ATAPI_PACKET.SECTOR+2),A	;R01
		LD	A,XL
		LD	(RAM_ATAPI_RW_CMD + ATAPI_PACKET.SECTOR+3),A	;R01
		LD	A,B
		LD	(RAM_ATAPI_RW_CMD + ATAPI_PACKET.COUNTER+1),A	;R01
		;
		; EX	AF,AF'
		; OUT	(SLOT3),A
		;
		; POP	AF
		; OUT	(SLOT3),A
		LD	HL,RAM_ATAPI_RW_CMD
		CALL	EXEC_PACKET_COMMAND
		;
.exit:		POP	BC
		;LD	C,SLOT3
		OUT	(C),B
		RET
		;
.error_media:	EXX
		LD	A,BIOS.Error.ATAPI.UnitAttention
		SCF
		JR	.exit

;[]===========================================================[#52, #55]

;[]================================================================[#56]
;Function: Write Sectors
;	A - Disk
;   HL:IX - Sector
;      DE - Address
;	B - Sector counter
;Return:
;   HL:IX - Sector + Sector counter
;      DE - Address + (Sector counter *	Size sector)
;WRITE SECTOR(S)
CD_5x_WRITE:
	EX	AF,AF'
	 IN	A,(SLOT3)
	EX	AF,AF'
;[]================================================================[#53]
;Function: Long	Write Sectors
;	A - Disk
;   HL:IX - Sector
;      DE - Address
;	B - Sector counter
;	A'- Memory Page Number
;Return:
;   HL:IX - Sector + Sector counter
;      DE - Address + (Sector counter *	Size sector)
;WRITE SECTOR(S)
CD_5x_LONG_WRITE:
		AND	A
		;
		PUSH	IY
		SAFE_PORTY_2
		PUSH	BC
		PUSH	IX
		PUSH	HL
		;
		 EX	AF,AF'
		  SCF		;write
		 EX	AF,AF'
		 CALL	RW_ATAPI_SECTORs
		;
		JP	HDD_5x_LONG_READ.shared

;[]================================================================[#57]
;Function: Detect Disk
;	   A - Disk
;Return:   CF=0 - A=Drive type 
;	   CF=1 - drive not present, A=#02
CD_5x_DETECT:	LD	C,IDE.Device.ATAPI
		AND	%1011'1111
		CALL	DRV_DETECT
		RET	C
		;
		PUSH	AF
		LD	BC,SLOT3
		IN	B,(C)
		LD	A,SYS_PAGE
		OUT	(C),A
		INC	HL			;!HARDCODE HDD_INIT_TABLE
		INC	HL
		INC	HL
		LD	A,(HL)
		OUT	(C),B
		AND	%0000'0010
		JR	Z,.exit
		;
		POP	AF
		LD	A,BIOS.Error.ATAPI.UnitAttention
		SCF
		RET
		;
.exit:		POP	AF
		RET

;[]================================================================[#57]


;[]================================================================[#5E]
; [ ]
;Function: Extended
;	   A - Disk
;	   B - SubFunction
;Return:   
;	   
CD_5x_Extended:
	LD	C,IDE.Device.ATAPI
	CALL	SELECT_DRIVE
	RET	C
	;
	LD	A,B
	CP	2
	JR	C,TRAY_FN		; B = 0 или 1
	;
	JR	Z,CD_REQUEST_SENSE	; B = 2
	; ...
	; ...
	;LD	A,#AA
	LD	A,BIOS.Error.InvalidSubFunction
	SCF
	RET
;[]================================================================[#5E]

;----------------------------------------------------------------------;!TODO сделать доступной через расширенную функцию API
; вход:	DE - адрес для данных
CD_REQUEST_SENSE:
		LD	HL,ATAPI_CMD_PACKET.REQUEST_SENSE
		JR	EXEC_PACKET_COMMAND
;----------------------------------------------------------------------;

;[ ] media changed
;----------------------------------------------------------------------;
CD_CHECK_MEDIA_CHANGED:
		EXX
		 LD	DE,256*(IDE.CtrlByte.Error) + 0
		 CALL	CD_WAITPRT.Custom
		EXX
		;RET	NC
		JR	C,.noWait
		;
		EXX
		 LD	BC,SLOT3
		 IN	B,(C)
		 LD	A,SYS_PAGE
		 OUT	(C),A
		 ;
		 LD	A,(IY + IDE.HDD_INIT_TABLE.RemovableMedia)
		 OUT	(C),B
		EXX
		RRA
		RRA
		LD	A,BIOS.Error.ATAPI.UnitAttention
		RET
		;
.noWait:	EXX
		 CALL	CD_GET_ERROR
		 OR	#70
		EXX
		CP	BIOS.Error.ATAPI.NoSence
		JP	Z,CD_MEDIA_CHANGED_ERROR
		;SCF
		RET
;----------------------------------------------------------------------;

;----------------------------------------------------------------------;
TRAY_FN:	LD	HL,ATAPI_CMD_PACKET.CLOSE
		LD	DE,0	; маркер того, что не нужно читать с устройства в ОЗУ
		DEC	A
		JR	Z,EXEC_PACKET_COMMAND
		LD	HL,ATAPI_CMD_PACKET.OPEN
		;JR	EXEC_PACKET_COMMAND
		
; INPUT:  HL - AP packet (12bytes)
;	  DE - address for/with data if needed
;
; RETURN: CF - ERROR
;	!TODO CD ERRORS to INCLUDES
;	 #01 - RECOVERED ERROR
;	 #02 - NOT READY
;	 #03 - MEDIUM ERROR
;	 #04 - HARDWARE	ERROR
;	 #05 - ILLEGAL REQUEST
;	 #06 - UNIT ATTETION
;	 #07 - DATA PROTECT
;	 #0B - ABORTED COMMAND
;	 #80 - TIME OUT
EXEC_PACKET_COMMAND:
		EXX 
		 CALL	CD_WAITPRT
		EXX 
		JR	NC,.READY
		;
		; [ ] media changed
		;  CP	+(BIOS.Error.UnitAttention & #0F)
		;  JR	NZ,.reset
		;  ;
		;  CALL	CD_MEDIA_CHANGED_ERROR
		;  OR	#70	; error prefix for ATAPI in BIOS
		;  SCF
		;  RET
		;
.reset:		LD	BC,IDE.Write.Command
		LD	A,IDE.ATAPI.Reset
		OUT	(C),A
		;
		LD	B,#80
.pause:		DJNZ	.pause
		;
		EXX 
		 CALL	CD_WAITPRT
		EXX
		JR	C,.error
		;JR	C,CD_CHECK_MEDIA_CHANGED.noWait
		;
.READY:		LD	C,SLOT3
		IN	B,(C)
		PUSH	DE
		PUSH	BC
		;
		LD	A,SYS_PAGE
		OUT	(C),A
		LD	DE,RAM_ATAPI_PK	;!FIXIT может на стеке выделять место?
		LD	BC,PACKET_SIZE
		LDIR
		;
		POP	BC
		POP	DE
		OUT	(C),B
		;
		XOR	A
		EXX
		 ;OUT	(C),A
		 ;XOR	A
		 LD	BC,IDE.Write.Features
		 OUT	(C),A
		 LD	DE,MAX_ATAPI_SEC_SIZE	;SIZE BLOCK	;!HARDCODE доставать из переменной какой-нибудь
		 LD	BC,IDE.Write.ByteCountLow
		 OUT	(C),E
		 LD	BC,IDE.Write.ByteCountHigh
		 OUT	(C),D
		 LD	BC,IDE.Write.Command
		 LD	A,IDE.ATAPI.Packet
		 OUT	(C),A
		 CALL	CD_WAITPRT
		EXX 
		JR	C,.error
		;JR	C,CD_CHECK_MEDIA_CHANGED.noWait
		;
		EXX 
		 LD	DE,256*(IDE.CtrlByte.DataRequest+IDE.CtrlByte.Error)+IDE.CtrlByte.DataRequest
		 CALL	CD_WAITPRT.Custom
		EXX 
		JR	NC,.YEP_DRQ
		;
		CP	#FF
		JR	Z,.error_fail
		;
		RRA					;AND IDE.CtrlByte.Error
		JR	C,CD_CHECK_MEDIA_CHANGED.noWait
		;
		LD	A,BIOS.Error.ATAPI.TimeOut
		RET
		;
.error:		CP	#FF
		SCF
.error_fail:	LD	A,BIOS.Error.Failure
		RET	Z
		LD	A,BIOS.Error.Busy
		RET
; .CMD_ERROR:	 CALL	CD_GET_ERROR
; 		 OR	#70
; 		 CP	BIOS.Error.UnitAttention
; 		 CALL	Z,CD_MEDIA_CHANGED_ERROR
; 		 ;LD	BC,IDE.Read.Error	;ERROR
; 		 ;IN	A,(C)
; 		 ;RRCA 
; 		 ;RRCA 
; 		 ;RRCA 
; 		 ;RRCA 
; 		 ;AND	#0F
; 		;!FIXIT ; [ ] sector size. make REQUEST SENSE if A=6
; 		SCF 
; 		RET
		; EXEC ATAPI PACKET COMMAND
.YEP_DRQ:	LD	C,SLOT3
		IN	B,(C)
		PUSH	BC
		LD	A,SYS_PAGE
		OUT	(SLOT3),A
		LD	HL,RAM_ATAPI_PK
		LD	BC,IDE.Write.Data
		LD	A,PACKET_SIZE/4	; !FIXIT брать из IDENTIFY PACKET DEVICE
.OUTPKT:	OUTI 
		OUTI
		OUTI
		OUTI
		DEC	A
		JR	NZ,.OUTPKT
		;
		POP	BC
		OUT	(C),B
		;
		LD	B,#80
.pause2: 	DJNZ	.pause2
		;
		EX	AF,AF'
		 LD	XH,A	; страница для R/W_LONG
		 LD	XL,0
		EX	AF,AF'
		;
		EX	DE,HL
.AP_LOOP:	EX	DE,HL
		IN	A,(SLOT3)
		EX	AF,AF'		;>-----------> \
		;
		EXX 
		 CALL	CD_WAITPRT
		EXX 
		JR	C,.error
		;
		LD	BC,IDE.Read.Status
		IN	A,(C)
		BIT	IDE.CtrlBit.Error,A
		JP	NZ,CD_CHECK_MEDIA_CHANGED.noWait
		;
		AND	IDE.CtrlByte.DataRequest
		RET	Z ;NO DATA REQUEST. A = 0: BIOS.Error.NoErrors
		;
		LD	A,XH
		OUT	(SLOT3),A
	;
	;====== IF DATA REQUEST =======================================;
	;
		EX	DE,HL
		LD	BC,IDE.Read.ByteCountLow
		IN	E,(C)
		LD	BC,IDE.Read.ByteCountHigh
		IN	D,(C)	;TRANSFER BLOCK	SIZE
		LD	A,D
		OR	E
		RET	Z	;BLOCK = 0
		;
		LD	BC,IDE.Read.InterruptReason
		IN	A,(C)
		AND	IDE.InterruptReasonByte.IO
		LD	BC,IDE.Read.Data
		JR	Z,.WRITE_DATA
		;
	;READ
.read_loop:	INI 
		INI 
		DEC	DE
		DEC	DE
		LD	A,D
		OR	E
		JR	NZ,.read_loop
		;
.return_rw:	INC	XL		;INC LOADED SECTORS
		EX	AF,AF'		;<-----------< /
		OUT	(SLOT3),A
		;
		LD	A,H
		OR	L
		JR	NZ,.AP_LOOP
		; next page in mem block
		LD	HL,#C000
		IN	A,(SLOT3)
		EX	AF,AF'		;>-----------> \
		 LD	A,SYS_PAGE
		 OUT	(SLOT3),A
		 LD	D,high SYS_PAGE.RAM_TABLE
		 LD	E,XH
		 LD	A,(DE)
		 LD	XH,A
		EX	AF,AF'		;<-----------< /
		OUT	(SLOT3),A
		JR	.AP_LOOP
	;	;
	;WRITE
.WRITE_DATA:	INC	B ; LD	BC,IDE.Write.Data
.write_loop:	OUTI 
		OUTI 
		DEC	DE
		DEC	DE
		LD	A,D
		OR	E
		JR	NZ,.write_loop
		JR	.return_rw

;.NULL:		LD	BC,IDE.Read.Data
;.RD_N_CD:	IN	A,(C)
; 		DEC	B
; 		IN	A,(C)
; 		DEC	B
; 		DEC	DE
; 		DEC	DE
; 		LD	A,D
; 		OR	E
; 		JR	NZ,.RD_N_CD
; 		; DE = 0
; 		JR	.AP_LOOP
;----------------------------------------------------------------------;


;----------------------------------------------------------------------;
CD_GET_ERROR:	LD	BC,IDE.Read.Error	;ERROR
		IN	A,(C)
		RRCA 
		RRCA 
		RRCA 
		RRCA 
		AND	#0F
		RET
;----------------------------------------------------------------------;



;----------------------------------------------------------------------;
; D - MASK, E - PATTERN
CD_WAITPRT:	LD	DE,256*IDE.CtrlByte.Busy + 0
.Custom:	LD	B,100
		LD	HL,#0000
.LOOP:		LD	A,high IDE.Read.Status
		IN	A,(low IDE.Read.Status)
		CP	#FF
		JR	Z,.error
		AND	D
		CP	E
		;
		RET	Z
		;
.NEXT_TRY:	DEC	L
		JR	NZ,.LOOP
		DEC	H
		JR	NZ,.LOOP
		DJNZ	.LOOP
.error:		SCF 
		RET
;----------------------------------------------------------------------;


;----------------------------------------------------------------------;
; CD_TEST:	LD	HL,ATAPI_CMD_PACKET.NOP
; 		LD	DE,0	; маркер того, что не нужно читать с устройства в ОЗУ
; 		JP	EXEC_PACKET_COMMAND
;----------------------------------------------------------------------;


;----------------------------------------------------------------------;
CD_MEDIA_CHANGED_ERROR:
		IN	A,(SLOT3)
		PUSH	AF
		LD	A,SYS_PAGE
		OUT	(SLOT3),A
		;
		LD	DE,SYS_PAGE.SHARED_BUFFER_256b
		CALL	CD_REQUEST_SENSE
		;
		LD	A,(SYS_PAGE.SHARED_BUFFER_256b + 2)		; SenceKey. 06
		CP	6
		JR	NZ,.exit
		;
		LD	A,(SYS_PAGE.SHARED_BUFFER_256b + 12)		; AdditionalSenceKey. #28
		CP	#28		
		JR	NZ,.exit
		;
		LD	A,(SYS_PAGE.SHARED_BUFFER_256b + 13)		; AdditionalSenseCodeQualifier. 0
		AND	A
		JR	NZ,.exit
		;
		LD	A,(IY + IDE.HDD_INIT_TABLE.RemovableMedia)
		OR	%0000'0011
		LD	(IY + IDE.HDD_INIT_TABLE.RemovableMedia),A
		;
		LD	HL,ATAPI_CMD_PACKET.READ_CAPACITY_DATA
		LD	DE,SYS_PAGE.TMP_BUFFER
		CALL	EXEC_PACKET_COMMAND
		LD	HL,#FFFF
		JR	C,.No_Media
		;
		LD	HL,(SYS_PAGE.TMP_BUFFER + 6)	; sector size (high byte, low byte)
		;
.No_Media:	LD	(IY+IDE.HDD_INIT_TABLE.SectorSize),H			;[ ] sector size
		LD	(IY+IDE.HDD_INIT_TABLE.SectorSize + 1),L		
		;
		POP	AF
		OUT	(SLOT3),A
		LD	A,BIOS.Error.ATAPI.UnitAttention
		SCF
		RET
		;
.exit:		POP	AF
		OUT	(SLOT3),A
		; CF=0
		;AND	A
		RET
;----------------------------------------------------------------------;



////////////////////////////////////////////////////////////////////////
ATAPI_CMD_PACKET:
.NOP:	DUP	12
	 DB	#00
	EDUP
;
.OPEN:	DB	#1B
	DB	#00,#00,#00
	DB	#02
	DB	#00,#00,#00,#00,#00,#00,#00
;
.CLOSE:	DB	#1B
	DB	#00,#00,#00
	DB	#03
	DB	#00,#00,#00,#00,#00,#00,#00
;
.READ:	DB	#28,#00
	DB	#00,#00,#00,#00	; sector dword
	DB	#00
	DB	#00,#01,#00,#00	; counter dword
	DB	#00
;
.WRITE:	DB	#2E,#00
	DB	#00,#00,#00,#00	; sector dword
	DB	#00
	DB	#00,#01,#00,#00	; counter dword
	DB	#00
;
.READ_CAPACITY_DATA:
	DB	#25
	BLOCK	11,0
;
.REQUEST_SENSE:
	DB	#03
	DB	#00,#00,#00
	DB	MAX_DATA_PACKET_FOR_REQUEST_SENSE
	DB	#00,#00,#00,#00,#00,#00,#00
;

ATAPI_PACKET:
.SECTOR		EQU	2
.COUNTER	EQU	7
////////////////////////////////////////////////////////////////////////
;
; E - Second * 10
; PAUSE	LD	HL,#0000
; PAUSE1	DEC	L
; 	JR	NZ,PAUSE1
; 	DEC	H
; 	JR	NZ,PAUSE1
; 	DEC	E
; 	JR	NZ,PAUSE1
; 	RET 
;
/*
Если ловится ошибка media changed, то биос должен выставлять в HDD_INIT_TABLE.RemovableMedia = 3
и затирать FF SectorSize.
Дос после получения такой ошибки должен вызывать BIOS.DRV_DETECT и если всё ОК, то ReScanDRV
*/