Commit d8b3edf1 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 340fc58c 0dbd84c6
...@@ -157,23 +157,109 @@ static struct irq_info irq_lists[NR_IRQS]; ...@@ -157,23 +157,109 @@ static struct irq_info irq_lists[NR_IRQS];
/* /*
* Here we define the default xmit fifo size used for each type of UART. * Here we define the default xmit fifo size used for each type of UART.
*/ */
static const struct serial8250_config uart_config[PORT_MAX_8250+1] = { static const struct serial8250_config uart_config[] = {
{ "unknown", 1, 1, 0 }, [PORT_UNKNOWN] = {
{ "8250", 1, 1, 0 }, .name = "unknown",
{ "16450", 1, 1, 0 }, .fifo_size = 1,
{ "16550", 1, 1, 0 }, .tx_loadsz = 1,
{ "16550A", 16, 16, UART_CAP_FIFO }, },
{ "Cirrus", 1, 1, 0 }, [PORT_8250] = {
{ "ST16650", 1, 1, UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR }, .name = "8250",
{ "ST16650V2", 32, 16, UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR }, .fifo_size = 1,
{ "TI16750", 64, 64, UART_CAP_FIFO | UART_CAP_SLEEP }, .tx_loadsz = 1,
{ "Startech", 1, 1, 0 }, },
{ "16C950/954", 128, 128, UART_CAP_FIFO }, [PORT_16450] = {
{ "ST16654", 64, 32, UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR }, .name = "16450",
{ "XR16850", 128, 128, UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR }, .fifo_size = 1,
{ "RSA", 2048, 2048, UART_CAP_FIFO }, .tx_loadsz = 1,
{ "NS16550A", 16, 16, UART_CAP_FIFO | UART_NATSEMI }, },
{ "XScale", 32, 32, UART_CAP_FIFO }, [PORT_16550] = {
.name = "16550",
.fifo_size = 1,
.tx_loadsz = 1,
},
[PORT_16550A] = {
.name = "16550A",
.fifo_size = 16,
.tx_loadsz = 16,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO,
},
[PORT_CIRRUS] = {
.name = "Cirrus",
.fifo_size = 1,
.tx_loadsz = 1,
},
[PORT_16650] = {
.name = "ST16650",
.fifo_size = 1,
.tx_loadsz = 1,
.flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
},
[PORT_16650V2] = {
.name = "ST16650V2",
.fifo_size = 32,
.tx_loadsz = 16,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
UART_FCR_T_TRIG_00,
.flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
},
[PORT_16750] = {
.name = "TI16750",
.fifo_size = 64,
.tx_loadsz = 64,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
UART_FCR7_64BYTE,
.flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE,
},
[PORT_STARTECH] = {
.name = "Startech",
.fifo_size = 1,
.tx_loadsz = 1,
},
[PORT_16C950] = {
.name = "16C950/954",
.fifo_size = 128,
.tx_loadsz = 128,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO,
},
[PORT_16654] = {
.name = "ST16654",
.fifo_size = 64,
.tx_loadsz = 32,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
UART_FCR_T_TRIG_10,
.flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
},
[PORT_16850] = {
.name = "XR16850",
.fifo_size = 128,
.tx_loadsz = 128,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
},
[PORT_RSA] = {
.name = "RSA",
.fifo_size = 2048,
.tx_loadsz = 2048,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11,
.flags = UART_CAP_FIFO,
},
[PORT_NS16550A] = {
.name = "NS16550A",
.fifo_size = 16,
.tx_loadsz = 16,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO | UART_NATSEMI,
},
[PORT_XSCALE] = {
.name = "XScale",
.fifo_size = 32,
.tx_loadsz = 32,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO,
},
}; };
static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
...@@ -404,6 +490,11 @@ static void autoconfig_has_efr(struct uart_8250_port *up) ...@@ -404,6 +490,11 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
{ {
unsigned char id1, id2, id3, rev, saved_dll, saved_dlm; unsigned char id1, id2, id3, rev, saved_dll, saved_dlm;
/*
* Everything with an EFR has SLEEP
*/
up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
/* /*
* First we check to see if it's an Oxford Semiconductor UART. * First we check to see if it's an Oxford Semiconductor UART.
* *
...@@ -514,6 +605,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) ...@@ -514,6 +605,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
unsigned char status1, status2; unsigned char status1, status2;
up->port.type = PORT_16550A; up->port.type = PORT_16550A;
up->capabilities |= UART_CAP_FIFO;
/* /*
* Check for presence of the EFR when DLAB is set. * Check for presence of the EFR when DLAB is set.
...@@ -525,6 +617,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) ...@@ -525,6 +617,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
if (serial_in(up, UART_EFR) != 0) { if (serial_in(up, UART_EFR) != 0) {
DEBUG_AUTOCONF("EFRv1 "); DEBUG_AUTOCONF("EFRv1 ");
up->port.type = PORT_16650; up->port.type = PORT_16650;
up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
} else { } else {
DEBUG_AUTOCONF("Motorola 8xxx DUART "); DEBUG_AUTOCONF("Motorola 8xxx DUART ");
} }
...@@ -577,6 +670,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) ...@@ -577,6 +670,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
#endif #endif
up->port.type = PORT_NS16550A; up->port.type = PORT_NS16550A;
up->capabilities |= UART_NATSEMI;
return; return;
} }
} }
...@@ -600,6 +694,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) ...@@ -600,6 +694,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
if (status1 == 6 && status2 == 7) { if (status1 == 6 && status2 == 7) {
up->port.type = PORT_16750; up->port.type = PORT_16750;
up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP;
return; return;
} }
} }
...@@ -630,6 +725,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) ...@@ -630,6 +725,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
spin_lock_irqsave(&up->port.lock, flags); spin_lock_irqsave(&up->port.lock, flags);
// save_flags(flags); cli(); // save_flags(flags); cli();
up->capabilities = 0;
if (!(up->port.flags & UPF_BUGGY_UART)) { if (!(up->port.flags & UPF_BUGGY_UART)) {
/* /*
* Do a simple existence test first; if we fail this, * Do a simple existence test first; if we fail this,
...@@ -740,6 +837,13 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) ...@@ -740,6 +837,13 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
#endif #endif
serial_outp(up, UART_LCR, save_lcr); serial_outp(up, UART_LCR, save_lcr);
if (up->capabilities != uart_config[up->port.type].flags) {
printk(KERN_WARNING
"ttyS%d: detected caps %08x should be %08x\n",
up->port.line, up->capabilities,
uart_config[up->port.type].flags);
}
up->port.fifosize = uart_config[up->port.type].fifo_size; up->port.fifosize = uart_config[up->port.type].fifo_size;
up->capabilities = uart_config[up->port.type].flags; up->capabilities = uart_config[up->port.type].flags;
up->tx_loadsz = uart_config[up->port.type].tx_loadsz; up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
...@@ -822,6 +926,12 @@ static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop) ...@@ -822,6 +926,12 @@ static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
up->ier &= ~UART_IER_THRI; up->ier &= ~UART_IER_THRI;
serial_out(up, UART_IER, up->ier); serial_out(up, UART_IER, up->ier);
} }
/*
* We only do this from uart_stop - if we run out of
* characters to send, we don't want to prevent the
* FIFO from emptying.
*/
if (up->port.type == PORT_16C950 && tty_stop) { if (up->port.type == PORT_16C950 && tty_stop) {
up->acr |= UART_ACR_TXDIS; up->acr |= UART_ACR_TXDIS;
serial_icr_write(up, UART_ACR, up->acr); serial_icr_write(up, UART_ACR, up->acr);
...@@ -866,7 +976,7 @@ static _INLINE_ void ...@@ -866,7 +976,7 @@ static _INLINE_ void
receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
{ {
struct tty_struct *tty = up->port.info->tty; struct tty_struct *tty = up->port.info->tty;
unsigned char ch; unsigned char ch, lsr = *status;
int max_count = 256; int max_count = 256;
do { do {
...@@ -880,13 +990,23 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) ...@@ -880,13 +990,23 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
*tty->flip.flag_buf_ptr = TTY_NORMAL; *tty->flip.flag_buf_ptr = TTY_NORMAL;
up->port.icount.rx++; up->port.icount.rx++;
if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | #ifdef CONFIG_SERIAL_8250_CONSOLE
UART_LSR_FE | UART_LSR_OE))) { /*
* Recover the break flag from console xmit
*/
if (up->port.line == up->port.cons->index) {
lsr |= up->lsr_break_flag;
up->lsr_break_flag = 0;
}
#endif
if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
UART_LSR_FE | UART_LSR_OE))) {
/* /*
* For statistics only * For statistics only
*/ */
if (*status & UART_LSR_BI) { if (lsr & UART_LSR_BI) {
*status &= ~(UART_LSR_FE | UART_LSR_PE); lsr &= ~(UART_LSR_FE | UART_LSR_PE);
up->port.icount.brk++; up->port.icount.brk++;
/* /*
* We do the SysRQ and SAK checking * We do the SysRQ and SAK checking
...@@ -896,41 +1016,34 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) ...@@ -896,41 +1016,34 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
*/ */
if (uart_handle_break(&up->port)) if (uart_handle_break(&up->port))
goto ignore_char; goto ignore_char;
} else if (*status & UART_LSR_PE) } else if (lsr & UART_LSR_PE)
up->port.icount.parity++; up->port.icount.parity++;
else if (*status & UART_LSR_FE) else if (lsr & UART_LSR_FE)
up->port.icount.frame++; up->port.icount.frame++;
if (*status & UART_LSR_OE) if (lsr & UART_LSR_OE)
up->port.icount.overrun++; up->port.icount.overrun++;
/* /*
* Mask off conditions which should be ingored. * Mask off conditions which should be ingored.
*/ */
*status &= up->port.read_status_mask; lsr &= up->port.read_status_mask;
#ifdef CONFIG_SERIAL_8250_CONSOLE if (lsr & UART_LSR_BI) {
if (up->port.line == up->port.cons->index) {
/* Recover the break flag from console xmit */
*status |= up->lsr_break_flag;
up->lsr_break_flag = 0;
}
#endif
if (*status & UART_LSR_BI) {
DEBUG_INTR("handling break...."); DEBUG_INTR("handling break....");
*tty->flip.flag_buf_ptr = TTY_BREAK; *tty->flip.flag_buf_ptr = TTY_BREAK;
} else if (*status & UART_LSR_PE) } else if (lsr & UART_LSR_PE)
*tty->flip.flag_buf_ptr = TTY_PARITY; *tty->flip.flag_buf_ptr = TTY_PARITY;
else if (*status & UART_LSR_FE) else if (lsr & UART_LSR_FE)
*tty->flip.flag_buf_ptr = TTY_FRAME; *tty->flip.flag_buf_ptr = TTY_FRAME;
} }
if (uart_handle_sysrq_char(&up->port, ch, regs)) if (uart_handle_sysrq_char(&up->port, ch, regs))
goto ignore_char; goto ignore_char;
if ((*status & up->port.ignore_status_mask) == 0) { if ((lsr & up->port.ignore_status_mask) == 0) {
tty->flip.flag_buf_ptr++; tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++; tty->flip.char_buf_ptr++;
tty->flip.count++; tty->flip.count++;
} }
if ((*status & UART_LSR_OE) && if ((lsr & UART_LSR_OE) &&
tty->flip.count < TTY_FLIPBUF_SIZE) { tty->flip.count < TTY_FLIPBUF_SIZE) {
/* /*
* Overrun is special, since it's reported * Overrun is special, since it's reported
...@@ -943,9 +1056,10 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) ...@@ -943,9 +1056,10 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
tty->flip.count++; tty->flip.count++;
} }
ignore_char: ignore_char:
*status = serial_inp(up, UART_LSR); lsr = serial_inp(up, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0)); } while ((lsr & UART_LSR_DR) && (max_count-- > 0));
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
*status = lsr;
} }
static _INLINE_ void transmit_chars(struct uart_8250_port *up) static _INLINE_ void transmit_chars(struct uart_8250_port *up)
...@@ -1493,25 +1607,22 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios, ...@@ -1493,25 +1607,22 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) { if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
if (baud < 2400) if (baud < 2400)
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
#ifdef CONFIG_SERIAL_8250_RSA
else if (up->port.type == PORT_RSA)
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
#endif
else else
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; fcr = uart_config[up->port.type].fcr;
} }
/* /*
* TI16C750: hardware flow control and 64 byte FIFOs. When AFE is * MCR-based auto flow control. When AFE is enabled, RTS will be
* enabled, RTS will be deasserted when the receive FIFO contains * deasserted when the receive FIFO contains more characters than
* more characters than the trigger, or the MCR RTS bit is cleared. * the trigger, or the MCR RTS bit is cleared. In the case where
* the remote UART is not using CTS auto flow control, we must
* have sufficient FIFO entries for the latency of the remote
* UART to respond. IOW, at least 32 bytes of FIFO.
*/ */
if (up->port.type == PORT_16750) { if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) {
up->mcr &= ~UART_MCR_AFE; up->mcr &= ~UART_MCR_AFE;
if (termios->c_cflag & CRTSCTS) if (termios->c_cflag & CRTSCTS)
up->mcr |= UART_MCR_AFE; up->mcr |= UART_MCR_AFE;
fcr |= UART_FCR7_64BYTE;
} }
/* /*
...@@ -1565,9 +1676,17 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios, ...@@ -1565,9 +1676,17 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
serial_out(up, UART_IER, up->ier); serial_out(up, UART_IER, up->ier);
if (up->capabilities & UART_CAP_EFR) { if (up->capabilities & UART_CAP_EFR) {
unsigned char efr = 0;
/*
* TI16C752/Startech hardware flow control. FIXME:
* - TI16C752 requires control thresholds to be set.
* - UART_MCR_RTS is ineffective if auto-RTS mode is enabled.
*/
if (termios->c_cflag & CRTSCTS)
efr |= UART_EFR_CTS;
serial_outp(up, UART_LCR, 0xBF); serial_outp(up, UART_LCR, 0xBF);
serial_outp(up, UART_EFR, serial_outp(up, UART_EFR, efr);
termios->c_cflag & CRTSCTS ? UART_EFR_CTS :0);
} }
if (up->capabilities & UART_NATSEMI) { if (up->capabilities & UART_NATSEMI) {
...@@ -1797,7 +1916,7 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) ...@@ -1797,7 +1916,7 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
{ {
if (ser->irq >= NR_IRQS || ser->irq < 0 || if (ser->irq >= NR_IRQS || ser->irq < 0 ||
ser->baud_base < 9600 || ser->type < PORT_UNKNOWN || ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
ser->type > PORT_MAX_8250 || ser->type == PORT_CIRRUS || ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS ||
ser->type == PORT_STARTECH) ser->type == PORT_STARTECH)
return -EINVAL; return -EINVAL;
return 0; return 0;
...@@ -1861,7 +1980,8 @@ static void __init serial8250_isa_init_ports(void) ...@@ -1861,7 +1980,8 @@ static void __init serial8250_isa_init_ports(void)
} }
} }
static void __init serial8250_register_ports(struct uart_driver *drv) static void __init
serial8250_register_ports(struct uart_driver *drv, struct device *dev)
{ {
int i; int i;
...@@ -1872,6 +1992,7 @@ static void __init serial8250_register_ports(struct uart_driver *drv) ...@@ -1872,6 +1992,7 @@ static void __init serial8250_register_ports(struct uart_driver *drv)
up->port.line = i; up->port.line = i;
up->port.ops = &serial8250_pops; up->port.ops = &serial8250_pops;
up->port.dev = dev;
init_timer(&up->timer); init_timer(&up->timer);
up->timer.function = serial8250_timeout; up->timer.function = serial8250_timeout;
...@@ -2038,60 +2159,6 @@ static struct uart_driver serial8250_reg = { ...@@ -2038,60 +2159,6 @@ static struct uart_driver serial8250_reg = {
.cons = SERIAL8250_CONSOLE, .cons = SERIAL8250_CONSOLE,
}; };
/*
* register_serial and unregister_serial allows for 16x50 serial ports to be
* configured at run-time, to support PCMCIA modems.
*/
static int __register_serial(struct serial_struct *req, int line)
{
struct uart_port port;
port.iobase = req->port;
port.membase = req->iomem_base;
port.irq = req->irq;
port.uartclk = req->baud_base * 16;
port.fifosize = req->xmit_fifo_size;
port.regshift = req->iomem_reg_shift;
port.iotype = req->io_type;
port.flags = req->flags | UPF_BOOT_AUTOCONF;
port.mapbase = req->iomap_base;
port.line = line;
if (share_irqs)
port.flags |= UPF_SHARE_IRQ;
if (HIGH_BITS_OFFSET)
port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET;
/*
* If a clock rate wasn't specified by the low level
* driver, then default to the standard clock rate.
*/
if (port.uartclk == 0)
port.uartclk = BASE_BAUD * 16;
return uart_register_port(&serial8250_reg, &port);
}
/**
* register_serial - configure a 16x50 serial port at runtime
* @req: request structure
*
* Configure the serial port specified by the request. If the
* port exists and is in use an error is returned. If the port
* is not currently in the table it is added.
*
* The port is then probed and if necessary the IRQ is autodetected
* If this fails an error is returned.
*
* On success the port is ready to use and the line number is returned.
*/
int register_serial(struct serial_struct *req)
{
return __register_serial(req, -1);
}
int __init early_serial_setup(struct uart_port *port) int __init early_serial_setup(struct uart_port *port)
{ {
if (port->line >= ARRAY_SIZE(serial8250_ports)) if (port->line >= ARRAY_SIZE(serial8250_ports))
...@@ -2103,18 +2170,6 @@ int __init early_serial_setup(struct uart_port *port) ...@@ -2103,18 +2170,6 @@ int __init early_serial_setup(struct uart_port *port)
return 0; return 0;
} }
/**
* unregister_serial - remove a 16x50 serial port at runtime
* @line: serial line number
*
* Remove one serial port. This may be called from interrupt
* context.
*/
void unregister_serial(int line)
{
uart_unregister_port(&serial8250_reg, line);
}
/* /*
* This is for ISAPNP only. * This is for ISAPNP only.
*/ */
...@@ -2153,6 +2208,174 @@ void serial8250_resume_port(int line) ...@@ -2153,6 +2208,174 @@ void serial8250_resume_port(int line)
uart_resume_port(&serial8250_reg, &serial8250_ports[line].port); uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
} }
static int serial8250_suspend(struct device *dev, u32 state, u32 level)
{
int i;
if (level != SUSPEND_DISABLE)
return 0;
for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.type != PORT_UNKNOWN && up->port.dev == dev)
uart_suspend_port(&serial8250_reg, &up->port);
}
return 0;
}
static int serial8250_resume(struct device *dev, u32 level)
{
int i;
if (level != RESUME_ENABLE)
return 0;
for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.type != PORT_UNKNOWN && up->port.dev == dev)
uart_resume_port(&serial8250_reg, &up->port);
}
return 0;
}
static struct device_driver serial8250_isa_driver = {
.name = "serial8250",
.bus = &platform_bus_type,
.suspend = serial8250_suspend,
.resume = serial8250_resume,
};
/*
* serial8250_register_port and serial8250_unregister_port allows for
* 16x50 serial ports to be configured at run-time, to support PCMCIA
* modems and PCI multiport cards.
*/
static DECLARE_MUTEX(serial_sem);
/*
* Are the two ports equivalent?
*/
static int uart_match_port(struct uart_port *port1, struct uart_port *port2)
{
if (port1->iotype != port2->iotype)
return 0;
switch (port1->iotype) {
case UPIO_PORT:
return (port1->iobase == port2->iobase);
case UPIO_HUB6:
return (port1->iobase == port2->iobase) &&
(port1->hub6 == port2->hub6);
case UPIO_MEM:
return (port1->membase == port2->membase);
}
return 0;
}
static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
{
int i;
/*
* First, find a port entry which matches.
*/
for (i = 0; i < UART_NR; i++)
if (uart_match_port(&serial8250_ports[i].port, port))
return &serial8250_ports[i];
/*
* We didn't find a matching entry, so look for the first
* free entry. We look for one which hasn't been previously
* used (indicated by zero iobase).
*/
for (i = 0; i < UART_NR; i++)
if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
serial8250_ports[i].port.iobase == 0)
return &serial8250_ports[i];
/*
* That also failed. Last resort is to find any entry which
* doesn't have a real port associated with it.
*/
for (i = 0; i < UART_NR; i++)
if (serial8250_ports[i].port.type == PORT_UNKNOWN)
return &serial8250_ports[i];
return NULL;
}
/**
* serial8250_register_port - register a serial port
* @port: serial port template
*
* Configure the serial port specified by the request. If the
* port exists and is in use, it is hung up and unregistered
* first.
*
* The port is then probed and if necessary the IRQ is autodetected
* If this fails an error is returned.
*
* On success the port is ready to use and the line number is returned.
*/
int serial8250_register_port(struct uart_port *port)
{
struct uart_8250_port *uart;
int ret = -ENOSPC;
down(&serial_sem);
uart = serial8250_find_match_or_unused(port);
if (uart) {
uart_remove_one_port(&serial8250_reg, &uart->port);
uart->port.iobase = port->iobase;
uart->port.membase = port->membase;
uart->port.irq = port->irq;
uart->port.uartclk = port->uartclk;
uart->port.fifosize = port->fifosize;
uart->port.regshift = port->regshift;
uart->port.iotype = port->iotype;
uart->port.flags = port->flags | UPF_BOOT_AUTOCONF;
uart->port.mapbase = port->mapbase;
if (port->dev)
uart->port.dev = port->dev;
ret = uart_add_one_port(&serial8250_reg, &uart->port);
if (ret == 0)
ret = uart->port.line;
}
up(&serial_sem);
return ret;
}
EXPORT_SYMBOL(serial8250_register_port);
/**
* serial8250_unregister_port - remove a 16x50 serial port at runtime
* @line: serial line number
*
* Remove one serial port. This may not be called from interrupt
* context. We hand the port back to the our control.
*/
void serial8250_unregister_port(int line)
{
struct uart_8250_port *uart = &serial8250_ports[line];
down(&serial_sem);
uart_remove_one_port(&serial8250_reg, &uart->port);
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
uart->port.type = PORT_UNKNOWN;
uart->port.dev = NULL;
uart_add_one_port(&serial8250_reg, &uart->port);
up(&serial_sem);
}
EXPORT_SYMBOL(serial8250_unregister_port);
static int __init serial8250_init(void) static int __init serial8250_init(void)
{ {
int ret, i; int ret, i;
...@@ -2161,13 +2384,23 @@ static int __init serial8250_init(void) ...@@ -2161,13 +2384,23 @@ static int __init serial8250_init(void)
"%d ports, IRQ sharing %sabled\n", (int) UART_NR, "%d ports, IRQ sharing %sabled\n", (int) UART_NR,
share_irqs ? "en" : "dis"); share_irqs ? "en" : "dis");
ret = driver_register(&serial8250_isa_driver);
if (ret)
goto out;
for (i = 0; i < NR_IRQS; i++) for (i = 0; i < NR_IRQS; i++)
spin_lock_init(&irq_lists[i].lock); spin_lock_init(&irq_lists[i].lock);
ret = uart_register_driver(&serial8250_reg); ret = uart_register_driver(&serial8250_reg);
if (ret >= 0) if (ret)
serial8250_register_ports(&serial8250_reg); goto unreg;
serial8250_register_ports(&serial8250_reg, NULL);
goto out;
unreg:
driver_unregister(&serial8250_isa_driver);
out:
return ret; return ret;
} }
...@@ -2179,13 +2412,12 @@ static void __exit serial8250_exit(void) ...@@ -2179,13 +2412,12 @@ static void __exit serial8250_exit(void)
uart_remove_one_port(&serial8250_reg, &serial8250_ports[i].port); uart_remove_one_port(&serial8250_reg, &serial8250_ports[i].port);
uart_unregister_driver(&serial8250_reg); uart_unregister_driver(&serial8250_reg);
driver_unregister(&serial8250_isa_driver);
} }
module_init(serial8250_init); module_init(serial8250_init);
module_exit(serial8250_exit); module_exit(serial8250_exit);
EXPORT_SYMBOL(register_serial);
EXPORT_SYMBOL(unregister_serial);
EXPORT_SYMBOL(serial8250_get_irq_map); EXPORT_SYMBOL(serial8250_get_irq_map);
EXPORT_SYMBOL(serial8250_suspend_port); EXPORT_SYMBOL(serial8250_suspend_port);
EXPORT_SYMBOL(serial8250_resume_port); EXPORT_SYMBOL(serial8250_resume_port);
...@@ -2202,3 +2434,61 @@ module_param_array(probe_rsa, ulong, probe_rsa_count, 0444); ...@@ -2202,3 +2434,61 @@ module_param_array(probe_rsa, ulong, probe_rsa_count, 0444);
MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
#endif #endif
MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR); MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
/**
* register_serial - configure a 16x50 serial port at runtime
* @req: request structure
*
* Configure the serial port specified by the request. If the
* port exists and is in use an error is returned. If the port
* is not currently in the table it is added.
*
* The port is then probed and if necessary the IRQ is autodetected
* If this fails an error is returned.
*
* On success the port is ready to use and the line number is returned.
*/
int register_serial(struct serial_struct *req)
{
struct uart_port port;
port.iobase = req->port;
port.membase = req->iomem_base;
port.irq = req->irq;
port.uartclk = req->baud_base * 16;
port.fifosize = req->xmit_fifo_size;
port.regshift = req->iomem_reg_shift;
port.iotype = req->io_type;
port.flags = req->flags | UPF_BOOT_AUTOCONF;
port.mapbase = req->iomap_base;
port.dev = NULL;
if (share_irqs)
port.flags |= UPF_SHARE_IRQ;
if (HIGH_BITS_OFFSET)
port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET;
/*
* If a clock rate wasn't specified by the low level
* driver, then default to the standard clock rate.
*/
if (port.uartclk == 0)
port.uartclk = BASE_BAUD * 16;
return serial8250_register_port(&port);
}
EXPORT_SYMBOL(register_serial);
/**
* unregister_serial - remove a 16x50 serial port at runtime
* @line: serial line number
*
* Remove one serial port. This may not be called from interrupt
* context. We hand the port back to our local PM control.
*/
void unregister_serial(int line)
{
serial8250_unregister_port(line);
}
EXPORT_SYMBOL(unregister_serial);
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include <linux/config.h> #include <linux/config.h>
int serial8250_register_port(struct uart_port *);
void serial8250_unregister_port(int line);
void serial8250_get_irq_map(unsigned int *map); void serial8250_get_irq_map(unsigned int *map);
void serial8250_suspend_port(int line); void serial8250_suspend_port(int line);
void serial8250_resume_port(int line); void serial8250_resume_port(int line);
...@@ -38,14 +40,16 @@ struct old_serial_port { ...@@ -38,14 +40,16 @@ struct old_serial_port {
*/ */
struct serial8250_config { struct serial8250_config {
const char *name; const char *name;
unsigned int fifo_size; unsigned short fifo_size;
unsigned int tx_loadsz; unsigned short tx_loadsz;
unsigned char fcr;
unsigned int flags; unsigned int flags;
}; };
#define UART_CAP_FIFO (1 << 8) /* UART has FIFO */ #define UART_CAP_FIFO (1 << 8) /* UART has FIFO */
#define UART_CAP_EFR (1 << 9) /* UART has EFR */ #define UART_CAP_EFR (1 << 9) /* UART has EFR */
#define UART_CAP_SLEEP (1 << 10) /* UART has IER sleep */ #define UART_CAP_SLEEP (1 << 10) /* UART has IER sleep */
#define UART_CAP_AFE (1 << 11) /* MCR-based hw flow control */
#undef SERIAL_DEBUG_PCI #undef SERIAL_DEBUG_PCI
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/8250_pci.h> #include <linux/8250_pci.h>
...@@ -75,7 +74,7 @@ struct pci_serial_quirk { ...@@ -75,7 +74,7 @@ struct pci_serial_quirk {
u32 subdevice; u32 subdevice;
int (*init)(struct pci_dev *dev); int (*init)(struct pci_dev *dev);
int (*setup)(struct pci_dev *dev, struct pci_board *board, int (*setup)(struct pci_dev *dev, struct pci_board *board,
struct serial_struct *req, int idx); struct uart_port *port, int idx);
void (*exit)(struct pci_dev *dev); void (*exit)(struct pci_dev *dev);
}; };
...@@ -100,34 +99,32 @@ static void moan_device(const char *str, struct pci_dev *dev) ...@@ -100,34 +99,32 @@ static void moan_device(const char *str, struct pci_dev *dev)
} }
static int static int
setup_port(struct pci_dev *dev, struct serial_struct *req, setup_port(struct pci_dev *dev, struct uart_port *port,
int bar, int offset, int regshift) int bar, int offset, int regshift)
{ {
struct serial_private *priv = pci_get_drvdata(dev); struct serial_private *priv = pci_get_drvdata(dev);
unsigned long port, len; unsigned long base, len;
if (bar >= PCI_NUM_BAR_RESOURCES) if (bar >= PCI_NUM_BAR_RESOURCES)
return -EINVAL; return -EINVAL;
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) { if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
port = pci_resource_start(dev, bar); base = pci_resource_start(dev, bar);
len = pci_resource_len(dev, bar); len = pci_resource_len(dev, bar);
if (!priv->remapped_bar[bar]) if (!priv->remapped_bar[bar])
priv->remapped_bar[bar] = ioremap(port, len); priv->remapped_bar[bar] = ioremap(base, len);
if (!priv->remapped_bar[bar]) if (!priv->remapped_bar[bar])
return -ENOMEM; return -ENOMEM;
req->io_type = UPIO_MEM; port->iotype = UPIO_MEM;
req->iomap_base = port + offset; port->mapbase = base + offset;
req->iomem_base = priv->remapped_bar[bar] + offset; port->membase = priv->remapped_bar[bar] + offset;
req->iomem_reg_shift = regshift; port->regshift = regshift;
} else { } else {
port = pci_resource_start(dev, bar) + offset; base = pci_resource_start(dev, bar) + offset;
req->io_type = UPIO_PORT; port->iotype = UPIO_PORT;
req->port = port; port->iobase = base;
if (HIGH_BITS_OFFSET)
req->port_high = port >> HIGH_BITS_OFFSET;
} }
return 0; return 0;
} }
...@@ -138,7 +135,7 @@ setup_port(struct pci_dev *dev, struct serial_struct *req, ...@@ -138,7 +135,7 @@ setup_port(struct pci_dev *dev, struct serial_struct *req,
*/ */
static int static int
afavlab_setup(struct pci_dev *dev, struct pci_board *board, afavlab_setup(struct pci_dev *dev, struct pci_board *board,
struct serial_struct *req, int idx) struct uart_port *port, int idx)
{ {
unsigned int bar, offset = board->first_offset; unsigned int bar, offset = board->first_offset;
...@@ -150,7 +147,7 @@ afavlab_setup(struct pci_dev *dev, struct pci_board *board, ...@@ -150,7 +147,7 @@ afavlab_setup(struct pci_dev *dev, struct pci_board *board,
offset += (idx - 4) * board->uart_offset; offset += (idx - 4) * board->uart_offset;
} }
return setup_port(dev, req, bar, offset, board->reg_shift); return setup_port(dev, port, bar, offset, board->reg_shift);
} }
/* /*
...@@ -191,7 +188,7 @@ static int __devinit pci_hp_diva_init(struct pci_dev *dev) ...@@ -191,7 +188,7 @@ static int __devinit pci_hp_diva_init(struct pci_dev *dev)
*/ */
static int static int
pci_hp_diva_setup(struct pci_dev *dev, struct pci_board *board, pci_hp_diva_setup(struct pci_dev *dev, struct pci_board *board,
struct serial_struct *req, int idx) struct uart_port *port, int idx)
{ {
unsigned int offset = board->first_offset; unsigned int offset = board->first_offset;
unsigned int bar = FL_GET_BASE(board->flags); unsigned int bar = FL_GET_BASE(board->flags);
...@@ -213,7 +210,7 @@ pci_hp_diva_setup(struct pci_dev *dev, struct pci_board *board, ...@@ -213,7 +210,7 @@ pci_hp_diva_setup(struct pci_dev *dev, struct pci_board *board,
offset += idx * board->uart_offset; offset += idx * board->uart_offset;
return setup_port(dev, req, bar, offset, board->reg_shift); return setup_port(dev, port, bar, offset, board->reg_shift);
} }
/* /*
...@@ -309,7 +306,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev) ...@@ -309,7 +306,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev)
/* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */ /* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
static int static int
sbs_setup(struct pci_dev *dev, struct pci_board *board, sbs_setup(struct pci_dev *dev, struct pci_board *board,
struct serial_struct *req, int idx) struct uart_port *port, int idx)
{ {
unsigned int bar, offset = board->first_offset; unsigned int bar, offset = board->first_offset;
...@@ -324,7 +321,7 @@ sbs_setup(struct pci_dev *dev, struct pci_board *board, ...@@ -324,7 +321,7 @@ sbs_setup(struct pci_dev *dev, struct pci_board *board,
} else /* we have only 8 ports on PMC-OCTALPRO */ } else /* we have only 8 ports on PMC-OCTALPRO */
return 1; return 1;
return setup_port(dev, req, bar, offset, board->reg_shift); return setup_port(dev, port, bar, offset, board->reg_shift);
} }
/* /*
...@@ -522,7 +519,7 @@ static int __devinit pci_timedia_init(struct pci_dev *dev) ...@@ -522,7 +519,7 @@ static int __devinit pci_timedia_init(struct pci_dev *dev)
*/ */
static int static int
pci_timedia_setup(struct pci_dev *dev, struct pci_board *board, pci_timedia_setup(struct pci_dev *dev, struct pci_board *board,
struct serial_struct *req, int idx) struct uart_port *port, int idx)
{ {
unsigned int bar = 0, offset = board->first_offset; unsigned int bar = 0, offset = board->first_offset;
...@@ -547,7 +544,7 @@ pci_timedia_setup(struct pci_dev *dev, struct pci_board *board, ...@@ -547,7 +544,7 @@ pci_timedia_setup(struct pci_dev *dev, struct pci_board *board,
bar = idx - 2; bar = idx - 2;
} }
return setup_port(dev, req, bar, offset, board->reg_shift); return setup_port(dev, port, bar, offset, board->reg_shift);
} }
/* /*
...@@ -555,7 +552,7 @@ pci_timedia_setup(struct pci_dev *dev, struct pci_board *board, ...@@ -555,7 +552,7 @@ pci_timedia_setup(struct pci_dev *dev, struct pci_board *board,
*/ */
static int static int
titan_400l_800l_setup(struct pci_dev *dev, struct pci_board *board, titan_400l_800l_setup(struct pci_dev *dev, struct pci_board *board,
struct serial_struct *req, int idx) struct uart_port *port, int idx)
{ {
unsigned int bar, offset = board->first_offset; unsigned int bar, offset = board->first_offset;
...@@ -571,7 +568,7 @@ titan_400l_800l_setup(struct pci_dev *dev, struct pci_board *board, ...@@ -571,7 +568,7 @@ titan_400l_800l_setup(struct pci_dev *dev, struct pci_board *board,
offset = (idx - 2) * board->uart_offset; offset = (idx - 2) * board->uart_offset;
} }
return setup_port(dev, req, bar, offset, board->reg_shift); return setup_port(dev, port, bar, offset, board->reg_shift);
} }
static int __devinit pci_xircom_init(struct pci_dev *dev) static int __devinit pci_xircom_init(struct pci_dev *dev)
...@@ -582,7 +579,7 @@ static int __devinit pci_xircom_init(struct pci_dev *dev) ...@@ -582,7 +579,7 @@ static int __devinit pci_xircom_init(struct pci_dev *dev)
static int static int
pci_default_setup(struct pci_dev *dev, struct pci_board *board, pci_default_setup(struct pci_dev *dev, struct pci_board *board,
struct serial_struct *req, int idx) struct uart_port *port, int idx)
{ {
unsigned int bar, offset = board->first_offset, maxnr; unsigned int bar, offset = board->first_offset, maxnr;
...@@ -598,7 +595,7 @@ pci_default_setup(struct pci_dev *dev, struct pci_board *board, ...@@ -598,7 +595,7 @@ pci_default_setup(struct pci_dev *dev, struct pci_board *board,
if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
return 1; return 1;
return setup_port(dev, req, bar, offset, board->reg_shift); return setup_port(dev, port, bar, offset, board->reg_shift);
} }
/* This should be in linux/pci_ids.h */ /* This should be in linux/pci_ids.h */
...@@ -1610,7 +1607,6 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) ...@@ -1610,7 +1607,6 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
struct serial_private *priv; struct serial_private *priv;
struct pci_board *board, tmp; struct pci_board *board, tmp;
struct pci_serial_quirk *quirk; struct pci_serial_quirk *quirk;
struct serial_struct serial_req;
int rc, nr_ports, i; int rc, nr_ports, i;
if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
...@@ -1690,19 +1686,22 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) ...@@ -1690,19 +1686,22 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
pci_set_drvdata(dev, priv); pci_set_drvdata(dev, priv);
for (i = 0; i < nr_ports; i++) { for (i = 0; i < nr_ports; i++) {
memset(&serial_req, 0, sizeof(serial_req)); struct uart_port serial_port;
serial_req.flags = UPF_SKIP_TEST | UPF_AUTOPROBE | memset(&serial_port, 0, sizeof(struct uart_port));
UPF_SHARE_IRQ;
serial_req.baud_base = board->base_baud; serial_port.flags = UPF_SKIP_TEST | UPF_AUTOPROBE |
serial_req.irq = get_pci_irq(dev, board, i); UPF_SHARE_IRQ;
if (quirk->setup(dev, board, &serial_req, i)) serial_port.uartclk = board->base_baud * 16;
serial_port.irq = get_pci_irq(dev, board, i);
serial_port.dev = &dev->dev;
if (quirk->setup(dev, board, &serial_port, i))
break; break;
#ifdef SERIAL_DEBUG_PCI #ifdef SERIAL_DEBUG_PCI
printk("Setup PCI port: port %x, irq %d, type %d\n", printk("Setup PCI port: port %x, irq %d, type %d\n",
serial_req.port, serial_req.irq, serial_req.io_type); serial_port.iobase, serial_port.irq, serial_port.iotype);
#endif #endif
priv->line[i] = register_serial(&serial_req); priv->line[i] = serial8250_register_port(&serial_port);
if (priv->line[i] < 0) { if (priv->line[i] < 0) {
printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]); printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]);
break; break;
...@@ -1732,7 +1731,7 @@ static void __devexit pciserial_remove_one(struct pci_dev *dev) ...@@ -1732,7 +1731,7 @@ static void __devexit pciserial_remove_one(struct pci_dev *dev)
int i; int i;
for (i = 0; i < priv->nr; i++) for (i = 0; i < priv->nr; i++)
unregister_serial(priv->line[i]); serial8250_unregister_port(priv->line[i]);
for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) { for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
if (priv->remapped_bar[i]) if (priv->remapped_bar[i])
......
...@@ -2225,6 +2225,15 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) ...@@ -2225,6 +2225,15 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
*/ */
tty_register_device(drv->tty_driver, port->line, port->dev); tty_register_device(drv->tty_driver, port->line, port->dev);
/*
* If this driver supports console, and it hasn't been
* successfully registered yet, try to re-register it.
* It may be that the port was not available.
*/
if (port->type != PORT_UNKNOWN &&
port->cons && !(port->cons->flags & CON_ENABLED))
register_console(port->cons);
out: out:
up(&port_sem); up(&port_sem);
......
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