bk://bk.arm.linux.org.uk/linux-2.6-serial alex.williamson@com.rmk.(none)[rmk]|ChangeSet|20050228160945|30565 alex.williamson # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/02/28 16:09:45+00:00 alex.williamson@com.rmk.(none) # [SERIAL] 8250 woraround for buggy uart # # Patch from Alex Williamson # # This patch adds support for detecting and working around a bug in # the A2 rev of the Exar ST16C2550 UART. The chip incorrectly # advertises an EFR and mis-detects as having the wrong size FIFO. # Much of the patch below is Russell's proposed solution to the # problem. The only changes I've made are to check the FIFO size # on the part (because there is a real part with the same divisor # ID and larger FIFO) and save and restore the LCR register around # the size_fifo() routine (it doesn't work correctly with a LCR # value of 0xBF). # # Signed-off-by: Alex Williamson # Signed-off-by: Russell King # # drivers/serial/8250.c # 2005/02/28 16:05:18+00:00 alex.williamson@com.rmk.(none) +54 -18 # [PATCH] 8250 woraround for buggy uart # # ChangeSet # 2005/02/11 23:23:06+00:00 bjorn.helgaas@com.rmk.(none) # [SERIAL] add TP560 data/fax/modem support # # Patch from Bjorn Helgaas # # Claim Topic TP560 data/fax/voice modem. This device reports as class 0x0780, # so we don't claim it by default: # # 00:0d.0 Class 0780: 151f:0000 # Subsystem: 151f:0000 # Interrupt: pin A routed to IRQ 11 # Region 0: I/O ports at a400 [size=8] # 00: 1f 15 00 00 01 00 00 02 00 00 80 07 00 00 00 00 # 10: 01 a4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 20: 00 00 00 00 00 00 00 00 00 00 00 00 1f 15 00 00 # 30: 00 00 00 00 00 00 00 00 00 00 00 00 0b 01 00 00 # # Some rc.serial scripts extract IRQ and I/O port information from # /proc/pci and stuff it into an unused port using setserial. That # doesn't work reliably anymore because pci_enable_device() is never # called, so the IRQ may not be enabled. # # Thanks to Evan Clarke for reporting and helping debug this problem. # # Signed-off-by: Bjorn Helgaas # # include/linux/pci_ids.h # 2005/02/11 23:18:13+00:00 bjorn.helgaas@com.rmk.(none) +3 -0 # [PATCH] add TP560 data/fax/modem support # # drivers/serial/8250_pci.c # 2005/02/11 23:18:12+00:00 bjorn.helgaas@com.rmk.(none) +7 -0 # [PATCH] add TP560 data/fax/modem support # # ChangeSet # 2005/02/11 23:04:52+00:00 c.lucas@com.rmk.(none) # [SERIAL] drivers/serial/*: convert to pci_register_driver # # Patch from Christophe Lucas # # convert from pci_module_init to pci_register_driver # # Signed-off-by: Christophe Lucas # # drivers/serial/8250_pci.c # 2005/02/11 22:59:12+00:00 c.lucas@com.rmk.(none) +1 -1 # [PATCH] drivers/serial/*: convert to pci_register_driver # # ChangeSet # 2005/02/09 21:18:47+00:00 bjorn.helgaas@com.rmk.(none) # [SERIAL] discover PNP ports before PCI, etc # # Patch from Bjorn Helgaas # # PNP ports tend to be built-in, and discovering them after # PCI ports means the names of the built-in ports can change # if you add or remove PCI ports. # # (And yes, we should look at getting rid of 8250_acpi.c # now that we have PNPACPI, but that's for another patch.) # # Signed-off-by: Bjorn Helgaas # # drivers/serial/Makefile # 2005/02/09 21:14:12+00:00 bjorn.helgaas@com.rmk.(none) +1 -1 # [PATCH] SERIAL: discover PNP ports before PCI, etc # diff -Nru a/drivers/serial/8250.c b/drivers/serial/8250.c --- a/drivers/serial/8250.c 2005-02-28 17:20:33 -08:00 +++ b/drivers/serial/8250.c 2005-02-28 17:20:33 -08:00 @@ -450,9 +450,11 @@ */ static int size_fifo(struct uart_8250_port *up) { - unsigned char old_fcr, old_mcr, old_dll, old_dlm; + unsigned char old_fcr, old_mcr, old_dll, old_dlm, old_lcr; int count; + old_lcr = serial_inp(up, UART_LCR); + serial_outp(up, UART_LCR, 0); old_fcr = serial_inp(up, UART_FCR); old_mcr = serial_inp(up, UART_MCR); serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | @@ -475,11 +477,40 @@ serial_outp(up, UART_LCR, UART_LCR_DLAB); serial_outp(up, UART_DLL, old_dll); serial_outp(up, UART_DLM, old_dlm); + serial_outp(up, UART_LCR, old_lcr); return count; } /* + * Read UART ID using the divisor method - set DLL and DLM to zero + * and the revision will be in DLL and device type in DLM. We + * preserve the device state across this. + */ +static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) +{ + unsigned char old_dll, old_dlm, old_lcr; + unsigned int id; + + old_lcr = serial_inp(p, UART_LCR); + serial_outp(p, UART_LCR, UART_LCR_DLAB); + + old_dll = serial_inp(p, UART_DLL); + old_dlm = serial_inp(p, UART_DLM); + + serial_outp(p, UART_DLL, 0); + serial_outp(p, UART_DLM, 0); + + id = serial_inp(p, UART_DLL) | serial_inp(p, UART_DLM) << 8; + + serial_outp(p, UART_DLL, old_dll); + serial_outp(p, UART_DLM, old_dlm); + serial_outp(p, UART_LCR, old_lcr); + + return id; +} + +/* * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. * When this function is called we know it is at least a StarTech * 16650 V2, but it might be one of several StarTech UARTs, or one of @@ -491,7 +522,7 @@ */ static void autoconfig_has_efr(struct uart_8250_port *up) { - unsigned char id1, id2, id3, rev, saved_dll, saved_dlm; + unsigned int id1, id2, id3, rev; /* * Everything with an EFR has SLEEP @@ -541,21 +572,13 @@ * 0x12 - XR16C2850. * 0x14 - XR16C854. */ - serial_outp(up, UART_LCR, UART_LCR_DLAB); - saved_dll = serial_inp(up, UART_DLL); - saved_dlm = serial_inp(up, UART_DLM); - serial_outp(up, UART_DLL, 0); - serial_outp(up, UART_DLM, 0); - id2 = serial_inp(up, UART_DLL); - id1 = serial_inp(up, UART_DLM); - serial_outp(up, UART_DLL, saved_dll); - serial_outp(up, UART_DLM, saved_dlm); - - DEBUG_AUTOCONF("850id=%02x:%02x ", id1, id2); - - if (id1 == 0x10 || id1 == 0x12 || id1 == 0x14) { - if (id1 == 0x10) - up->rev = id2; + id1 = autoconfig_read_divisor_id(up); + DEBUG_AUTOCONF("850id=%04x ", id1); + + id2 = id1 >> 8; + if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) { + if (id2 == 0x10) + up->rev = id1 & 255; up->port.type = PORT_16850; return; } @@ -597,6 +620,19 @@ up->port.type = PORT_16450; } +static int broken_efr(struct uart_8250_port *up) +{ + /* + * Exar ST16C2550 "A2" devices incorrectly detect as + * having an EFR, and report an ID of 0x0201. See + * http://www.exar.com/info.php?pdf=dan180_oct2004.pdf + */ + if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) + return 1; + + return 0; +} + /* * We know that the chip has FIFOs. Does it have an EFR? The * EFR is located in the same register position as the IIR and @@ -633,7 +669,7 @@ * (other ST16C650V2 UARTs, TI16C752A, etc) */ serial_outp(up, UART_LCR, 0xBF); - if (serial_in(up, UART_EFR) == 0) { + if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) { DEBUG_AUTOCONF("EFRv2 "); autoconfig_has_efr(up); return; diff -Nru a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c --- a/drivers/serial/8250_pci.c 2005-02-28 17:20:33 -08:00 +++ b/drivers/serial/8250_pci.c 2005-02-28 17:20:33 -08:00 @@ -2212,6 +2212,13 @@ 0, pbn_exar_XR17C158 }, /* + * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) + */ + { PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_115200 }, + + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL */ @@ -2241,7 +2248,7 @@ static int __init serial8250_pci_init(void) { - return pci_module_init(&serial_pci_driver); + return pci_register_driver(&serial_pci_driver); } static void __exit serial8250_pci_exit(void) diff -Nru a/drivers/serial/Makefile b/drivers/serial/Makefile --- a/drivers/serial/Makefile 2005-02-28 17:20:33 -08:00 +++ b/drivers/serial/Makefile 2005-02-28 17:20:33 -08:00 @@ -6,9 +6,9 @@ serial-8250-y := serial-8250-$(CONFIG_SERIAL_8250_ACPI) += 8250_acpi.o +serial-8250-$(CONFIG_PNP) += 8250_pnp.o serial-8250-$(CONFIG_GSC) += 8250_gsc.o serial-8250-$(CONFIG_PCI) += 8250_pci.o -serial-8250-$(CONFIG_PNP) += 8250_pnp.o serial-8250-$(CONFIG_HP300) += 8250_hp300.o obj-$(CONFIG_SERIAL_CORE) += serial_core.o diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h 2005-02-28 17:20:33 -08:00 +++ b/include/linux/pci_ids.h 2005-02-28 17:20:33 -08:00 @@ -1972,6 +1972,9 @@ #define PCI_DEVICE_ID_BCM4401 0x4401 #define PCI_DEVICE_ID_BCM4401B0 0x4402 +#define PCI_VENDOR_ID_TOPIC 0x151f +#define PCI_DEVICE_ID_TOPIC_TP560 0x0000 + #define PCI_VENDOR_ID_ENE 0x1524 #define PCI_DEVICE_ID_ENE_1211 0x1211 #define PCI_DEVICE_ID_ENE_1225 0x1225