home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / modem / com_pkg1.arc / COM_PKG1.ASM
Assembly Source File  |  1984-04-20  |  12KB  |  433 lines

  1.     title    COM_PKG1
  2.     page    60,132
  3. ;
  4. ; COM_PKG1.ASM library of serial I/O routines
  5. ; For the IBM PC's first serial port
  6. ; Uses Microsoft Pascal calling conventions
  7. ; See GLASSTTY.PAS for sample driver program
  8. ;
  9. ; Adapted from code by John Romkey and Jerry Saltzer of MIT
  10. ; by Richard Gillmann (GILLMANN@ISIB), 1983
  11. ;
  12. ; Package entry points (MS Pascal calling conventions) are:
  13. ;
  14. ; init_au(divisor:word)    initializes port and interrupt vector
  15. ; close_a        turns off interrupts from the aux port
  16. ; dtr_off        turns off dtr
  17. ; dtr_on        turns on dtr
  18. ; crcnt : word        returns number of characters in input buffer
  19. ; cread : byte        reads next character in input buffer
  20. ; cwcnt : word        returns number of free bytes in output buffer
  21. ; cwrit(ch:byte)    writes a character to the output buffer
  22. ; wlocal(ch:byte)    writes a character to the input buffer
  23. ; make_br        causes a break to be sent
  24. ;
  25.     page
  26. rsize    equ    2048        ; size of receive buffer
  27. tsize    equ    256        ; size of transmit buffer
  28. base    equ    3f0h        ; base of address of aux. port registers
  29. int    equ    0ch        ; interrupt number for aux port
  30. int_off    equ    int*4        ; offset of interrupt vector
  31. datreg    equ    base + 8h    ; data register
  32. dll    equ    base + 8h    ; low divisor latch
  33. dlh    equ    base + 9h    ; high divisor latch
  34. ier    equ    base + 9h    ; interrupt enable register
  35. iir    equ    base + 0ah    ; interrupt identification register
  36. lcr    equ    base + 0bh    ; line control register
  37. mcr    equ    base + 0ch    ; modem control register
  38. lsr    equ    base + 0dh    ; line status register
  39. msr    equ    base + 0eh    ; modem status register
  40. dla    equ    80h        ; divisor latch access
  41. mode    equ    03h        ; 8-bits, no parity
  42. dtr    equ    0bh        ; bits to set dtr line
  43. dtr_of    equ    00h        ; turn off dtr, rts, and the interupt driver
  44. thre    equ    20h        ; mask to find status of xmit holding register
  45. rxint    equ    01h        ; enable data available interrupt
  46. txint    equ    02h        ; enable tx holding register empty interrupt
  47. tcheck    equ    20h        ; mask for checking tx reg status on interrupt
  48. rcheck    equ    01h        ; mask for checking rx reg status on interrupt
  49. imr    equ    21h        ; interuprt mask register
  50. int_mask equ    0efh        ; mask to clear bit 4
  51. int_pend equ    01h        ; there is an interrupt pending
  52. mstat    equ    00h        ; modem status interrupt
  53. wr    equ    02h        ; ready to xmit data
  54. rd    equ    04h        ; received data interrupt
  55. lstat    equ    06h        ; line status interrupt
  56. ack    equ    244        ; acknowledge symbol
  57. parity    equ    7fh        ; bits to mask off parity
  58. ocw2    equ    20h        ; operational control word on 8259
  59. eoi    equ    64h        ; specific end of interrupt 4
  60. break    equ    40h        ; bits to cause break
  61. true    equ    1        ; truth
  62. false    equ    0        ; falsehood
  63.     page
  64. data    segment public 'data'
  65. int_offset    dw    0    ; the original interrupt offset
  66. int_segment    dw    0    ; the original interrupt segment
  67. start_tdata    dw    0    ; index to first character in x-mit buffer
  68. end_tdata    dw    0    ; index to first free space in x-mit buffer
  69. size_tdata    dw    0    ; number of characters in x-mit buffer
  70. start_rdata    dw    0    ; index to first character in rec. buffer
  71. end_rdata    dw    0    ; index to first free space in rec. buffer
  72. size_rdata    dw    0    ; number of characters in rec. buffer
  73. tdata        db    tsize dup(?)    ; transmit buffer
  74. rdata        db    rsize dup(?)    ; receive buffr
  75. data    ends
  76. dgroup    group    data
  77.     page
  78.     assume    cs:auxhndlr,ds:dgroup,ss:dgroup
  79. auxhndlr segment 'code'
  80.  
  81.     public    init_au        ; initializes port and interrupt vector
  82.     public    close_a        ; turns off interrupts from the aux port
  83.     public    dtr_off        ; turns off dtr
  84.     public    dtr_on        ; turns on dtr
  85.     public    crcnt        ; returns number of characters in input buffer
  86.     public    cread        ; reads next character in input buffer
  87.     public    cwcnt        ; returns no. of free bytes in output buffer
  88.     public    cwrit        ; writes a character to output buffer
  89.     public    wlocal        ; writes a character to the input buffer
  90.     public    make_br        ; causes a break to be sent
  91.     page
  92. ;
  93. ; int_hndlr - handles interrupts generated by the aux. port
  94. ;
  95. dataseg    dw    0
  96. int_hndlr proc    far
  97.     push    bp
  98.     push    ds
  99.     push    di
  100.     push    ax
  101.     push    bx
  102.     push    cx
  103.     push    dx
  104.  
  105. ; set up data segment
  106.     mov    ax,cs:dataseg
  107.     mov    ds,ax
  108.  
  109. ; find out where interrupt came from and jump to routine to handle it
  110.     mov     dx,iir
  111.     in    al,dx
  112.     cmp     al,rd
  113.     jz      rx_int        ; if it's from the receiver
  114.     cmp     al,wr
  115.     jz      tx_int          ; if it's from the transmitter
  116.     cmp     al,lstat
  117.     jz      lstat_int       ; interrupt becuase of line status
  118.     cmp     al,mstat
  119.     jz      mstat_int       ; interrupt because of modem status
  120.     jmp     far ptr int_end    ; interrupt when no interrupt pending, go away
  121.  
  122. lstat_int:
  123.     mov     dx,lsr        ; clear interrupt
  124.     in    al,dx
  125.     jmp     repoll        ; see if any more interrupts
  126.  
  127. mstat_int:
  128.     mov     dx,msr        ; clear interrupt
  129.     in    al,dx
  130.     jmp     repoll          ; see if any more interrupts
  131.  
  132. tx_int:
  133.     mov     dx,lsr
  134.     in    al,dx
  135.     and     al,tcheck
  136.     jnz     goodtx          ; good interrupt
  137.     jmp     repoll          ; see if any more interrupts
  138.  
  139. goodtx: cmp     size_tdata,0    ; see if any more data to send
  140.     jne     have_data       ; if not equal then there is data to send
  141.  
  142. ; if no data to send then reset tx interrupt and return
  143.     mov     dx,ier
  144.     mov     al,rxint
  145.     out    dx,al
  146.     jmp     repoll
  147.  
  148. have_data:
  149.     mov     bx,start_tdata    ; bx points to next char. to be sent
  150.     mov     dx,datreg    ; dx equals port to send data to
  151.     mov     al,tdata[bx]    ; get data from buffer
  152.     out     dx,al        ; send data
  153.     inc     bx              ; increment start_tdata
  154.     cmp     bx,tsize    ; see if gone past end
  155.     jl      ntadj           ; if not then skip
  156.     sub     bx,tsize    ; reset to beginning
  157. ntadj:  mov     start_tdata,bx  ; save start_tdata
  158.     dec     size_tdata      ; one less character in x-mit buffer
  159.     jmp     repoll
  160.  
  161. rx_int:
  162.     mov     dx,lsr        ; check and see if read is real
  163.     in    al,dx
  164.     and     al,rcheck    ; look at receive data bit
  165.     jnz     good_rx         ; real, go get byte
  166.     jmp     repoll          ; go look for other interrupts
  167.  
  168. good_rx:
  169.     mov     dx,datreg
  170.     in      al,dx        ; get data
  171.     cmp     size_rdata,rsize    ; see if any room
  172.     jge    repoll          ; if no room then look for more interrupts
  173.     mov     bx,end_rdata    ; bx points to free space
  174.     mov     rdata[bx],al    ; send data to buffer
  175.     inc     size_rdata      ; got one more character
  176.     inc     bx              ; increment end_rdata pointer
  177.     cmp     bx,rsize    ; see if gone past end
  178.     jl      nradj           ; if not then skip
  179.     sub     bx,rsize    ; else adjust to beginning
  180. nradj:  mov     end_rdata,bx    ; save value
  181.  
  182. repoll:
  183.     mov     dx,lsr        ; we always expect receive data, so
  184.     in      al,dx        ; check status to see if any is ready.
  185.     and     al,rcheck    ; get received data bit
  186.     jnz     good_rx         ; yes, go accept the byte
  187.  
  188.     mov     dx,ier        ; look at transmit condition
  189.     in      al,dx        ; to see if we are enabled to send data
  190.     and     al,txint
  191.     jz      int_end        ; not enabled, so go away
  192.     mov     dx,lsr        ; we are enabled, so look for tx condition
  193.     in    al,dx
  194.     and     al,tcheck
  195.     jz    int_end
  196.     jmp    goodtx          ; transmitter is finished, go get more data
  197.  
  198. int_end:
  199.     mov     dx,ocw2        ; tell the 8259 that I'm done
  200.     mov     al,eoi
  201.     out    dx,al
  202.  
  203.     pop     dx
  204.     pop     cx
  205.     pop     bx
  206.     pop     ax
  207.     pop     di
  208.     pop     ds
  209.     pop     bp
  210.     iret
  211. int_hndlr endp
  212.     page
  213. ;
  214. ; init_au(divisor:word)
  215. ; initialize the Intel 8250 and set up interrupt vector to int_hndlr
  216. ; divisor is the divisor for the baud rate generator
  217. ;
  218. init_au    proc    far
  219.     push    bp
  220.     mov     bp,sp
  221.     cli
  222.  
  223.     mov    ax,ds
  224.     mov    cs:dataseg,ax
  225.  
  226. ; reset the UART
  227.     mov     al,0
  228.     mov     dx,mcr
  229.     out    dx,al
  230.  
  231.     mov     dx,lsr        ; reset line status condition
  232.     in    al,dx
  233.     mov     dx,datreg    ; reset recsive data condition
  234.     in    al,dx
  235.     mov     dx,msr        ; reset modem deltas and conditions
  236.     in    al,dx
  237.  
  238. ; set baud rate with the passed argument
  239.     mov     dx,lcr
  240.     mov     al,dla+mode
  241.     out    dx,al
  242.     mov     dx,dll
  243.     mov     al,6[bp]    ; low byte of passed argument
  244.     out    dx,al
  245.     mov     dx,dlh
  246.     mov     al,7[bp]    ; high byte of passed argument
  247.     out    dx,al
  248.  
  249. ; set 8250 to 8 bits, no parity
  250.     mov     dx,lcr
  251.     mov     al,mode
  252.     out    dx,al
  253.  
  254. ; set interrupt vector
  255.     push    ds
  256.     mov     ax,0
  257.     mov     ds,ax
  258.     mov     bx,ds:int_off
  259.     mov     cx,ds:int_off+2
  260.     mov     word ptr ds:int_off,offset int_hndlr
  261.     mov     ds:int_off+2,cs
  262.     pop     ds
  263.     mov     int_offset,bx
  264.     mov     int_segment,cx
  265.  
  266. ; enable interrupts on 8259 and 8250
  267.     in      al,imr        ; set enable bit on 8259
  268.     and     al,int_mask
  269.     out     imr,al
  270.     mov     dx,ier        ; enable interrupts on 8250
  271.     mov     al,rxint
  272.     out    dx,al
  273.     mov     dx,mcr        ; set dtr and enable int driver
  274.     mov     al,dtr
  275.     out    dx,al
  276.  
  277.     sti
  278.     pop     bp
  279.     ret    2
  280. init_au    endp
  281.     page
  282. ;
  283. ; close_a - turns off interrupts from the auxiliary port
  284. ;
  285. close_a    proc    far
  286. ; turn off 8250
  287.     mov     dx,ier
  288.     mov     al,0
  289.     out    dx,al
  290.  
  291. ; turn off 8259
  292.     mov     dx,imr
  293.     in    al,dx
  294.     or      al,not int_mask
  295.     out    dx,al
  296.  
  297. ; reset interrupt vector
  298.     cli
  299.     mov     bx,int_offset
  300.     mov     cx,int_segment
  301.     push    ds
  302.     mov     ax,0
  303.     mov     ds,ax
  304.     mov     ds:int_off,bx
  305.     mov     ds:int_off+2,cx
  306.     pop     ds
  307.     sti
  308.     ret
  309. close_a    endp
  310.     page
  311. ;
  312. ; dtr_off - turns off dtr to tell modems that the terminal has gone away
  313. ;           and to hang up the phone
  314. ;
  315. dtr_off    proc    far
  316.     mov     dx,mcr
  317.     mov     al,dtr_of
  318.     out    dx,al
  319.     ret
  320. dtr_off    endp
  321. ;
  322. ; dtr_on - turns dtr on
  323. ;
  324. dtr_on    proc    far
  325.     mov     dx,mcr
  326.     mov     al,dtr
  327.     out    dx,al
  328.     ret
  329. dtr_on    endp
  330.     page
  331. ;
  332. ; crcnt - returns number of bytes in the receive buffer
  333. ;
  334. crcnt    proc    far
  335.     mov     ax,size_rdata    ; get number of bytes used
  336.     ret
  337. crcnt    endp
  338. ;
  339. ; cread - returns the next character from the receive buffer and
  340. ;         removes it from the buffer
  341. ;
  342. cread    proc    far
  343.     mov     bx,start_rdata
  344.     mov     al,rdata[bx]
  345.     mov     ah,0
  346.     inc     bx              ; bump start_rdata so it points at next char
  347.     cmp     bx,rsize    ; see if past end
  348.     jl      L12             ; if not then skip
  349.     sub     bx,rsize    ; adjust to beginning
  350. L12:    mov     start_rdata,bx  ; save the new start_rdata value
  351.     dec     size_rdata      ; one less character
  352.     ret
  353. cread    endp
  354.     page
  355. ;
  356. ; cwcnt - returns the amount of free space remaining in the transmit buffer
  357. ;
  358. cwcnt    proc    far
  359.     mov     ax,tsize    ; get the size of the x-mit buffer
  360.     sub     ax,size_tdata   ; subtract the number of bytes used
  361.     ret
  362. cwcnt    endp
  363. ;
  364. ; cwrit(ch:byte) - the passed character is put in the transmit buffer
  365. ;
  366. cwrit    proc    far
  367.     push    bp
  368.     mov     bp,sp
  369.     mov     bx,end_tdata    ; bx points to free space
  370.     mov     al,6[bp]    ; move data from stack to x-mit buffer
  371.     mov     tdata[bx],al
  372.     inc     bx              ; increment end_tdata to point to free space
  373.     cmp     bx,tsize    ; see if past end
  374.     jl      L4              ; if not then skip
  375.     sub     bx,tsize    ; adjust to beginning
  376. L4:     mov     end_tdata,bx    ; save new end_tdata
  377.     inc     size_tdata      ; one more character in x-mit buffer
  378.     mov     dx,ier        ; see if tx interrupts are enabled
  379.     in    al,dx
  380.     and     al,txint
  381.     or      al,al
  382.     jnz     L44
  383.     mov     al,rxint+txint    ; if not then set them
  384.     out    dx,al
  385. L44:    pop     bp
  386.     ret    2
  387. cwrit    endp
  388. ;
  389. ; wlocal(ch:byte) - writes a character to the input buffer
  390. ;
  391. wlocal    proc    far
  392.     push    bp
  393.     mov     bp,sp
  394.     cli
  395.  
  396.     cmp     size_rdata,rsize    ; see if any room
  397.     jge    L14        ; if no room then quit
  398.     mov     bx,end_rdata    ; bx points to free space
  399.     mov     al,6[bp]    ; get data
  400.     mov     rdata[bx],al    ; send data to buffer
  401.     inc     size_rdata      ; got one more character
  402.     inc     bx              ; increment end_rdata pointer
  403.     cmp     bx,rsize    ; see if gone past end
  404.     jl      L13             ; if not then skip
  405.     sub     bx,rsize    ; else adjust to beginning
  406. L13:    mov     end_rdata,bx    ; save value
  407.  
  408. L14:    sti
  409.     pop     bp
  410.     ret    2
  411. wlocal    endp
  412.     page
  413. ;
  414. ; make_break - causes a break to be sent out on the line
  415. ;
  416. make_br    proc    far
  417.     mov     dx,lcr        ; save the line control register
  418.     in    al,dx
  419.     mov     bl,al
  420.             
  421.     mov     al,break    ; set break condition
  422.     out    dx,al
  423.  
  424.     mov     cx,0        ; wait a while
  425. wait:   loop    wait
  426.  
  427.     mov     al,bl           ; restore the line control register
  428.     out    dx,al
  429.     ret
  430. make_br    endp
  431. auxhndlr ends
  432.     end
  433.