jpm@bnl44.UUCP (John McNamee) (10/01/85)
The following program patches the Tandy 2000 BIOS so it won't lock up at random times during RS232 I/O. Assemble with MASM, process with LINK, and then use EXE2BIN to create RS232.COM. Place RS232 in your AUTOEXEC file. If you lack MASM or don't know how to use it, send me mail and maybe I can arrange to send you a disk. I can only do this for limited number of people since I'm not in the disk duplication business. I've had this patch up on CompuServe for a number of months, and everybody there seems very pleased with its operation. It has broken one program (Tandy 2000 FIDO), but that program is known to have many bugs so I'm not very concerned. The problem is probably not in my code since it works with everything else. This patch is available free for non-commercial use. I have retained a contract killer to enforce my copyright. You wouldn't want you and your family to become a murder statistic, would you? [Note to Arpanet INFO-IBMPC moderator: Feel free to include this in your online library.] ;---------------------------------------------------------------------------- ; ; Replacement for the Tandy 2000 RS232 handler ; ; Copyright 1985 by John McNamee. ; ; This software is made available for non-commercial use. If I find ; you selling it, my lawyers will teach you a lesson in the copyright ; laws that you will never forget. ; ;---------------------------------------------------------------------------- ; ; There are some differences between these routines and the BIOS. ; I do not check Data Set Ready, or any other modem status, before ; sending characters. If the UART is ready, I send the character. ; This makes it easier to do machine-to-machine hardwire connections. ; I do not fully implement the XON/XOFF processing. Only "HOST" type ; processing is done: if the other side sends an XOFF to the 2000, I ; stop transmitting until I get an XON. Nothing is done if the 2000 ; input buffer fills up; no XOFF is sent, and excess characters are ; just ignored. This was the easiest way to implement things, and ; should be OK for most people. It should be noted that the IBM PC ; doesn't do either type, so many programs handle all their own ; XON/XOFF processing already. ; ;---------------------------------------------------------------------------- bufsiz equ 256 ;Size of input buffer code segment public 'code' assume cs:code, ds:code org 100h entry: jmp setup ;---------------------------------------------------------------------------- ; Runtime data area ;---------------------------------------------------------------------------- port12: db ? ;Copy of last byte sent to port 12 hold: db ? ;XON/XOFF status flags inptr: dw ? ;Buffer input pointer outptr: dw ? ;Buffer output pointer inbuf: db bufsiz dup (?) ;---------------------------------------------------------------------------- ; INT 14 handler ;---------------------------------------------------------------------------- int14 proc near push bx push cx push dx push ds push cs pop ds ;DS=CS cmp ah,00 ;Reset Comm Port jnz not_0 and ah,3 ;We only want bits 0 and 1 mov byte ptr hold,dh ;Set XON/XOFF flags pushf db 9Ah ;Opcode for long jump oldint: dw ?,? call flush ;Flush the buffer mov al,36h ;Disable transmitter call outctl ;Output to control port call stat jmp exit14 not_0: cmp ah,01 ;Transmit Character jnz not_1 call send jmp exit14 not_1: cmp ah,02 ;Receive Character jnz not_2 call recv jmp exit14 not_2: cmp ah,03 ;Get Current Comm Status jnz not_3 call stat jmp exit14 not_3: cmp ah,04 ;Flush Comm Buffer jnz exit14 call flush exit14: pop ds pop dx pop cx pop bx iret int14 endp ;---------------------------------------------------------------------------- ; Send a character ;---------------------------------------------------------------------------- send proc near push ax mov al,37h ;Enable transmitter call outctl mov cx,0000 ;Timeout counter mov dl,2 wait1: in al,12h ;Get UART status test al,01 ;UART ready? jz wait2 test byte ptr hold,10h ;Is "stop transmitting" flag set? jz send1 wait2: loop wait1 dec dl ;Bump counter jnz wait1 pop ax call stat ;Get status or ah,80h ;Set timeout error ret send1: pop ax out 10h,al ;Send character call stat ;Return status ret send endp ;---------------------------------------------------------------------------- ; Receive a character ;---------------------------------------------------------------------------- recv proc near cli mov bx,outptr cmp bx,inptr ;Is buffer empty? jnz recv1 sti ;Allow interrupt to happen nop nop jmp recv ;Go back and try again recv1: mov al,cs:[bx] ;Get character inc bx cmp bx,offset inbuf+bufsiz ;At end of buffer? jnz recv2 mov bx,offset inbuf ;Wrap around recv2: mov outptr,bx mov ah,00h ;No errors returned sti ret recv endp ;---------------------------------------------------------------------------- ; Flush input buffer ;---------------------------------------------------------------------------- flush proc near cli and dh,3 mov byte ptr hold,dh mov ax,offset inbuf mov outptr,ax mov inptr,ax sti ret flush endp ;---------------------------------------------------------------------------- ; Get status ;---------------------------------------------------------------------------- stat proc near xor ah,ah push bx cli mov bx,inptr cmp bx,outptr sti pop bx jz stat1 or ah,01h ;There is data in the buffer stat1: in al,12h ;Get UART status push ax mov al,byte ptr port12 ;Get last value sent to UART call outctl ;Send it again to clear error status pop ax test al,10h ;Overrun error? jz stat2 or ah,02h stat2: test al,08h ;Parity error? jz stat3 or ah,04h stat3: test al,20h ;Framing error? jz stat4 or ah,08h stat4: test al,08h ;Break detected? jz stat5 or ah,10h stat5: test al,01h ;TxRDY? jz stat6 or ah,60h stat6: mov al,20h ;Fake modem status (CTS and DSR set) ret stat endp ;---------------------------------------------------------------------------- ; INT 72 handler ;---------------------------------------------------------------------------- int72 proc near cli push ax push bx push cx push dx push ds push cs pop ds ;DS = CS ; Get UART status. Check if a received character is ready. in al,12h test al,02h jz exit72 ; Get character from UART and stuff in buffer in al,10h push ax and al,7Fh ;Strip parity test byte ptr hold,02 ;Should we do XON/XOFF processing? jz int72b cmp al,'S'-40h ;Did we get an XOFF? jne int72a or byte ptr hold,10h ;Set "stop transmitting" flag pop ax jmp exit72 int72a: cmp al,'Q'-40h ;Did we get an XON? jne int72b and byte ptr hold,0EFh ;Clear "stop transmitting" flag pop ax jmp exit72 int72b: pop ax mov bx,inptr ;Get buffer input pointer mov [bx],al ;Store character in buffer inc bx cmp bx,offset inbuf+bufsiz ;At end of buffer jnz ckfull mov bx,offset inbuf ;Wrap around ckfull: cmp bx,outptr ;Buffer full? jz exit72 mov inptr,bx ; Clear interrupt and return exit72: mov al,36h ;Leave transmitter disabled call outctl mov dx,0060h mov al,20h out dx,al mov al,0Bh out dx,al ;Clear 8259 interrupt controler sti nop nop in al,dx or al,al jnz not186 cli mov dx,0FF22h mov ax,8000h out dx,ax ;Clear 186 interrupt controler not186: sti pop ds pop dx pop cx pop bx pop ax iret int72 endp ;---------------------------------------------------------------------------- ; Output byte to UART control port ;---------------------------------------------------------------------------- outctl proc near out 12h,al mov byte ptr port12,al ret outctl endp ;---------------------------------------------------------------------------- ; Initialize everything ;---------------------------------------------------------------------------- setup proc near push cs pop ds ;DS=CS ; Test version number mov ah,30h int 21h ;GetVersion cmp ax,0B02h ;Is it 02.11.xx? jz ver_ok mov dx,offset badver call prtmsg ;Print bad version message mov ax,4C01h int 21h ;Exit ver_ok: ; Get old vector mov ax,3514h ;Get vector for INT 14h int 21h mov oldint+2,es ;Save old interrupt segment mov oldint,bx ;Save old interrupt offset mov ax,es cmp ax,0060h ;Already installed jz not_in mov dx,offset inserr call prtmsg ;Print already installed message mov ax,4C01h int 21h ;Exit not_in: ; Setup pointers cli ;We need silence for this next trick xor al,al mov byte ptr hold,al mov ax,offset inbuf mov inptr,ax ;Set input pointer mov outptr,ax ;Set output pointer ; Install new vectors mov ax,2514h ;Set vector for INT 14h mov dx,offset int14 int 21h mov ax,2553h ;Set vector for INT 53h int 21h mov ax,2572h ;Set vector for INT 72h mov dx,offset int72 int 21h sti ; Initialize RS232 port to 300 baud, 8 bits, No parity, 1 stop bit mov ah,00h mov al,43h mov dx,0000h int 14h ; Let the user know everything is OK and exit mov dx,offset insmsg call prtmsg ;Print installed message mov ax,offset setup ;First byte after resident code mov cl,4 shr ax,cl ;Turn into paragraph count inc ax ;Keep one extra paragraph mov dx,ax ;DX=final paragraph count mov ax,3100h ;Keep process int 21h setup endp ;---------------------------------------------------------------------------- ; Print message ;---------------------------------------------------------------------------- prtmsg proc near mov ah,09 int 21h ret prtmsg endp db 'Copyright 1985 by John McNamee.' insmsg: db 13,10,'RS232 fix for Tandy 2000 BIOS installed.',13,10,'$' badver: db 13,10,'This fix is only needed on MSDOS 02.11.02!',13,10,'$' inserr: db 13,10,'RS232 fix already installed!',13,10,'$' code ends end entry -- John P. McNamee decvax!philabs!sbcs!bnl44!jpm jpm@BNL44.ARPA