kolibrios-gitea/drivers/old/uart.asm
bw 91d4003b6e uart driver
git-svn-id: svn://kolibrios.org@8384 a494cfbc-eb01-0410-851d-a64ba20cac60
2020-12-13 02:57:39 +00:00

995 lines
22 KiB
NASM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
format PE DLL native 0.05
entry START
__DEBUG__ equ 1
__DEBUG_LEVEL__ equ 1 ; 1 = verbose, 2 = errors only
API_VERSION equ 0
UART_VERSION equ API_VERSION
PG_SW equ 0x003
page_tabs equ 0xFDC00000 ;hack
OS_BASE equ 0x80000000
SLOT_BASE equ (OS_BASE+0x0080000)
TASK_COUNT equ (OS_BASE+0x0003004)
CURRENT_TASK equ (OS_BASE+0x0003000)
section '.flat' readable writable executable
include 'proc32.inc'
include 'struct.inc'
include 'macros.inc'
include 'fdo.inc'
include 'peimport.inc'
struc APPOBJ ;common object header
{
.magic dd ? ;
.destroy dd ? ;internal destructor
.fd dd ? ;next object in list
.bk dd ? ;prev object in list
.pid dd ? ;owner id
}
virtual at 0
APPOBJ APPOBJ
end virtual
THR_REG equ 0; x3f8 ;transtitter/reciever
IER_REG equ 1; x3f9 ;interrupt enable
IIR_REG equ 2; x3fA ;interrupt info
LCR_REG equ 3; x3FB ;line control
MCR_REG equ 4; x3FC ;modem control
LSR_REG equ 5; x3FD ;line status
MSR_REG equ 6; x3FE ;modem status
LCR_5BIT equ 0x00
LCR_6BIT equ 0x01
LCR_7BIT equ 0x02
LCR_8BIT equ 0x03
LCR_STOP_1 equ 0x00
LCR_STOP_2 equ 0x04
LCR_PARITY equ 0x08
LCR_EVEN equ 0x10
LCR_STICK equ 0x20
LCR_BREAK equ 0x40
LCR_DLAB equ 0x80
LSR_DR equ 0x01 ;data ready
LSR_OE equ 0x02 ;overrun error
LSR_PE equ 0x04 ;parity error
LSR_FE equ 0x08 ;framing error
LSR_BI equ 0x10 ;break interrupt
LSR_THRE equ 0x20 ;transmitter holding empty
LSR_TEMT equ 0x40 ;transmitter empty
LSR_FER equ 0x80 ;FIFO error
FCR_EFIFO equ 0x01 ;enable FIFO
FCR_CRB equ 0x02 ;clear reciever FIFO
FCR_CXMIT equ 0x04 ;clear transmitter FIFO
FCR_RDY equ 0x08 ;set RXRDY and TXRDY pins
FCR_FIFO_1 equ 0x00 ;1 byte trigger
FCR_FIFO_4 equ 0x40 ;4 bytes trigger
FCR_FIFO_8 equ 0x80 ;8 bytes trigger
FCR_FIFO_14 equ 0xC0 ;14 bytes trigger
IIR_INTR equ 0x01 ;1= no interrupts
IER_RDAI equ 0x01 ;reciever data interrupt
IER_THRI equ 0x02 ;transmitter empty interrupt
IER_LSI equ 0x04 ;line status interrupt
IER_MSI equ 0x08 ;modem status interrupt
MCR_DTR equ 0x01 ;0-> DTR=1, 1-> DTR=0
MCR_RTS equ 0x02 ;0-> RTS=1, 1-> RTS=0
MCR_OUT_1 equ 0x04 ;0-> OUT1=1, 1-> OUT1=0
MCR_OUT_2 equ 0x08 ;0-> OUT2=1, 1-> OUT2=0; enable intr
MCR_LOOP equ 0x10 ;loopback mode
MSR_DCTS equ 0x01 ;delta clear to send
MSR_DDSR equ 0x02 ;delta data set redy
MSR_TERI equ 0x04 ;trailinh edge of ring
MSR_DDCD equ 0x08 ;delta carrier detect
RATE_50 equ 0
RATE_75 equ 1
RATE_110 equ 2
RATE_134 equ 3
RATE_150 equ 4
RATE_300 equ 5
RATE_600 equ 6
RATE_1200 equ 7
RATE_1800 equ 8
RATE_2000 equ 9
RATE_2400 equ 10
RATE_3600 equ 11
RATE_4800 equ 12
RATE_7200 equ 13
RATE_9600 equ 14
RATE_19200 equ 15
RATE_38400 equ 16
RATE_57600 equ 17
RATE_115200 equ 18
COM_1 equ 1
COM_2 equ 2
COM_3 equ 3
COM_4 equ 4
COM_MAX equ 2 ;only two port supported
COM_1_BASE equ 0x3F8
COM_2_BASE equ 0x2F8
COM_1_IRQ equ 4
COM_2_IRQ equ 3
UART_CLOSED equ 0
UART_TRANSMIT equ 1
UART_STOP equ 2
struc UART
{
.lock dd ?
.base dd ?
.lcr_reg dd ?
.mcr_reg dd ?
.rate dd ?
.mode dd ?
.state dd ?
.rcvr_buff dd ?
.rcvr_rp dd ?
.rcvr_wp dd ?
.rcvr_count dd ?
.rcvr_top dd ?
.xmit_buff dd ?
.xmit_rp dd ?
.xmit_wp dd ?
.xmit_count dd ?
.xmit_free dd ?
.xmit_top dd ?
}
virtual at 0
UART UART
end virtual
UART_SIZE equ 18*4
struc CONNECTION
{
.magic dd ? ;'CNCT'
.destroy dd ? ;internal destructor
.fd dd ? ;next object in list
.bk dd ? ;prev object in list
.pid dd ? ;owner id
.id dd ? ;reserved
.uart dd ? ;uart pointer
}
virtual at 0
CONNECTION CONNECTION
end virtual
CONNECTION_SIZE equ 7*4
;proc START c, state:dword
; cmp [state], 1
align 4
proc START c, state:dword
DEBUGF 1, "Loading driver UART (entry at %x)...\n", START
push esi ; [bw] ???
cmp [state], DRV_ENTRY
jne .stop
mov esi, msg_start
invoke SysMsgBoardStr
mov eax, UART_SIZE
invoke Kmalloc
; invoke Kmalloc, UART_SIZE (1) -- failure
; invoke Kmalloc, UART_SIZE (2) -- success
; DEBUGF 1,"[UART.START] Kmalloc: UART_SIZE=%d eax=%d\n", UART_SIZE, eax
test eax, eax
jz .fail
DEBUGF 1, "Structure %x allocated\n", eax
mov [com1], eax
mov edi, eax
mov ecx, UART_SIZE/4
xor eax, eax
cld
rep stosd
mov eax, [com1]
mov [eax+UART.base], COM_1_BASE
invoke AllocKernelSpace, 32768
mov edi, [com1]
mov edx, eax
mov [edi+UART.rcvr_buff], eax
add eax, 8192
mov [edi+UART.rcvr_top], eax
add eax, 8192
mov [edi+UART.xmit_buff], eax
add eax, 8192
mov [edi+UART.xmit_top], eax
invoke AllocPage
test eax, eax
jz .fail
shr edx, 12
or eax, PG_SW
mov [page_tabs+edx*4], eax
mov [page_tabs+edx*4+8], eax
invoke AllocPage
test eax, eax
jz .fail
or eax, PG_SW
mov [page_tabs+edx*4+4], eax
mov [page_tabs+edx*4+12], eax
invoke AllocPage
test eax, eax
jz .fail
or eax, PG_SW
mov [page_tabs+edx*4+16], eax
mov [page_tabs+edx*4+24], eax
invoke AllocPage
test eax, eax
jz .fail
or eax, PG_SW
mov [page_tabs+edx*4+20], eax
mov [page_tabs+edx*4+28], eax
mov eax, [edi+UART.rcvr_buff]
invlpg [eax]
invlpg [eax+0x1000]
invlpg [eax+0x2000]
invlpg [eax+0x3000]
invlpg [eax+0x4000]
invlpg [eax+0x5000]
invlpg [eax+0x6000]
invlpg [eax+0x7000]
mov eax, edi
call uart_reset.internal ;eax= uart
invoke AttachIntHandler, COM_1_IRQ, com_1_isr, dword 0
test eax, eax
jnz @f
DEBUGF 2, "Could not attach int handler (%x)\n", COM_1_IRQ
jmp .fail
@@:
DEBUGF 1, "Attached int handler (%x)\n", COM_1_IRQ
pop esi
invoke RegService, sz_uart_srv, service_proc
ret
.fail:
.stop:
DEBUGF 2, "Failed\n"
pop esi
xor eax, eax
ret
endp
handle equ IOCTL.handle
io_code equ IOCTL.io_code
input equ IOCTL.input
inp_size equ IOCTL.inp_size
output equ IOCTL.output
out_size equ IOCTL.out_size
SRV_GETVERSION equ 0
PORT_OPEN equ 1
PORT_CLOSE equ 2
PORT_RESET equ 3
PORT_SETMODE equ 4
PORT_GETMODE equ 5
PORT_SETMCR equ 6
PORT_GETMCR equ 7
PORT_READ equ 8
PORT_WRITE equ 9
align 4
proc service_proc stdcall, ioctl:dword
mov ebx, [ioctl]
mov eax, [ebx+io_code]
cmp eax, PORT_WRITE
ja .fail
cmp eax, SRV_GETVERSION
jne @F
mov eax, [ebx+output]
cmp [ebx+out_size], 4
jne .fail
mov [eax], dword UART_VERSION
xor eax, eax
ret
@@:
cmp eax, PORT_OPEN
jne @F
cmp [ebx+out_size], 4
jne .fail
mov ebx, [ebx+input]
mov eax, [ebx]
call uart_open
mov ebx, [ioctl]
mov ebx, [ebx+output]
mov [ebx], ecx
ret
@@:
mov esi, [ebx+input] ;input buffer
mov edi, [ebx+output]
call [uart_func+eax*4]
ret
.fail:
or eax, -1
ret
endp
;restore handle
;restore io_code
;restore input
;restore inp_size
;restore output
;restore out_size
; param
; esi= input buffer
; +0 connection
;
; retval
; eax= error code
align 4
uart_reset:
mov eax, [esi]
cmp [eax+APPOBJ.magic], 'CNCT'
jne .fail
cmp [eax+APPOBJ.destroy], uart_close.destroy
jne .fail
mov eax, [eax+CONNECTION.uart]
test eax, eax
jz .fail
; set mode 2400 bod 8-bit
; disable DTR & RTS
; clear FIFO
; clear pending interrupts
;
; param
; eax= uart
align 4
.internal:
mov esi, eax
mov [eax+UART.state], UART_CLOSED
mov edx, [eax+UART.base]
add edx, MCR_REG
xor eax, eax
out dx, al ;clear DTR & RTS
mov eax, esi
; mov ebx, RATE_2400
mov ebx, RATE_115200
mov ecx, LCR_8BIT+LCR_STOP_1
call uart_set_mode.internal
mov edx, [esi+UART.base]
add edx, IIR_REG
mov eax, FCR_EFIFO+FCR_CRB+FCR_CXMIT+FCR_FIFO_14
out dx, al
.clear_RB:
mov edx, [esi+UART.base]
add edx, LSR_REG
in al, dx
test eax, LSR_DR
jz @F
mov edx, [esi+UART.base]
in al, dx
jmp .clear_RB
@@:
mov edx, [esi+UART.base]
add edx, IER_REG
mov eax, IER_RDAI+IER_THRI+IER_LSI
out dx, al
.clear_IIR:
mov edx, [esi+UART.base]
add edx, IIR_REG
in al, dx
test al, IIR_INTR
jnz .done
shr eax, 1
and eax, 3
jnz @F
mov edx, [esi+UART.base]
add edx, MSR_REG
in al, dx
jmp .clear_IIR
@@:
cmp eax, 1
je .clear_IIR
cmp eax, 2
jne @F
mov edx, [esi+UART.base]
in al, dx
jmp .clear_IIR
@@:
mov edx, [esi+UART.base]
add edx, LSR_REG
in al, dx
jmp .clear_IIR
.done:
mov edi, [esi+UART.rcvr_buff]
mov ecx, 8192/4
xor eax, eax
mov [esi+UART.rcvr_rp], edi
mov [esi+UART.rcvr_wp], edi
mov [esi+UART.rcvr_count], eax
cld
rep stosd
mov edi, [esi+UART.xmit_buff]
mov ecx, 8192/4
mov [esi+UART.xmit_rp], edi
mov [esi+UART.xmit_wp], edi
mov [esi+UART.xmit_count], eax
mov [esi+UART.xmit_free], 8192
rep stosd
ret ;eax= 0
.fail:
or eax, -1
ret
; param
; esi= input buffer
; +0 connection
; +4 rate
; +8 mode
;
; retval
; eax= error code
align 4
uart_set_mode:
mov eax, [esi]
cmp [eax+APPOBJ.magic], 'CNCT'
jne .fail
cmp [eax+APPOBJ.destroy], uart_close.destroy
jne .fail
mov eax, [eax+CONNECTION.uart]
test eax, eax
jz .fail
mov ebx, [esi+4]
mov ecx, [esi+8]
; param
; eax= uart
; ebx= baud rate
; ecx= mode
align 4
.internal:
cmp ebx, RATE_115200
ja .fail
cmp ecx, LCR_BREAK
jae .fail
mov [eax+UART.rate], ebx
mov [eax+UART.mode], ecx
mov esi, eax
mov bx, [divisor+ebx*2]
mov edx, [esi+UART.base]
push edx
add edx, LCR_REG
in al, dx
or al, 0x80
out dx, al
pop edx
mov al, bl
out dx, al
inc dx
mov al, bh
out dx, al
add edx, LCR_REG-1
mov eax, ecx
out dx, al
xor eax, eax
ret
.fail:
or eax, -1
ret
; param
; esi= input buffer
; +0 connection
; +4 modem control reg valie
;
; retval
; eax= error code
align 4
uart_set_mcr:
mov eax, [esi]
cmp [eax+APPOBJ.magic], 'CNCT'
jne .fail
cmp [eax+APPOBJ.destroy], uart_close.destroy
jne .fail
mov eax, [eax+CONNECTION.uart]
test eax, eax
jz .fail
mov ebx, [esi+4]
mov [eax+UART.mcr_reg], ebx
mov edx, [eax+UART.base]
add edx, MCR_REG
mov al, bl
out dx, al
xor eax, eax
ret
.fail:
or eax, -1
ret
; param
; eax= port
;
; retval
; ecx= connection
; eax= error code
align 4
uart_open:
dec eax
cmp eax, COM_MAX
jae .fail
mov esi, [com1+eax*4] ;uart
push esi
.do_wait:
cmp dword [esi+UART.lock], 0
je .get_lock
; call change_task
jmp .do_wait
.get_lock:
mov eax, 1
xchg eax, [esi+UART.lock]
test eax, eax
jnz .do_wait
mov eax, esi ;uart
call uart_reset.internal
mov ebx, [CURRENT_TASK]
shl ebx, 5
mov ebx, [CURRENT_TASK+ebx+4]
mov eax, CONNECTION_SIZE
invoke CreateObject
pop esi ;uart
test eax, eax
jz .fail
mov [eax+APPOBJ.magic], 'CNCT'
mov [eax+APPOBJ.destroy], uart_close.destroy
mov [eax+CONNECTION.uart], esi
mov ecx, eax
xor eax, eax
ret
.fail:
or eax, -1
ret
restore .uart
; param
; esi= input buffer
align 4
uart_close:
mov eax, [esi]
cmp [eax+APPOBJ.magic], 'CNCT'
jne .fail
cmp [eax+APPOBJ.destroy], uart_close.destroy
jne .fail
.destroy:
; DEBUGF 1, "[UART.destroy] eax=%x uart=%x\n", eax, [eax+CONNECTION.uart]
push [eax+CONNECTION.uart]
invoke DestroyObject ;eax= object
pop eax ;eax= uart
test eax, eax
jz .fail
mov [eax+UART.state], UART_CLOSED
mov [eax+UART.lock], 0 ;release port
xor eax, eax
ret
.fail:
or eax, -1
ret
; param
; eax= uart
; ebx= baud rate
align 4
set_rate:
cmp ebx, RATE_115200
ja .fail
mov [eax+UART.rate], ebx
mov bx, [divisor+ebx*2]
mov edx, [eax+UART.base]
add edx, LCR_REG
in al, dx
push eax
or al, 0x80
out dx, al
sub edx, LCR_REG
mov al, bl
out dx, al
inc edx
mov al, bh
out dx, al
pop eax
add edx, LCR_REG-1
out dx, al
.fail:
ret
; param
; ebx= uart
align 4
transmit:
push esi
push edi
mov edx, [ebx+UART.base]
pushfd
cli
mov esi, [ebx+UART.xmit_rp]
mov ecx, [ebx+UART.xmit_count]
test ecx, ecx
je .stop
cmp ecx, 16
jbe @F
mov ecx, 16
@@:
sub [ebx+UART.xmit_count], ecx
add [ebx+UART.xmit_free], ecx
cld
@@:
lodsb
out dx, al
dec ecx
jnz @B
cmp esi, [ebx+UART.xmit_top]
jb @F
sub esi, 8192
@@:
mov [ebx+UART.xmit_rp], esi
cmp [ebx+UART.xmit_count], 0
je .stop
mov [ebx+UART.state], UART_TRANSMIT
jmp @F
.stop:
mov [ebx+UART.state], UART_STOP
@@:
popfd
pop edi
pop esi
ret
; param
; esi= input buffer
; +0 connection
; +4 dst buffer
; +8 dst size
; edi= output buffer
; +0 bytes read
; retval
; eax= error code
align 4
uart_read:
mov eax, [esi]
cmp [eax+APPOBJ.magic], 'CNCT'
jne .fail
cmp [eax+APPOBJ.destroy], uart_close.destroy
jne .fail
mov eax, [eax+CONNECTION.uart]
test eax, eax
jz .fail
mov ebx, [esi+8] ;dst size
mov ecx, [eax+UART.rcvr_count]
cmp ecx, ebx
jbe @F
mov ecx, ebx
@@:
mov [edi], ecx ;bytes read
test ecx, ecx
jz .done
push ecx
mov edi, [esi+4] ;dst
mov esi, [eax+UART.rcvr_rp]
cld
rep movsb
pop ecx
cmp esi, [eax+UART.rcvr_top]
jb @F
sub esi, 8192
@@:
mov [eax+UART.rcvr_rp], esi
sub [eax+UART.rcvr_count], ecx
.done:
xor eax, eax
ret
.fail:
or eax, -1
ret
; param
; esi= input buffer
; +0 connection
; +4 src buffer
; +8 src size
;
; retval
; eax= error code
align 4
uart_write:
mov eax, [esi]
cmp [eax+APPOBJ.magic], 'CNCT'
jne .fail
cmp [eax+APPOBJ.destroy], uart_close.destroy
jne .fail
mov eax, [eax+CONNECTION.uart]
test eax, eax
jz .fail
mov ebx, [esi+4]
mov edx, [esi+8]
; param
; eax= uart
; ebx= src
; edx= count
align 4
.internal:
mov esi, ebx
mov edi, [eax+UART.xmit_wp]
.write:
test edx, edx
jz .fail
.wait:
cmp [eax+UART.xmit_free], 0
jne .fill
cmp [eax+UART.state], UART_TRANSMIT
je .wait
mov ebx, eax
push edx
call transmit
pop edx
mov eax, ebx
jmp .write
.fill:
mov ecx, [eax+UART.xmit_free]
cmp ecx, edx
jbe @F
mov ecx, edx
@@:
push ecx
cld
rep movsb
pop ecx
sub [eax+UART.xmit_free], ecx
add [eax+UART.xmit_count], ecx
sub edx, ecx
jnz .wait
.done:
cmp edi, [eax+UART.xmit_top]
jb @F
sub edi, 8192
@@:
mov [eax+UART.xmit_wp], edi
cmp [eax+UART.state], UART_TRANSMIT
je @F
mov ebx, eax
call transmit
@@:
xor eax, eax
ret
.fail:
or eax, -1
ret
align 4
com_2_isr:
mov ebx, [com2]
jmp com_1_isr.get_info
align 4
com_1_isr:
mov ebx, [com1]
.get_info:
mov edx, [ebx+UART.base]
add edx, IIR_REG
in al, dx
test al, IIR_INTR
jnz .done
shr eax, 1
and eax, 3
call [isr_action+eax*4]
jmp .get_info
.done:
ret
align 4
isr_line:
mov edx, [ebx+UART.base]
add edx, LSR_REG
in al, dx
ret
align 4
isr_recieve:
; DEBUGF 1, "[UART.isr_recieve] ebx=%x\n", ebx
mov esi, [ebx+UART.base]
add esi, LSR_REG
mov edi, [ebx+UART.rcvr_wp]
xor ecx, ecx
cld
.read:
mov edx, esi
in al, dx
test eax, LSR_DR
jz .done
mov edx, [ebx+UART.base]
in al, dx
stosb
inc ecx
jmp .read
.done:
cmp edi, [ebx+UART.rcvr_top]
jb @F
sub edi, 8192
@@:
mov [ebx+UART.rcvr_wp], edi
add [ebx+UART.rcvr_count], ecx
ret
align 4
isr_modem:
mov edx, [ebx+UART.base]
add edx, MSR_REG
in al, dx
ret
align 4
divisor dw 2304, 1536, 1047, 857, 768, 384
dw 192, 96, 64, 58, 48, 32
dw 24, 16, 12, 6, 3, 2, 1
align 4
uart_func dd 0 ;SRV_GETVERSION
dd 0 ;PORT_OPEN
dd uart_close ;PORT_CLOSE
dd uart_reset ;PORT_RESET
dd uart_set_mode ;PORT_SETMODE
dd 0 ;PORT_GETMODE
dd uart_set_mcr ;PORT_SETMODEM
dd 0 ;PORT_GETMODEM
dd uart_read ;PORT_READ
dd uart_write ;PORT_WRITE
isr_action dd isr_modem
dd transmit
dd isr_recieve
dd isr_line
version dd (5 shl 16) or (UART_VERSION and 0xFFFF)
sz_uart_srv db 'UART', 0
msg_start db 'Loading UART driver...',13,10,0
include_debug_strings ; All data wich FDO uses will be included here
align 4
com1 rd 1
com2 rd 1
align 4
data fixups
end data