TTY/Serial driver fixes for 3.14-rc3
Here are a small number of tty/serial driver fixes to resolve reported issues with 3.14-rc and earlier (in the case of the vt bugfix.) Some of these have been tested and reported by a number of people as the tty bugfix was pretty commonly hit on some platforms. All have been in linux-next for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iEYEABECAAYFAlL+iJAACgkQMUfUDdst+ynLeACfcDynM0/zoSAvfscALTpF796A KU8AnRyiac0BauTLDmryJSr6pJqkAzMM =6iYo -----END PGP SIGNATURE----- Merge tag 'tty-3.14-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial driver fixes from Greg KH: "Here are a small number of tty/serial driver fixes to resolve reported issues with 3.14-rc and earlier (in the case of the vt bugfix). Some of these have been tested and reported by a number of people as the tty bugfix was pretty commonly hit on some platforms. All have been in linux-next for a while" * tag 'tty-3.14-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: vt: Fix secure clear screen serial: 8250: Support XR17V35x fraction divisor n_tty: Fix stale echo output serial: sirf: fix kernel panic caused by unpaired spinlock serial: 8250_pci: unbreak last serial ports on NetMos 9865 cards n_tty: Fix poll() when TIME_CHAR and MIN_CHAR == 0 serial: omap: fix rs485 probe on defered pinctrl serial: 8250_dw: fix compilation warning when !CONFIG_PM_SLEEP serial: omap-serial: Move info message to probe function tty: Set correct tty name in 'active' sysfs attribute tty: n_gsm: Fix for modems with brk in modem status control drivers/tty/hvc: don't use module_init in non-modular hyp. console code
This commit is contained in:
commit
40a215fba1
14 changed files with 77 additions and 64 deletions
|
@ -3,7 +3,8 @@ Date: Nov 2010
|
||||||
Contact: Kay Sievers <kay.sievers@vrfy.org>
|
Contact: Kay Sievers <kay.sievers@vrfy.org>
|
||||||
Description:
|
Description:
|
||||||
Shows the list of currently configured
|
Shows the list of currently configured
|
||||||
console devices, like 'tty1 ttyS0'.
|
tty devices used for the console,
|
||||||
|
like 'tty1 ttyS0'.
|
||||||
The last entry in the file is the active
|
The last entry in the file is the active
|
||||||
device connected to /dev/console.
|
device connected to /dev/console.
|
||||||
The file supports poll() to detect virtual
|
The file supports poll() to detect virtual
|
||||||
|
|
|
@ -255,13 +255,7 @@ static int __init hvc_opal_init(void)
|
||||||
/* Register as a vio device to receive callbacks */
|
/* Register as a vio device to receive callbacks */
|
||||||
return platform_driver_register(&hvc_opal_driver);
|
return platform_driver_register(&hvc_opal_driver);
|
||||||
}
|
}
|
||||||
module_init(hvc_opal_init);
|
device_initcall(hvc_opal_init);
|
||||||
|
|
||||||
static void __exit hvc_opal_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&hvc_opal_driver);
|
|
||||||
}
|
|
||||||
module_exit(hvc_opal_exit);
|
|
||||||
|
|
||||||
static void udbg_opal_putc(char c)
|
static void udbg_opal_putc(char c)
|
||||||
{
|
{
|
||||||
|
|
|
@ -102,17 +102,7 @@ static int __init hvc_rtas_init(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
module_init(hvc_rtas_init);
|
device_initcall(hvc_rtas_init);
|
||||||
|
|
||||||
/* This will tear down the tty portion of the driver */
|
|
||||||
static void __exit hvc_rtas_exit(void)
|
|
||||||
{
|
|
||||||
/* Really the fun isn't over until the worker thread breaks down and
|
|
||||||
* the tty cleans up */
|
|
||||||
if (hvc_rtas_dev)
|
|
||||||
hvc_remove(hvc_rtas_dev);
|
|
||||||
}
|
|
||||||
module_exit(hvc_rtas_exit);
|
|
||||||
|
|
||||||
/* This will happen prior to module init. There is no tty at this time? */
|
/* This will happen prior to module init. There is no tty at this time? */
|
||||||
static int __init hvc_rtas_console_init(void)
|
static int __init hvc_rtas_console_init(void)
|
||||||
|
|
|
@ -80,14 +80,7 @@ static int __init hvc_udbg_init(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
module_init(hvc_udbg_init);
|
device_initcall(hvc_udbg_init);
|
||||||
|
|
||||||
static void __exit hvc_udbg_exit(void)
|
|
||||||
{
|
|
||||||
if (hvc_udbg_dev)
|
|
||||||
hvc_remove(hvc_udbg_dev);
|
|
||||||
}
|
|
||||||
module_exit(hvc_udbg_exit);
|
|
||||||
|
|
||||||
static int __init hvc_udbg_console_init(void)
|
static int __init hvc_udbg_console_init(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -561,18 +561,7 @@ static int __init xen_hvc_init(void)
|
||||||
#endif
|
#endif
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
device_initcall(xen_hvc_init);
|
||||||
static void __exit xen_hvc_fini(void)
|
|
||||||
{
|
|
||||||
struct xencons_info *entry, *next;
|
|
||||||
|
|
||||||
if (list_empty(&xenconsoles))
|
|
||||||
return;
|
|
||||||
|
|
||||||
list_for_each_entry_safe(entry, next, &xenconsoles, list) {
|
|
||||||
xen_console_remove(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int xen_cons_init(void)
|
static int xen_cons_init(void)
|
||||||
{
|
{
|
||||||
|
@ -598,10 +587,6 @@ static int xen_cons_init(void)
|
||||||
hvc_instantiate(HVC_COOKIE, 0, ops);
|
hvc_instantiate(HVC_COOKIE, 0, ops);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
module_init(xen_hvc_init);
|
|
||||||
module_exit(xen_hvc_fini);
|
|
||||||
console_initcall(xen_cons_init);
|
console_initcall(xen_cons_init);
|
||||||
|
|
||||||
#ifdef CONFIG_EARLY_PRINTK
|
#ifdef CONFIG_EARLY_PRINTK
|
||||||
|
|
|
@ -1090,6 +1090,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
|
||||||
{
|
{
|
||||||
unsigned int addr = 0;
|
unsigned int addr = 0;
|
||||||
unsigned int modem = 0;
|
unsigned int modem = 0;
|
||||||
|
unsigned int brk = 0;
|
||||||
struct gsm_dlci *dlci;
|
struct gsm_dlci *dlci;
|
||||||
int len = clen;
|
int len = clen;
|
||||||
u8 *dp = data;
|
u8 *dp = data;
|
||||||
|
@ -1116,6 +1117,16 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
len--;
|
||||||
|
if (len > 0) {
|
||||||
|
while (gsm_read_ea(&brk, *dp++) == 0) {
|
||||||
|
len--;
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modem <<= 7;
|
||||||
|
modem |= (brk & 0x7f);
|
||||||
|
}
|
||||||
tty = tty_port_tty_get(&dlci->port);
|
tty = tty_port_tty_get(&dlci->port);
|
||||||
gsm_process_modem(tty, dlci, modem, clen);
|
gsm_process_modem(tty, dlci, modem, clen);
|
||||||
if (tty) {
|
if (tty) {
|
||||||
|
|
|
@ -817,8 +817,7 @@ static void process_echoes(struct tty_struct *tty)
|
||||||
struct n_tty_data *ldata = tty->disc_data;
|
struct n_tty_data *ldata = tty->disc_data;
|
||||||
size_t echoed;
|
size_t echoed;
|
||||||
|
|
||||||
if ((!L_ECHO(tty) && !L_ECHONL(tty)) ||
|
if (ldata->echo_mark == ldata->echo_tail)
|
||||||
ldata->echo_mark == ldata->echo_tail)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_lock(&ldata->output_lock);
|
mutex_lock(&ldata->output_lock);
|
||||||
|
@ -1244,7 +1243,8 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
|
||||||
if (L_ECHO(tty)) {
|
if (L_ECHO(tty)) {
|
||||||
echo_char(c, tty);
|
echo_char(c, tty);
|
||||||
commit_echoes(tty);
|
commit_echoes(tty);
|
||||||
}
|
} else
|
||||||
|
process_echoes(tty);
|
||||||
isig(signal, tty);
|
isig(signal, tty);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1274,7 +1274,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
|
||||||
if (I_IXON(tty)) {
|
if (I_IXON(tty)) {
|
||||||
if (c == START_CHAR(tty)) {
|
if (c == START_CHAR(tty)) {
|
||||||
start_tty(tty);
|
start_tty(tty);
|
||||||
commit_echoes(tty);
|
process_echoes(tty);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (c == STOP_CHAR(tty)) {
|
if (c == STOP_CHAR(tty)) {
|
||||||
|
@ -1820,8 +1820,10 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
|
||||||
* Fix tty hang when I_IXON(tty) is cleared, but the tty
|
* Fix tty hang when I_IXON(tty) is cleared, but the tty
|
||||||
* been stopped by STOP_CHAR(tty) before it.
|
* been stopped by STOP_CHAR(tty) before it.
|
||||||
*/
|
*/
|
||||||
if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped)
|
if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) {
|
||||||
start_tty(tty);
|
start_tty(tty);
|
||||||
|
process_echoes(tty);
|
||||||
|
}
|
||||||
|
|
||||||
/* The termios change make the tty ready for I/O */
|
/* The termios change make the tty ready for I/O */
|
||||||
if (waitqueue_active(&tty->write_wait))
|
if (waitqueue_active(&tty->write_wait))
|
||||||
|
@ -1896,7 +1898,7 @@ err:
|
||||||
static inline int input_available_p(struct tty_struct *tty, int poll)
|
static inline int input_available_p(struct tty_struct *tty, int poll)
|
||||||
{
|
{
|
||||||
struct n_tty_data *ldata = tty->disc_data;
|
struct n_tty_data *ldata = tty->disc_data;
|
||||||
int amt = poll && !TIME_CHAR(tty) ? MIN_CHAR(tty) : 1;
|
int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1;
|
||||||
|
|
||||||
if (ldata->icanon && !L_EXTPROC(tty)) {
|
if (ldata->icanon && !L_EXTPROC(tty)) {
|
||||||
if (ldata->canon_head != ldata->read_tail)
|
if (ldata->canon_head != ldata->read_tail)
|
||||||
|
|
|
@ -2432,6 +2432,24 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
|
|
||||||
serial_dl_write(up, quot);
|
serial_dl_write(up, quot);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XR17V35x UARTs have an extra fractional divisor register (DLD)
|
||||||
|
*
|
||||||
|
* We need to recalculate all of the registers, because DLM and DLL
|
||||||
|
* are already rounded to a whole integer.
|
||||||
|
*
|
||||||
|
* When recalculating we use a 32x clock instead of a 16x clock to
|
||||||
|
* allow 1-bit for rounding in the fractional part.
|
||||||
|
*/
|
||||||
|
if (up->port.type == PORT_XR17V35X) {
|
||||||
|
unsigned int baud_x32 = (port->uartclk * 2) / baud;
|
||||||
|
u16 quot = baud_x32 / 32;
|
||||||
|
u8 quot_frac = DIV_ROUND_CLOSEST(baud_x32 % 32, 2);
|
||||||
|
|
||||||
|
serial_dl_write(up, quot);
|
||||||
|
serial_port_out(port, 0x2, quot_frac & 0xf);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
|
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
|
||||||
* is written without DLAB set, this mode will be disabled.
|
* is written without DLAB set, this mode will be disabled.
|
||||||
|
|
|
@ -391,7 +391,7 @@ static int dw8250_remove(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM_SLEEP
|
||||||
static int dw8250_suspend(struct device *dev)
|
static int dw8250_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||||
|
@ -409,7 +409,7 @@ static int dw8250_resume(struct device *dev)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM */
|
#endif /* CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
#ifdef CONFIG_PM_RUNTIME
|
#ifdef CONFIG_PM_RUNTIME
|
||||||
static int dw8250_runtime_suspend(struct device *dev)
|
static int dw8250_runtime_suspend(struct device *dev)
|
||||||
|
|
|
@ -783,7 +783,8 @@ static int pci_netmos_9900_setup(struct serial_private *priv,
|
||||||
{
|
{
|
||||||
unsigned int bar;
|
unsigned int bar;
|
||||||
|
|
||||||
if ((priv->dev->subsystem_device & 0xff00) == 0x3000) {
|
if ((priv->dev->device != PCI_DEVICE_ID_NETMOS_9865) &&
|
||||||
|
(priv->dev->subsystem_device & 0xff00) == 0x3000) {
|
||||||
/* netmos apparently orders BARs by datasheet layout, so serial
|
/* netmos apparently orders BARs by datasheet layout, so serial
|
||||||
* ports get BARs 0 and 3 (or 1 and 4 for memmapped)
|
* ports get BARs 0 and 3 (or 1 and 4 for memmapped)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -738,9 +738,6 @@ static int serial_omap_startup(struct uart_port *port)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
disable_irq(up->wakeirq);
|
disable_irq(up->wakeirq);
|
||||||
} else {
|
|
||||||
dev_info(up->port.dev, "no wakeirq for uart%d\n",
|
|
||||||
up->port.line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line);
|
dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line);
|
||||||
|
@ -1604,8 +1601,11 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
|
||||||
flags & SER_RS485_RTS_AFTER_SEND);
|
flags & SER_RS485_RTS_AFTER_SEND);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
} else
|
} else if (up->rts_gpio == -EPROBE_DEFER) {
|
||||||
|
return -EPROBE_DEFER;
|
||||||
|
} else {
|
||||||
up->rts_gpio = -EINVAL;
|
up->rts_gpio = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (of_property_read_u32_array(np, "rs485-rts-delay",
|
if (of_property_read_u32_array(np, "rs485-rts-delay",
|
||||||
rs485_delay, 2) == 0) {
|
rs485_delay, 2) == 0) {
|
||||||
|
@ -1687,6 +1687,9 @@ static int serial_omap_probe(struct platform_device *pdev)
|
||||||
up->port.iotype = UPIO_MEM;
|
up->port.iotype = UPIO_MEM;
|
||||||
up->port.irq = uartirq;
|
up->port.irq = uartirq;
|
||||||
up->wakeirq = wakeirq;
|
up->wakeirq = wakeirq;
|
||||||
|
if (!up->wakeirq)
|
||||||
|
dev_info(up->port.dev, "no wakeirq for uart%d\n",
|
||||||
|
up->port.line);
|
||||||
|
|
||||||
up->port.regshift = 2;
|
up->port.regshift = 2;
|
||||||
up->port.fifosize = 64;
|
up->port.fifosize = 64;
|
||||||
|
|
|
@ -542,8 +542,10 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
|
||||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
|
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
|
||||||
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
|
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
|
||||||
SIRFUART_IO_MODE);
|
SIRFUART_IO_MODE);
|
||||||
sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
|
|
||||||
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
|
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
|
||||||
|
spin_lock(&port->lock);
|
||||||
|
sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
|
||||||
|
spin_unlock(&port->lock);
|
||||||
if (sirfport->rx_io_count == 4) {
|
if (sirfport->rx_io_count == 4) {
|
||||||
spin_lock_irqsave(&sirfport->rx_lock, flags);
|
spin_lock_irqsave(&sirfport->rx_lock, flags);
|
||||||
sirfport->rx_io_count = 0;
|
sirfport->rx_io_count = 0;
|
||||||
|
|
|
@ -1267,16 +1267,17 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
|
||||||
* @p: output buffer of at least 7 bytes
|
* @p: output buffer of at least 7 bytes
|
||||||
*
|
*
|
||||||
* Generate a name from a driver reference and write it to the output
|
* Generate a name from a driver reference and write it to the output
|
||||||
* buffer.
|
* buffer. Return the number of bytes written.
|
||||||
*
|
*
|
||||||
* Locking: None
|
* Locking: None
|
||||||
*/
|
*/
|
||||||
static void tty_line_name(struct tty_driver *driver, int index, char *p)
|
static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p)
|
||||||
{
|
{
|
||||||
if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE)
|
if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE)
|
||||||
strcpy(p, driver->name);
|
return sprintf(p, "%s", driver->name);
|
||||||
else
|
else
|
||||||
sprintf(p, "%s%d", driver->name, index + driver->name_base);
|
return sprintf(p, "%s%d", driver->name,
|
||||||
|
index + driver->name_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3545,9 +3546,19 @@ static ssize_t show_cons_active(struct device *dev,
|
||||||
if (i >= ARRAY_SIZE(cs))
|
if (i >= ARRAY_SIZE(cs))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
while (i--)
|
while (i--) {
|
||||||
count += sprintf(buf + count, "%s%d%c",
|
struct tty_driver *driver;
|
||||||
cs[i]->name, cs[i]->index, i ? ' ':'\n');
|
const char *name = cs[i]->name;
|
||||||
|
int index = cs[i]->index;
|
||||||
|
|
||||||
|
driver = cs[i]->device(cs[i], &index);
|
||||||
|
if (driver) {
|
||||||
|
count += tty_line_name(driver, index, buf + count);
|
||||||
|
count += sprintf(buf + count, "%c", i ? ' ':'\n');
|
||||||
|
} else
|
||||||
|
count += sprintf(buf + count, "%s%d%c",
|
||||||
|
name, index, i ? ' ':'\n');
|
||||||
|
}
|
||||||
console_unlock();
|
console_unlock();
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
|
|
@ -1164,6 +1164,8 @@ static void csi_J(struct vc_data *vc, int vpar)
|
||||||
scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,
|
scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,
|
||||||
vc->vc_screenbuf_size >> 1);
|
vc->vc_screenbuf_size >> 1);
|
||||||
set_origin(vc);
|
set_origin(vc);
|
||||||
|
if (CON_IS_VISIBLE(vc))
|
||||||
|
update_screen(vc);
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 2: /* erase whole display */
|
case 2: /* erase whole display */
|
||||||
count = vc->vc_cols * vc->vc_rows;
|
count = vc->vc_cols * vc->vc_rows;
|
||||||
|
|
Loading…
Add table
Reference in a new issue