;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; 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