Commit 9dfd7048 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk/linux-2.6-serial

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 2fb99976 25f34d0f
......@@ -450,9 +450,11 @@ static void disable_rsa(struct uart_8250_port *up)
*/
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,10 +477,39 @@ static int size_fifo(struct uart_8250_port *up)
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
......@@ -491,7 +522,7 @@ static int size_fifo(struct uart_8250_port *up)
*/
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 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
* 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 @@ static void autoconfig_8250(struct uart_8250_port *up)
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 @@ static void autoconfig_16550a(struct uart_8250_port *up)
* (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;
......
......@@ -2211,6 +2211,13 @@ static struct pci_device_id serial_pci_tbl[] = {
0,
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 struct pci_driver serial_pci_driver = {
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)
......
......@@ -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
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment