home *** CD-ROM | disk | FTP | other *** search
- /*
- This program clears the 16550A's FIFO to prevent system hangs
- when "Super I/O" cards with SMC665 or SMC666 chips are used with
- communications programs that enable the 16550A UART. Just run this
- program before you run your favorite communications program and you
- should *not* experience further system hangs. NOTE: If you have an
- external device connect it and turn it on BEFORE you run this program.
-
- The specific problem is that if you output a 0x7 to the FIFO control
- register of these chips while there is data in the FIFO the chip will
- go into a state where the Receive Ready flag (bit 0 in the LSR)
- remains high NO MATTER HOW MANY TIMES YOU READ THE RECEIVER BUFFER
- REGISTER. If your communication program is unfortunate enough to enable
- interrupts while the UART is in this condition your system will lockup,
- and require a hardware reset or power cycle to restore operation.
- Needless to say this is inconvenient!
-
- I discovered this problem when I upgraded my "SUPER I/O card" to a
- "SIDE jr L" vlb card. While the features are great I immediately ran into
- problem with EVERY program I have that uses serial I/O. I found that I
- could only execute Windows programs that used serial I/O once, the
- whole system locked up the second time I ran the program. This occurred
- with several different Windows programs. Searching the Microsoft Knowledge
- base yielded the answer... an updated SERIAL.386 driver (search for
- WG1001 for the new driver). Unfortunately the new Windows driver did
- nothing for DOS programs I use regularly such as Qmodem and Telix, that is
- why I wrote this program. The Microsoft writeup provided enough
- information on the problem for this program to be written.
-
-
- Comments are welcome:
-
- Skip Hansen WB6YMH.
- internet: wb6ymh@amsat.org
- BBS: (310) 541-2503
- Packet: WB6YMH@WB6YMH.#SOCAL.CA.USA
-
- If you find this program of value I am pleased, send no cash!
- */
-
- enum UART_TYPE{
- UNKNOWN,
- UART_TYPE_8250,
- UART_TYPE_16450,
- UART_TYPE_16550,
- UART_TYPE_16550A
- };
-
-
- #define RBR 0
- #define THR 0
- #define IER 1
- #define FCR 2
- #define IIR 2
- #define LCR 3
- #define MCR 4
- #define LSR 5
- #define MSR 6
- #define SCR 7
-
- #define FIFO_ENABLED_6 0x40
- #define FIFO_ENABLED_7 0x80
-
- #define FIFO_ENABLE 1
-
-
- void reset(int port)
- {
- int i;
-
- outp(port+FCR,1); // enable FIFO
- if( (inp(port+IIR) & 0xc0) != 0xc0){
- printf("Port 0x%0x does not appear to be an 16550 UART.\n",port);
- return;
- }
- outp(port+FCR,0); // disable FIFO
- i = 0;
- while(i++ < 16 && (inp(port+LSR) & 1)){
- inp(port+RBR);
- }
- if(i == 16){
- printf("Unable to clear FIFO on UART at port 0x%0x after 16 reads!\n",port);
- }
- return;
- }
-
- enum UART_TYPE id_uart(int port)
- {
- char temp;
-
- // first check the scratch register
-
- temp = inp(port+SCR);
- outp(port+SCR,0x55);
- if(inp(port+SCR) != 0x55){
- printf("Uart at port 0x%0x is a 8250.\n",port);
- return UART_TYPE_8250;
- }
-
- outp(port+SCR,0xaa);
- if(inp(port+SCR) != 0xaa){
- printf("UART at port 0x%0x is a 8250.\n",port);
- return UART_TYPE_8250;
- }
-
- outp(port+SCR,temp); // restore original value (an case anyone cares!)
-
- // we have at least a 16450.
-
- outp(port+FCR,0); // disable the FIFO
-
- if((inp(port+IIR) & FIFO_ENABLED_6) != 0 || (inp(port+IIR) & FIFO_ENABLED_6) != 0){
- printf("Unknown UART at port 0x%0x.\n",port);
- printf("(Bits 6 and 7 of the IIR are not ZERO with the FIFO disabled.\n");
- return UNKNOWN;
- }
-
- outp(port+FCR,FIFO_ENABLE); // enable the FIFO
-
- if((inp(port+IIR) & FIFO_ENABLED_6) != FIFO_ENABLED_6) {
- printf("UART at port 0x%0x is a 16450.\n",port);
- return UART_TYPE_16450;
- }
-
- if((inp(port+IIR) & FIFO_ENABLED_7) != FIFO_ENABLED_7) {
- printf("UART at port 0x%0x is a 16550.\n",port);
- printf("(NOT a 16550A, do not use the FIFO function, it's BROKEN!)\n");
- return UART_TYPE_16550;
- }
-
- printf("UART at port 0x%0x is a 16550A.\n",port);
- return UART_TYPE_16550A;
-
- }
-
- main()
- {
- if(id_uart(0x2f8) == UART_TYPE_16550A){
- reset(0x2f8);
- }
- if(id_uart(0x3f8) == UART_TYPE_16550A){
- reset(0x3f8);
- }
- }
-