diff -ruN linux-2.6.16.20-virgin/drivers/serial/8250.c linux-2.6.16.20-ajk/drivers/serial/8250.c --- linux-2.6.16.20-virgin/drivers/serial/8250.c 2006-06-05 13:18:23.000000000 -0400 +++ linux-2.6.16.20-ajk/drivers/serial/8250.c 2006-06-07 09:07:37.000000000 -0400 @@ -18,6 +18,16 @@ * * mapbase is the physical address of the IO port. * membase is an 'ioremapped' cookie. + * + * The following additions/fixes are by Andrew J. Kroll + * TX overrun bugfixs by setting workload to 1 for any non-AFE chip. + * One should never assume the other endpoint has any sort of rx FIFO. + * The safe assumption is 1 character. Now all my hardware dumb terminals + * work without dropping characters even at extreme baud rates. + * A userspace tool for tweeking this would be the best idea. + * TL16C550C/D detection 2006/06/06 Thank you TI for the engeneering samples. + * AFE/CTS bug fix 2006/06/07 + * */ #include @@ -173,7 +183,7 @@ [PORT_16550A] = { .name = "16550A", .fifo_size = 16, - .tx_loadsz = 16, + .tx_loadsz = 1 /* was 16, no AFE set to 1 -- AJK */, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO, }, @@ -191,7 +201,7 @@ [PORT_16650V2] = { .name = "ST16650V2", .fifo_size = 32, - .tx_loadsz = 16, + .tx_loadsz = 1 /* was 16, no AFE set to 1 --AJK */, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_00, .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, @@ -199,7 +209,7 @@ [PORT_16750] = { .name = "TI16750", .fifo_size = 64, - .tx_loadsz = 64, + .tx_loadsz = 64 /* AFE, OK to keep at 64 --AJK */, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | UART_FCR7_64BYTE, .flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE, @@ -212,14 +222,14 @@ [PORT_16C950] = { .name = "16C950/954", .fifo_size = 128, - .tx_loadsz = 128, + .tx_loadsz = 1 /* was 128, no AFE set to 1 --AJK */, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO, }, [PORT_16654] = { .name = "ST16654", .fifo_size = 64, - .tx_loadsz = 32, + .tx_loadsz = 1 /* was 32, no AFE set to 1 --AJK */, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_10, .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, @@ -227,31 +237,38 @@ [PORT_16850] = { .name = "XR16850", .fifo_size = 128, - .tx_loadsz = 128, + .tx_loadsz = 1 /* was 128, no AFE set to 1 --AJK */, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, }, [PORT_RSA] = { .name = "RSA", .fifo_size = 2048, - .tx_loadsz = 2048, + .tx_loadsz = 1 /* was 2048, no AFE set to 1 --AJK */, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11, .flags = UART_CAP_FIFO, }, [PORT_NS16550A] = { .name = "NS16550A", .fifo_size = 16, - .tx_loadsz = 16, + .tx_loadsz = 1 /* was 16, no AFE set to 1 --AJK */, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO | UART_NATSEMI, }, [PORT_XSCALE] = { .name = "XScale", .fifo_size = 32, - .tx_loadsz = 32, + .tx_loadsz = 1 /* was 32, no AFE set to 1 --AJK */, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO | UART_CAP_UUE, }, + [PORT_TL16C550C] = { + .name = "TL16C550C", + .fifo_size = 16, + .tx_loadsz = 16 /* AFE, OK for full tx fifo --AJK */, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, }; #ifdef CONFIG_SERIAL_8250_AU1X00 @@ -687,6 +704,8 @@ * EFR is located in the same register position as the IIR and * we know the top two bits of the IIR are currently set. The * EFR should contain zero. Try to read the EFR. + * + * Also checks for AFE on TL16C550C/D. --AJK */ static void autoconfig_16550a(struct uart_8250_port *up) { @@ -829,6 +848,19 @@ DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 "); } serial_outp(up, UART_IER, iersave); + /* At this point the ACE is considered a 16550A, one last + * test here rules out any AFE abilities. The 16550A will + * not allow you to set the AFE bit. -- AJK + */ + status1 = serial_in(up, UART_MCR); + serial_outp(up, UART_MCR, status1 | UART_MCR_AFE); + status2 = serial_in(up, UART_MCR); + if(status2 == (status1 | UART_MCR_AFE)) { + up->port.type = PORT_TL16C550C; + up->capabilities |= UART_CAP_AFE; + DEBUG_AUTOCONF("TL16C550C "); + } + serial_outp(up, UART_MCR, status1); } /* @@ -1255,7 +1287,20 @@ up->port.icount.dsr++; if (status & UART_MSR_DDCD) uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); - if (status & UART_MSR_DCTS) + /* + * AFE and uart_handle_cts_change() conflict. + * When you have AFE, you must ignore any IRQ's caused + * by flow control due to how this driver is written. + * If we are using AFE, uart_handle_cts_change() + * will lock up the ACE, causing no more data to transmit + * unless there is another IRQ generated, which allows + * the driver to see there was a change back. + * RMK... + * should the AFE check go into the serial_core.h file instead? + * --AJK + */ + + if ((status & UART_MSR_DCTS) && !(up->capabilities & UART_CAP_AFE)) uart_handle_cts_change(&up->port, status & UART_MSR_CTS); wake_up_interruptible(&up->port.info->delta_msr_wait); @@ -1784,7 +1829,7 @@ * have sufficient FIFO entries for the latency of the remote * UART to respond. IOW, at least 32 bytes of FIFO. */ - if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) { + if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 16 /* was 32 -- AJK */) { up->mcr &= ~UART_MCR_AFE; if (termios->c_cflag & CRTSCTS) up->mcr |= UART_MCR_AFE; diff -ruN linux-2.6.16.20-virgin/include/linux/serial.h linux-2.6.16.20-ajk/include/linux/serial.h --- linux-2.6.16.20-virgin/include/linux/serial.h 2006-06-05 13:18:23.000000000 -0400 +++ linux-2.6.16.20-ajk/include/linux/serial.h 2006-06-06 12:20:01.000000000 -0400 @@ -76,7 +76,8 @@ #define PORT_16654 11 #define PORT_16850 12 #define PORT_RSA 13 /* RSA-DV II/S card */ -#define PORT_MAX 13 +#define PORT_TL16C550C 14 +#define PORT_MAX 14 #define SERIAL_IO_PORT 0 #define SERIAL_IO_HUB6 1