[ 061/128] 8250: blacklist Winbond CIR port

Ben Hutchings
2013-02-03T15:14:41Z

From: Sean Young <sean@mess.org>

commit 65ecc9c02dbad033a73a32916d17c107c5b25031 upstream.

The legacy serial driver will detect the Winbond CIR device as a serial
port, since it looks exactly like a serial port unless you know what
it is from the PNP ID.

Here we track this port as a special PORT_8250_CIR type, preventing the
legacy serial driver from probing it.

Signed-off-by: Sean Young <sean@mess.org>
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[bwh: Backported to 3.2:
- Adjust filenames
- Adjust context
- First available port type number is 22 not 23
- s/uart\.port/port/]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
drivers/tty/serial/8250.c | 16 ++++++++++++++--
drivers/tty/serial/8250_pnp.c | 20 +++++++++++++++-----
include/linux/serial_core.h | 3 ++-
3 files changed, 31 insertions(+), 8 deletions(-)

--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -316,6 +316,9 @@ static const struct serial8250_config ua
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR,
},
+ [PORT_8250_CIR] = {
+ .name = "CIR port"
+ }
};

#if defined(CONFIG_MIPS_ALCHEMY)
@@ -1984,6 +1987,9 @@ static int serial8250_startup(struct uar
unsigned char lsr, iir;
int retval;

+ if (port->type == PORT_8250_CIR)
+ return -ENODEV;
+
up->port.fifosize = uart_config[up->port.type].fifo_size;
up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
up->capabilities = uart_config[up->port.type].flags;
@@ -2628,7 +2634,10 @@ static int serial8250_request_port(struc
{
struct uart_8250_port *up =
container_of(port, struct uart_8250_port, port);
- int ret = 0;
+ int ret;
+
+ if (port->type == PORT_8250_CIR)
+ return -ENODEV;

ret = serial8250_request_std_resource(up);
if (ret == 0 && up->port.type == PORT_RSA) {
@@ -2647,6 +2656,9 @@ static void serial8250_config_port(struc
int probeflags = PROBE_ANY;
int ret;

+ if (port->type == PORT_8250_CIR)
+ return;
+
/*
* Find the region that we can probe for. This in turn
* tells us whether we can probe for the type of port.
@@ -3215,7 +3227,7 @@ int serial8250_register_port(struct uart
mutex_lock(&serial_mutex);

uart = serial8250_find_match_or_unused(port);
- if (uart) {
+ if (uart && uart->port.type != PORT_8250_CIR) {
uart_remove_one_port(&serial8250_reg, &uart->port);

uart->port.iobase = port->iobase;
--- a/drivers/tty/serial/8250_pnp.c
+++ b/drivers/tty/serial/8250_pnp.c
@@ -25,7 +25,7 @@
#include "8250.h"

#define UNKNOWN_DEV 0x3000
-
+#define CIR_PORT 0x0800

static const struct pnp_device_id pnp_dev_table[] = {
/* Archtek America Corp. */
@@ -362,6 +362,9 @@ static const struct pnp_device_id pnp_de
{ "PNPCXXX", UNKNOWN_DEV },
/* More unknown PnP modems */
{ "PNPDXXX", UNKNOWN_DEV },
+ /* Winbond CIR port, should not be probed. We should keep track
+ of it to prevent the legacy serial driver from probing it */
+ { "WEC1022", CIR_PORT },
{ "", 0 }
};

@@ -409,7 +412,7 @@ static int __devinit check_resources(str
* PnP modems, alternatively we must hardcode all modems in pnp_devices[]
* table.
*/
-static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
+static int __devinit serial_pnp_guess_board(struct pnp_dev *dev)
{
if (!(check_name(pnp_dev_name(dev)) ||
(dev->card && check_name(dev->card->name))))
@@ -428,7 +431,7 @@ serial_pnp_probe(struct pnp_dev *dev, co
int ret, line, flags = dev_id->driver_data;

if (flags & UNKNOWN_DEV) {
- ret = serial_pnp_guess_board(dev, &flags);
+ ret = serial_pnp_guess_board(dev);
if (ret < 0)
return ret;
}
@@ -436,7 +439,10 @@ serial_pnp_probe(struct pnp_dev *dev, co
memset(&port, 0, sizeof(struct uart_port));
if (pnp_irq_valid(dev, 0))
port.irq = pnp_irq(dev, 0);
- if (pnp_port_valid(dev, 0)) {
+ if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) {
+ port.iobase = pnp_port_start(dev, 2);
+ port.iotype = UPIO_PORT;
+ } else if (pnp_port_valid(dev, 0)) {
port.iobase = pnp_port_start(dev, 0);
port.iotype = UPIO_PORT;
} else if (pnp_mem_valid(dev, 0)) {
@@ -451,6 +457,10 @@ serial_pnp_probe(struct pnp_dev *dev, co
"Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
port.iobase, port.mapbase, port.irq, port.iotype);
#endif
+ if (flags & CIR_PORT) {
+ port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ port.type = PORT_8250_CIR;
+ }

port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
@@ -459,7 +469,7 @@ serial_pnp_probe(struct pnp_dev *dev, co
port.dev = &dev->dev;

line = serial8250_register_port(&port);
- if (line < 0)
+ if (line < 0 || (flags & CIR_PORT))
return -ENODEV;

pnp_set_drvdata(dev, (void *)((long)line + 1));
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -47,7 +47,8 @@
#define PORT_U6_16550A 19 /* ST-Ericsson U6xxx internal UART */
#define PORT_TEGRA 20 /* NVIDIA Tegra internal UART */
#define PORT_XR17D15X 21 /* Exar XR17D15x UART */
-#define PORT_MAX_8250 21 /* max port ID */
+#define PORT_8250_CIR 22 /* CIR infrared port, has its own driver */
+#define PORT_MAX_8250 22 /* max port ID */

/*
* ARM specific type numbers. These are not currently guaranteed