Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watnot!watmath!clyde!rutgers!lll-lcc!well!hoptoad!gnu From: gnu@hoptoad.UUCP Newsgroups: net.sources Subject: uuslave (free uucp), version hoptoad-1.11, part 2 of 2 Message-ID: <1926@hoptoad.uucp> Date: Tue, 24-Mar-87 04:01:41 EST Article-I.D.: hoptoad.1926 Posted: Tue Mar 24 04:01:41 1987 Date-Received: Thu, 26-Mar-87 01:17:46 EST References: <1925@hoptoad.uucp> Organization: Nebula Consultants in San Francisco Lines: 1234 Here is part 2 of the latest uuslave distribution. Have fun... John "Use the Source, Luke" Gilmore PS: In the subject of part 1, I called uuslave public domain. This version is copyright by me and distributed under the GNU rules. Thus it is free, but not public domain. Sorry for the confusion. : To unbundle, sh this file echo packet.driver.ms cat >packet.driver.ms <<'@@@ Fin de packet.driver.ms' .\" @(#) packet.driver.ms Version hoptoad-1.3 87/03/24 .\" .\" format this with [nt]roff -ms. .\" .\" From: greg@sgi.uucp (Greg Chesson) .\" Newsgroups: mod.std.unix .\" Volume-Number: Volume 9, Number 55 .\" Subject: Packet Driver Protocol .\" Message-ID: <7136@ut-sally.UUCP> .\" Date: 11 Feb 87 23:44:09 GMT .\" .\" This message contains a copy of ``Packet Driver Protocol,'' .\" written by G. L. Chesson while he was at Bell Laboratories. .\" He remarks that it was approved for public distribution, and that .\" .\" The version of the note that you probably have omits the .\" detail that the transmitted checksum is really 0125252 .\" - the block checksum function. .\" .\" [Note that 0125252 is 0xAAAA, which is easier to remember. .\" I have folded this update into the document. -- hoptoad!gnu] .ce .B Packet Driver Protocol .R .sp 1 .ce G. L. Chesson .br .ce Bell Laboratories .SH Abstract .in +.5i .PP These notes describe the packet driver link protocol that was supplied with the Seventh Edition of .UX and is used by the UUCP program. .in -.5i .SH General .PP Information flow between a pair of machines may be regulated by first representing the data as sequence-numbered .I packets .R of data and then establishing conventions that govern the use of sequence numbers. The .I PK, .R or .I packet driver, .R protocol is a particular instance of this type of flow-control discipline. The technique depends on the notion of a transmission .I window .R to determine upper and lower bounds for valid sequence numbers. The transmitter is allowed to retransmit packets having sequence numbers within the window until the receiver indicates that packets have been correctly received. Positive acknowledgement from the receiver moves the window; negative acknowledgement or no acknowledgement causes retransmission. The receiver must ignore duplicate transmission, detect the various errors that may occur, and inform the transmitter when packets are correctly or incorrectly received. .PP The following paragraphs describe the packet formats, message exchanges, and framing used by the protocol as coded in the UUCP program and the .UX kernel. Although no attempt will be made here to present internal details of the algorithms that were used, the checksum routine is supplied for the benefit of other implementors. .SH Packet Formats .PP The protocol is defined in terms of message transmissions of 8-bit bytes. Each message includes one .I control .R byte plus a .I data segment .R of zero or more information bytes. The allowed data segment sizes range between 32 and 4096 as determined by the formula 32(2\uk\d) where k is a 3-bit number. The packet sequence numbers are likewise constrained to 3-bits; i.e. counting proceeds modulo-8. .PP The control byte is partitioned into three fields as depicted below. .bp .nf .sp .in 1i .ls 1 bit 7 6 5 4 3 2 1 0 t t x x x y y y .ls 1 .in -1i .fi .sp The .I t .R bits indicate a packet type and determine the interpretation to be placed on the .I xxx .R and .I yyy .R fields. The various interpretations are as follows: .in +1i .sp .nf .ls 1 .I tt interpretation .sp .R 00 control packet 10 data packet 11 `short' data packet 01 alternate channel .ls 1 .fi .sp .in -1i A data segment accompanies all non-control packets. Each transmitter is constrained to observe the maximum data segment size established during initial synchronization by the receiver that it sends to. Type 10 packets have maximal size data segments. Type 11, or `short', packets have zero or more data bytes but less than the maximum. The first one or two bytes of the data segment of a short packet are `count' bytes that indicate the difference between the maximum size and the number of bytes in the short segment. If the difference is less than 127, one count byte is used. If the difference exceeds 127, then the low-order seven bits of the difference are put in the first data byte and the high-order bit is set as an indicator that the remaining bits of the difference are in the second byte. Type 01 packets are never used by UUCP and need not be discussed in detail here. .PP The sequence number of a non-control packet is given by the .I xxx .R field. Control packets are not sequenced. The newest sequence number, excluding duplicate transmissions, accepted by a receiver is placed in the .I yyy .R field of non-control packets sent to the `other' receiver. .PP There are no data bytes associated with a control packet, the .I xxx .R field is interpreted as a control message, and the .I yyy .R field is a value accompanying the control message. The control messages are listed below in decreasing priority. That is, if several control messages are to be sent, the lower-numbered ones are sent first. .in +1i .nf .ls 1 .sp .I xxx name yyy .R 1 CLOSE n/a 2 RJ last correctly received sequence number 3 SRJ sequence number to retransmit 4 RR last correctly received sequence number 5 INITC window size 6 INITB data segment size 7 INITA window size .in -i .ls 1 .fi .sp .PP The CLOSE message indicates that the communications channel is to be shut down. The RJ, or .I reject, .R message indicates that the receiver has detected an error and the sender should retransmit after using the .I yyy .R field to update the window. This mode of retransmission is usually referred to as a `go-back-N' procedure. The SRJ, or .I selective reject, .R message carries with it the sequence number of a particular packet to be retransmitted. The RR, or .I receiver ready, .R message indicates that the receiver has detected no errors; the .I yyy .R field updates the sender's window. The INITA/B/C messages are used to set window and data segment sizes. Segment sizes are calculated by the formula 32(2\uyyy\d) as mentioned above, and window sizes may range between 1 and 7. .PP Measurements of the protocol running on communication links at rates up to 9600 baud showed that a window size of 2 is optimal given a packet size greater than 32 bytes. This means that the link bandwidth can be fully utilized by the software. For this reason the SRJ message is not as important as it might otherwise be. Therefore the .UX implementations no longer generate or respond to SRJ messages. It is mentioned here for historical accuracy only, and one may assume that SRJ is no longer part of the protocol. .SH Message Exchanges .SH Initialization .PP Messages are exchanged between four cooperating entities: two senders and two receivers. This means that the communication channel is thought of as two independent half-duplex data paths. For example the window and segment sizes need not be the same in each direction. .PP Initial synchronization is accomplished with two 3-way handshakes: two each of INITA/INITB/INITC. Each sender transmits INITA messages repeatedly. When an INITA message is received, INITB is sent in return. When an INITB message is received .I and .R an INITB message has been sent, an INITC message is sent. The INITA and INITB messages carry with them the packet and window size that each receiver wants to use, and the senders are supposed to comply. When a receiver has seen all three INIT messages, the channel is considered to be open. .PP It is possible to design a protocol that starts up using fewer messages than the interlocked handshakes described above. The advantage of the more complicated design lies in its use as a research vehicle: the initial handshake sequence is completely symmetric, a handshake can be initiated by one side of the link while the connection is in use, and the software to do this can utilize code that would ordinarily be used only once at connection setup time. These properties were used in experiments with dynamically adjusted parameters. That is attempts were made to adapt the window and segment sizes to changes observed in traffic while a link was in use. Other experiments used the initial handshake in a different way for restarting the protocol without data loss after machine crashes. These experiments never worked well in the packet driver and basically provided the impetus for other protocol designs. The result as far as UUCP is concerned is that initial synchronization uses the two 3-way handshakes, and the INIT messages are ignored elsewhere. .SH Data Transport .PP After initial synchronization each receiver sets a modulo-8 incrementing counter R to 0; each sender sets a similar counter S to 1. The value of R is always the number of the most recent correctly received packet. The value of S is always the first sequence number in the output window. Let W denote window size. Note that the value of W may be different for each sender. .PP A sender may transmit packets with sequence numbers in the range S to (S+W-1)\ mod-8. At any particular time a receiver expects arriving packets to have numbers in the range (R+1)\ mod-8 to (R+W)\ mod-8. Packets must arrive in sequence number order are are only acknowledged in order. That is, the `next' packet a receiver will acknowledge must have sequence number (R+1)\ mod-8. .PP A receiver acknowledges receipt of data packets by arranging for the value of its R counter to be sent across the channel where it will be used to update an S counter. This is done in two ways. If data is flowing in both directions across a channel then each receiver's current R value is carried in the .I yyy .R field of non-control packets. Otherwise when there is no bidirectional data flow, each receiver's R value is transmitted across the link as the .I yyy .R field of an RR control packet. .PP Error handling is up to the discretion of the receiver. It can ignore all errors in which case transmitter timeouts must provide for retransmission. The receiver may also generate RJ error control packets. The .I yyy .R field of an incoming RJ message replaces the S value of the local sender and constitutes a request for retransmission to start at that sequence number. The .I yyy .R field of an incoming SRJ message selects a particular packet for retransmission. .PP The resemblance between the flow control procedure in the packet driver and that defined for X.25 is no accident. The packet driver protocol began life as an attempt at cleaning up X.25. That is why, for example, control information is uniform in length (one byte), there is no RNR message (not needed), and there is but one timeout defined in the sender. .SH Termination .PP The CLOSE message is used to terminate communications. Software on either or both ends of the communication channel may initiate termination. In any case when one end wants to terminate it sends CLOSE messages until one is received from the other end or until a programmable limit on the number of CLOSE messages is reached. Receipt of a CLOSE message causes a CLOSE message to be sent. In the .UX environment it also causes the SIGPIPE or `broken pipe' signal to be sent to the local process using the communication channel. .SH Framing .PP The term .I framing .R is used to denote the technique by which the beginning and end of a message is detected in a byte stream; .I error control .R denotes the method by which transmission errors are detected. Strategies for framing and error control depend upon additional information being transmitted along with the control byte and data segment, and the choice of a particular strategy usually depends on characteristics of input/output devices and transmission media. .PP Several framing techniques are in used in support of PK protocol implementations, not all of which can be described in detail here. The technique used on asynchronous serial lines will be described. .PP A six byte framing .I envelope .R is constructed using the control byte C of a packet and five other bytes as depicted below. .in +1i .in -1i The symbol denotes the ASCII ctrl/P character. If the envelope is to be followed by a data segment, has the value log\d2\u(size)-4; i.e. 1 \(<= k \(<= 8. If k is 9, then the envelope represents a control packet. The and bytes are the low-order and high-order bytes respectively of 0xAAAA minus a 16-bit checksum. For control packets, this 16-bit checksum is the same as the control byte C. For data packets, the checksum is calculated by the program below. The byte is the exclusive-or of . Error control is accomplished by checking a received framing envelope for compliance with the definition, and comparing a checksum function of the data segment with . .PP This particular framing strategy assumes data segments are constant-sized: the `unused' bytes in a short packet are actually transmitted. This creates a certain amount of overhead which can be eliminated by a more complicated framing technique. The advantage of this strategy is that i/o devices can be programmed to take advantage of the constant-sized framing envelopes and data segments. .bp .PP The checksum calculation is displayed below as a C function. Note that the code is not truly portable because the definitions of .I short and .I char are not necessarily uniform across all machines that might support this language. This code assumes that .I short and .I char are 16 and 8-bits respectively. .PP .in +.5i .nf .ft CW .ls 1 /* [Original document's version corrected to actual version] */ chksum(s,n) register char *s; register n; { register short sum; register unsigned short t; register short x; sum = -1; x = 0; do { if (sum<0) { sum <<= 1; sum++; } else sum <<= 1; t = sum; sum += (unsigned)*s++ & 0377; x += sum^n; if ((unsigned short)sum <= t) { sum ^= x; } } while (--n > 0); return(sum); } .fi .in -.5i .ft R @@@ Fin de packet.driver.ms echo comport.h cat >comport.h <<'@@@ Fin de comport.h' /* * Comport.h * * defines the bit masking for the get_mcr() * * @(#) comport.h Version hoptoad-1.3 87/03/24 * * Copyright (C) Tim M. Pozar 1987 * Anyone can use this code for anything, but it is copyright by Tim * and you must leave his copyright in the code. * */ /* * get_msr() * Function to read (get) the byte located in the Modem Status * Register (3FEh). The table below describes the byte returned. * bit description * 0 Delta Clear to Send (DCTS) * Indicates that the !CTS input to the chip has changed state * since the last time it was read by the processor. * 1 Delta Data Set Ready (DDSR) * Indicates that the !DRS input to the chip has changed since * last time it was read by the processor. * 2 Trailing Edge Ring Indicator (TERI) * Indicates that the !RI input to the chip has changed from * an on (logical 1) to an off (logical 0) condition. * 3 Delta Rx Line Signal detect (DRLSD) * Indicates that the !RLSD input to the chip has changed state. * NOTE: Whenever bit 0, 1, 2, or 3 is set to a logical 1, a modem status * interrupt is generated. * * 4 Clear to Send (CTS) * This bit is the complement of the clear to send (!CTS) input. * If bit 4 (LOOP) of the MCR is set to a logical 1, this is * equivalent to RTS in the MCR. * 5 Data Set Ready (DSR) * This bit is the complement of the data set ready (!DSR) input. * If bit 4 (LOOP) of the MCR is set to a logical 1, this is * equivalent to DTR in the MCR. * 6 Ring Indicator (RI) * This bit is the complement of the ring indicator (!RI) input. * If bit 4 (LOOP) of the MCR is set to a logical 1, this is * equivalent to OUT 1 in the MCR. * 7 Receive Line Signal Detect (RLSD) or Carrier Detect (CD). * This bit is the complement of the received line signal detect * (!RLSD) input. If bit 4 (LOOP) of the MCR is set to a logical 1, * this is equivalent to OUT 2 in the MCR. */ #define DCTS 1 #define DDSR 2 #define TERI 4 #define DRLSD 8 #define CTS 16 #define DST 32 #define RI 64 #define RLSD 128 /* Also known as ... */ #define CD 128 @@@ Fin de comport.h echo comport.asm cat >comport.asm <<'@@@ Fin de comport.asm' title IBM PC Communications I/O Routines ; ; @(#) comport.asm Version hoptoad-1.3 87/03/24 ; ; Orginal code -- Curt Klinsing ; ; Changes and updates -- Copyright (c) 1987 Tim Pozar ; Anyone can use this code for anything, but it is copyright by Tim ; and you must leave his copyright in the code. ; ; ver: 0 ; rev: 2 ; March 13th 1987 ; This code is in a very early stage and should not be let out. ; Several other extensive functions are planned as well as changes ; to the current code. ; ; 2/20/87 ; Changed segment declarations and function names (eg. _function) ; to fit Microsoft C 4.0 and linker requirements. ; ; FUNCTIONS CHANGED/ADDED -- ; set_tty(port_number) ; Function to find current settings of the port and set up serial ; port for 'baud' and 'lcbyte', and enable DTR. This will set up the ; port number base addressed passed to it (eg. 3F8h) and all functions ; will use this port until the function is used again. (NOT READY FOR USE) ; ; reset_tty() ; Function to put the port back into the state it was when it was ; first found by set_tty(). If set_tty() was not called it will not ; change the settings of the port. (NOT READY FOR USE) ; ; 3/13/87 ; get_msr() ; Function to read (get) the byte located in the Modem Status ; Register (3FEh). The table below describes the byte returned. ; bit description ; 0 Delta Clear to Send (DCTS) ; Indicates that the !CTS input to the chip has changed state ; since the last time it was read by the processor. ; 1 Delta Data Set Ready (DDSR) ; Indicates that the !DRS input to the chip has changed since ; last time it was read by the processor. ; 2 Trailing Edge Ring Indicator (TERI) ; Indicates that the !RI input to the chip has changed from ; an on (logical 1) to an off (logical 0) condition. ; 3 Delta Rx Line Signal detect (DRLSD) ; Indicates that the !RLSD input to the chip has changed state. ; NOTE: Whenever bit 0, 1, 2, or 3 is set to a logical 1, a modem status ; interrupt is generated. ; ; 4 Clear to Send (CTS) ; This bit is the complement of the clear to send (!CTS) input. ; If bit 4 (LOOP) of the MCR is set to a logical 1, this is ; equivalent to RTS in the MCR. ; 5 Data Set Ready (DSR) ; This bit is the complement of the data set ready (!DSR) input. ; If bit 4 (LOOP) of the MCR is set to a logical 1, this is ; equivalent to DTR in the MCR. ; 6 Ring Indicator (RI) ; This bit is the complement of the ring indicator (!RI) input. ; If bit 4 (LOOP) of the MCR is set to a logical 1, this is ; equivalent to OUT 1 in the MCR. ; 7 Receive Line Signal Detect (RLSD). ; This bit is the complement of the received line signal detect ; (!RLSD) input. If bit 4 (LOOP) of the MCR is set to a logical 1, ; this is equivalent to OUT 2 in the MCR. ; ; Currently this driver is set up for COM1 (3f8h). ; If you are using the interupt driven buffer, take out the code ; that enables the DTR so that it doesn't get raised until the vectors ; are initilized. ; _TEXT SEGMENT BYTE PUBLIC 'CODE' _TEXT ENDS _DATA SEGMENT BYTE PUBLIC 'DATA' _DATA ENDS CONST SEGMENT BYTE PUBLIC 'CONST' CONST ENDS _BBS SEGMENT BYTE PUBLIC 'BBS' _BBS ENDS DGROUP GROUP CONST, _BBS, _DATA ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP _TEXT SEGMENT ; ;A set of Lattice C and MSC callable functions to support ;interrupt driven character I/O on the IBM PC. Input ;is buffered, output is polled. ; ;added functions (TMP) -- public _set_tty ;find current settings, and initialize ;comm port to 8 bits and set DTR public _reset_tty ;reset to settings that set_tty() found public _get_msr ;get MSR byte from port. ; ;original functions -- public _init_comm ;initialize the comm port interupts, public _uninit_comm ;remove initialization, public _set_xoff ;enable/disable XON/XOFF, public _get_xoff ;read XON/XOFF state, public _rcvd_xoff ;returns true if XOFF rcvd, public _sent_xoff ;true if XOFF sent, public _inp_cnt ;returns count of rcv chars, public _inp_char ;get one char from buffer, public _inp_flush ;flush input buffer, public _outp_char ;output a character, ; ;A better description can be found in the comment ;block in each function. ; ; assume cs:pgroup ; FALSE EQU 0 TRUE EQU NOT FALSE ; BASE EQU 03F8H ;BASE FOR SERIAL BOARD ; LCR equ BASE+3 ; Line control register IER equ BASE+1 ; Interrup Enable Register MCR EQU BASE+4 ;modem control register MDMSTA EQU BASE+5 ;line status register MDMMSR EQU BASE+6 ;modem status register MDMBAD EQU BASE ;lsb baud resgister EnblDRdy equ 01H ; enable 'data-ready' interrupt bit IntCtlr EQU 21H ;OCW 1 FOR 8259 CONTROLLER EnblIRQ4 EQU 0EFH ;Enable COMMUNICATIONS (IRQ4) dataport EQU BASE ;transmit/receive data port MaskIRQ4 EQU 10H ;BIT TO DISABLE COMM INTERRUPT (IRQ4) MDMCD EQU 80H ;mask for carrier dectect SETBAU EQU 80H ;code for Divisor Latch Access Bit MDMTBE EQU 20H ;8250 tbe flag MDMBRK EQU 40H ;command code for 8250 break LINMOD EQU 03H ;line mode=8 bit, no parity MDMMOD EQU 0BH ;modem mode = DTR and RTS HIGH STOP2 EQU 04H ;BIT FOR TWO STOP BITS IF BAUD<300 RS8259 EQU 20H ;OCW 3 FOR 8259 RSTINT EQU 64H ;SPECIFIC EOI FOR COMM INTERRUPT XOFF EQU 13H ;XOFF character XON EQU 11H ;XON character ; ; MISCELLANEOUS EQUATES ; CR EQU 13 LF EQU 10 DosCall EQU 33 ;INTERRUPT NUMBER FOR DOS CALL CNSTAT EQU 11 ;FUNCTION NUMBER FOR CONSOLE STATUS CNIN EQU 1 ;FUNCTION NUMBER FOR CONSOLE INPUT BUFSIZ EQU 512 ;Max NUMBER OF CHARS SetIntVect EQU 25H ;SET INTERRUPT VECTOR FUNCTION NUMBER ; ; Communication parameters -- ; baud equ 96 ; 1047 = 110 (are you kidding?) ; 384 = 300 ; 96 = 1200 ; 48 = 2400 ; 24 = 4800 ; 12 = 9600 parity equ 00000b ;00000 = none ;01000 = odd ;11000 = even stopbit equ 000b ; 000 = 1 bit ; 100 = 2 bits wordlth equ 11b ; 10 = 7 bits ; 11 = 8 bits lcbyte equ parity+stopbit+wordlth ;line control byte div_on equ 80h ;divisor latch access bit (DLAB) ; ; DUMP BUFFER, COUNT AND POINTER. ; CIRC_BUF DB BUFSIZ DUP(?) ;ALLOW 512 MaxIMUM BUFFERED CHARACTERS BUF_TOP EQU $ - 1 ;KEEP TRACK OF THE TOP OF THE BUFFER CIRC_TOP DW BUF_TOP ; ; CIRC_IN DW OFFSET CIRC_BUF ;POINTER TO LAST CHAR. PLACED IN BUFFER CIRC_CUR DW OFFSET CIRC_BUF ;POINTER TO NEXT CHAR. TO BE RETRIEVED FROM ; BUFFER CIRC_CT DW 0 ;COUNT OF CHARACTERS USED IN BUFFER SNT_XOFF DB FALSE ;FLAG TO CHECK IF AN XOFF HAS BEEN SEND GOT_XOFF DB FALSE ;FLAG TO CHECK IF AN XOFF HAS BEEN RECEIVED SEE_XOFF DB FALSE ;FLAT TO SEE IF WE ARE INTERESTED IN XON/XOFF ; ; ; set_tty() ; _set_tty proc near push bp ; mov dx,mcr ; in al,dx ; get modem parameters ; mov MCR_BYTE,al ; save them mov dx,lcr ; in al,dx ; get line parameters ; mov LCR_BYTE,al ; save them mov al,div_on out dx,al ; set 8250 for baud rate selection ; can the baud rate divisor be read to save the settings? ; if so, stick the code here. mov ax,baud mov dx,mdmbad out dx,al ; low byte divisor mov al,ah inc dx out dx,al ; high byte divisor mov dx,lcr mov al,lcbyte out dx,al ; set line control reg. mov dx,mcr in al,dx or al,mdmmod out dx,al ; set DTR high flsh: mov dx,dataport in al,dx mov dx,mdmsta in al,dx and al,1 jnz flsh pop bp ret _set_tty endp _reset_tty proc near push bp pop bp ret _reset_tty endp _get_msr proc near push bp push ds ; save data segment push cs pop ds xor ax,ax mov dx,MDMMSR in al,dx pop ds pop bp ret _get_msr endp ; ; set_xoff(flag) Enable (flag != 0) or disable ;int flag; (flag == 0) XON/ XOFF protocol ; for the character input stream. ;If enabled, an XOFF will be sent when the buffer ;reaches 3/4 full. NOTE: an XON will not be sent auto- ;matically. Your program must do it when it sees ;the _rcvd_xoff() flag, and ready for more chars. ; _set_xoff proc near push bp PUSH DS ;SAVE DATA SEGMENT mov bx,[bp+6] push cs pop ds ; move code seg addr to data seg reg. cmp bx,0 jnz to_on mov see_xoff,FALSE jmp done1 to_on: mov see_xoff,TRUE done1: pop ds pop bp ret _set_xoff endp ; ;flag = get_xoff() Returns the current setting ; of the XON/ XOFF flag set ;by set_xoff(), above. ; _get_xoff proc near push bp push ds ; save data reg push cs pop ds ; move code seg addr to data seg reg. xor ax,ax mov al,see_xoff pop ds pop bp ret _get_xoff endp ; ;flag = sent_xoff(); Returns true if an XOFF ; character was sent, indicating ;the receive buffer is 3/4 full. ; _sent_xoff proc near push bp push ds ; save data reg push cs pop ds ; move code seg addr to data seg reg. xor ax,ax mov al,snt_xoff pop ds pop bp ret _sent_xoff endp ; ; rcvd_xoff() Returns true if an XOFF was ; received; will return false as ;soon as an XON is received. Does not effect data output, ;only indicates the above. (Obviously useless for binary ;data.) ; _rcvd_xoff proc near push bp push ds ; save data reg push cs pop ds ; move code seg addr to data seg reg. xor ax,ax mov al,got_xoff pop ds ; restore data reg pop bp ret _rcvd_xoff endp ; ;count = inp_cnt() Returns the number of characters ; available in the input buffer. ; _inp_cnt proc near push bp push ds ; save data segment push cs pop ds ; move code seg addr to data seg reg mov ax,circ_ct pop ds pop bp ret _inp_cnt endp ; ; inp_flush() Flush the input buffer. ; _inp_flush proc near push bp push ds ; save data reg push cs pop ds ; move code seg addr to data seg reg. mov bx,offset circ_buf mov circ_in,bx mov circ_cur,bx xor ax,ax mov circ_ct,ax pop ds pop bp ret _inp_flush endp ; --------- Init ----------------------------------- ; Program initialization: ; -- Set up vector for RS232 interrupt (0CH) ; -- Enbl IRQ4 ; -- Enbl RS232 interrupt on data ready ; ; --------------------------------------------------- _init_comm proc near push bp cli ; ---- Set up INT x'0C' for IRQ4 push ds push cs pop ds ;cs to ds mov dx,offset IntHdlr ;relative adddres of interrupt handler mov al,0cH ;interrupt number for comm. mov ah,SetIntVect ;function number for setting int vector int DosCall ;set interrupt in 8086 table pop ds ;restore DS ; ---- Enbl IRQ4 on 8259 interrupt controller cli in al,IntCtlr ; get current masks and al,EnblIRQ4 ; Reset IRQ4 mask out IntCtlr,al ; And restore to IMR ; --- Enbl 8250 data ready interrupt mov dx,LCR ; DX ==> LCR in al,dx ; Reset DLAB for IER access and al,7FH out dx,al mov dx,IER ; Interrupt Enbl Register mov al,EnblDRdy ; Enable 'data-ready' interrupt out dx,al ; --- Enbl OUT2 on 8250 mov dx,MCR ; modem control register in al,dx ; Enable OUT2 or al,08h ; find out what is in there and out dx,al ; enable the DTR sti pop bp ret _init_comm endp ; ; uninit_comm() Removes the interrupt structure ; installed by _init_comm(). Must be ;done before passing control to the DOS, else chars received ;will be stored into the next program loaded! ; _uninit_comm proc near push bp ; --- Disable IRQ4 on 8259 cli in al,IntCtlr ;GET OCW1 FROM 8259 or al,MaskIRQ4 ;DISABLE COMMUNICATIONS INTERRUPT out IntCtlr,al ; --- Disable 8250 data ready interrupt mov dx,LCR ; DX ==> LCR in al,dx ; Reset DLAB for IER access and al,7FH out dx,al mov dx,IER ; Interrupt Enbl Register mov al,0 ; Disable all 8250 interrupts out dx,al ; --- Disable OUT2 on 8250 mov dx,MCR ; modem control register mov al,0 ; Disable OUT2 out dx,al sti pop bp ret _uninit_comm endp ; ;char inp_char() Return a character from the input ; buffer. Assumes you have called ;inp_cnt() to see if theres any characters to get. ; _inp_char proc near push bp push ds ; save data reg push cs pop ds ; move code seg addr to data seg reg. mov bx,circ_cur xor ax,ax mov al,[bx] ;get next char from circ_buf DEC circ_ct ;decrement circ_buf COUNT CMP bx,circ_top ;ARE WE AT THE TOP OF THE circ_buf? JZ reset_cur ;JUMP IF SO INC bx ;ELSE, BUMP PTR JMP SHORT upd_cur reset_cur: mov bx,OFFSET circ_buf ;RESET circ_in TO BOTTOM OF BUF. upd_cur: mov circ_cur,bx ;SAVE NEW PTR xor cx,cx mov cl,see_xoff ;check if interested in xon/xoff cmp cl,TRUE jnz clnup2 ;not interested, so goto return cmp snt_xoff,TRUE ;have we sent an xoff? jnz clnup2 ;no, so return cmp circ_ct,80h ;yes, so see in buf is now emptying jg clnup2 ;not empty enuf to send xon, jump to ret mov snt_xoff,FALSE mov cl,XON push ax ; save char call comout pop ax clnup2: pop DS ;GET BACK ENTERING DS pop bp ret _inp_char endp ; ; outp_char(c) Output the character to the ;char c; serial port. This is not buffered ; or interrupt driven. ; _outp_char proc near push bp mov bp,sp mov cl,[bp+4] sti call comout pop bp ret _outp_char endp ; ;Local subroutine: output CL to the port. ; comout: mov dx,MDMSTA in al,dx ; get 8250 status and al,MDMTBE ; check for transmitter ready jz comout ; jump if not to wait mov al,cl ; get char to al mov dx,dataport out dx,al ; output char to 8251 ret ; ; RECEIVE INTERRUPT HANDLER (CHANGED TO PLACE CHARACTERS IN A ; CIRCULAR circ_buf AND TO SEND AN XOFF IF THE circ_buf IS MORE THAN ; 3/4 FULL - S.G.) ; IntHdlr: CLI push cx push dx push bx push ax push ds mov ax,cs ;get cur code segment mov ds,ax ;and set it as data segment mov bx,circ_in ;GET circ_buf IN PTR mov DX,dataport ;GET DATA PORT NUMBER IN AL,DX ;GET RECEIVED CHARACTER ; push ax ; push dx ; xor ax,ax ; xor dx,dx ; mov dl,al ; mov ah,2 ; int DosCall ; pop dx ; pop ax xor cx,cx mov cl,see_xoff ;check if interested in xon/xoff cmp cl,TRUE jnz ck_full ;not interested goto ck if buf full mov cl,al ;put char in cl for testing and cl,7fh ;turn off any parity bits cmp cl,XOFF ;see if we got an xoff jnz ck_xon mov got_Xoff,TRUE ; code for handling xon/xoff from remote jmp clnup ck_xon: cmp cl,XON jnz reg_ch mov got_Xoff,FALSE jmp clnup ; ;Normal character; not XON/XOFF, or XON/XOFF disabled. ; reg_ch: test snt_Xoff,TRUE ;SEE IF sentXoff IS SET jnz ck_full ;IF SO, DON'T SEND ANOTHER XOFF CMP circ_ct,(BUFSIZ * 3)/4 ;ALLOW BUF TO BECOME 3/4 FULL BEFORE ; SENDING XOFF jb savch ;IF IT'S OK, CONTINUE push ax ;SAVE CHARACTER mov CL,XOFF ;GET XOFF CHARACTER mov snt_Xoff,TRUE ;RESET sentXoff call comout ; AND SEND IT pop ax ;RETRIEVE CHARACTER JMP SHORT savch ;IF WE'RE HERE, THE circ_buf HAS BUFSIZ-80H ; CHARACTERS ck_full: CMP circ_ct,BUFSIZ ;SEE IF circ_buf ALREADY FULL JZ clnup ; JUMP IF SO, DO NOT PLACE CHARACTER IN BFR savch: mov [bx],AL ;SAVE NEW CHARACTER IN circ_buf inc circ_ct ;BUMP circ_buf COUNT CMP bx,circ_top ;ARE WE AT THE TOP OF THE circ_buf? JZ reset_in ;JUMP IF SO inc bx ;ELSE, BUMP PTR JMP SHORT into_buf reset_in: mov bx,OFFSET circ_buf ;RESET circ_in TO BOTTOM OF BUF. into_buf: mov circ_in,bx ;SAVE NEW PTR clnup: mov AL,RSTINT OUT RS8259,AL ;ISSUE SPECIFIC EOI FOR 8259 pop ds ;GET BACK ENTERING DS pop ax pop bx pop dx pop cx sti iret _TEXT ENDS end @@@ Fin de comport.asm exit 0 -- Copyright 1987 John Gilmore; you can redistribute only if your recipients can. (This is an effort to bend Stargate to work with Usenet, not against it.) {sun,ptsfa,lll-crg,ihnp4,ucbvax}!hoptoad!gnu gnu@ingres.berkeley.edu