home *** CD-ROM | disk | FTP | other *** search
/ PC-Test Pro / PCTESTPRO.iso / commtls / uart / entp / uart.asm < prev    next >
Encoding:
Assembly Source File  |  1995-07-23  |  23.3 KB  |  997 lines

  1.         PAGE    60,132
  2. NAME    UART
  3.     TITLE    UART Version 1.2 1993 June 17
  4. COMMENT √
  5.  
  6. UART C:
  7. Detect UART type of serial port
  8.   UART COM1:
  9.   If Errorlevel 5 GoTo SyntaxError
  10.   If Errorlevel 4 GoTo PS2TYPE3
  11.   If ErrorLevel 3 GoTo AT16550FIFO
  12.   If ErrorLevel 2 GoTo AT16450
  13.   If ErrorLevel 1 GoTo XT8250
  14.   If ErrorLevel 0 GoTo NoSuchPort
  15.  
  16. UART by itself is considered a syntax error and generates a
  17. usage message.
  18.  
  19. Sets errorlevel to type of UART detected.
  20.  
  21. This code is based on the MASM routines on page 364 Of PC
  22. Magazine May 26, 1992.
  23.  
  24. In DESQview often ports COM1: and COM2: are not accessible.  You
  25. must have access priviledge in your PIF.
  26.  
  27. Under OS/2 virtualization makes all com ports look like 8250s.
  28.  
  29. Supports only COM1: .. COM4:.  Looks in BIOS Table to find the
  30. corresponding physical addresses.
  31.  
  32. It expects this pattern COM1: COM2: COM3: COM4:
  33.           port:  3f8   2f8   3e8   2e8
  34.            irq:    4     3     4     3
  35.            int:    C     B     C     B
  36.  
  37. If for example COM1: has port 2f8, then irq 3 would be
  38. anticipated and its interrupts would be fielded on int vector B.
  39. Port has precedence over com port number in determining irq.
  40.  
  41. To Do
  42.  
  43. - extend support to COM5..COM8
  44.   I don't know the expected IRQs or port addresses for these beasts.
  45.   If you have info on how these are supposed to work, please pass
  46.   it along.  Also I would need someone with a machine with such ports
  47.   to beta test.
  48.  
  49. √    ; end of comment
  50.  
  51. ;======
  52. ; M A C R O S
  53.  
  54. PEEK    MACRO    portoffset
  55. ;;    read port then delay
  56.     if    (portoffset NE DITTO)
  57.     lea    dx,[bx+portoffset]
  58.     endif
  59.     in    al,dx
  60.     call    breath
  61.     ENDM
  62.  
  63. POKE    MACRO    portoffset
  64. ;;    write port then delay
  65.     if    (portoffset NE DITTO)
  66.     lea    dx,[bx+portoffset]
  67.     endif
  68.     out    dx,al
  69.     call    breath
  70.     ENDM
  71.  
  72. ;======
  73. ; E Q U A T E S
  74. PIC    EQU    21h        ; 21h PIC interrupt controller
  75.                 ; bits 76543210 - 1-disable interrupt
  76. RBR    EQU    0        ; 3F8 Receive Buffer Register
  77. THR    EQU    0        ; 3F8 Transmit Holding    Register
  78. LSBDIV    EQU    0        ; 3F8 LSB divisor, latch bit must be on
  79.                 ;     in the LCR
  80. IER    EQU    1        ; 3F9 Interrupt Enable Register
  81.                 ;     0000MLTR 1=enable
  82.                 ;     Modem status, Line, Transmit, Receive
  83. MSBDIV    EQU    1        ; 3F9 MSB divisor, DBLAB bit must be on
  84. IIR    EQU    2        ; 3FA Interrupt Ident Register
  85.                 ;     001 none
  86.                 ;     110 line error, read line status
  87.                 ;     100 data avail, read char
  88.                 ;     010 thr empty, read IIR, send char
  89.                 ;     000 modem status, read MSR
  90. FIFO    EQU    2        ; 3FA Fifo Control Register
  91. LCR    EQU    3        ; 3FB Line Control Register
  92.                 ;     DBSEPSWW
  93.                 ;     Divisor latch, Break, Stick, Even
  94.                 ;     Parity, Stop bits, word length11=8
  95. MCR    EQU    4        ; 3FC Modem Control Register
  96.                 ;     000L21RD
  97.                 ;     Loopback, Out-2, Out-1, RTS, DTR
  98.                 ;     Out-2 enables ints, Out-1 does reset
  99. LSR    EQU    5        ; 3FD Line Status Register
  100.                 ;     0THBFPOD
  101.                 ;     Tx shift, Tx Hold, Break, Frame, Parity,
  102.                 ;     Overrun, Data ready
  103. MSR    EQU    6        ; 3FE Modem Status Register
  104.                 ;     SRDCSRDC
  105.                 ;     line Signal, Ring, DSR, CTS
  106.                 ;     delta line Signal, Ring, DSR, CTS
  107. SCR    EQU    7        ; 3FF Scratch
  108. ENH    EQU    8003h        ; 83FB Enhanced register
  109. DITTO    EQU    9999        ; use same port as previously.
  110.  
  111. stack    segment stack        ; keep MS link happy by providing null stack
  112. stack    ends
  113.  
  114. ;==============================================================
  115.  
  116. CODE    SEGMENT PARA        ; start off in code.
  117.  
  118. ;==============================================================
  119.  
  120. data    segment word        ; provide a separate DATA segment
  121.                 ; Even though it appears in the source
  122.                 ; before the code, it the COM file it
  123.  
  124. ;=============================================
  125.  
  126.  
  127. BIOSDATA    segment AT 40h    ; dummy segment in low RAM
  128.     org    0h
  129.  
  130. BIOSComAddrs    dw    ?    ; 4 words of COM1: .. COM4:
  131.         dw    ?    ; device addresses
  132.         dw    ?
  133.         dw    ?
  134.  
  135. BIOSDATA    ends
  136.  
  137. ;=============================================
  138. ;    E R R O R   M E S S A G E S
  139. ;=============================================
  140.  
  141. CopyrightMsg    label    byte
  142.  db 13,10
  143.  db '░▒▓█ UART 1.2 █▓▒░',13,10
  144.  db 13,10
  145.  db 'Determines UART type on specified COM port.',13,10
  146.  db 13,10
  147.  DB '(c) Copyright Roedy Green Canadian Mind Products 1992,1993.',13,10
  148.  DB '#601 - 1330 Burrard Street, Vancouver BC CANADA V6Z 2B8  (604) 685-8412',13,10
  149.  db 'May be freely distributed and used for any purpose except military.',13,10
  150.  db 13,10,'$'
  151.  
  152. UsageMsg    label    Byte
  153.  db 'Error in command line.  Note the mandatory colon.  Try:',13,10
  154.  db 13,10
  155.  db 'UART COM1:',13,10
  156.  db 'If Errorlevel 5 GoTo SyntaxError',13,10
  157.  db 'If Errorlevel 4 GoTo PS2TYPE3',13,10
  158.  db 'If ErrorLevel 3 GoTo AT16550FIFO',13,10
  159.  db 'If ErrorLevel 2 GoTo AT16450',13,10
  160.  db 'If ErrorLevel 1 GoTo XT8250',13,10
  161.  db 'If ErrorLevel 0 GoTo NoSuchPort',13,10,'$'
  162.  
  163. PortMsg     db    "COM"
  164. PortPatch1    db    "x: is at hex port address: "
  165. HexPatch1    db    "xxxx.",13,10,'$'
  166.  
  167. ; Messages to describe the various types of chip found.
  168.  
  169. code0 db "Port not accessible or not installed.",13,10,'$'
  170. code1 db "XT style 8250 UART.",13,10,'$'
  171. code2 db "AT style 16450 unbuffered UART (might possibly be old-style 16550 or 8250a).",13,10,'$'
  172. code3 db "AT style 16550AF buffered FIFO UART",13,10,'$'
  173. code4 db "PS/2 style IBM type 3 DMA serial port",13,10,'$'
  174.  
  175. WrongPortMsg    db    "Warning, COM"
  176. portpatch2    db    "x: should be at hex port address: "
  177. HexPatch2    db    "xxxx.    ",13,10,'$'
  178.  
  179. GoodIRQmsg    db    "Port correctly configured to IRQ "
  180. IrqPatch1    db    "x.",13,10,'$'
  181. BadIRQMsg    db    "ERROR: port not properly configured to IRQ "
  182. IrqPatch2    db    "x.",13,10
  183.         db    13,10
  184.         db    "If the port appears to be configured correctly, retry the UART test",13,10
  185.         db    "but first try one or more of the following:",13,10
  186.         db    13,10
  187.         db    " 1. Remove any external devices (e.g. modems or serial mice)",13,10
  188.         db    "    connected to the COM ports.",13,10
  189.         db    13,10
  190.         db    " 2. Install a loopback plug on the COM port under test.",13,10
  191.         db    13,10
  192.         db    " 3. Boot from a floppy disk you are sure installs no drivers on the COM ports.",13,10,"$"
  193.  
  194. ConfusedIRQMsg    db    "WARNING: another port sharing IRQ "
  195. IrqPatch3    db         "x or driver software",13,10
  196.         db    "      is interfering with this test.",13,10,"$"
  197.  
  198. DescList    dw    offset COM:code0
  199.         dw    offset com:code1
  200.         dw    offset com:code2
  201.         dw    offset com:code3
  202.         dw    offset com;code4
  203.  
  204. ExpectedList    dw    3f8h    ; expected port address for COM1
  205.         dw    2f8h    ;                COM2
  206.         dw    3E8h    ;                COM3
  207.         dw    2e8h    ;                COM4
  208.  
  209. OldVect dd    0        ; CS:IP of current interrupt vector
  210.  
  211. OldPIC    db    0        ; old value of PIC interrupt enable reg.
  212. OldIER    db    0        ; old value of Interrupt Enable Register
  213. OldMCR    db    0        ; old value of Modem Control Register
  214. OldLCR    db    0        ; old value for Line Control Register
  215. OldLSBDivisor    db    0    ; old value of latch baud rate divisor
  216. OldMSBDivisor    db    0    ; " MSB
  217. OldScr    db    0        ; old value of Scratch register
  218. OldENH    db    0        ; old value of Enhance register 1
  219.  
  220.  
  221. ComNo    dw    0        ; 0=COM1: 1=COM2:
  222.  
  223. Comaddr dw    0        ; 3F8=COM1: 2F8=COM2: 3E8=COM3: 2E8=COM4:
  224.  
  225. IRQ    db    0        ; 3 or 4, corresponds to int B or C.
  226.  
  227. Vector    db    0        ; B or C interrupt vector
  228.  
  229. EventCount    dw    0    ; counts how many interrupts.  Should be one.
  230.  
  231. data    endS
  232.  
  233. ;==============================================================
  234.  
  235. com    group    code,data
  236.  
  237.     ASSUME    CS:COM,DS:COM,ES:COM
  238.     ORG    100H
  239. Start:
  240.     Call    Parse        ; prepare the command line
  241.     Call    Analyse     ; analyse the command line for drive letter
  242.     mov    bx,ComAddr    ; hex port address for com port
  243.     Call    UartType    ; return code in bx
  244.     push    bx
  245.     Call    DisplayUARTType ; message to describe type we found.
  246.     Call    CheckPort    ; check if port is one expected
  247.     Call    CheckIRQ    ; Check that IRQ is one expected
  248.                 ; This code does not work yet.
  249.     pop    bx
  250.     mov    al,bl
  251.     mov    ah,04ch     ; exit to dos, errorlevel in AL
  252.     int    21h
  253.  
  254. Failed:
  255.     lea    dx,Copyrightmsg
  256.     call    say
  257.     lea    dx,usagemsg
  258.     call    say
  259.     mov    ax,4c05h    ; exit back to DOS with error code 5
  260.     int    21h
  261.  
  262.  
  263. ;==============================================================
  264.  
  265. UARTTYPE    Proc    Near
  266.  
  267. ;    on entry BX is serial I/O port: e.g. 3F8
  268. ;    On exit BX contains the serial port type
  269. ;    This code is very similar to code in PC Magazine page 364
  270. ;    May 26, 1992.  I added two null checks and tighted up the code.
  271. ;    0=not present, and sets carry
  272. ;    1=8250
  273. ;    2=16450, old style 16550, 8250A
  274. ;    3=16550AF with FIFO queues
  275. ;    4=IBM type 3 serial port with DMA
  276. ;    trashes bx,cx,dx
  277.  
  278.     test    bx,bx
  279.     jz    isNullComm
  280.     Call    SaveChipState
  281.     cli            ; port might be in use, e.g. mouse
  282.                 ; attempt to do as little damage as possible.
  283.     mov    al,00000011b    ; set up a vanilla n81 setting
  284.     POKE    LCR        ; 3FB attempt to write to line control register
  285.     PEEK    DITTO        ; see if it took
  286.     sti
  287.     cmp    al,00000011b
  288.     jne    isNullComm    ; no, must be no port at all.
  289.     PEEK    MCR        ; 3FC modem control reg
  290.     and    al,11110011b    ; disable serial interrupt
  291.                 ; Out-2 must be on for interrupts to happen
  292.                 ; out-1 does a reset
  293.                 ; Where is this documented?
  294.     POKE    DITTO
  295.     cli
  296.     mov    al,55h        ; see if scratch register exists
  297.     POKE    SCR
  298.     PEEK    DITTO        ; see if 55 comes back.
  299.     sti
  300.     cmp    al,55h
  301.     jne    is8250        ; 8250 has no scratch reg
  302.  
  303.     mov    al,0aah     ; just in case, try that again
  304.     cli
  305.     POKE    DITTO
  306.     PEEK    DITTO
  307.     sti
  308.     cmp    al,0aah
  309.     jne    is8250        ; 8250 has no scratch reg
  310.  
  311. ; must be something more advanced than the 8250
  312.  
  313.     mov    al,7        ; attempt to enable FIFOs
  314.     cli
  315.     POKE    FIFO        ; 3FA
  316.     PEEK    IIR        ; 3FA interrupt id reg
  317.     sti
  318.     and    al,0c0h     ; strip out all but FIFO bits
  319.     jz    Is16450     ; all 0 if no FIFO.
  320.  
  321. ; must be more advanced than the 16450
  322.     cli
  323.     PEEK    ENH        ; 83FB read enhanced register 1
  324.     or    al,01000000b    ; enable DMA Xmit mode
  325.     POKE    DITTO
  326.     PEEK    IIR
  327.     sti
  328.     and    al,0c0h     ; mask all but FIFO ID
  329.     cmp    al,040h
  330.     jne    Is16550
  331.  
  332.     jmp    IsIBMType3
  333.  
  334.  
  335. IsNullComm:
  336.     mov    bx,0
  337.     stc
  338.     ret
  339.  
  340. Is8250:
  341.     mov    cx,1
  342.     jmp    UARTTypeDone
  343.  
  344. Is16450:
  345.     mov    cx,2
  346.     jmp    UARTTypeDone
  347.  
  348. Is16550:
  349.     mov    cx,3
  350.     jmp    UARTTypeDone
  351.  
  352. IsIBMType3:
  353.     mov    cx,4
  354.  
  355. UARTTypeDone:
  356.  
  357.     Call    RestoreChipState
  358.     mov    bx,cx
  359.     clc
  360.     ret
  361.  
  362. UARTTYPE    EndP
  363.  
  364. ;=============================================
  365.  
  366. DisplayUARTType Proc    Near
  367.  
  368. ;    on entry BX is the type code for the UART type.
  369. ;    we display a message describing it.
  370. ;    trash everything
  371.  
  372.     push    bx
  373.  
  374.     mov    ax,Comaddr    ; get hex address
  375.     call    AsHex        ; patch in the hex address to the
  376.                 ; output message.
  377.     lea    si,AsHexBuf
  378.     lea    di,HexPatch1
  379.     movsw
  380.     movsw
  381.     mov    ax,ComNo    ; 0=COM1: 1=COM2:
  382.     add    al,'1'
  383.     mov    PortPatch1,al    ; patch com port number in message.
  384.     lea    dx,PortMsg    ; echo port number and address.
  385.     call    Say
  386.  
  387.     pop    bx
  388.     shl    bx,1        ; index table of words
  389.     mov    dx,DescList[BX]
  390.     Call    Say        ; display corresponding description
  391.     ret
  392.  
  393. DisplayUARTType EndP
  394.  
  395. ;==============================================================
  396.  
  397. CheckPort Proc    Near
  398.  
  399. ;    check that ComPort is usual value for this ComNo.
  400. ;    If not, print a warning message.
  401. ;    Presume Comaddr has been calculated already.
  402. ;    trash everything
  403.  
  404.     test    Comaddr,-1
  405.     jz    UsingProperPort ; if not in use, don't count as error.
  406.     mov    bx,ComNo
  407.     shl    bx,1
  408.     mov    bx,ExpectedList[bx]
  409.                 ; expect comport #
  410.     cmp    bx,ComAddr
  411.     je    UsingProperPort
  412.  
  413. ;    Oops, this is not the port we would usually use
  414.  
  415.     mov    ax,bx
  416.     call    AsHex        ; patch in the hex address to the
  417.                 ; output message.
  418.     lea    si,AsHexBuf
  419.     lea    di,HexPatch2
  420.     movsw
  421.     movsw
  422.     mov    ax,ComNo    ; 0=COM1: 1=COM2:
  423.     add    al,'1'
  424.     mov    PortPatch2,al    ; patch com port number in message.
  425.     lea    dx,WrongPortMsg ; echo port number and address.
  426.     call    Say
  427.  
  428. UsingProperPort:
  429.     ret
  430.  
  431. CheckPort EndP
  432.  
  433. ;==============================================================
  434.  
  435. SaveChipState        Proc    Near
  436.  
  437. ;    Save values of UART registers so we can restore later
  438.  
  439.     mov    dx,PIC        ; save state of PIC
  440.     in    al,dx
  441.     mov    OldPIC,al
  442.  
  443.     mov    bx,ComAddr    ; e.g 3F8
  444.     PEEK    MCR        ; 3FC save current modem control reg.
  445.     mov    OldMCR,al
  446.  
  447.     PEEK    IER        ; 3F9 save current interrupt enable register
  448.     mov    OldIER,al
  449.  
  450.     PEEK    LCR        ; 3FB save current line control register
  451.     mov    OldLCR,al
  452.  
  453.     PEEK    SCR        ; 3FF save old scratch register
  454.     mov    oldSCR,al
  455.  
  456.     PEEK    ENH        ; 83FB save old enhanced reg1
  457.     mov    oldENH,al
  458.  
  459.     mov    al,10000011b    ; set up n81, access divisor
  460.     POKE    DITTO
  461.     PEEK    LSBDIV        ; save old baud rate divisor
  462.     mov    OldLSBDivisor,al
  463.     PEEK    MSBDIV
  464.     mov    OldMSBDivisor,al
  465.  
  466.     mov    al,OldLCR    ; 3FB just save LCR, don't change it yet.
  467.     POKE    LCR
  468.  
  469.  
  470.     ret
  471.  
  472. SaveChipState        EndP
  473.  
  474. ;=============================================
  475.  
  476. RestoreChipState    Proc    Near
  477.  
  478. ;    put all registers in chip back the way they were.
  479.  
  480.     cli            ; restore PIC back the way it
  481.     mov    dx,PIC        ; was.    Non 3/4 IRQs may have legitimately
  482.     in    al,dx        ; changed during our run.  We don't put them
  483.     and    al,0e7h     ; back, just irq 3/4.
  484.     mov    ah,OldPic    ; 0=enabled 1=disabled
  485.     and    ah,018h
  486.     or    al,ah
  487.     out    dx,al
  488.     sti
  489.  
  490.     mov    bx,ComAddr    ; e.g 3F8
  491.     mov    al,OldIER    ; 3F9 restore interrupt enable register 3F9
  492.     POKE    IER
  493.  
  494.     mov    al,OldMCR    ; 3FC restore original modem control register 3FC
  495.     POKE    MCR
  496.  
  497.     mov    al,oldSCR
  498.     POKE    SCR        ; 3FF restore old scratch register
  499.  
  500.     mov    al,oldENH
  501.     POKE    ENH        ; 83FB restore old enhanced reg1
  502.  
  503.     mov    al,10000011b    ; set up n81, access divisor
  504.     POKE    LCR        ; 3FB restore divisor
  505.     mov    al,OldLSBdivisor
  506.     POKE    LSBDIV
  507.     mov    al,OldMSBDivisor
  508.     POKE    MSBDIV
  509.  
  510.     mov    al,OldLCR    ; 3FB restore line status register
  511.     POKE    LCR
  512.                 ; we cannot directly restore the IIR
  513.                 ; but we can turn off the FIFO
  514.     mov    al,0
  515.     POKE    FIFO        ; 3FA
  516.  
  517.     ret
  518.  
  519. RestoreChipState    EndP
  520.  
  521. ;=============================================
  522.  
  523. ;COMMENT √        ; this routine does not work yet. WHY???
  524.             ; I have chewed on this for days!!!
  525.  
  526. CheckIRQ    Proc    Near
  527.  
  528. ;    Check the that exactly one interrupt at the expected IRQ
  529.  
  530.     Call    CalcIRQ     ; figure out which IRQ should be used
  531.     Call    SetTrap     ; trap interrupts from expected IRQ
  532.     Call    Trigger1Int    ; Trigger 1 interrupt using loopback
  533.     Call    RestoreIRQ    ; put trap back the way it was
  534.     Call    PatchIRQ    ; patch expected IRQ # into error messages.
  535.     cmp    Eventcount,1    ; should see 1 int
  536.     jb    BadIRQ
  537.     ja    ConfusedIRQ
  538.  
  539. ;    Just right, saw 1 interrupt
  540. GoodIRQ:
  541.     lea    dx,GoodIRQMsg
  542.     call    Say
  543.     ret
  544.  
  545. BadIRQ:
  546.     lea    dx,BadIRQMsg
  547.     call    Say
  548.     ret
  549.  
  550. ConfusedIRQ:
  551.     lea    dx,ConfusedIRQMsg
  552.     call    Say
  553.     ret
  554.  
  555. CheckIRQ    EndP
  556.  
  557. ;==============================================================
  558.  
  559. CalcIRQ Proc    Near
  560.  
  561. ;    Calculate the IRQ 4 or 3 to match hex address
  562.  
  563.     mov    ax,ComAddr
  564.     lea    di,Expectedlist     ; scan list of legal port #s
  565.     mov    cx,4            ; to make sure it is in the list.
  566.     repne scasw
  567.     jne    NoIrq
  568.                     ; ax still has the address.
  569.     mov    al,ah            ; 3f8 2f8 3e8 2e8 -> 2 or 3
  570.     sub    ah,ah
  571.     inc    ax            ; 3 -> 4    2 -> 3
  572.     mov    IRQ,al
  573.     add    al,8            ; 3->B    4->C
  574.     mov    Vector,al        ; which interrupt vector,
  575.                     ; not same as IRQ
  576.     clc
  577.  
  578.     ret
  579.  
  580. NoIRQ:    mov    IRQ,0
  581.     mov    Vector,0
  582.     stc
  583.     ret
  584.  
  585. CalcIRQ EndP
  586.  
  587. ; =============================================
  588.  
  589. PatchIRQ    Proc    Near
  590.  
  591. ;    Patch expected the IRQ number into various possible error messages.
  592.  
  593.     mov    al,IRQ            ; 3 or 4 binary
  594.     add    al,030h         ; 3 or 4 ASCII
  595.     mov    IrqPatch1,al
  596.     mov    IrqPatch2,al
  597.     mov    IrqPatch3,al
  598.     ret
  599.  
  600. PatchIRQ    EndP
  601.  
  602. ; =============================================
  603.  
  604.     ASSUME    DS:nothing,ES:nothing
  605.  
  606. SetTrap Proc    near
  607.  
  608. ;    Trap interrupts from the expected source irq 3 or 4.
  609.  
  610.     push    DS
  611.     push    ES
  612.     mov    ah,35h
  613.     mov    al,Vector    ; save old B/C vector
  614.     int    21h        ; result in ES:BX
  615.     mov    word ptr OldVect, bx
  616.     mov    word ptr OldVect+2, ES
  617.     pop    ES
  618.     push    CS
  619.     pop    DS
  620.  
  621.     lea    dx,CS:IntHandler
  622.     mov    ah,25h
  623.     mov    al,Vector    ; set up new B/C vector to point to our
  624.                 ; miniature handler
  625.     int    21h
  626.     pop    DS
  627.     ret
  628.  
  629. SetTrap EndP
  630.  
  631.  
  632. ; =============================================
  633.  
  634.     ASSUME    DS:NOTHING,ES:NOTHING
  635.  
  636. IntHandler    Proc    Near
  637.  
  638. ;    Interrupt handler for irq 3 or 4 int B or C.
  639.  
  640.                 ; ints are off right now
  641.     push    ax        ; must not disturb ANYTHING!
  642.     push    bx
  643.     push    cx
  644.     push    dx
  645.     inc    CS:EventCount    ; only CS: works,
  646.                 ; count how many interrupts.
  647.                 ; should be only one.
  648.     mov    al,20h
  649.     out    20h,al        ; send eoi command to PIC
  650.     call    Breath
  651.  
  652.     Call    ClearPendingInterrupt
  653.     sti
  654.     pop    dx
  655.     pop    cx
  656.     pop    bx
  657.     pop    ax
  658.  
  659.     iret
  660.  
  661.     IntHandler    EndP
  662.  
  663.  
  664. ;=============================================
  665.     ASSUME    DS:COM,ES:COM
  666.  
  667. Trigger1Int    Proc    Near
  668.  
  669. ;    Trigger one interrupt and count how many ints appeared at the
  670. ;    expected interrupt.
  671.  
  672.  
  673.     Call    SaveChipState    ; save current values of all regs we will wreck.
  674.  
  675.  
  676.     mov    al,10000011b    ; set up n81, access divisor
  677.     POKE    LCR        ; 3FB
  678.     mov    al,030h
  679.     POKE    LSBDIV        ; set up 2400 baud
  680.     mov    al,0
  681.     POKE    MSBDIV
  682.  
  683.     mov    al,00000011b    ; set up n81, access regular regs
  684.     POKE    LCR        ; 3FB
  685.  
  686.     cli            ; Turn on ints 3 and 4 in the PIC
  687.     mov    dx,PIC
  688.     in    al,dx
  689.     and    al,0e7h     ; 0=enabled 1=disabled.
  690.     out    dx,al
  691.     sti
  692.  
  693.     mov    al,0        ; disable any FIFOs
  694.     POKE    FIFO        ; 3FA
  695.  
  696.     mov    al,00000110b    ; enable interrupts, just THR empty & overrun
  697.     POKE    IER        ; 3F9 Some pending interrupt might trigger
  698.  
  699. ; Loopback does not work.  IBM does not let the PIC see the
  700. ; interrupts in loopback mode.
  701.  
  702.     mov    al,00001000b    ; out-1 does a reset of attached modem
  703.                 ; must clear
  704.                 ; out-2 enables interrupts
  705.                 ; turn off DTR and RTS, to reset
  706.                 ; any attached modem
  707.  
  708.     POKE    MCR        ; 3FC  might generate an interrupt
  709.     call    BigBreath
  710.  
  711.     mov    al,00001011b    ; out-1 does a reset of attached modem
  712.                 ; must clear
  713.                 ; out-2 enables interrupts
  714.                 ; turn on DTR and RTS
  715.  
  716.     POKE    MCR        ; 3FC  might generate an interrupt
  717.     call    BigBreath
  718.  
  719.     mov    EventCount,0    ; clear interrupt counter
  720.     sti            ; ints should be on anyway.
  721.     mov    al,0        ; send a null character
  722.     POKE    THR        ; Five things can happen:
  723.                 ; 1. device accepts the char
  724.                 ; 2. device keeps CTS low, so char
  725.                 ;    never goes out.  We never get an int.
  726.                 ; 3. device is powered off or missing.
  727.                 ;    Then we get a line status int.
  728.                 ; 4. IRQ not set properly.  We see no int.
  729.                 ; 5. Some other device is using same IRQ.
  730.                 ;    We see multiple ints.
  731.  
  732.     Call    BigBreath    ; Wait long enough for interrupt to happen
  733.  
  734.     call    ClearPendingInterrupt
  735.     Call    RestoreChipState
  736.     ret
  737.  
  738. Trigger1Int    EndP
  739.  
  740. ;=============================================
  741.  
  742. ClearPendingInterrupt    Proc    Near
  743.  
  744. ;    If there is a pending interrupt, get it cleared
  745. ;    See page 1-242 XT tech ref.
  746. ;    trashes ax,bx,dx
  747. ;    Called from Int handler.  Cannot use DS:
  748.  
  749.     mov    bx,CS:ComAddr    ; e.g 3F8
  750.  
  751.     PEEK    IIR        ; 3FA read IIR to clear
  752.                 ; any modem transmitter holding empty interrupt
  753.  
  754.     PEEK    RBR        ; 3F8 read receive buffer register to clear
  755.                 ; any char in interrupt
  756.  
  757.     PEEK    LSR        ; e.g. 3FD read line status register to clear
  758.                 ; any parity interrupt
  759.  
  760.     PEEK    MSR        ; e.g. 3FE read modem status register to clear
  761.                 ; any modem status interrupt
  762.     ret
  763.  
  764. ClearPendingInterrupt    EndP
  765.  
  766. ;=============================================
  767.  
  768.     ASSUME    DS:NOTHING,ES:NOTHING
  769.  
  770. RestoreIRQ    proc    near
  771.  
  772. ;    Put the B/C vector back the way it was
  773.  
  774.     push    DS
  775.     mov    dx,word ptr OldVect
  776.     mov    ax,word ptr OldVect+2
  777.     mov    DS,ax
  778.     mov    ah,25h
  779.     mov    al,Vector        ; set B/C vector
  780.     int    21h
  781.     pop    DS
  782.     ret
  783.  
  784. RestoreIRQ    EndP
  785.     ; end of commented out code
  786.  
  787.     ASSUME    DS:COM,ES:COM
  788.  
  789. ;=============================================
  790. ;    C O M M A N D    L I N E   P A R S I N G   R O U T I N E S
  791. ;=============================================
  792.  
  793. MLeading    PROC    Near
  794.  
  795. ;    Remove leading blanks
  796. ;    on entry ES:BX is addr of string, CX its length
  797. ;    trims off any leading blanks, leaving result in BX CX
  798. ;    length may also be 0 or 1, but not -ve
  799. ;    If the entire string is blank the result is the null string
  800.  
  801.     mov    di,bx
  802.     mov    al,20H        ; AL = blank  -- the search char
  803.     jcxz    mleading2    ; jump if null string
  804.     repe    scasb        ; scan ES:DI forwards till hit non blank
  805.                 ; DI points just after it (wrap ok)
  806.                 ; cx IS ONE TOO SMALL, OR 0 IF NONE FOUND
  807.     je    mleading1    ; jump if entire string was blank
  808.     inc    cx        ; CX is length of remainder of string
  809. mleading1:
  810.     dec    di        ; DI points to non-blank
  811. mleading2:
  812.     mov    bx,di        ; put address back
  813.     ret
  814.  
  815. MLeading    ENDP
  816.  
  817. ;========================================
  818.  
  819. MTrailing    PROC    Near
  820.  
  821. ;    Remove trailing blanks.
  822. ;    on entry ES:BX is addr of string, CX its length
  823. ;    trims off any trailing blanks, leaving result in BX CX
  824. ;    length may also be 0 or 1, but not -ve
  825. ;    If the entire string is blank the result is the null string
  826.  
  827.     mov    di,bx
  828.     add    di,cx        ; calc addr last char in string
  829.     dec    di
  830.     mov    al,20H        ; AL = blank  -- the search char
  831.     jcxz    mtrailing1    ; jump if null string
  832.     std
  833.     repe    scasb        ; scan ES:DI backwards till hit non blank
  834.                 ; DI points just ahead of it (wrap ok)
  835.                 ; CX is one too small, or 0 if none found
  836.     cld
  837.     je    mtrailing1    ; jump if whole string was blank
  838.     inc    cx
  839. mtrailing1:
  840.     ret
  841.  
  842. MTrailing    ENDP
  843.  
  844. ;========================================
  845.  
  846. Parse        PROC    NEAR
  847. ;    Parse the command line to remove lead/trail blanks from
  848. ;    the single drive parameter and terminate it by 2 nulls.
  849. ;    sample inputs
  850. ;    UART COM1:
  851. ;    UART    COM2:
  852. ;    UART
  853. ;    ES: points to PSP
  854. ;    When Done ES:BX points to start of string.
  855. ;    String will be terminated by 2 nulls
  856. ;    CX counts bytes in string exclusive of nulls
  857.                 ; counted string at HEX 80 PSP
  858.                 ; contains command line.
  859.                 ; Preceeded by unwanted spaces.
  860.                 ; possibly followed by unwanted spaces.
  861.                 ; currently missing a trailing null.
  862.     xor    ch,ch
  863.     mov    cl,es:[80H]
  864.     mov    bx,81H
  865.     call    Mleading    ; get rid of leading blanks
  866.     call    MTrailing    ; get rid of trailing blanks
  867.     mov    di,bx        ; calc addr of byte just past end
  868.     add    di,cx
  869.     mov    word ptr ES:[di],0 ; plop in pair of nulls after string
  870.     ret
  871.  
  872. Parse        ENDP
  873.  
  874. ;======================================
  875. Analyse     PROC    NEAR
  876. ;    analyses the command line allowing COM1: COM2:
  877. ;    On entry ES:BX points to start of string.
  878. ;    String will be terminated by 2 nulls
  879. ;    CX counts bytes in string exclusive of nulls
  880. ;    lead/trail spaces are gone.
  881.     jcxz    BadCmd        ; was no command
  882.     cmp    cx,5        ; COM1: - must be 5 chars
  883.     jne    BadCmd
  884.     mov    al,ES:[bx+4]
  885.     cmp    al,':'        ; make sure last char is :
  886.     jne    BadCmd
  887.     mov    al,ES:[bx+3]
  888.     sub    al,'1'        ;  '1'->0 '2'->1  '3'->2 '4'->3
  889.     cmp    al,3
  890.     ja    BadCmd        ; allow only COM1: to COM4:
  891.     mov    Byte Ptr ComNo,AL
  892.     push    ES
  893.     mov    ax,BIOSDATA    ; convert to port address
  894.     mov    es,ax
  895.     ASSUME    ES:BIOSDATA
  896.     mov    di,word Ptr ComNo
  897.     shl    di,1        ; address a table of words it low RAM
  898.     mov    ax,ES:BIOSComAddrs[di]
  899.     ASSUME    ES:COM
  900.     pop    ES
  901.     mov    ComAddr,ax
  902. AnalDone:
  903.     RET
  904. BadCmd:
  905.     Jmp    Failed
  906.  
  907. Analyse     ENDP
  908.  
  909. ;=============================================
  910.  
  911. AsHex    Proc    Near
  912.  
  913. ;    calculates 4 digit (16 bits) hex number in AX
  914. ;    get digits into place, don't worry about excess high order stuff.
  915. ;    leaves result in AsHexBuf
  916.  
  917.     mov    AsHexBuf+3,al
  918.     mov    cx,4
  919.     shr    al,cl
  920.     mov    AsHexBuf+2,al
  921.     mov    AsHexBuf+1,ah
  922.     shr    ah,cl
  923.     mov    AsHexbuf+0,ah
  924.     lea    si,AsHexBuf
  925.     mov    cx,4
  926. AsHexLoop:
  927.     lodsb            ; fix up each character in turn
  928.     and    al,0Fh
  929.     cmp    al,0Ah
  930.     jle    IsDigit
  931.     add    al,'A'-0ah
  932.     jmp    SaveDigit
  933. IsDigit:
  934.     add    al,'0'
  935. SaveDigit:
  936.     mov    [si-1],al    ; lodsb incremented si already
  937.     loop    AsHexLoop
  938.     ret
  939.  
  940. Data    segment
  941. AsHexBuf    db    '0000$'
  942. Data    Ends
  943.  
  944. AsHex    EndP
  945.  
  946. ;=============================================
  947. Say    Proc    Near
  948. ;    on entry DX points to a string to display on screen
  949.     MOV    AH,9
  950.     Int    21h
  951.     ret
  952. Say        EndP
  953.  
  954. ;=======================================
  955.  
  956. BigBreath    Proc    Near
  957.  
  958. ;    Wait a decent length of time for triggered interrupt to happen.
  959.  
  960.     push    cx
  961.     mov    cx,20d        ; nested wait loop
  962. wait1:
  963.  
  964.     push    cx
  965.     mov    cx,60000d
  966. wait2:
  967.     loop    Wait2
  968.     pop    cx
  969.  
  970.     loop    Wait1
  971.     pop    cx
  972.     ret
  973.  
  974. BigBreath    EndP
  975.  
  976. ;=======================================
  977.  
  978. Breath    Proc    Near
  979.  
  980. ;    Take a breath between pokes to the UART chip to give it time to
  981. ;    recover ready for next i/o command.  JMP $+2 is a little too tight.
  982.  
  983.     push    cx
  984.     mov    cx,10d
  985. wait3:
  986.     loop    Wait3
  987.     pop    cx
  988.  
  989.     ret
  990.  
  991. Breath    EndP
  992.  
  993. ;=======================================
  994.  
  995. CODE ends
  996. end start
  997.