8250: blacklist Winbond CIR port
authorSean Young <sean@mess.org>
Fri, 7 Sep 2012 18:06:24 +0000 (19:06 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 26 Sep 2012 20:25:41 +0000 (13:25 -0700)
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>
drivers/tty/serial/8250/8250.c
drivers/tty/serial/8250/8250_pnp.c
include/linux/serial_core.h

index a2042c6..3ba4234 100644 (file)
@@ -290,6 +290,9 @@ static const struct serial8250_config uart_config[] = {
                                  UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00,
                .flags          = UART_CAP_FIFO,
        },
+       [PORT_8250_CIR] = {
+               .name           = "CIR port"
+       }
 };
 
 /* Uart divisor latch read */
@@ -1900,6 +1903,9 @@ static int serial8250_startup(struct uart_port *port)
        unsigned char lsr, iir;
        int retval;
 
+       if (port->type == PORT_8250_CIR)
+               return -ENODEV;
+
        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;
@@ -2557,7 +2563,10 @@ static int serial8250_request_port(struct uart_port *port)
 {
        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 && port->type == PORT_RSA) {
@@ -2576,6 +2585,9 @@ static void serial8250_config_port(struct uart_port *port, int flags)
        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.
@@ -3147,7 +3159,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
        mutex_lock(&serial_mutex);
 
        uart = serial8250_find_match_or_unused(&up->port);
-       if (uart) {
+       if (uart && uart->port.type != PORT_8250_CIR) {
                if (uart->port.dev)
                        uart_remove_one_port(&serial8250_reg, &uart->port);
 
index 28bf830..f8ee250 100644 (file)
@@ -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_dev_table[] = {
        {       "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(struct pnp_dev *dev)
  * 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, const struct pnp_device_id *dev_id)
        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, const struct pnp_device_id *dev_id)
        memset(&uart, 0, sizeof(uart));
        if (pnp_irq_valid(dev, 0))
                uart.port.irq = pnp_irq(dev, 0);
-       if (pnp_port_valid(dev, 0)) {
+       if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) {
+               uart.port.iobase = pnp_port_start(dev, 2);
+               uart.port.iotype = UPIO_PORT;
+       } else if (pnp_port_valid(dev, 0)) {
                uart.port.iobase = pnp_port_start(dev, 0);
                uart.port.iotype = UPIO_PORT;
        } else if (pnp_mem_valid(dev, 0)) {
@@ -451,6 +457,10 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
                "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
                       uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype);
 #endif
+       if (flags & CIR_PORT) {
+               uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
+               uart.port.type = PORT_8250_CIR;
+       }
 
        uart.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, const struct pnp_device_id *dev_id)
        uart.port.dev = &dev->dev;
 
        line = serial8250_register_8250_port(&uart);
-       if (line < 0)
+       if (line < 0 || (flags & CIR_PORT))
                return -ENODEV;
 
        pnp_set_drvdata(dev, (void *)((long)line + 1));
index 7cf0b68..bb01003 100644 (file)
@@ -48,7 +48,8 @@
 #define PORT_TEGRA     20      /* NVIDIA Tegra internal UART */
 #define PORT_XR17D15X  21      /* Exar XR17D15x UART */
 #define PORT_LPC3220   22      /* NXP LPC32xx SoC "Standard" UART */
-#define PORT_MAX_8250  22      /* max port ID */
+#define PORT_8250_CIR  23      /* CIR infrared port, has its own driver */
+#define PORT_MAX_8250  23      /* max port ID */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed