; This module contains all the low level communications port I/O ; routines. This code mimics much of what the BIOS does. ;12/19/83 Brian Orr-- Added serial control port initialization routine ; to set RTS and DTR high. CSEG $ mnstat EQU 042H ; Status port. mndata EQU 040H ; Data port. mnctrl EQU 002H ; Control port. ; Interrupt vector locations. These are all in data segment 0. mnoff EQU 90H ; Main data port interrupt routine offset. mnseg EQU 92H ; Main data port interrupt routine segment. mnchnd EQU 80H ; Size of circular buffer. output EQU 04H ; Bit for output ready. input EQU 01H ; Bit for input ready. ; Input data from port. Preserves all ACs and returns char in ; AL. Gets the char from the ring buffer. Assumes a char is ; already there. inchr: push bx cli ; Disable interrupts while were are playing. dec mnchrn ; Decrement the number of chars in the buffer. mov bx, mnchop ; Get the pointer into the buffer. inc bx ; Increment to the next char. cmp bx, OFFSET mnchrs+mnchnd ; Past the end? jb inchr2 lea bx, mnchrs ; If so wrap around to the start. inchr2: mov mnchop, bx ; Save the updated pointer. mov al, [bx] ; Get the character. sti ; All done, we can restore interrupts. pop bx ret ; Output data to port. Trashes DX and prints char in AL. outchr: mov dx, mndata out dx, al ret ; Test if data is available from port. instat: cmp mnchrn, 0 ; Any chars in the buffer? jnz inst2 ret inst2: jmp rskp ; Test if port is ready to send next char. Returns RETSKP if ready. ; Trashes dx. outwt: push ax mov dx, mnstat in al, dx test al, output pop ax jnz outwt2 ret outwt2: jmp rskp ; Output the character, checking first to make sure the port is clear. prtout: push dx prtou2: call outwt ; Wait til the port is ready. jmp prtou2 call outchr ; Output it. pop dx ret ; This routine handles the interrupts on input. mnint: push ax ; Save anything we might mess up. push bx push dx push ds mov ax, cs:mndseg ; Set old DSEG as our present segment. mov ds, ax call mnproc ; Process the character. mov dx, mnstat ; Get the status port. mov al, 38H out dx, al ; Tell the port we finished with the interrupt. pop ds pop dx pop bx pop ax iret ; Restore and return from the interrupt. ; This routine (called by MNINT) gets a char from the main port ; and puts it in the infamous circular buffer. mnproc: mov dx, mnstat in al, dx ; Get the port status. test al, input ; Any there? jnz mnpro2 ; Yup, go take care of it. ret ; Whoops, just a false alarm. mnpro2: mov al, 1 ; Point to RR1. out dx, al in al, dx ; Read RR1. mov ah, al ; Save it. mov al, 30H ; Reset any errors. out dx, al mov dx, mndata in al, dx ; Read the char. cmp mnchrn, mnchnd ; Is the buffer full? je mnperr ; If so, take care of the error. inc mnchrn ; Increment the character count. mov bx, mnchip ; Get the buffer input pointer. inc bx ; Increment it. cmp bx, OFFSET mnchrs+mnchnd ; Past the end? jb mnpro3 lea bx, mnchrs ; Yes, point to the start again. mnpro3: mov mnchip, bx ; Save the pointer. mov [bx], al ; Put the character in the buffer. ret mnperr: ret ; Just return on an error for now. mndseg DW 0 ; Storage in CSEG to point to DSEG (for ; interrupt handler). ; Init the 7201 for 8 bits, no parity, and 1 stop bit. serini: cmp mnintf, 0 ; Have we initialized already? jz serin2 ; No, proceed. ret ; Yes, don't bother to do it again. serin2: mov mnintf, 0FFH ; Say we've already init'ed. mov ax, ds mov cs:mndseg, ax ; Save the data segment somewhere in CSEG. push ds ; Save the data segment. mov ax, 0 mov ds, ax ; We want DSEG = 0. cli ; Turn off interrupts. mov ax, OFFSET mnint ; Point to the interrupt routine offset. mov .mnoff, ax ; Put in the main port interrupt offset addr. mov ax, cs ; Get our code segment. mov .mnseg, ax ; Put in the main port interrupt segment addr. sti ; Restore interrupts. pop ds ; Restore data segment. mov dx, mnstat ; Point to status port. mov al, 18H out dx, al ; Reset the port. mov al, 14H out dx, al ; Select register 4. mov al, 44H ; 16X clock, 1 stop bit, no parity. out dx, al mov al, 13H out dx, al ; Select register 3. mov al, 0C1H ; 8 bits/char, RX enable. out dx, al mov al, 15H out dx, al ; Select register 5. mov al, 0EAH ; 8 bits/char, TX enable, RTS and DTR. out dx, al mov al, 11H out dx, al ; Select register 1. mov al, 18H out dx, al ; Enable interrupt processing on this port. ret ; Init the communications control port (02H) to set RTS & DTR high serin3: mov dx, mnctrl ;point to comm control port mov al, 0F0H ;set RTS & DTR high out dx, al ret DSEG $ mnintf DB 0 ; Flag saying whether we've init'ed port. mnchrn DB 0 ; Number of chars in the buffer. mnchrs RB 80H ; Circular character buffer for input. mnchip DW mnchrs-1+mnchnd ; Input pointer into character buffer. mnchop DW mnchrs-1+mnchnd ; Output pointer into character buffer.