home *** CD-ROM | disk | FTP | other *** search
/ Hacker Chronicles 2 / HACKER2.BIN / 884.PRMBIO.98T / QUADBIOS.ASM < prev   
Assembly Source File  |  1987-01-04  |  34KB  |  1,026 lines

  1.         PAGE    60,132
  2.         TITLE   QUADBIOS - Serial interface (5 port Quadram Quadport)
  3. ;--------------------------------------------------------------------------;
  4. ;                                                                          ;
  5. ;Interupt driven RS232 serial port routines.                               ;
  6. ; these routines replace the BIOS rs232 calls with a version that has      ;
  7. ; interupt driven character receive, and can thus operate at considerably  ;
  8. ;  higher speeds than the standard bios calls (int 14h).                   ;
  9. ;                                                                          ;
  10. ;This version for the Quadram Quadport board                               ;
  11. ;--------------------------------------------------------------------------;
  12.  
  13. ;--------------------------------------------------------------------------;
  14. ; Set up the works                                                         ;
  15. ;--------------------------------------------------------------------------;
  16.  
  17. everything SEGMENT PUBLIC
  18.       ASSUME CS: everything           ; These assumptions are for the
  19.       ASSUME DS: everything           ; assembler's benefit.  The code
  20.       ASSUME ES: nothing              ; jerks things around as it pleases
  21.       ASSUME SS: nothing              ;
  22.  
  23. ;--------------------------------------------------------------------------;
  24. ; Program start and buffer declares                                        ;
  25. ;--------------------------------------------------------------------------;
  26.  
  27.           ORG     100H
  28. foo:      JMP     start               ; Entry point
  29.  
  30.           ORG     0                   ; Back up so we can use this all as
  31.                                       ; buffer space
  32.  
  33. ;--------------------------------------------------------------------------;
  34. ; Area where things are declared                                           ;
  35. ;--------------------------------------------------------------------------;
  36.  
  37. buffer_size EQU 1024                  ; Bytes in each buffer
  38. buffer_full EQU  950                  ; Max count before handshaking
  39.  
  40. dummy:                                ; Dummy labels to provide a structure
  41.  
  42. buffer    DB      buffer_size dup(?)  ; Buffer (1 per com card)
  43. buffer_e:                             ; End of buffer
  44. comnumber DB      ?                   ; Comm number - 1
  45. flags     DB      ?                   ; Flag byte
  46. last_rs   DB      ?                   ; Last receive status
  47. baseaddr  DW      ?                   ; Base port address
  48. count     DW      ?                   ; # of chars in buffer
  49. buffer_in DW      ?                   ; Buffer in pointer
  50. buffer_out DW     ?                   ; Buffer out pointer
  51. dummy_end:
  52.  
  53.           ORG     dummy               ; Back up over this
  54. ;--------------------------------------------------------------------------;
  55. ; These are the things to work with                                        ;
  56. ;--------------------------------------------------------------------------;
  57.  
  58. number_of_com EQU 5                   ; Number of com ports
  59.  
  60.  
  61.           DB      buffer_size dup(?)  ; Buffer (1 per com card)
  62.           DB      2                   ; Com number
  63.           DB      0                   ; Flags
  64.           DB      0                   ; Last receive status
  65.           DW      0                  ; Base port address
  66.           DW      0                   ; # of chars in buffer
  67.           DW      ?                   ; Buffer in pointer
  68.           DW      ?                   ; Buffer out pointer
  69.  
  70.  
  71.           DB      buffer_size dup(?)  ; Buffer (1 per com card)
  72.           DB      3                   ; Com number
  73.           DB      0                   ; Flags
  74.           DB      0                   ; Last receive status
  75.           DW      10H                 ; Base port address
  76.           DW      0                   ; # of chars in buffer
  77.           DW      ?                   ; Buffer in pointer
  78.           DW      ?                   ; Buffer out pointer
  79.  
  80.  
  81.           DB      buffer_size dup(?)  ; Buffer (1 per com card)
  82.           DB      4                   ; Com number
  83.           DB      0                   ; Flags
  84.           DB      0                   ; Last receive status
  85.           DW      20H                 ; Base port address
  86.           DW      0                   ; # of chars in buffer
  87.           DW      ?                   ; Buffer in pointer
  88.           DW      ?                   ; Buffer out pointer
  89.  
  90.  
  91.           DB      buffer_size dup(?)  ; Buffer (1 per com card)
  92.           DB      5                   ; Com number
  93.           DB      0                   ; Flags
  94.           DB      0                   ; Last receive status
  95.           DW      30H                 ; Base port address
  96.           DW      0                   ; # of chars in buffer
  97.           DW      ?                   ; Buffer in pointer
  98.           DW      ?                   ; Buffer out pointer
  99.  
  100.  
  101.           DB      buffer_size dup(?)  ; Buffer (1 per com card)
  102.           DB      6                   ; Com number
  103.           DB      0                   ; Flags
  104.           DB      0                   ; Last receive status
  105.           DW      40H                 ; Base port address
  106.           DW      0                   ; # of chars in buffer
  107.           DW      ?                   ; Buffer in pointer
  108.           DW      ?                   ; Buffer out pointer
  109.  
  110. comend:                               ; Marker for last com port
  111.  
  112. ;--------------------------------------------------------------------------;
  113. ; Hardware constants                                                       ;
  114. ;--------------------------------------------------------------------------;
  115.  
  116. pic_cmd_port     EQU       020H   ; 8259 interrupt controller command address
  117. pic_mask_port    EQU       021H   ; 8259 interrupt controller mask address
  118.  
  119. ;--------------------------------------------------------------------------;
  120. ; 8250 hardware constants                                                  ;
  121. ;--------------------------------------------------------------------------;
  122.  
  123. rbr_8250         EQU 00H   ;       xF8   Receive Buffer Register
  124. thr_8250         EQU 00H   ;       xF8   Transmitter Holding Register
  125. ier_8250         EQU 01H   ;       xF9   Interrupt Enable Register
  126. iir_8250         EQU 02H   ;       xFA   Interrupt Identification Register
  127. lcr_8250         EQU 03H   ;       xFB   Line Control Register
  128. mcr_8250         EQU 04H   ;       xFC   Modem Control Register
  129. lsr_8250         EQU 05H   ;       xFD   Line Status Register
  130. msr_8250         EQU 06H   ;       xFE   Modem Status Register
  131. dll_8250         EQU 00H   ;       xF8   Divisor Latch Least Significant
  132. dlm_8250         EQU 01H   ;       xF9   Divisor Latch Most  Significant
  133.  
  134. ;--------------------------------------------------------------------------;
  135. ; Other constants                                                          ;
  136. ;--------------------------------------------------------------------------;
  137.  
  138. CR    EQU 0DH                           ; Carriage Return
  139. LF    EQU 0AH                           ; Line Feed
  140.  
  141. ;--------------------------------------------------------------------------;
  142. ; Static variables                                                         ;
  143. ;--------------------------------------------------------------------------;
  144.  
  145. old_bios_vector   DW  ?            ; Save previous interrupt vector
  146.                   DW  ?            ;
  147.  
  148. QINTR    DW    0    ;CONTAINS 2D3 IF 280 BOARD IS IN
  149.             ;OR 2DB if 288 board is in
  150. MQUAD    DB    0    ;CONTAINS 1 OR 2 DEPENDING WHICH INT TO USE
  151. QBASE    DW    0280H    ;Base address of Quadboard
  152. M8259    DB    0FFH    ;MASK USED TO SET 8259 INTERRUPT ENABLE
  153.  
  154. divisor_table LABEL WORD            ;
  155.         DW      1047                ; 110
  156.         DW      768                 ; 150
  157.         DW      384                 ; 300
  158.         DW      192                 ; 600
  159.         DW      96                  ; 1200
  160.         DW      48                  ; 2400
  161.         DW      24                  ; 4800
  162.         DW      12                  ; 9600
  163.  
  164.  
  165. ;--------------------------------------------------------------------------;
  166. ; Our BIOS handler                                                         ;
  167. ;--------------------------------------------------------------------------;
  168.  
  169. rsint:
  170.  
  171.         ASSUME DS: NOTHING         ; Don't use DS
  172.         ASSUME ES: NOTHING         ; Don't use ES
  173.         ASSUME SS: NOTHING         ; Don't use SS
  174.  
  175.  
  176. ;--------------------------------------------------------------------------;
  177. ; See if this is our vector?                                               ;
  178. ;--------------------------------------------------------------------------;
  179.  
  180.         STI                         ; Not disabled
  181.         PUSH    BP                  ; Save BP over our loop
  182.         XOR     BP,BP               ;
  183.  
  184. com_srch_loop:                      ;
  185.  
  186.         CMP     DL,CS:comnumber[BP] ; Is this our port?
  187.         JE      rsint_ours          ; Yes...
  188.  
  189.         ADD     BP,OFFSET dummy_end ; Increment to next com port block
  190.  
  191.         CMP     BP,OFFSET comend    ; Anything left to be checked?
  192.         JL      com_srch_loop       ; Yep....
  193.  
  194. ;--------------------------------------------------------------------------;
  195. ; Not us.. Pop things out and call regular handler                         ;
  196. ;--------------------------------------------------------------------------;
  197.  
  198. not_us:
  199.  
  200.         POP     BP                  ; Pop BP
  201.         JMP     CS:DWORD PTR old_bios_vector
  202.  
  203. ;--------------------------------------------------------------------------;
  204. ; BP now contains the pointer to the com block...  See what                ;
  205. ; the user has requested and we may or may not do it.......                ;
  206. ;--------------------------------------------------------------------------;
  207.  
  208. rsint_ours:
  209.  
  210.         PUSH    DX                  ; We need the DX register
  211.         PUSH    CX                  ; We need the CX register
  212.         PUSH    BX                  ; We need the BX register
  213.  
  214.         MOV     CX,Qbase        ; Get base address for chip
  215.         ADD     CX,baseaddr[BP]     ; Get base address for chip
  216.  
  217.         OR      AH,AH               ; Initialize
  218.         JE      rsint_init          ; Yes...
  219.  
  220.         DEC     AH                  ; 1 = Send character
  221.         JZ      rsint_send
  222.  
  223.         DEC     AH                  ; 2 = Receive character
  224.         JZ      rsint_recv_jmp
  225.  
  226.         DEC     AH                  ; 3 = Status request
  227.         JZ      rsint_status_jmp
  228.  
  229.         DEC     AH                  ; 4 = Inquiry         
  230.         JZ      rsint_inquiry_jmp
  231.  
  232.         DEC     AH                  ; 5 = Drop RTS         
  233.         JZ      rsint_RTS_off_jmp
  234.  
  235.         DEC     AH                  ; 6 = Raise RTS         
  236.         JZ      rsint_RTS_on_jmp
  237.  
  238.         DEC     AH                  ; 7 = Send break
  239.         JZ      rsint_break_jmp
  240.  
  241.         DEC     AH                  ; 8 = Non-destructive read
  242.         JNZ     rsint_exit          ;      Nope..
  243.         JMP     rsint_nd_recv       ;      Yep..
  244.  
  245. rsint_recv_jmp:
  246.     JMP     rsint_recv
  247. rsint_status_jmp:
  248.     JMP     rsint_status
  249. rsint_inquiry_jmp:
  250.     JMP     rsint_inquiry
  251. rsint_RTS_off_jmp:
  252.     JMP     rsint_RTS_off
  253. rsint_RTS_on_jmp:
  254.     JMP     rsint_RTS_on
  255. rsint_break_jmp:
  256.         JMP     rsint_break
  257.  
  258. ;--------------------------------------------------------------------------;
  259. ; Interrupt exit                                                           ;
  260. ;--------------------------------------------------------------------------;
  261.  
  262. rsint_exit:
  263.  
  264.         POP     BX                  ; Restore registers
  265.         POP     CX                  ;
  266.         POP     DX                  ;
  267.         POP     BP                  ;
  268.         IRET                        ;      and leave
  269.  
  270. ;--------------------------------------------------------------------------;
  271. ; Init..                                                                   ;
  272. ;--------------------------------------------------------------------------;
  273.  
  274. rsint_init:
  275.  
  276.  
  277.         MOV     AH,AL               ; Save the parms for later
  278.  
  279.         MOV     BL,AH               ; Look up the baud rate
  280.         MOV     CL,4                ; parameter
  281.         ROL     BL,CL               ;
  282.         AND     BX,0EH              ;
  283.         MOV     BX,divisor_table[BX] ;
  284.  
  285.         MOV     CX,Qbase        ; Get base address for chip
  286.         ADD     CX,baseaddr[BP]     ; Get base address for chip
  287.         MOV     DX,CX               ; Address of LCR
  288.         ADD     DX,lcr_8250         ;
  289.         MOV     AL,10000000B        ; Enable access to divisor
  290.         OUT     DX,AL               ;
  291.  
  292.         MOV     DX,CX               ; Address of lower divisior half
  293.         ADD     DX,dll_8250         ;
  294.         MOV     AL,BL               ; Put lower half
  295.         OUT     DX,AL               ;
  296.  
  297.         MOV     DX,CX               ; Address of upper divisior half
  298.         ADD     DX,dlm_8250         ;
  299.         MOV     AL,BH               ; Put upper half
  300.         OUT     DX,AL               ;
  301.  
  302.         MOV     AL,AH               ; Get parms back
  303.         AND     AL,01FH             ; Throw away baud rate
  304.         MOV     DX,CX               ; Address of LCR
  305.         ADD     DX,lcr_8250         ;
  306.         OUT     DX,AL               ; Output the parms
  307.  
  308.         JMP     rsint_status        ; Now just status please
  309.  
  310. ;--------------------------------------------------------------------------;
  311. ; Send a character                                                         ;
  312. ;--------------------------------------------------------------------------;
  313.  
  314. rsint_send:
  315.  
  316.         MOV     AH,AL               ; Save the character to send
  317.  
  318. rsint_send_loop:                    ; Loop here until we can send
  319.  
  320.         MOV     DX,CX               ; Compute port address for the MSR
  321.         ADD     DX,msr_8250         ;      and then
  322.         IN      AL,DX               ;      get it into AX
  323.         AND     AL,00110000B        ; CTS & DSR?
  324.         CMP     AL,00110000B        ; 
  325.     JNE    rsint_send_loop
  326.  
  327.         MOV     DX,CX               ; Compute port address for the LSR
  328.         ADD     DX,lsr_8250         ;      and then
  329.         IN      AL,DX               ;      get itinto AX
  330.         TEST    AL,00100000B        ; THR empty?
  331.         JZ      rsint_send_loop     ;      No.. Loop back
  332.  
  333.         MOV     AL,AH               ; Get ready to out character
  334.  
  335.         MOV     DX,CX               ; Compute port address for the THR
  336. ;       ADD     DX,thr_8250         ;      and then
  337.         OUT     DX,AL               ;      out the character
  338.  
  339.         JMP     rsint_status        ; Do a status
  340.  
  341. ;--------------------------------------------------------------------------;
  342. ; Receive a character                                                      ;
  343. ;--------------------------------------------------------------------------;
  344.  
  345. rsint_recv:
  346.  
  347.         MOV     BX,buffer_out[BP]   ; Get buffer output pointer
  348.  
  349. rsint_recv_loop:
  350.  
  351.         CMP     count[BP],0         ; See in anything in buffer
  352.         JE      rsint_recv_loop     ; Wait for it
  353.  
  354. rsint_get_char:
  355.         MOV     AL,CS:[BX]          ; Get character from buffer
  356.         PUSH    AX                  ; Save char
  357.         INC     BX                  ; Bump pointer
  358.         DEC     count[BP]           ; Dec char count
  359.         MOV     DX,OFFSET buffer_e  ; Compute end of buffer
  360.         ADD     DX,BP               ;
  361.         CMP     BX,DX               ; Have we wrapped the buffer?
  362.         JL      test_handshake      ;      No.. All done
  363.         MOV     BX,OFFSET buffer    ;      Yes.. Reset pointer
  364.         ADD     BX,BP               ;
  365. test_handshake:
  366.         cmp     count[BP],80H
  367.         jnb     test_full
  368.         mov     ah,flags[BP]
  369.         test    ah,1
  370.         jz      test_full
  371. roll_hands:
  372.         mov     DX,CX
  373.         add     DX,mcr_8250
  374.         in      AL,DX
  375.           or    AL,00001011B      ; Raise DTR, RTS  & OUT2 
  376.         out     DX,AL
  377.         and     AH,0FEH
  378.         mov     flags[BP],AH
  379.  
  380. test_full:
  381.     POP    AX                  ; Restore Char
  382.  
  383.         MOV     buffer_out[BP],BX   ; Save pointer
  384.         MOV     AH,last_rs[BP]      ; Get last LSR from receive
  385.         AND     AH,11111110B        ; Remove data ready bit
  386.         CMP     count[BP],0         ; Anything left in buffer?
  387.         JE      short_exit          ;      Nope so leave
  388.         OR      AH,00000001B        ; Turn on data ready
  389. short_exit:
  390.         JMP     rsint_exit          ;      and go leave
  391.  
  392. ;--------------------------------------------------------------------------;
  393. ; Non-destructive Receive character                                        ;
  394. ;   (get next character, no pointer updates, no check for character ready) ;
  395. ;--------------------------------------------------------------------------;
  396.  
  397. rsint_nd_recv:
  398.  
  399.         MOV     BX,buffer_out[BP]   ; Get buffer output pointer
  400.         MOV     AL,CS:[BX]          ; Get character from buffer
  401.         JMP     rsint_exit          ;      and go leave
  402.  
  403. ;--------------------------------------------------------------------------;
  404. ; Status..                                                                 ;
  405. ;--------------------------------------------------------------------------;
  406.  
  407. rsint_status:
  408.  
  409.         MOV     DX,CX               ; Compute port address for the LSR
  410.         ADD     DX,lsr_8250         ;      and then
  411.         IN      AL,DX               ;      get it
  412.  
  413.         AND     AL,11111110B        ; Remove data ready bit
  414.  
  415.         CMP     count[BP],0         ; Anything left in buffer?
  416.         JE      rsint_status_nodr   ;      Nope so leave
  417.         OR      AL,00000001B        ; Turn on data ready
  418. rsint_status_nodr:
  419.         MOV     AH,AL               ; Save LSR
  420.  
  421.         MOV     DX,CX               ; Compute port address for the MSR
  422.         ADD     DX,msr_8250         ;      and then
  423.         IN      AL,DX               ;      get it
  424.  
  425.         JMP     rsint_exit          ; All done
  426.  
  427. ;--------------------------------------------------------------------------;
  428. ; Inquiry                                                                  ;
  429. ; (Return AA55H in AX - Just an identification scheme to tell              ;
  430. ;  if this silly driver has been loaded)                                   ;
  431. ;--------------------------------------------------------------------------;
  432.  
  433. rsint_inquiry:
  434.  
  435.         MOV    AX,0AA55H
  436.         JMP     rsint_exit          ;      and go leave
  437.  
  438.  
  439.  
  440. ;--------------------------------------------------------------------------;
  441. ; RTS off                                                                  ;
  442. ; (Drop RTS)                                                               ;
  443. ;--------------------------------------------------------------------------;
  444.  
  445. rsint_RTS_off:
  446.  
  447.         MOV    DX,CX
  448.         add    DX,mcr_8250
  449.         in    AL,DX
  450.           and    AL,11111100B        ; Drop DTR & RTS
  451.           out    DX,AL
  452.         JMP     rsint_exit          ;      and go leave
  453.  
  454. ;--------------------------------------------------------------------------;
  455. ; RTS on                                                                   ;
  456. ; (Raise RTS)                                                              ;
  457. ;--------------------------------------------------------------------------;
  458.  
  459. rsint_RTS_on:
  460.  
  461.         MOV    DX,CX
  462.         add    DX,mcr_8250
  463.         in    AL,DX
  464.           or    AL,00001011B      ; Raise DTR, RTS  & OUT2 
  465.           out    DX,AL
  466.  
  467. ;make sure the interrupt is still turned on
  468.  
  469.         CLI                       ; Disable interrupts
  470.         MOV     DX,CX             ; Compute port address for the IER
  471.         ADD     DX,ier_8250       ;
  472.         MOV     AL,00000001B      ; Enable data interrupt only
  473.         OUT     DX,AL             ;
  474.  
  475. ;while we are at it, lets make sure the 8259 didnt get turned off!
  476.  
  477.         IN      AL,pic_mask_port  ; Set up 8259 interupt controller
  478.         AND     AL,M8259          ; Enable the interrupts for this device
  479.         OUT     pic_mask_port,AL  ;
  480.         STI
  481.  
  482.         JMP     rsint_exit          ;      and go leave
  483.  
  484.  
  485.  
  486. ;--------------------------------------------------------------------------;
  487. ; Send Break                                                               ;
  488. ;                                                                          ;
  489. ;--------------------------------------------------------------------------;
  490.  
  491. rsint_break:
  492.  
  493.         MOV    DX,CX
  494.         add    DX,lcr_8250
  495.         in    AL,DX
  496.           mov    bl,al        ;save old LCR
  497.  
  498.     or      al,40H       ; set break condition
  499.     out    dx,al
  500.      
  501.     mov     cx,0        ; wait a while
  502. bkwait: loop    bkwait
  503.      
  504.     mov     al,bl           ; restore LCR
  505.     out    dx,al
  506.         JMP     rsint_exit      ;      and exit
  507.  
  508.  
  509.  
  510. ;--------------------------------------------------------------------------;
  511. ; 8250 interrupt handler                                                   ;
  512. ;--------------------------------------------------------------------------;
  513.  
  514. serint_2_8250:
  515.  
  516.         PUSH    BP
  517.         PUSH    DX
  518.         PUSH    AX
  519.         mov     dx,Qintr
  520.         in      al,dx
  521.         and     al,00011111B
  522.         jz      exit
  523.  
  524.         mov     BP,0
  525. next_block:
  526.         shr     al,1
  527.         jb      serint_8250
  528.         add     BP,OFFSET dummy_end
  529.         jmp     next_block              
  530.  
  531.  
  532. serint_8250:
  533.  
  534.         PUSH    CX                  ; Save some registers
  535.         PUSH    DI                  ;
  536.  
  537.         MOV     CX,Qbase        ; Get base address for chip
  538.         ADD     CX,baseaddr[BP]     ; Get base address for chip
  539.  
  540.         MOV     DX,CX               ; Get the IIR
  541.         ADD     DX,iir_8250         ;
  542.         IN      AL,DX               ;
  543.  
  544.         TEST    AL,00000001B        ; Interrupt pending?
  545.         JZ      service
  546. exit:   JMP     serint_8250_exit    ;     No leave...
  547.  
  548. service:
  549.         MOV     DX,CX               ; Get the LSR
  550.         ADD     DX,lsr_8250         ;
  551.         IN      AL,DX               ;
  552.         MOV     last_rs[BP],AL      ; And tuck it away
  553.  
  554.         MOV     DX,CX               ; Get the RBR
  555. ;       ADD     DX,rbr_8250         ;
  556.         IN      AL,DX               ;
  557.         MOV     DI,buffer_in[BP]    ; Get the buffer pointer
  558.         MOV     CS:[DI],AL          ; Save the character
  559.         INC     DI                  ; Bump pointer and handle wrap
  560.         inc     count[BP]           ; inc char count
  561.         MOV     AX,OFFSET buffer_e  ;
  562.         ADD     AX,BP               ;
  563.         CMP     DI,AX               ;
  564.         JL      serint_8250_nowrap  ;
  565.         MOV     DI,OFFSET buffer    ;
  566.         ADD     DI,BP               ;
  567.  
  568. serint_8250_nowrap:
  569.  
  570.         cmp    count[BP],buffer_full
  571.         jb     hand_done
  572.         mov    DX,CX
  573.         add    DX,mcr_8250
  574.         in     al,DX
  575.           and    AL,11111100B        ; Drop DTR & RTS
  576.         out    DX,AL
  577.         mov    ah,flags[BP]
  578.         or     AH,1
  579.         mov    flags[BP],AH 
  580.  
  581. hand_done:
  582.      
  583.         CMP     DI,buffer_out[BP]   ; Overflow of buffer?
  584.         JNE     serint_8250_noover  ;
  585.         OR      last_rs[BP],02H     ; Overrun indicate
  586.         JMP     SHORT serint_8250_exit ;  Don't save the updated pointer
  587. serint_8250_noover:
  588.         MOV     buffer_in[BP],DI    ; Save the updated pointer
  589.  
  590. serint_8250_exit:
  591.  
  592.         MOV     AL,020H             ; Tell 8259 we are done
  593.         OUT     pic_cmd_port,AL     ;
  594.     MOV    DX,QINTR            ; Reset Quadport Int
  595.     XOR    AL,AL   
  596.     OUT    DX,AL
  597.     MOV    DX,QINTR
  598.     MOV    AL,MQUAD
  599.     OUT    DX,AL
  600.         POP     DI                  ; Restore registers
  601.         POP     CX                  ;
  602.         POP     AX                  ;
  603.         POP     DX                  ;
  604.         POP     BP                  ;
  605.  
  606.         IRET                        ; Exit
  607.  
  608. program_end:
  609.  
  610.  
  611. ;--------------------------------------------------------------------------;
  612. ; Initialization 
  613. ;--------------------------------------------------------------------------;
  614.  
  615.       ASSUME DS: everything          
  616.  
  617. ;--------------------------------------------------------------------------;
  618. ; Constants only needed by initialization                                  ;
  619. ;--------------------------------------------------------------------------;
  620.  
  621. inter_8250_count DW 0              ; Number of 8250s done * 2
  622.  
  623. DOSPT    DB    0    ;NUMBER OF PORTS
  624. QUAPT    DB    0    ;NUMBER OF PORTS
  625. P3F8     DB    0    ;1 IF CARD AT 3F8
  626. P2F8     DB    0    ;1 IF CARD AT 2F8
  627. P280     DB    0    ;1 IF CARD AT 280
  628. P288     DB    0    ;1 IF CARD AT 288
  629.  
  630. HELLO    DB    CR,LF
  631.     DB    'QUADBIOS - Quadport Driver v1.6',CR,LF
  632.     DB    'Dec 31, 1986'
  633.     DB    CR,LF,'$'
  634.  
  635. BYE      DB    CR,LF
  636.     DB    'Driver Installed OK!'
  637.     DB    CR,LF,'$'
  638.  
  639. LOADED     DB    CR,LF
  640.     DB    'QUADBIOS already loaded!'
  641.     DB    CR,LF,'$'
  642.  
  643. COM1F    DB    CR,LF
  644.     DB    'COM1: board found at 03F8',CR,LF
  645.     DB    '$'
  646.  
  647. COM2F    DB    CR,LF
  648.     DB    'COM2: board found at 02F8',CR,LF
  649.     DB    '$'
  650.  
  651. QUA1F    DB    CR,LF
  652.     DB    'Quadport board found at 0280',CR,LF
  653.     DB    '$'
  654.  
  655. QUA2F    DB    CR,LF
  656.     DB    'Quadport board found at 0288',CR,LF
  657.     DB    '$'
  658.  
  659.  
  660. TWOCOM    DB    CR,LF
  661.     DB    'I/O boards were found at both standard DOS addresses.'
  662.     DB    CR,LF
  663.     DB    'Either your Quadport board must be set for non-DOS compatible mode'
  664.     DB    CR,LF
  665.     DB    'or you must remove a standard I/O board.'
  666.     DB    CR,LF
  667.     DB    'Driver NOT installed!',CR,LF
  668.     DB    '$'
  669.  
  670. NOQUAD    DB    CR,LF
  671.     DB    'No Quadport board was found.'
  672.     DB    CR,LF
  673.     DB    'Be sure your Quadport board is set for non-DOS compatible mode.'
  674.     DB    CR,LF
  675.     DB    'Driver NOT installed!',CR,LF
  676.     DB    '$'
  677.  
  678. TWOQUAD    DB    CR,LF
  679.     DB    'Two Quadport boards were found.  This program only supports one.'
  680.     DB    CR,LF
  681.     DB    'Please remove one.'
  682.     DB    CR,LF
  683.     DB    'Driver NOT installed!',CR,LF
  684.     DB    '$'
  685.  
  686. ; INITIALIZE ROUTINE
  687.  
  688. start:  MOV     AX,CS                 ; Point DS in the right place
  689.         MOV     DS,AX                
  690.     CALL    SINON    ;PRINT SIGN ON
  691.  
  692.     MOV    DX,02    ;Check to see if support already loaded
  693.     MOV    AH,04
  694.     INT    14H
  695.     CMP    AX,0AA55H
  696.     JZ    LOEXIT    ;Must be loaded already
  697.  
  698.     CALL    CNFIG    ;CHECK CONFIGURATION
  699.     OR    AX,AX
  700.     JNZ    EREXIT    ;JMP IF ERRORS
  701.     CALL    FNDINT  ;ASSIGN INTERRUPT ADDRESSES
  702.  
  703.     CALL    init_vectors    ;SET INTERRUPT VECTORS
  704.  
  705.     CALL    SINOFF        ;PRINT SIGN OFF
  706.     MOV    AL,0        ;set exit code
  707.         MOV     DX,OFFSET program_end
  708.         MOV    CL,4
  709.         SHR    DX,CL
  710.         INC    DX
  711.     MOV    AH,31H
  712.     INT    21H             ; Terminate but stay resident
  713.  
  714. EREXIT:    MOV    AL,1        ;set exit code = Error
  715.     MOV    AH,4CH
  716.     INT    21H             ; Terminate and return
  717.  
  718. LOEXIT:    LEA    DX,LOADED
  719.     MOV    AH,9
  720.     INT    21H
  721.          MOV    AL,0        ;set exit code = Ok
  722.     MOV    AH,4CH
  723.     INT    21H             ; Terminate and return
  724.  
  725.  
  726. ;---------
  727. CNFIG:  CALL    FNDPT        ;Find Ports
  728.     CMP    P3F8,1
  729.     JNE    CNF1
  730.     INC    DOSPT        ;# of Dos Ports
  731.           LEA    DX,COM1F    ;Say COM1 Found
  732.     MOV    AH,9
  733.     INT    21H
  734.  
  735. CNF1:    CMP    P2F8,1
  736.     JNE    CNF2
  737.     INC    DOSPT        ;# of Dos Ports
  738.           LEA    DX,COM2F    ;Say COM2 Found
  739.     MOV    AH,9
  740.     INT    21H
  741.  
  742. CNF2:      CMP     DOSPT,2
  743.     JNE    CNF3
  744.           LEA    DX,TWOCOM    ;Say OOPS
  745.     MOV    AH,9
  746.     INT    21H
  747.     JMP    CNFERR
  748.  
  749. CNF3:    CMP    P280,1
  750.     JNE    CNF4
  751.     INC    QUAPT        ;# of Quad Ports
  752.           LEA    DX,QUA1F    ;Say Quad Found
  753.     MOV    AH,9
  754.     INT    21H
  755.  
  756. CNF4:    CMP    P288,1
  757.     JNE    CNF5
  758.     INC    QUAPT        ;# of Quad Ports
  759.           LEA    DX,QUA2F    ;Say Quad Found
  760.     MOV    AH,9
  761.     INT    21H
  762.  
  763. CNF5:      CMP     QUAPT,2
  764.     JNE    CNF6
  765.           LEA    DX,TWOQUAD    ;Say OOPS
  766.     MOV    AH,9
  767.     INT    21H
  768.     JMP    CNFERR
  769.  
  770. CNF6:      CMP     QUAPT,0
  771.     JNE    CNF7
  772.           LEA    DX,NOQUAD    ;Say OOPS
  773.     MOV    AH,9
  774.     INT    21H
  775. CNFERR:    MOV    AX,0FFFFH    ;Set Error
  776.     RET
  777.  
  778. CNF7:    SUB    AX,AX
  779.     RET
  780.  
  781. ;------------
  782.  
  783. FNDPT:    MOV    DX,03F8H
  784.     CALL    CKPORT
  785.     CMP    BP,0
  786.     JZ    PT2
  787.  
  788.     INC    P3F8
  789.  
  790. PT2:    MOV    DX,02F8H
  791.     CALL    CKPORT
  792.     CMP    BP,0
  793.     JZ    PT3
  794.  
  795.     INC    P2F8
  796.  
  797. PT3:    MOV    DX,0280H
  798.     CALL    CKPORT
  799.     CMP    BP,0
  800.     JZ    PT4
  801.  
  802.     INC    P280
  803.     MOV    Qbase,0280H
  804.  
  805. PT4:    MOV    DX,0288H
  806.     CALL    CKPORT
  807.     CMP    BP,0
  808.     JZ    PT5
  809.  
  810.     INC    P288
  811.     MOV    Qbase,0288H
  812. PT5:    RET
  813.  
  814.  
  815. ;----------------------
  816. ;Check for valid Port
  817. ;Enter with DX containing Port address
  818. ;Exit with BP=Port address if port found  BP=0 if not found
  819.  
  820.  
  821. CKPORT: MOV     BP,DX        ;For return
  822.     MOV    CL,DL        ;Keep DL Handy
  823.  
  824.     ADD    DX,3
  825.     IN    AL,DX        ;Save old LCR in CH
  826.     MOV    CH,AL
  827.  
  828.           MOV    AL,80H        ;Address Divisor Latch
  829.     OUT    DX,AL
  830.     CALL    WAIT
  831.  
  832.     MOV    DL,CL
  833.     IN    AL,DX        
  834.     MOV    AH,AL        ;Save old Divisor
  835.     CALL    WAIT
  836.  
  837.     INC    DX
  838.     IN    AL,DX        ;Save old Divisor
  839.     MOV    BX,AX
  840.     CALL    WAIT
  841.  
  842.     MOV    DL,CL
  843.     MOV    AL,55H            ;OUTPUT 55
  844.     OUT    DX,AL
  845.     CALL    WAIT
  846.  
  847.     INC    DX
  848.     MOV    AL,0AAH
  849.     OUT    DX,AL        ;OUTPUT AA
  850.     CALL    WAIT
  851.  
  852.     MOV    DL,CL
  853.     IN    AL,DX        ;Read New Divisor
  854.     MOV    AH,AL
  855.     CALL    WAIT
  856.  
  857.     INC    DX
  858.     IN    AL,DX
  859.     CMP    AX,55AAH    ;DO THEY MATCH?
  860.     JZ     Match
  861.  
  862.     XOR    BP,BP        ;Zero - no match
  863.  
  864. Match:    MOV    DL,CL
  865.     MOV    AL,BH        ;Restore old Divisor
  866.     OUT    DX,AL
  867.     CALL    WAIT
  868.  
  869.     INC    DX
  870.     MOV     AL,BL
  871.     OUT    DX,AL
  872.     CALL    WAIT
  873.  
  874.     INC    DX
  875.     INC    DX        ;and old LCR
  876.     MOV    AL,CH
  877.     OUT    DX,AL
  878.     CALL    WAIT
  879.  
  880. WAIT:    RET
  881.  
  882. ;---------
  883. FNDINT:    CMP    P280,1
  884.     JNZ    FND2
  885.     MOV    QINTR,02D3H
  886.     CMP     P3F8,1        ;if COM1 exists
  887.     JNE    FND1
  888.     AND    M8259,0F7H    ;then use COM2
  889.     MOV    MQUAD,1        ;interrupts (IRQ3)
  890.     JMP    FND2
  891.  
  892. FND1:    AND    M8259,0EFH
  893.     MOV    MQUAD,2
  894.  
  895. FND2:    CMP    P288,1
  896.     JNZ    FND3
  897.     MOV    QINTR,02DBH
  898.     CMP     P3F8,1
  899.     JNE    FND4
  900.     AND    M8259,0F7H
  901.     MOV    MQUAD,1
  902.     JMP    FND3
  903.  
  904. FND4:    AND    M8259,0EFH
  905.     MOV    MQUAD,2
  906. FND3:    RET
  907.  
  908. ;-----
  909. ;PRINT SIGNON 
  910. SINON:    LEA    DX,HELLO
  911.     MOV    AH,9
  912.     INT    21H
  913.     RET
  914.  
  915. ;PRINT SIGNOFF
  916. SINOFF:    LEA    DX,BYE
  917.     MOV    AH,9
  918.     INT    21H
  919.     RET
  920.  
  921.  
  922.  
  923. ;--------------------------------------------------------------------------;
  924. ; Now snatch the BIOS comm vector  (Int 14)                                ;
  925. ;--------------------------------------------------------------------------;
  926.  
  927. init_vectors:
  928.     MOV    AL,14H
  929.     MOV    AH,35H
  930.     INT    21H
  931.         MOV     old_bios_vector,BX     ;      save old vector
  932.         MOV     old_bios_vector+2,ES   ;
  933.  
  934.         MOV     DX,OFFSET rsint     ; Replace with our vector
  935.     MOV    AL,14H
  936.     MOV    AH,25H
  937.     INT    21H
  938.  
  939.         CLI                       ; Disable interrupts
  940.  
  941.         IN      AL,pic_mask_port  ; Set up 8259 interupt controller
  942.         AND     AL,M8259          ; Enable the interrupts for this device
  943.         OUT     pic_mask_port,AL  ;
  944.  
  945.     MOV    DX,QINTR          ; Set int vector used by Quadport
  946.     MOV    AL,MQUAD
  947.     OUT    DX,AL
  948.  
  949.  
  950. ;--------------------------------------------------------------------------;
  951. ; Set the hardware interrupt vector                                        ;
  952. ;--------------------------------------------------------------------------;
  953.  
  954.  
  955.         MOV     DX,OFFSET serint_2_8250  ; Get our address
  956.     MOV    AL,0CH
  957.     CMP     MQUAD,2        ;MQUAD=2 if we use IRQ4 (0C)
  958.     JE     vect0C
  959.     MOV    AL,0BH
  960. vect0C:    MOV    AH,25H
  961.     INT    21H
  962.  
  963. ;--------------------------------------------------------------------------;
  964. ; Loop initializing each COM port                                          ;
  965. ;--------------------------------------------------------------------------;
  966.  
  967.         XOR     AX,AX                 ; Get a zero
  968.         MOV     BP,AX                 ; Place to start the comm loop is  0
  969.  
  970. init_loop:
  971.  
  972.  
  973. ;--------------------------------------------------------------------------;
  974. ; Initialize the buffer ring pointers                                      ;
  975. ;--------------------------------------------------------------------------;
  976.  
  977.         MOV     AX,OFFSET buffer  ; Get start of buffer address
  978.         ADD     AX,BP             ; include our offset
  979.         MOV     buffer_in[BP],AX  ; Put in the buffer pointers
  980.         MOV     buffer_out[BP],AX ; Put in the buffer pointers
  981.  
  982. ;--------------------------------------------------------------------------;
  983. ; Set the interrupt registers in the UART and clean things up              ;
  984. ;--------------------------------------------------------------------------;
  985.  
  986.         MOV     CX,Qbase        ; Get base address for chip
  987.         ADD     CX,baseaddr[BP]     ; Get base address for chip
  988.  
  989.         MOV     DX,CX             ; Compute port address for the IER
  990.         ADD     DX,ier_8250       ;
  991.         MOV     AL,00000001B      ; Enable data interrupt only
  992.         OUT     DX,AL             ;
  993.  
  994.         MOV     DX,CX             ; Compute port address for the MCR
  995.         ADD     DX,mcr_8250       ;
  996.         MOV     AL,00001000B      ; Raise OUT2.  OUT2 turns
  997.                                   ; on interrupts
  998.         OUT     DX,AL             ;
  999.  
  1000.         MOV     DX,CX             ; Compute port address for the MCR
  1001.         ADD     DX,rbr_8250       ;
  1002.         IN      AL,DX             ; Read the input buffer and throw it away
  1003.  
  1004. ;--------------------------------------------------------------------------;
  1005. ; Loop thru the next comm port                                             ;
  1006. ;--------------------------------------------------------------------------;
  1007.  
  1008.         ADD     BP,OFFSET dummy_end ; Increment to next com port block
  1009.  
  1010.         CMP     BP,OFFSET comend    ; Anything left to be done?
  1011.         JGE     com_done            ; Nope...
  1012.         JMP     init_loop           ; Yep.. Loop back
  1013.  
  1014. com_done:
  1015.  
  1016. ;--------------------------------------------------------------------------;
  1017. ; Enable interrupts                                                        ;
  1018. ;--------------------------------------------------------------------------;
  1019.  
  1020.         STI                        ; Enable CPU to receive interupts
  1021.         RET
  1022.  
  1023. everything ENDS
  1024.  
  1025.         END foo
  1026.