Skip to content

Commit

Permalink
tty: serial8250: allow platforms to override irq handler
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jamie Iles authored and Greg Kroah-Hartman committed Aug 23, 2011
1 parent a74036f commit 583d28e
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 4 deletions.
39 changes: 35 additions & 4 deletions drivers/tty/serial/8250.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand 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
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions include/linux/serial_8250.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 583d28e

Please sign in to comment.