[comp.unix.microport] Try thisne!

sandy@turnkey.TCC.COM (Sanford 'Sandy' Zelkovitz) (11/17/88)

The following program was uploaded to my BBS which I though my interest all
users of Microport System V/AT!
 
Sanford <sandy> Zelkovitz     XBBS     714-898-8634

----------------------- cut/snip/whatever here ------------------------------


/******************************************************************************
                            16550 

      a utility that iturns on the FIFO of a NS 16550 chip

               by John Welch, of Igloo Computers

                     Public Domain Software

 Hobbyists, feel free to use, abuse, pirate and re-distribute this program.

       Commercial use prohibited without consent of the author.

                   Send fan mail to jjw@igloo

                  Send flames to jjw@/dev/null

******************************************************************************/
#include <sys/types.h>

#include <sys/io_op.h>

#include <fcntl.h>



int fd;

void outb();

extern int errno;



main() 

{





/*

		I've waded through the NS 16550 docs for several days now,

	and what follows seems accurate enough.

	At any rate, the basic idea is that a 16550 with FIFO enabled

	has (*FINALLY!*) cured igloo's problems with losing newsfeeds. I

	thought I'd make this available to the net in the hopes that it may

	help other people who've been singing the 'microport lost character

	blues.' As microport has been unable to cure this, we finally fixed

	it ourselves. By the way, if you aren't tech-y, this may bore you

	to death. I've got it written to patch tty0 and tty1, and since on a

	16450 or earlier this register isn't writable it should cause no

	problems. Just un-shar it by typing

		sh 16550.shar

	and compile this with

		cc -o 16550 -O 16550.c

	It might be a good idea to chmod this to 700, to prevent users from

	flushing the buffers on you. Adding this to the inittab file or some

	such place should be all thats needed. Run it once at boot-up and

	forget it.

		A bit of history here: Microport's serial port drivers are

	brain-dead. Apparently the problem is with the high-water mark in

	the kernel, and so it's *not* fixable with new drivers. What this means
	is that you lose characters sometimes. It is particularly noticable

	while doing a 9600-baud newsfeed on one serial line while another

	user on the other line is cat-ing a text file at 300 baud. Usually

	when this happens, you get many errors during the newsfeed and as

	often as not you lose the feed altogether. Microport has been told of

	this problem many times, and they've piddled and fuddled and moped

	around trying to fix it. At first they said we should get faster

	hardware because an 8Mhz AT couldn't handle 9600 baud. Fine, we found

	a place that loaned us a 20Mhz 0-wait 4Mbyte 386 board for a weekend.

	Guess what??? The problem was just as bad as before. Then they sent

	us  new driver to install, which did not help the problem. They then

	suggested that we need a smart serial card, to the tune of around

	$1500 or so. They think that 9600 baud cannot be done on these machines.
	That's bull-squat, folks! XENIX does 9600 baud just fine. Microport is

	unable and unwilling to fix this problem. We had to explore alternate

	ways of doing it ourselves, preferrably without costing us hobbyists

	an arm and a leg. We feel we've found an acceptable solution with the

	16550 UART chip.

		The 16550 is a half-way step between a 'smart' serial card

	and the usual 16450-type 'dumb' card. Using the FIFOs in the 16550

	can not only prevent lost characters, but can result in more efficient

	CPU utilization, with less time wasted in processor overhead to read

	each character sent. It does this by a device called a FIFO buffer, a

	First-In, First-Out scheme. When receiving characters, the 16550 will

	only interrupt the CPU when one of two events happens: When enough

	characters have been received (you can define 'enough' to be 1, 4, 8

	or 14) or when at least 1 character has been received and there has

	not been another character come through for 4 times the time 'width'

	of a character. In this manner, when the CPU finally gets interrupted,

	much more data can be dumped to the CPU at once, cutting down on all

	the overhead involved in context-swiching and so forth.

		In addition, if the CPU takes too long to read the FIFO, the

	16550 will send its own flow-control to throttle back the incoming

	data, preventing buffer over-runs that have plagued microport from day

	one.

		The 16550 chip is a drop-in replacement for the 16450, and it

	costs about $25 or so (not much more than the 16450). With this chip

	and a trivial amount of software, you can not only cure microports

	brain-dead serial device driver problems, but you can also enjoy most

	of the benefits of a 'smart' card with very little cost.

		What follows is an explaination of what this program does and

	why it does it. If you have multi-port 'dumb' boards with 8250's,

	16450's or whatever, you *should* be able to replace those chips with

	16550s and modify this program to set (base+2) for each port.

		tty0's base address is 3f8. The FIFO control register is at

	base+2 (3fa). The byte written at this address is defined as follows:



	 Bits 7 & 6 define at what level the 16550 interrupts the CPU. 11 is 14

	bytes deep, 10 is 8 bytes deep, 01 is 4 bytes deep and 00 is 1 byte deep


	 Bits 5 & 4 are not used, so I set them to 00.



	 Bit 3 defines the performance of some pins that are not used on the

	16450, so it's not likely to be of consequence to anything we do. I've

	chosen to keep them performing the way a 16450 would, setting this bit

	0.

	 Bit 2 clears and resets the transmit FIFO.

	 Bit 1 clears and resets the Receive FIFO.

	 Bit 0 turns the FIFO buffering on.

		To turn on the FIFO at tty1 to a 4-byte level, one should

	write a 0x47 to port 0x2fa. To set tty0 at the maximum FIFO level,

	send 0xc7 to port 0x3fa. To disable FIFOs at tty1 send 0 to 0x2fa.

*/





    if ((fd = open("/dev/mem",O_RDWR)) == -1) /* open mem dev for read/write */
    {

        perror("Open /dev/mem");

        exit(1);

    }





    outb(0x3fa,0x87); /* this turns on tty0's FIFO, 8 characters deep */

    outb(0x2fa,0x87); /* this turns on tty1's FIFO, 8 characters deep */



    close(fd); /* all done setting up FIFOs. */

}





void outb(portno, data)

int portno;

unsigned char data;

{

    io_op_t  iop;



    iop.io_port = portno;

    iop.io_byte = data;

    errno = 0; /* clear error indicator */

    ioctl(fd, IOCIOP_WB, &iop); /* write the data to that port */

    if (errno)

	printf("Error setting port %04x\n",portno);

        /* send to stdout so they can re-direct easier */

}