home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / COMM / MISC / SRC26_2.ZIP / SRC / SERDRVPC.ASM < prev    next >
Encoding:
Assembly Source File  |  1990-07-03  |  9.9 KB  |  458 lines

  1.     name    serdrvpc
  2. ;
  3. ; serdrvpc.asm: hterm serial driver for IBM-PC and J-3100
  4. ;
  5. ; Author: HIRANO Satoshi
  6. ;
  7. ; (C) 1989  Halca Computer Science Laboratory TM
  8. ;           University of Tokyo
  9. ;
  10. ; Reference:
  11. ;  Interface 1984 de-ta tsusin no xterm
  12. ;
  13. ; Edition History:
  14. ; 2.2 89/05/16 Halca.Hirano V2.2 distribution
  15. ; 2.3 89/06/20 Halca.Hirano rename from xportpc.asm
  16. ; 2.4 89/07/27 Halca.Hirano far, rewrite entirely
  17. ;    move non time sensitive part to port.c
  18. ;    support multiple port 
  19. ; 2.5 89/08/05 Halca.Hirano add mouse handler
  20. ; 2.7 89/09/15 Halca.Hirano add RTS/CTS flow control
  21. ; 2.8 89/09/25 Halca.Hirano mask char on getSerial
  22. ;    ---- V2.4.0 distribution ----
  23. ; 2.9 89/10/26 Halca.Hirano change buffer size from 500 to 2000
  24. ; 3.0 89/11/10 Tominaga@Titech add comments for J3100 porting
  25. ; 3.1 89/11/19 Halca.Hirano fix MCR offset bug
  26. ;
  27. ; $Header: serdrvpc.asv  1.7  90/07/03 21:09:34  hirano  Exp $
  28.  
  29. ;
  30. ; constants
  31. ;
  32. NS16450_DATA     EQU    0h    ; NS16450 THR data register (offset)
  33. NS16450_MCR    EQU    4h    ; MCR modem control register (offset)
  34. NS16450_MSR    EQU    6h    ; MSR modem status register (offset)
  35. NS16450_STATUS    EQU    5h    ; LCR line status register (offset)
  36. TX_READY    EQU    20h    ; transmitter buffer empty
  37. I8259_ICR    equ    20h    ; i8259 interrupt control register (address)
  38. I8259_IMR    equ    21h    ; i8259 interrupt mask register (address)
  39. EOI        EQU    20H    ; i8259 end of interrupt command
  40. TRUE        EQU    -1
  41. FALSE        EQU    0
  42. YES        equ    1
  43. NO        equ    0
  44.  
  45. BUFSIZE    EQU    2000        ; receive buffer size
  46. OFFLIM1    EQU    1900        ; XOFF send timing 1
  47. OFFLIM2    EQU    1950        ; XOFF send timing 2
  48. OFFLIM3    EQU    1965        ; XOFF send timing 3
  49. ONLIMIT    EQU    1000        ; XON send timing
  50. XON    EQU    011H
  51. XOFF    EQU    013H
  52. ;
  53. ; C interface
  54. ;
  55. extrn    _cMask:byte            ; character mask
  56. extrn    _maskFlag:byte            ; 1=XOFFed
  57. extrn    _downLoading:byte        ; 1=down loading
  58. extrn    _xonXoff:byte            ; 1=XON/XOFF enable, 2=RTS/CTS enable
  59. extrn    _portAddress:word        ; port address
  60. extrn    _onMask:byte            ; interrupt on mask for IMR
  61. extrn    _offMask:byte            ; interrupt off mask for IMR
  62. extrn    _mouseEvent: far        ; mouse handler C part procedure
  63. ;
  64. ; static storage in the data segment (ring buffer)
  65. ;
  66. _DATA    segment word public 'DATA' 
  67. buffer    db    BUFSIZE dup(?)
  68. _DATA    ends
  69.  
  70. DGROUP    group    _DATA
  71. _TEXT    segment    byte public 'CODE'
  72. _TEXT    ends
  73.     assume    ds:DGROUP, cs:_TEXT
  74. _TEXT    segment
  75. ;
  76. ; static strage in the code segment
  77. ;
  78. htermDS    dw    0    ; DS of hterm is saved for this assembler part
  79. head    dw    0    ; reading point where get data out of the ring buffer
  80. tail    dw    0    ; entry point where data from RS is written at
  81. full    dw    0    ; indicates the buffer is full
  82. xoffed    dw    0
  83.  
  84. ;
  85. ; getPortInterruptHandlerAddress()
  86. ; in: none
  87. ; out: retuns far address of interrupt handler
  88. ;
  89.     public    _getPortInterruptHandlerAddress
  90. _getPortInterruptHandlerAddress proc    far
  91.     mov    cs:htermDS,ds    ; get DS and save it for later use
  92.     mov    ax,offset cs:portInterruptHandler
  93.     mov    dx,cs        ; return far pointer
  94.     ret
  95. _getPortInterruptHandlerAddress endp
  96.  
  97.  
  98. initwait:
  99.     nop
  100.     nop
  101.     nop
  102.     nop
  103.     nop
  104.     nop
  105.     nop
  106.     ret
  107.  
  108.  
  109. ;
  110. ; port interrupt handler
  111. ;
  112. portInterruptHandler proc near
  113.     cli                    ; disable interrupts
  114.     push    ax
  115.     push    ds
  116.     push    es
  117.     push    dx
  118.     ;
  119.     mov    dx,cs:htermDS            ; get DS of hterm
  120.     mov    es,dx                ; put it into ES and DS
  121.     mov    ds,dx
  122.     ;
  123. si5:    ; receive one char from the port
  124.     mov    dx,_portAddress
  125.     add    dx,NS16450_DATA            ; read from rx data buffer
  126.     in    al,dx
  127.     ;
  128. ; check XON or XOFF from the remote system if not downloading nor xonXoff mode
  129.     cmp     byte ptr _downLoading,YES    ; if downloading or
  130.     jz    int02
  131.     cmp    byte ptr _xonXoff,YES        ; XON/XOFF is active,
  132.     jz    int02                ; jump.(? reversed?)
  133.     cmp    al,XOFF                ; if XOFF char received,
  134.     jne    int00
  135.     mov    byte ptr _maskFlag,YES        ; set mask.
  136.     jmp    si1
  137.  
  138. int00:
  139.     cmp    al,XON                ; XON char is received,
  140.     jne    int02
  141.     mov    byte ptr _maskFlag,NO        ; clear mask.
  142.     jmp    si1
  143.  
  144. int02:
  145.     cmp    cs:full,TRUE            ; if the buffer is full,
  146.     je    si1                ; jump.
  147.     ; put the data into the buffer
  148.     push    di
  149.     push    si
  150.     mov    si,cs:head
  151.     mov    di,cs:tail
  152.     push    ax                ; save the data into stack
  153.     ;
  154.     call    getsize                ; check how much space remains
  155.                         ; in the buffer
  156.     cmp    ax,OFFLIM1
  157.     jle    si2                ; enough space left. jump.
  158.  
  159.     ; less space is left in the buffer
  160.     ; (the value of xoffed changes as this: NO -> YES -> 2)
  161.     mov    dx,cs:xoffed
  162.     cmp    dx,NO
  163.     jne    off1
  164.     inc    cs:xoffed
  165.     jmp    off3
  166. off1:    cmp    dx,YES
  167.     jne    off2
  168.     cmp    ax,OFFLIM2
  169.     jle    si2
  170.  
  171.     inc    cs:xoffed
  172.     jmp    off3
  173. off2:    cmp    ax,OFFLIM3
  174.     jle    si2
  175. off3:    call    dc3                ; send XOFF or negate RTS
  176.     ;
  177. si2:    pop    ax                ; restore the data from stack
  178.     cld
  179.     stosb
  180.     cmp    di,offset ds:buffer+BUFSIZE
  181.     jne    si3
  182.     mov    di,offset ds:buffer
  183. si3:    mov    cs:tail,di
  184.  
  185.     cmp    si,di
  186.     jne    si4
  187.     mov    cs:full,TRUE
  188. si4:    pop    si
  189.     pop    di
  190.     ;
  191. si1:    ; check if any data remain in port receive buffer
  192. ;    mov    dx,_portAddress
  193. ;    add    dx,NS16450_STATUS
  194. ;    in    al,dx                ; get line status
  195. ;    ;
  196. ;    and    al,01h                ; any data rest?
  197. ;    jz    si0                ; no. buffer empty
  198. ;    jmp    si5                ; yes. read again.
  199. ;    ;
  200. si0:    ; end point of this handler
  201.     pop    dx
  202.     pop    es
  203.     pop    ds
  204.     sti
  205.     mov    al,EOI
  206.     out    I8259_ICR,al
  207.     pop    ax
  208.     iret
  209. portInterruptHandler endp
  210.  
  211. ;
  212. ; getsize: calculate how much data is in the ring buffer
  213. ;
  214. getsize:
  215.     mov    ax,di        ; di is assumed to have the value of `tail'
  216.     mov    dx,si        ; si, `head'
  217.     cmp    ax,dx        ; which is former in their `physical' position?
  218.     jae    sizeg
  219.                 ; head < tail. data is linear in the buffer
  220.     sub    dx,ax
  221.     neg    dx
  222.     add    dx,BUFSIZE
  223.     mov    ax,dx        ; return( BUFSIZE - (`tail' - `head') )
  224.     ret
  225.                 ; tail <= head. data is wrapping around the end
  226. sizeg:    sub    ax,dx        ; return( `head' - `tail' )
  227.     ret
  228.  
  229. ;
  230. ; dc1: send XON or assert RTS
  231. ;
  232. dc1:
  233.     push    ax
  234.     mov    al,byte ptr _xonXoff
  235.     cmp    al,1            ; ? XON/XOFF enable
  236.     jne    dc12            ; bra if no
  237.     mov    al,XON
  238.     push    ax
  239.     call    _putSerial            ; send XON
  240.     pop    ax
  241.     jmp    dc19
  242. dc12:
  243.     cmp    al,2            ; ? RTS/CTS enable
  244.     jne    dc19            ; bra if no, no flow control
  245.     push    dx
  246.     mov    dx,_portAddress        ; get port address
  247.     add    dx,NS16450_MCR
  248.     mov    al,0bh
  249.     out    dx,al            ; assert RTS,DTR
  250.     pop    dx
  251. dc19:
  252.     pop    ax
  253.     ret
  254.  
  255. ;
  256. ; send XOFF or negate RTS
  257. ;
  258. dc3:    push    ax
  259.      mov    al,byte ptr _xonXoff
  260.     cmp    al,1            ; ? XON/XOFF enable
  261.     jne    dc32            ; bra if no
  262.      mov    al,XOFF            ; send XOFF
  263.     push    ax
  264.     call    _putSerial            ; send XOFF
  265.     pop    ax
  266.     jmp    dc39
  267. dc32:
  268.     cmp    al,2            ; ? RTS/CTS enable
  269.     jne    dc39            ; bra if no, no flow control
  270.     push    dx
  271.     mov    dx,_portAddress        ; get port address
  272.     add    dx,NS16450_MCR
  273.     mov    al,9h
  274.     out    dx,al            ; assert DTR, negate RTS
  275.     pop    dx
  276. dc39:
  277.     pop    ax
  278.     ret
  279.  
  280. ;
  281. ; putSerial(data)  output data
  282. ; al: data; 
  283. ;
  284. _putSerial proc
  285.     push    dx                
  286.     push    ax                    ; save sending character
  287.     mov        dx,_portAddress        ; load device address    
  288.     push    dx                    ; save it for later
  289.     add        dx,NS16450_STATUS    ; point to status register
  290. rswait:    
  291.     in        al,dx                ; get status
  292.     and        al,TX_READY            ; is ready to transmit?
  293.     je        rswait                ; no. loop and wait.
  294.     pop        dx                    ; load device address
  295.     pop        ax
  296.     add        dx,NS16450_DATA        ; point to data register
  297.     out        dx,al                ; output data to port
  298.     pop        dx
  299.     ret
  300. _putSerial    endp
  301.  
  302. ;
  303. ; initPortBuffer()  buffer initialize
  304. ;
  305.     public    _initPortBuffer
  306. _initPortBuffer proc far
  307.     mov    ax,offset ds:buffer
  308.     mov    cs:head,ax
  309.     mov    cs:tail,ax
  310.     ret
  311. _initPortBuffer endp
  312.  
  313. ;
  314. ; disable receive interrupt
  315. ;
  316. disable:
  317.     cli
  318.     in    al,I8259_IMR        ; read current value of mask register
  319.     or    al,ds:_offMask        ; disable RS interrupt
  320.     out    I8259_IMR,al        ; write it into mask register
  321.     sti
  322.     ret
  323. ;
  324. ; enable receive interrupt
  325. ;
  326. enable:
  327.     cli
  328.     in    al,I8259_IMR        ; read current mask
  329.     and    al,ds:_onMask        ; enable RS interrupt
  330.     out    I8259_IMR,al        ; set mask
  331.     sti
  332.     ret
  333. ;
  334. ; short getSerial() get a char from the buffer
  335. ;
  336.     public    _getSerial
  337. _getSerial proc far
  338.     push    di
  339.     push    si
  340.     call    disable        ; disable RS interrupt
  341.  
  342.     mov    si,cs:head
  343.     mov    di,cs:tail
  344.     cmp    si,di
  345.     jne    sd1        ; jump if head != tail (buffer has some data)
  346.  
  347.     cmp    cs:full,TRUE
  348.     je    sd2        ; jump if the buffer is full
  349.  
  350.                 ; otherwise, buffer is empty
  351.     call    enable        ; enable RS interrupt
  352.     mov    ax,-1        ; return(buffer is empty)
  353.     pop    si
  354.     pop    di
  355.     ret
  356.  
  357.                 ; case that the buffer is full
  358. sd2:    mov    cs:full,FALSE    ; buffer will become to have a room
  359.     cld
  360. sd1:                ; case that the buffer has data
  361.     lodsb            ; al <- head (get the top byte)
  362.     mov    ah,ds:_cMask
  363.     and    al,ah            ;mask char
  364.     mov    ah,0
  365.     push    ax        ; now ax has the byte read from ring buffer
  366.     cmp    si,offset ds:buffer+BUFSIZE    ; if head has exceeded the end
  367.     jne    sd3                ; of the ring buffer, rewind
  368.     mov    si,offset ds:buffer        ; it to the top
  369.  
  370. sd3:
  371.     mov    cs:head,si    ; save the value of head
  372.     cmp    cs:xoffed,NO
  373.     je    sd4
  374.                 ; now is XOFFed state
  375.     call    getsize        ; get the size of data in the buffer
  376.     cmp    ax,ONLIMIT    ; if it is less than ONLIMIT,
  377.     jge    sd4
  378.     call    dc1        ; send XON or assert RTS
  379.  
  380.     mov    cs:xoffed,FALSE    ; and is not XOFFed state
  381.  
  382. sd4:    call    enable        ; enable RS interrupt
  383.     pop    ax        ; restore ax... is the byte from ring buffer
  384.     pop    si
  385.     pop    di
  386.     ret            ; returns the byte from ring buffer
  387. _getSerial endp
  388.  
  389. ;
  390. ; checkSerial() check serial buffer
  391. ; if empty return 0
  392. ;
  393.     public    _checkSerial
  394. _checkSerial proc far
  395.     cli
  396.     push    di
  397.     push    si
  398.     mov    ax,YES            ; prepare buffer not empty
  399.     mov    si,cs:head
  400.     mov    di,cs:tail
  401.     cmp    si,di            ; ? head == tail
  402.     jne    checkK2            ; bra if no
  403.     mov    ax,NO            ; flag buffer empty
  404. checkK2:
  405.     pop    si
  406.     pop    di
  407.     sti
  408.     ret
  409. _checkSerial endp
  410.  
  411. ;
  412. ; getMouseInterruptHandlerAddress
  413. ;
  414.     public _getMouseIntAddress
  415. _getMouseIntAddress proc    far
  416.     mov    cs:htermDS,ds    ; save DS for later use
  417.     mov    ax,offset cs:mouseInterruptHandler
  418.     mov    dx,cs        ; return the address
  419.     ret
  420. _getMouseIntAddress endp
  421.  
  422. ;
  423. ; mouseInterruptHandler()
  424. ; this procedures is called by far call from mouse driver
  425. ;
  426.     public mouseInterruptHandler
  427. mouseInterruptHandler proc    far
  428.     push    es
  429.     push    ss
  430.     push    ds
  431.     push    ax
  432.     push    bx
  433.     push    cx
  434.     push    dx            ; save registers
  435.  
  436.     push    dx            ; y
  437.     push    cx            ; x
  438.     push    ax            ; event (arg may be changed)
  439.     mov    ds,cs:htermDS
  440.     call    far ptr _mouseEvent    ; call C part
  441.     add    sp,6
  442. ; for debug
  443. ;    mov    al,07h
  444. ;    out    037h,al            ; stop bell
  445.  
  446.     pop    dx
  447.     pop    cx
  448.     pop    bx
  449.     pop    ax
  450.     pop    ds
  451.     pop    ss
  452.     pop    es
  453.     ret
  454. mouseInterruptHandler endp
  455.  
  456. _TEXT    ends
  457.     end
  458.