; ****************************************************************************
; TRDOS386.ASM (TRDOS 386 Kernel - v2.0.0) - MAIN PROGRAM : trdosk8.s
; ----------------------------------------------------------------------------
; Last Update: 24/01/2016
; ----------------------------------------------------------------------------
; Beginning: 24/01/2016
; ----------------------------------------------------------------------------
; Assembler: NASM version 2.11 (trdos386.s)
; ----------------------------------------------------------------------------
; Derived from TRDOS Operating System v1.0 (8086) source code by Erdogan Tan
; XXXXXXXX.ASM (XX/XX/2011)
;
; Derived from 'Retro UNIX 386 Kernel - v0.2.1.0' source code by Erdogan Tan
; u0.s (20/11/2015)
; ****************************************************************************

INT4Ah:
	; 24/01/2016
	; this procedure will be called by 'RTC_INT' (in 'timer.s')
	retn

; u0.s
; Retro UNIX 386 v1 Kernel (v0.2) - SYS0.INC
; Last Modification: 20/11/2015

com2_int:
	; 07/11/2015 
	; 24/10/2015
	; 23/10/2015
	; 14/03/2015 (Retro UNIX 386 v1 - Beginning)
	; 28/07/2014 (Retro UNIX 8086 v1)
	; < serial port 2 interrupt handler >
	;
	mov 	[esp], eax ; overwrite call return address
	;push	eax
	mov	ax, 9
	jmp	short comm_int
com1_int:
	; 07/11/2015
	; 24/10/2015
	mov 	[esp], eax ; overwrite call return address
	; 23/10/2015
	;push	eax
	mov	ax, 8
comm_int:
	; 20/11/2015
	; 18/11/2015
	; 17/11/2015
	; 16/11/2015
	; 09/11/2015
	; 08/11/2015
	; 07/11/2015
	; 06/11/2015 (serial4.asm, 'serial')	
	; 01/11/2015
	; 26/10/2015
	; 23/10/2015
	push	ebx
	push	esi
	push	edi
	push 	ds
	push 	es
	; 18/11/2015
	mov	ebx, cr3
	push	ebx ; ****
	;
	push	ecx ; ***
	push	edx ; **
	;
	mov	ebx, KDATA
	mov	ds, bx
	mov	es, bx
	;
	mov	ecx, [k_page_dir]
	mov	cr3, ecx
	; 20/11/2015
	; Interrupt identification register
	mov	dx, 2FAh ; COM2
	;
	cmp 	al, 8 
	ja 	short com_i0
	;
	; 20/11/2015
	; 17/11/2015
	; 16/11/2015
	; 15/11/2015
	; 24/10/2015
	; 14/03/2015 (Retro UNIX 386 v1 - Beginning)
	; 28/07/2014 (Retro UNIX 8086 v1)
	; < serial port 1 interrupt handler >
	;
	inc	dh ; 3FAh ; COM1 Interrupt id. register
com_i0:
	;push	eax ; *
	; 07/11/2015
	mov 	byte [ccomport], al
	; 09/11/2015
	movzx	ebx, ax ; 8 or 9
	; 17/11/2015
 	; reset request for response status
	mov	[ebx+req_resp-8], ah ; 0
	;
	; 20/11/2015
	in	al, dx		; read interrupt id. register
	JMP	$+2	   	; I/O DELAY
	and	al, 4		; received data available?	
	jz	short com_eoi	; (transmit. holding reg. empty)
	;
	; 20/11/2015
	sub	dl, 3FAh-3F8h	; data register (3F8h, 2F8h)
	in	al, dx     	; read character
	;JMP	$+2	   	; I/O DELAY
	; 08/11/2015
	; 07/11/2015
	mov	esi, ebx 
	mov	edi, ebx
	add 	esi, rchar - 8 ; points to last received char
	add	edi, schar - 8 ; points to last sent char
	mov	[esi], al ; received char (current char)
	; query
	and	al, al
	jnz	short com_i2
   	; response
	; 17/11/2015
	; set request for response status
        inc     byte [ebx+req_resp-8] ; 1 
	;
	add	dx, 3FDh-3F8h	; (3FDh, 2FDh)
	in	al, dx	   	; read line status register 
	JMP	$+2	   	; I/O DELAY
	and	al, 20h	   	; transmitter holding reg. empty?
	jz	short com_eoi 	; no
	mov 	al, 0FFh   	; response			
	sub	dx, 3FDh-3F8h 	; data port (3F8h, 2F8h)
	out	dx, al	   	; send on serial port
	; 17/11/2015
	cmp 	byte [edi], 0   ; query ? (schar)
	jne 	short com_i1    ; no
	mov	[edi], al 	; 0FFh (responded)
com_i1:
	; 17/11/2015
	; reset request for response status (again)
        dec     byte [ebx+req_resp-8] ; 0 
	jmp	short com_eoi
com_i2:	
	; 08/11/2015
	cmp 	al, 0FFh	; (response ?)
	je	short com_i3	; (check for response signal)
	; 07/11/2015
	cmp	al, 04h	; EOT
	jne	short com_i4	
	; EOT = 04h (End of Transmit) - 'CTRL + D'
	;(an EOT char is supposed as a ctrl+brk from the terminal)
	; 08/11/2015
		; ptty -> tty 0 to 7 (pseudo screens)
	xchg	bl, [ptty]  ; tty number (8 or 9)
	call 	ctrlbrk
	xchg	[ptty], bl ; (restore ptty value and BL value)
	;mov	al, 04h ; EOT
	; 08/11/2015
	jmp	short com_i4	
com_i3:
	; 08/11/2015
	; If 0FFh has been received just after a query
	; (schar, ZERO), it is a response signal.
	; 17/11/2015
        cmp     byte [edi], 0 ; query ? (schar)
	ja	short com_i4 ; no
	; reset query status (schar)
	mov	[edi], al ; 0FFh
	inc	al ; 0
com_i4:
	; 27/07/2014
	; 09/07/2014
	shl	bl, 1	
	add	ebx, ttychr
	; 23/07/2014 (always overwrite)
	;;cmp	word [ebx], 0
	;;ja	short com_eoi
	;
	mov	[ebx], ax   ; Save ascii code
			    ; scan code = 0
com_eoi:
	;mov	al, 20h
	;out	20h, al	   ; end of interrupt
	;
	; 07/11/2015
      	;pop	eax ; *
	mov	al, byte [ccomport] ; current COM port
	 ; al = tty number (8 or 9)
        call	wakeup
com_iret:
	; 23/10/2015
	pop	edx ; **
	pop	ecx ; ***
	; 18/11/2015
	;pop	eax ; ****
	;mov	cr3, eax
	;jmp	iiret
	jmp	iiretp

;iiretp: ; 01/09/2015
;	; 28/08/2015
;	pop	eax ; (*) page directory
;	mov	cr3, eax
;iiret:
;	; 22/08/2014
;	mov	al, 20h ; END OF INTERRUPT COMMAND TO 8259
;	out	20h, al	; 8259 PORT
;	;
;	pop	es
;	pop	ds
;	pop	edi
;	pop	esi
;	pop	ebx ; 29/08/2014
;	pop 	eax
;	iretd

sp_init:
	; 07/11/2015
	; 29/10/2015
	; 26/10/2015
	; 23/10/2015
	; 29/06/2015
	; 14/03/2015 (Retro UNIX 386 v1 - 115200 baud)
	; 28/07/2014 (Retro UNIX 8086 v1 - 9600 baud)
	; Initialization of Serial Port Communication Parameters
	; (COM1 base port address = 3F8h, COM1 Interrupt = IRQ 4)
	; (COM2 base port address = 2F8h, COM1 Interrupt = IRQ 3)
	;
	; ((Modified registers: EAX, ECX, EDX, EBX))
	;
	; INPUT:  (29/06/2015)
	;	AL = 0 for COM1
	;	     1 for COM2
	;	AH = Communication parameters	
	;
	;  (*) Communication parameters (except BAUD RATE):
	;	Bit	4	3	2	1	0
	;		-PARITY--   STOP BIT  -WORD LENGTH-	 		 
	;  this one -->	00 = none    0 = 1 bit  11 = 8 bits
	;		01 = odd     1 = 2 bits	10 = 7 bits
	;		11 = even
	;  Baud rate setting bits: (29/06/2015)
	;		Retro UNIX 386 v1 feature only !
	;	Bit	7    6    5  | Baud rate
	;		------------------------
	;	value	0    0    0  | Default (Divisor = 1)
	;		0    0    1  | 9600 (12)
	;		0    1    0  | 19200 (6) 
	;		0    1	  1  | 38400 (3) 
	;		1    0	  0  | 14400 (8)
	;		1    0	  1  | 28800 (4)
	;		1    1    0  | 57600 (2)
	;		1    1    1  | 115200 (1) 	
	
	; References:	
	; (1) IBM PC-XT Model 286 BIOS Source Code
	;     RS232.ASM --- 10/06/1985 COMMUNICATIONS BIOS (RS232)
	; (2) Award BIOS 1999 - ATORGS.ASM
	; (3) http://wiki.osdev.org/Serial_Ports
	;
	; Set communication parameters for COM1 (= 03h)	
	;
	mov	ebx, com1p		; COM1 parameters  
	mov	dx, 3F8h		; COM1
	 ; 29/10/2015
	mov	cx, 301h  ; divisor = 1 (115200 baud)
	call	sp_i3	; call A4	
	test	al, 80h
	jz	short sp_i0 ; OK..
		; Error !
	;mov	dx, 3F8h
	sub	dl, 5 ; 3FDh -> 3F8h
	mov	cx, 30Eh  ; divisor = 12 (9600 baud)
	call	sp_i3	; call A4	
	test	al, 80h
	jnz	short sp_i1
sp_i0:
        ; (Note: Serial port interrupts will be disabled here...)	
        ; (INT 14h initialization code disables interrupts.)
	;
	mov	byte [ebx], 0E3h ; 11100011b
	call	sp_i5 ; 29/06/2015
sp_i1:
	inc	ebx
	mov	dx, 2F8h		; COM2
	 ; 29/10/2015
	mov	cx, 301h  ; divisor = 1 (115200 baud)
	call	sp_i3	; call A4	
	test	al, 80h
	jz	short sp_i2 ; OK..
		; Error !
	;mov	dx, 2F8h
	sub	dl, 5 ; 2FDh -> 2F8h
	mov	cx, 30Eh  ; divisor = 12 (9600 baud)
	call	sp_i3	; call A4	
	test	al, 80h
	jnz	short sp_i7
sp_i2:
	mov	byte [ebx], 0E3h ; 11100011b
sp_i6:
	;; COM2 - enabling IRQ 3
	; 07/11/2015
	; 26/10/2015
	pushf
	cli
	;
	mov	dx, 2FCh   		; modem control register
	in	al, dx 	   		; read register
	JMP	$+2	   		; I/O DELAY
	or	al, 8      		; enable bit 3 (OUT2)
	out	dx, al     		; write back to register
	JMP	$+2	   		; I/O DELAY
	mov	dx, 2F9h   		; interrupt enable register
	in	al, dx     		; read register
	JMP	$+2	   		; I/O DELAY
	;or	al, 1      		; receiver data interrupt enable and
	or	al, 3	   		; transmitter empty interrupt enable
	out	dx, al 	   		; write back to register
	JMP	$+2        		; I/O DELAY
	in	al, 21h    		; read interrupt mask register
	JMP	$+2	   		; I/O DELAY
	and	al, 0F7h   		; enable IRQ 3 (COM2)
	out	21h, al    		; write back to register
	;
	; 23/10/2015
	mov 	eax, com2_int
	mov	[com2_irq3], eax
	; 26/10/2015
	popf	
sp_i7:
	retn

sp_i3:
;A4:  	;-----	INITIALIZE THE COMMUNICATIONS PORT
	; 28/10/2015
	inc	dl	; 3F9h (2F9h)	; 3F9h, COM1 Interrupt enable register 
	mov	al, 0
	out	dx, al			; disable serial port interrupt
	JMP	$+2			; I/O DELAY
	add	dl, 2 	; 3FBh (2FBh)	; COM1 Line control register (3FBh)
	mov	al, 80h			
	out	dx, al			; SET DLAB=1 ; divisor latch access bit
	;-----	SET BAUD RATE DIVISOR
	; 26/10/2015
	sub 	dl, 3   ; 3F8h (2F8h)	; register for least significant byte
					; of the divisor value
	mov	al, cl	; 1
	out	dx, al			; 1 = 115200 baud (Retro UNIX 386 v1)
					; 2 = 57600 baud
					; 3 = 38400 baud
					; 6 = 19200 baud
					; 12 = 9600 baud (Retro UNIX 8086 v1)
	JMP	$+2			; I/O DELAY
	sub	al, al
	inc	dl      ; 3F9h (2F9h)	; register for most significant byte
					; of the divisor value
	out	dx, al ; 0
	JMP	$+2			; I/O DELAY
	;	
	mov	al, ch ; 3		; 8 data bits, 1 stop bit, no parity
	;and	al, 1Fh ; Bits 0,1,2,3,4	
	add	dl, 2	; 3FBh (2FBh)	; Line control register
	out	dx, al			
	JMP	$+2			; I/O DELAY
	; 29/10/2015
	dec 	dl 	; 3FAh (2FAh)	; FIFO Control register (16550/16750)
	xor	al, al			; 0
	out	dx, al			; Disable FIFOs (reset to 8250 mode)
	JMP	$+2	
sp_i4:
;A18:	;-----	COMM PORT STATUS ROUTINE
	; 29/06/2015 (line status after modem status)
	add	dl, 4	; 3FEh (2FEh)	; Modem status register
sp_i4s:
	in	al, dx			; GET MODEM CONTROL STATUS
	JMP	$+2			; I/O DELAY
	mov	ah, al			; PUT IN (AH) FOR RETURN
	dec	dl	; 3FDh (2FDh)	; POINT TO LINE STATUS REGISTER
					; dx = 3FDh for COM1, 2FDh for COM2
	in	al, dx			; GET LINE CONTROL STATUS
	; AL = Line status, AH = Modem status
	retn

sp_status:
	; 29/06/2015
	; 27/06/2015 (Retro UNIX 386 v1)
	; Get serial port status
	mov	dx, 3FEh		; Modem status register (COM1)
	sub	dh, al			; dh = 2 for COM2 (al = 1)
					; dx = 2FEh for COM2
	jmp	short sp_i4s

sp_setp: ; Set serial port communication parameters
	; 07/11/2015
	; 29/10/2015
	; 29/06/2015
	; Retro UNIX 386 v1 feature only !	
	;
	; INPUT:
	;	AL = 0 for COM1
	;	     1 for COM2
	;	AH = Communication parameters (*)
	; OUTPUT:
	;	CL = Line status
	;	CH = Modem status
	;   If cf = 1 -> Error code in [u.error]
	;		 'invalid parameter !' 
	;		 	 or
	;		 'device not ready !' error
	;	
	;  (*) Communication parameters (except BAUD RATE):
	;	Bit	4	3	2	1	0
	;		-PARITY--   STOP BIT  -WORD LENGTH-	 		 
	;  this one -->	00 = none    0 = 1 bit  11 = 8 bits
	;		01 = odd     1 = 2 bits	10 = 7 bits
	;		11 = even
	;  Baud rate setting bits: (29/06/2015)
	;		Retro UNIX 386 v1 feature only !
	;	Bit	7    6    5  | Baud rate
	;		------------------------
	;	value	0    0    0  | Default (Divisor = 1)
	;		0    0    1  | 9600 (12)
	;		0    1    0  | 19200 (6) 
	;		0    1	  1  | 38400 (3) 
	;		1    0	  0  | 14400 (8)
	;		1    0	  1  | 28800 (4)
	;		1    1    0  | 57600 (2)
	;		1    1    1  | 115200 (1) 
	;
	; (COM1 base port address = 3F8h, COM1 Interrupt = IRQ 4)
	; (COM2 base port address = 2F8h, COM1 Interrupt = IRQ 3)
	;
	; ((Modified registers: EAX, ECX, EDX, EBX))
	;
	mov	dx, 3F8h
	mov	ebx, com1p ; COM1 control byte offset
	cmp	al, 1
	ja 	short sp_invp_err
	jb	short sp_setp1 ;  COM1 (AL = 0)
	dec	dh ; 2F8h
	inc	ebx ; COM2 control byte offset
sp_setp1:
	; 29/10/2015
	mov	[ebx], ah
	movzx 	ecx, ah
	shr	cl, 5 ; -> baud rate index
	and	ah, 1Fh ; communication parameters except baud rate
	mov	al, [ecx+b_div_tbl]
	mov	cx, ax
	call	sp_i3
	mov	cx, ax ; CL = Line status, CH = Modem status
	test	al, 80h
	jz	short sp_setp2
        mov     byte [ebx], 0E3h ; Reset to initial value (11100011b)
stp_dnr_err:
	mov	dword [u.error], ERR_DEV_NOT_RDY ; 'device not ready !'
	; CL = Line status, CH = Modem status
	stc
	retn
sp_setp2:
	cmp	dh, 2 ; COM2 (2F?h)
        jna     sp_i6 
		      ; COM1 (3F?h)
sp_i5: 
	; 07/11/2015
	; 26/10/2015
	; 29/06/2015
	;
	;; COM1 - enabling IRQ 4
	pushf
	cli
	mov	dx, 3FCh   		; modem control register
	in	al, dx 	   		; read register
	JMP	$+2			; I/O DELAY
	or	al, 8      		; enable bit 3 (OUT2)
	out	dx, al     		; write back to register
	JMP	$+2			; I/O DELAY
	mov	dx, 3F9h   		; interrupt enable register
	in	al, dx     		; read register
	JMP	$+2			; I/O DELAY
	;or	al, 1      		; receiver data interrupt enable and
	or	al, 3	   		; transmitter empty interrupt enable
	out	dx, al 	   		; write back to register
	JMP	$+2        		; I/O DELAY
	in	al, 21h    		; read interrupt mask register
	JMP	$+2			; I/O DELAY
	and	al, 0EFh   		; enable IRQ 4 (COM1)
	out	21h, al    		; write back to register
	;
	; 23/10/2015
	mov 	eax, com1_int
	mov	[com1_irq4], eax
	; 26/10/2015
	popf
	retn

sp_invp_err:
	mov	dword [u.error], ERR_INV_PARAMETER ; 'invalid parameter !' 
	xor	ecx, ecx
	dec	ecx ; 0FFFFh
	stc
	retn

; 29/10/2015
b_div_tbl: ; Baud rate divisor table (115200/divisor)
	db 1, 12, 6, 3, 8, 4, 1


; 23/10/2015
com1_irq4:
	dd dummy_retn
com2_irq3:
	dd dummy_retn

dummy_retn:
	retn

wakeup:
	; 24/01/2016
	retn