]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
tty: serial8250: allow platforms to override irq handler
authorJamie Iles <jamie@jamieiles.com>
Mon, 15 Aug 2011 09:17:52 +0000 (10:17 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 23 Aug 2011 17:52:59 +0000 (10:52 -0700)
Some ports (e.g. Synopsys DesignWare 8250) have special requirements for
handling the interrupts.  Allow these platforms to specify their own
interrupt handler that will override the default.
serial8250_handle_irq() is provided so that platforms can extend the IRQ
handler rather than completely replacing it.

Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/tty/serial/8250.c
include/linux/serial_8250.h

index f2dfec82faf85d19f78d3ea4d755ae730b336911..833e011a426fe5183e0046fd6284b5c0c8eceacd 100644 (file)
@@ -509,6 +509,8 @@ static void io_serial_out(struct uart_port *p, int offset, int value)
        outb(value, p->iobase + offset);
 }
 
+static int serial8250_default_handle_irq(struct uart_port *port);
+
 static void set_io_from_upio(struct uart_port *p)
 {
        struct uart_8250_port *up =
@@ -557,6 +559,7 @@ static void set_io_from_upio(struct uart_port *p)
        }
        /* Remember loaded iotype */
        up->cur_iotype = p->iotype;
+       p->handle_irq = serial8250_default_handle_irq;
 }
 
 static void
@@ -1621,6 +1624,28 @@ static void serial8250_handle_port(struct uart_8250_port *up)
        spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
+int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       if (!(iir & UART_IIR_NO_INT)) {
+               serial8250_handle_port(up);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int serial8250_default_handle_irq(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned int iir = serial_in(up, UART_IIR);
+
+       return serial8250_handle_irq(port, iir);
+}
+
 /*
  * This is the serial driver's interrupt routine.
  *
@@ -1648,13 +1673,12 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
        l = i->head;
        do {
                struct uart_8250_port *up;
-               unsigned int iir;
+               struct uart_port *port;
 
                up = list_entry(l, struct uart_8250_port, list);
+               port = &up->port;
 
-               iir = serial_in(up, UART_IIR);
-               if (!(iir & UART_IIR_NO_INT)) {
-                       serial8250_handle_port(up);
+               if (port->handle_irq(port)) {
 
                        handled = 1;
 
@@ -3048,6 +3072,10 @@ int __init early_serial_setup(struct uart_port *port)
                p->serial_in = port->serial_in;
        if (port->serial_out)
                p->serial_out = port->serial_out;
+       if (port->handle_irq)
+               p->handle_irq = port->handle_irq;
+       else
+               p->handle_irq = serial8250_default_handle_irq;
 
        return 0;
 }
@@ -3116,6 +3144,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
                port.type               = p->type;
                port.serial_in          = p->serial_in;
                port.serial_out         = p->serial_out;
+               port.handle_irq         = p->handle_irq;
                port.set_termios        = p->set_termios;
                port.pm                 = p->pm;
                port.dev                = &dev->dev;
@@ -3281,6 +3310,8 @@ int serial8250_register_port(struct uart_port *port)
                        uart->port.serial_in = port->serial_in;
                if (port->serial_out)
                        uart->port.serial_out = port->serial_out;
+               if (port->handle_irq)
+                       uart->port.handle_irq = port->handle_irq;
                /*  Possibly override set_termios call */
                if (port->set_termios)
                        uart->port.set_termios = port->set_termios;
index 97f5b45bbc072fcb33b2c3d29c8178b90d14bdc3..1f05bbeac01e3605b7e11bd544e3edc7483c474a 100644 (file)
@@ -35,6 +35,7 @@ struct plat_serial8250_port {
        void            (*set_termios)(struct uart_port *,
                                       struct ktermios *new,
                                       struct ktermios *old);
+       int             (*handle_irq)(struct uart_port *);
        void            (*pm)(struct uart_port *, unsigned int state,
                              unsigned old);
 };
@@ -80,6 +81,7 @@ extern void serial8250_do_set_termios(struct uart_port *port,
                struct ktermios *termios, struct ktermios *old);
 extern void serial8250_do_pm(struct uart_port *port, unsigned int state,
                             unsigned int oldstate);
+int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
 
 extern void serial8250_set_isa_configurator(void (*v)
                                        (int port, struct uart_port *up,