home *** CD-ROM | disk | FTP | other *** search
- name serdrvpc
- ;
- ; serdrvpc.asm: hterm serial driver for IBM-PC and J-3100
- ;
- ; Author: HIRANO Satoshi
- ;
- ; (C) 1989 Halca Computer Science Laboratory TM
- ; University of Tokyo
- ;
- ; Reference:
- ; Interface 1984 de-ta tsusin no xterm
- ;
- ; Edition History:
- ; 2.2 89/05/16 Halca.Hirano V2.2 distribution
- ; 2.3 89/06/20 Halca.Hirano rename from xportpc.asm
- ; 2.4 89/07/27 Halca.Hirano far, rewrite entirely
- ; move non time sensitive part to port.c
- ; support multiple port
- ; 2.5 89/08/05 Halca.Hirano add mouse handler
- ; 2.7 89/09/15 Halca.Hirano add RTS/CTS flow control
- ; 2.8 89/09/25 Halca.Hirano mask char on getSerial
- ; ---- V2.4.0 distribution ----
- ; 2.9 89/10/26 Halca.Hirano change buffer size from 500 to 2000
- ; 3.0 89/11/10 Tominaga@Titech add comments for J3100 porting
- ; 3.1 89/11/19 Halca.Hirano fix MCR offset bug
- ;
- ; $Header: serdrvpc.asv 1.7 90/07/03 21:09:34 hirano Exp $
-
- ;
- ; constants
- ;
- NS16450_DATA EQU 0h ; NS16450 THR data register (offset)
- NS16450_MCR EQU 4h ; MCR modem control register (offset)
- NS16450_MSR EQU 6h ; MSR modem status register (offset)
- NS16450_STATUS EQU 5h ; LCR line status register (offset)
- TX_READY EQU 20h ; transmitter buffer empty
- I8259_ICR equ 20h ; i8259 interrupt control register (address)
- I8259_IMR equ 21h ; i8259 interrupt mask register (address)
- EOI EQU 20H ; i8259 end of interrupt command
- TRUE EQU -1
- FALSE EQU 0
- YES equ 1
- NO equ 0
-
- BUFSIZE EQU 2000 ; receive buffer size
- OFFLIM1 EQU 1900 ; XOFF send timing 1
- OFFLIM2 EQU 1950 ; XOFF send timing 2
- OFFLIM3 EQU 1965 ; XOFF send timing 3
- ONLIMIT EQU 1000 ; XON send timing
- XON EQU 011H
- XOFF EQU 013H
- ;
- ; C interface
- ;
- extrn _cMask:byte ; character mask
- extrn _maskFlag:byte ; 1=XOFFed
- extrn _downLoading:byte ; 1=down loading
- extrn _xonXoff:byte ; 1=XON/XOFF enable, 2=RTS/CTS enable
- extrn _portAddress:word ; port address
- extrn _onMask:byte ; interrupt on mask for IMR
- extrn _offMask:byte ; interrupt off mask for IMR
- extrn _mouseEvent: far ; mouse handler C part procedure
- ;
- ; static storage in the data segment (ring buffer)
- ;
- _DATA segment word public 'DATA'
- buffer db BUFSIZE dup(?)
- _DATA ends
-
- DGROUP group _DATA
- _TEXT segment byte public 'CODE'
- _TEXT ends
- assume ds:DGROUP, cs:_TEXT
- _TEXT segment
- ;
- ; static strage in the code segment
- ;
- htermDS dw 0 ; DS of hterm is saved for this assembler part
- head dw 0 ; reading point where get data out of the ring buffer
- tail dw 0 ; entry point where data from RS is written at
- full dw 0 ; indicates the buffer is full
- xoffed dw 0
-
- ;
- ; getPortInterruptHandlerAddress()
- ; in: none
- ; out: retuns far address of interrupt handler
- ;
- public _getPortInterruptHandlerAddress
- _getPortInterruptHandlerAddress proc far
- mov cs:htermDS,ds ; get DS and save it for later use
- mov ax,offset cs:portInterruptHandler
- mov dx,cs ; return far pointer
- ret
- _getPortInterruptHandlerAddress endp
-
-
- initwait:
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- ret
-
-
- ;
- ; port interrupt handler
- ;
- portInterruptHandler proc near
- cli ; disable interrupts
- push ax
- push ds
- push es
- push dx
- ;
- mov dx,cs:htermDS ; get DS of hterm
- mov es,dx ; put it into ES and DS
- mov ds,dx
- ;
- si5: ; receive one char from the port
- mov dx,_portAddress
- add dx,NS16450_DATA ; read from rx data buffer
- in al,dx
- ;
- ; check XON or XOFF from the remote system if not downloading nor xonXoff mode
- cmp byte ptr _downLoading,YES ; if downloading or
- jz int02
- cmp byte ptr _xonXoff,YES ; XON/XOFF is active,
- jz int02 ; jump.(? reversed?)
- cmp al,XOFF ; if XOFF char received,
- jne int00
- mov byte ptr _maskFlag,YES ; set mask.
- jmp si1
-
- int00:
- cmp al,XON ; XON char is received,
- jne int02
- mov byte ptr _maskFlag,NO ; clear mask.
- jmp si1
-
- int02:
- cmp cs:full,TRUE ; if the buffer is full,
- je si1 ; jump.
- ; put the data into the buffer
- push di
- push si
- mov si,cs:head
- mov di,cs:tail
- push ax ; save the data into stack
- ;
- call getsize ; check how much space remains
- ; in the buffer
- cmp ax,OFFLIM1
- jle si2 ; enough space left. jump.
-
- ; less space is left in the buffer
- ; (the value of xoffed changes as this: NO -> YES -> 2)
- mov dx,cs:xoffed
- cmp dx,NO
- jne off1
- inc cs:xoffed
- jmp off3
- off1: cmp dx,YES
- jne off2
- cmp ax,OFFLIM2
- jle si2
-
- inc cs:xoffed
- jmp off3
- off2: cmp ax,OFFLIM3
- jle si2
- off3: call dc3 ; send XOFF or negate RTS
- ;
- si2: pop ax ; restore the data from stack
- cld
- stosb
- cmp di,offset ds:buffer+BUFSIZE
- jne si3
- mov di,offset ds:buffer
- si3: mov cs:tail,di
-
- cmp si,di
- jne si4
- mov cs:full,TRUE
- si4: pop si
- pop di
- ;
- si1: ; check if any data remain in port receive buffer
- ; mov dx,_portAddress
- ; add dx,NS16450_STATUS
- ; in al,dx ; get line status
- ; ;
- ; and al,01h ; any data rest?
- ; jz si0 ; no. buffer empty
- ; jmp si5 ; yes. read again.
- ; ;
- si0: ; end point of this handler
- pop dx
- pop es
- pop ds
- sti
- mov al,EOI
- out I8259_ICR,al
- pop ax
- iret
- portInterruptHandler endp
-
- ;
- ; getsize: calculate how much data is in the ring buffer
- ;
- getsize:
- mov ax,di ; di is assumed to have the value of `tail'
- mov dx,si ; si, `head'
- cmp ax,dx ; which is former in their `physical' position?
- jae sizeg
- ; head < tail. data is linear in the buffer
- sub dx,ax
- neg dx
- add dx,BUFSIZE
- mov ax,dx ; return( BUFSIZE - (`tail' - `head') )
- ret
- ; tail <= head. data is wrapping around the end
- sizeg: sub ax,dx ; return( `head' - `tail' )
- ret
-
- ;
- ; dc1: send XON or assert RTS
- ;
- dc1:
- push ax
- mov al,byte ptr _xonXoff
- cmp al,1 ; ? XON/XOFF enable
- jne dc12 ; bra if no
- mov al,XON
- push ax
- call _putSerial ; send XON
- pop ax
- jmp dc19
- dc12:
- cmp al,2 ; ? RTS/CTS enable
- jne dc19 ; bra if no, no flow control
- push dx
- mov dx,_portAddress ; get port address
- add dx,NS16450_MCR
- mov al,0bh
- out dx,al ; assert RTS,DTR
- pop dx
- dc19:
- pop ax
- ret
-
- ;
- ; send XOFF or negate RTS
- ;
- dc3: push ax
- mov al,byte ptr _xonXoff
- cmp al,1 ; ? XON/XOFF enable
- jne dc32 ; bra if no
- mov al,XOFF ; send XOFF
- push ax
- call _putSerial ; send XOFF
- pop ax
- jmp dc39
- dc32:
- cmp al,2 ; ? RTS/CTS enable
- jne dc39 ; bra if no, no flow control
- push dx
- mov dx,_portAddress ; get port address
- add dx,NS16450_MCR
- mov al,9h
- out dx,al ; assert DTR, negate RTS
- pop dx
- dc39:
- pop ax
- ret
-
- ;
- ; putSerial(data) output data
- ; al: data;
- ;
- _putSerial proc
- push dx
- push ax ; save sending character
- mov dx,_portAddress ; load device address
- push dx ; save it for later
- add dx,NS16450_STATUS ; point to status register
- rswait:
- in al,dx ; get status
- and al,TX_READY ; is ready to transmit?
- je rswait ; no. loop and wait.
- pop dx ; load device address
- pop ax
- add dx,NS16450_DATA ; point to data register
- out dx,al ; output data to port
- pop dx
- ret
- _putSerial endp
-
- ;
- ; initPortBuffer() buffer initialize
- ;
- public _initPortBuffer
- _initPortBuffer proc far
- mov ax,offset ds:buffer
- mov cs:head,ax
- mov cs:tail,ax
- ret
- _initPortBuffer endp
-
- ;
- ; disable receive interrupt
- ;
- disable:
- cli
- in al,I8259_IMR ; read current value of mask register
- or al,ds:_offMask ; disable RS interrupt
- out I8259_IMR,al ; write it into mask register
- sti
- ret
- ;
- ; enable receive interrupt
- ;
- enable:
- cli
- in al,I8259_IMR ; read current mask
- and al,ds:_onMask ; enable RS interrupt
- out I8259_IMR,al ; set mask
- sti
- ret
- ;
- ; short getSerial() get a char from the buffer
- ;
- public _getSerial
- _getSerial proc far
- push di
- push si
- call disable ; disable RS interrupt
-
- mov si,cs:head
- mov di,cs:tail
- cmp si,di
- jne sd1 ; jump if head != tail (buffer has some data)
-
- cmp cs:full,TRUE
- je sd2 ; jump if the buffer is full
-
- ; otherwise, buffer is empty
- call enable ; enable RS interrupt
- mov ax,-1 ; return(buffer is empty)
- pop si
- pop di
- ret
-
- ; case that the buffer is full
- sd2: mov cs:full,FALSE ; buffer will become to have a room
- cld
- sd1: ; case that the buffer has data
- lodsb ; al <- head (get the top byte)
- mov ah,ds:_cMask
- and al,ah ;mask char
- mov ah,0
- push ax ; now ax has the byte read from ring buffer
- cmp si,offset ds:buffer+BUFSIZE ; if head has exceeded the end
- jne sd3 ; of the ring buffer, rewind
- mov si,offset ds:buffer ; it to the top
-
- sd3:
- mov cs:head,si ; save the value of head
- cmp cs:xoffed,NO
- je sd4
- ; now is XOFFed state
- call getsize ; get the size of data in the buffer
- cmp ax,ONLIMIT ; if it is less than ONLIMIT,
- jge sd4
- call dc1 ; send XON or assert RTS
-
- mov cs:xoffed,FALSE ; and is not XOFFed state
-
- sd4: call enable ; enable RS interrupt
- pop ax ; restore ax... is the byte from ring buffer
- pop si
- pop di
- ret ; returns the byte from ring buffer
- _getSerial endp
-
- ;
- ; checkSerial() check serial buffer
- ; if empty return 0
- ;
- public _checkSerial
- _checkSerial proc far
- cli
- push di
- push si
- mov ax,YES ; prepare buffer not empty
- mov si,cs:head
- mov di,cs:tail
- cmp si,di ; ? head == tail
- jne checkK2 ; bra if no
- mov ax,NO ; flag buffer empty
- checkK2:
- pop si
- pop di
- sti
- ret
- _checkSerial endp
-
- ;
- ; getMouseInterruptHandlerAddress
- ;
- public _getMouseIntAddress
- _getMouseIntAddress proc far
- mov cs:htermDS,ds ; save DS for later use
- mov ax,offset cs:mouseInterruptHandler
- mov dx,cs ; return the address
- ret
- _getMouseIntAddress endp
-
- ;
- ; mouseInterruptHandler()
- ; this procedures is called by far call from mouse driver
- ;
- public mouseInterruptHandler
- mouseInterruptHandler proc far
- push es
- push ss
- push ds
- push ax
- push bx
- push cx
- push dx ; save registers
-
- push dx ; y
- push cx ; x
- push ax ; event (arg may be changed)
- mov ds,cs:htermDS
- call far ptr _mouseEvent ; call C part
- add sp,6
- ; for debug
- ; mov al,07h
- ; out 037h,al ; stop bell
-
- pop dx
- pop cx
- pop bx
- pop ax
- pop ds
- pop ss
- pop es
- ret
- mouseInterruptHandler endp
-
- _TEXT ends
- end
-