提交 ef11f1b7 编写于 作者: L Linus Torvalds

Merge tag 'tty-5.6-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial driver fixes from Greg KH:
 "Here are a number of small tty and serial driver fixes for 5.6-rc3
  that resolve a bunch of reported issues.

  They are:
   - vt selection and ioctl fixes
   - serdev bugfix
   - atmel serial driver fixes
   - qcom serial driver fixes
   - other minor serial driver fixes

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'tty-5.6-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  vt: selection, close sel_buffer race
  vt: selection, handle pending signals in paste_selection
  serial: cpm_uart: call cpm_muram_init before registering console
  tty: serial: qcom_geni_serial: Fix RX cancel command failure
  serial: 8250: Check UPF_IRQ_SHARED in advance
  tty: serial: imx: setup the correct sg entry for tx dma
  vt: vt_ioctl: fix race in VT_RESIZEX
  vt: fix scrollback flushing on background consoles
  tty: serial: tegra: Handle RX transfer in PIO mode if DMA wasn't started
  tty/serial: atmel: manage shutdown in case of RS485 or ISO7816 mode
  serdev: ttyport: restore client ops on deregistration
  serial: ar933x_uart: set UART_CS_{RX,TX}_READY_ORIDE
...@@ -265,7 +265,6 @@ struct device *serdev_tty_port_register(struct tty_port *port, ...@@ -265,7 +265,6 @@ struct device *serdev_tty_port_register(struct tty_port *port,
struct device *parent, struct device *parent,
struct tty_driver *drv, int idx) struct tty_driver *drv, int idx)
{ {
const struct tty_port_client_operations *old_ops;
struct serdev_controller *ctrl; struct serdev_controller *ctrl;
struct serport *serport; struct serport *serport;
int ret; int ret;
...@@ -284,7 +283,6 @@ struct device *serdev_tty_port_register(struct tty_port *port, ...@@ -284,7 +283,6 @@ struct device *serdev_tty_port_register(struct tty_port *port,
ctrl->ops = &ctrl_ops; ctrl->ops = &ctrl_ops;
old_ops = port->client_ops;
port->client_ops = &client_ops; port->client_ops = &client_ops;
port->client_data = ctrl; port->client_data = ctrl;
...@@ -297,7 +295,7 @@ struct device *serdev_tty_port_register(struct tty_port *port, ...@@ -297,7 +295,7 @@ struct device *serdev_tty_port_register(struct tty_port *port,
err_reset_data: err_reset_data:
port->client_data = NULL; port->client_data = NULL;
port->client_ops = old_ops; port->client_ops = &tty_port_default_client_ops;
serdev_controller_put(ctrl); serdev_controller_put(ctrl);
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -312,8 +310,8 @@ int serdev_tty_port_unregister(struct tty_port *port) ...@@ -312,8 +310,8 @@ int serdev_tty_port_unregister(struct tty_port *port)
return -ENODEV; return -ENODEV;
serdev_controller_remove(ctrl); serdev_controller_remove(ctrl);
port->client_ops = NULL;
port->client_data = NULL; port->client_data = NULL;
port->client_ops = &tty_port_default_client_ops;
serdev_controller_put(ctrl); serdev_controller_put(ctrl);
return 0; return 0;
......
...@@ -446,7 +446,6 @@ static int aspeed_vuart_probe(struct platform_device *pdev) ...@@ -446,7 +446,6 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
port.port.line = rc; port.port.line = rc;
port.port.irq = irq_of_parse_and_map(np, 0); port.port.irq = irq_of_parse_and_map(np, 0);
port.port.irqflags = IRQF_SHARED;
port.port.handle_irq = aspeed_vuart_handle_irq; port.port.handle_irq = aspeed_vuart_handle_irq;
port.port.iotype = UPIO_MEM; port.port.iotype = UPIO_MEM;
port.port.type = PORT_16550A; port.port.type = PORT_16550A;
......
...@@ -174,7 +174,7 @@ static int serial_link_irq_chain(struct uart_8250_port *up) ...@@ -174,7 +174,7 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
struct hlist_head *h; struct hlist_head *h;
struct hlist_node *n; struct hlist_node *n;
struct irq_info *i; struct irq_info *i;
int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0; int ret;
mutex_lock(&hash_mutex); mutex_lock(&hash_mutex);
...@@ -209,9 +209,8 @@ static int serial_link_irq_chain(struct uart_8250_port *up) ...@@ -209,9 +209,8 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
INIT_LIST_HEAD(&up->list); INIT_LIST_HEAD(&up->list);
i->head = &up->list; i->head = &up->list;
spin_unlock_irq(&i->lock); spin_unlock_irq(&i->lock);
irq_flags |= up->port.irqflags;
ret = request_irq(up->port.irq, serial8250_interrupt, ret = request_irq(up->port.irq, serial8250_interrupt,
irq_flags, up->port.name, i); up->port.irqflags, up->port.name, i);
if (ret < 0) if (ret < 0)
serial_do_unlink(i, up); serial_do_unlink(i, up);
} }
......
...@@ -202,7 +202,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev, ...@@ -202,7 +202,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->type = type; port->type = type;
port->uartclk = clk; port->uartclk = clk;
port->irqflags |= IRQF_SHARED;
if (of_property_read_bool(np, "no-loopback-test")) if (of_property_read_bool(np, "no-loopback-test"))
port->flags |= UPF_SKIP_TEST; port->flags |= UPF_SKIP_TEST;
......
...@@ -2177,6 +2177,10 @@ int serial8250_do_startup(struct uart_port *port) ...@@ -2177,6 +2177,10 @@ int serial8250_do_startup(struct uart_port *port)
} }
} }
/* Check if we need to have shared IRQs */
if (port->irq && (up->port.flags & UPF_SHARE_IRQ))
up->port.irqflags |= IRQF_SHARED;
if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) { if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) {
unsigned char iir1; unsigned char iir1;
/* /*
......
...@@ -286,6 +286,10 @@ static void ar933x_uart_set_termios(struct uart_port *port, ...@@ -286,6 +286,10 @@ static void ar933x_uart_set_termios(struct uart_port *port,
ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
AR933X_UART_CS_HOST_INT_EN); AR933X_UART_CS_HOST_INT_EN);
/* enable RX and TX ready overide */
ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE);
/* reenable the UART */ /* reenable the UART */
ar933x_uart_rmw(up, AR933X_UART_CS_REG, ar933x_uart_rmw(up, AR933X_UART_CS_REG,
AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S, AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S,
...@@ -418,6 +422,10 @@ static int ar933x_uart_startup(struct uart_port *port) ...@@ -418,6 +422,10 @@ static int ar933x_uart_startup(struct uart_port *port)
ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
AR933X_UART_CS_HOST_INT_EN); AR933X_UART_CS_HOST_INT_EN);
/* enable RX and TX ready overide */
ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE);
/* Enable RX interrupts */ /* Enable RX interrupts */
up->ier = AR933X_UART_INT_RX_VALID; up->ier = AR933X_UART_INT_RX_VALID;
ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
......
...@@ -570,7 +570,8 @@ static void atmel_stop_tx(struct uart_port *port) ...@@ -570,7 +570,8 @@ static void atmel_stop_tx(struct uart_port *port)
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
if (atmel_uart_is_half_duplex(port)) if (atmel_uart_is_half_duplex(port))
atmel_start_rx(port); if (!atomic_read(&atmel_port->tasklet_shutdown))
atmel_start_rx(port);
} }
......
...@@ -1373,6 +1373,7 @@ static struct console cpm_scc_uart_console = { ...@@ -1373,6 +1373,7 @@ static struct console cpm_scc_uart_console = {
static int __init cpm_uart_console_init(void) static int __init cpm_uart_console_init(void)
{ {
cpm_muram_init();
register_console(&cpm_scc_uart_console); register_console(&cpm_scc_uart_console);
return 0; return 0;
} }
......
...@@ -599,7 +599,7 @@ static void imx_uart_dma_tx(struct imx_port *sport) ...@@ -599,7 +599,7 @@ static void imx_uart_dma_tx(struct imx_port *sport)
sport->tx_bytes = uart_circ_chars_pending(xmit); sport->tx_bytes = uart_circ_chars_pending(xmit);
if (xmit->tail < xmit->head) { if (xmit->tail < xmit->head || xmit->head == 0) {
sport->dma_tx_nents = 1; sport->dma_tx_nents = 1;
sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes); sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
} else { } else {
......
...@@ -129,6 +129,7 @@ static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop); ...@@ -129,6 +129,7 @@ static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop);
static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop); static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop);
static unsigned int qcom_geni_serial_tx_empty(struct uart_port *port); static unsigned int qcom_geni_serial_tx_empty(struct uart_port *port);
static void qcom_geni_serial_stop_rx(struct uart_port *uport); static void qcom_geni_serial_stop_rx(struct uart_port *uport);
static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop);
static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200, static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
32000000, 48000000, 64000000, 80000000, 32000000, 48000000, 64000000, 80000000,
...@@ -599,7 +600,7 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport) ...@@ -599,7 +600,7 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport)
u32 irq_en; u32 irq_en;
u32 status; u32 status;
struct qcom_geni_serial_port *port = to_dev_port(uport, uport); struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
u32 irq_clear = S_CMD_DONE_EN; u32 s_irq_status;
irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN);
irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN); irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN);
...@@ -615,10 +616,19 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport) ...@@ -615,10 +616,19 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport)
return; return;
geni_se_cancel_s_cmd(&port->se); geni_se_cancel_s_cmd(&port->se);
qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG, qcom_geni_serial_poll_bit(uport, SE_GENI_S_IRQ_STATUS,
S_GENI_CMD_CANCEL, false); S_CMD_CANCEL_EN, true);
/*
* If timeout occurs secondary engine remains active
* and Abort sequence is executed.
*/
s_irq_status = readl(uport->membase + SE_GENI_S_IRQ_STATUS);
/* Flush the Rx buffer */
if (s_irq_status & S_RX_FIFO_LAST_EN)
qcom_geni_serial_handle_rx(uport, true);
writel(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR);
status = readl(uport->membase + SE_GENI_STATUS); status = readl(uport->membase + SE_GENI_STATUS);
writel(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR);
if (status & S_GENI_CMD_ACTIVE) if (status & S_GENI_CMD_ACTIVE)
qcom_geni_serial_abort_rx(uport); qcom_geni_serial_abort_rx(uport);
} }
......
...@@ -692,11 +692,22 @@ static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, ...@@ -692,11 +692,22 @@ static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
count, DMA_TO_DEVICE); count, DMA_TO_DEVICE);
} }
static void do_handle_rx_pio(struct tegra_uart_port *tup)
{
struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
struct tty_port *port = &tup->uport.state->port;
tegra_uart_handle_rx_pio(tup, port);
if (tty) {
tty_flip_buffer_push(port);
tty_kref_put(tty);
}
}
static void tegra_uart_rx_buffer_push(struct tegra_uart_port *tup, static void tegra_uart_rx_buffer_push(struct tegra_uart_port *tup,
unsigned int residue) unsigned int residue)
{ {
struct tty_port *port = &tup->uport.state->port; struct tty_port *port = &tup->uport.state->port;
struct tty_struct *tty = tty_port_tty_get(port);
unsigned int count; unsigned int count;
async_tx_ack(tup->rx_dma_desc); async_tx_ack(tup->rx_dma_desc);
...@@ -705,11 +716,7 @@ static void tegra_uart_rx_buffer_push(struct tegra_uart_port *tup, ...@@ -705,11 +716,7 @@ static void tegra_uart_rx_buffer_push(struct tegra_uart_port *tup,
/* If we are here, DMA is stopped */ /* If we are here, DMA is stopped */
tegra_uart_copy_rx_to_tty(tup, port, count); tegra_uart_copy_rx_to_tty(tup, port, count);
tegra_uart_handle_rx_pio(tup, port); do_handle_rx_pio(tup);
if (tty) {
tty_flip_buffer_push(port);
tty_kref_put(tty);
}
} }
static void tegra_uart_rx_dma_complete(void *args) static void tegra_uart_rx_dma_complete(void *args)
...@@ -749,8 +756,10 @@ static void tegra_uart_terminate_rx_dma(struct tegra_uart_port *tup) ...@@ -749,8 +756,10 @@ static void tegra_uart_terminate_rx_dma(struct tegra_uart_port *tup)
{ {
struct dma_tx_state state; struct dma_tx_state state;
if (!tup->rx_dma_active) if (!tup->rx_dma_active) {
do_handle_rx_pio(tup);
return; return;
}
dmaengine_terminate_all(tup->rx_dma_chan); dmaengine_terminate_all(tup->rx_dma_chan);
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
...@@ -816,18 +825,6 @@ static void tegra_uart_handle_modem_signal_change(struct uart_port *u) ...@@ -816,18 +825,6 @@ static void tegra_uart_handle_modem_signal_change(struct uart_port *u)
uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS); uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS);
} }
static void do_handle_rx_pio(struct tegra_uart_port *tup)
{
struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
struct tty_port *port = &tup->uport.state->port;
tegra_uart_handle_rx_pio(tup, port);
if (tty) {
tty_flip_buffer_push(port);
tty_kref_put(tty);
}
}
static irqreturn_t tegra_uart_isr(int irq, void *data) static irqreturn_t tegra_uart_isr(int irq, void *data)
{ {
struct tegra_uart_port *tup = data; struct tegra_uart_port *tup = data;
......
...@@ -52,10 +52,11 @@ static void tty_port_default_wakeup(struct tty_port *port) ...@@ -52,10 +52,11 @@ static void tty_port_default_wakeup(struct tty_port *port)
} }
} }
static const struct tty_port_client_operations default_client_ops = { const struct tty_port_client_operations tty_port_default_client_ops = {
.receive_buf = tty_port_default_receive_buf, .receive_buf = tty_port_default_receive_buf,
.write_wakeup = tty_port_default_wakeup, .write_wakeup = tty_port_default_wakeup,
}; };
EXPORT_SYMBOL_GPL(tty_port_default_client_ops);
void tty_port_init(struct tty_port *port) void tty_port_init(struct tty_port *port)
{ {
...@@ -68,7 +69,7 @@ void tty_port_init(struct tty_port *port) ...@@ -68,7 +69,7 @@ void tty_port_init(struct tty_port *port)
spin_lock_init(&port->lock); spin_lock_init(&port->lock);
port->close_delay = (50 * HZ) / 100; port->close_delay = (50 * HZ) / 100;
port->closing_wait = (3000 * HZ) / 100; port->closing_wait = (3000 * HZ) / 100;
port->client_ops = &default_client_ops; port->client_ops = &tty_port_default_client_ops;
kref_init(&port->kref); kref_init(&port->kref);
} }
EXPORT_SYMBOL(tty_port_init); EXPORT_SYMBOL(tty_port_init);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -29,6 +30,8 @@ ...@@ -29,6 +30,8 @@
#include <linux/console.h> #include <linux/console.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <linux/sched/signal.h>
/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
#define isspace(c) ((c) == ' ') #define isspace(c) ((c) == ' ')
...@@ -43,6 +46,7 @@ static volatile int sel_start = -1; /* cleared by clear_selection */ ...@@ -43,6 +46,7 @@ static volatile int sel_start = -1; /* cleared by clear_selection */
static int sel_end; static int sel_end;
static int sel_buffer_lth; static int sel_buffer_lth;
static char *sel_buffer; static char *sel_buffer;
static DEFINE_MUTEX(sel_lock);
/* clear_selection, highlight and highlight_pointer can be called /* clear_selection, highlight and highlight_pointer can be called
from interrupt (via scrollback/front) */ from interrupt (via scrollback/front) */
...@@ -184,7 +188,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) ...@@ -184,7 +188,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
char *bp, *obp; char *bp, *obp;
int i, ps, pe, multiplier; int i, ps, pe, multiplier;
u32 c; u32 c;
int mode; int mode, ret = 0;
poke_blanked_console(); poke_blanked_console();
...@@ -210,6 +214,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) ...@@ -210,6 +214,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
if (ps > pe) /* make sel_start <= sel_end */ if (ps > pe) /* make sel_start <= sel_end */
swap(ps, pe); swap(ps, pe);
mutex_lock(&sel_lock);
if (sel_cons != vc_cons[fg_console].d) { if (sel_cons != vc_cons[fg_console].d) {
clear_selection(); clear_selection();
sel_cons = vc_cons[fg_console].d; sel_cons = vc_cons[fg_console].d;
...@@ -255,9 +260,10 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) ...@@ -255,9 +260,10 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
break; break;
case TIOCL_SELPOINTER: case TIOCL_SELPOINTER:
highlight_pointer(pe); highlight_pointer(pe);
return 0; goto unlock;
default: default:
return -EINVAL; ret = -EINVAL;
goto unlock;
} }
/* remove the pointer */ /* remove the pointer */
...@@ -279,7 +285,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) ...@@ -279,7 +285,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
else if (new_sel_start == sel_start) else if (new_sel_start == sel_start)
{ {
if (new_sel_end == sel_end) /* no action required */ if (new_sel_end == sel_end) /* no action required */
return 0; goto unlock;
else if (new_sel_end > sel_end) /* extend to right */ else if (new_sel_end > sel_end) /* extend to right */
highlight(sel_end + 2, new_sel_end); highlight(sel_end + 2, new_sel_end);
else /* contract from right */ else /* contract from right */
...@@ -307,7 +313,8 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) ...@@ -307,7 +313,8 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
if (!bp) { if (!bp) {
printk(KERN_WARNING "selection: kmalloc() failed\n"); printk(KERN_WARNING "selection: kmalloc() failed\n");
clear_selection(); clear_selection();
return -ENOMEM; ret = -ENOMEM;
goto unlock;
} }
kfree(sel_buffer); kfree(sel_buffer);
sel_buffer = bp; sel_buffer = bp;
...@@ -332,7 +339,9 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) ...@@ -332,7 +339,9 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
} }
} }
sel_buffer_lth = bp - sel_buffer; sel_buffer_lth = bp - sel_buffer;
return 0; unlock:
mutex_unlock(&sel_lock);
return ret;
} }
EXPORT_SYMBOL_GPL(set_selection_kernel); EXPORT_SYMBOL_GPL(set_selection_kernel);
...@@ -350,6 +359,7 @@ int paste_selection(struct tty_struct *tty) ...@@ -350,6 +359,7 @@ int paste_selection(struct tty_struct *tty)
unsigned int count; unsigned int count;
struct tty_ldisc *ld; struct tty_ldisc *ld;
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
int ret = 0;
console_lock(); console_lock();
poke_blanked_console(); poke_blanked_console();
...@@ -361,10 +371,17 @@ int paste_selection(struct tty_struct *tty) ...@@ -361,10 +371,17 @@ int paste_selection(struct tty_struct *tty)
tty_buffer_lock_exclusive(&vc->port); tty_buffer_lock_exclusive(&vc->port);
add_wait_queue(&vc->paste_wait, &wait); add_wait_queue(&vc->paste_wait, &wait);
mutex_lock(&sel_lock);
while (sel_buffer && sel_buffer_lth > pasted) { while (sel_buffer && sel_buffer_lth > pasted) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
ret = -EINTR;
break;
}
if (tty_throttled(tty)) { if (tty_throttled(tty)) {
mutex_unlock(&sel_lock);
schedule(); schedule();
mutex_lock(&sel_lock);
continue; continue;
} }
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
...@@ -373,11 +390,12 @@ int paste_selection(struct tty_struct *tty) ...@@ -373,11 +390,12 @@ int paste_selection(struct tty_struct *tty)
count); count);
pasted += count; pasted += count;
} }
mutex_unlock(&sel_lock);
remove_wait_queue(&vc->paste_wait, &wait); remove_wait_queue(&vc->paste_wait, &wait);
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
tty_buffer_unlock_exclusive(&vc->port); tty_buffer_unlock_exclusive(&vc->port);
tty_ldisc_deref(ld); tty_ldisc_deref(ld);
return 0; return ret;
} }
EXPORT_SYMBOL_GPL(paste_selection); EXPORT_SYMBOL_GPL(paste_selection);
...@@ -936,10 +936,21 @@ static void flush_scrollback(struct vc_data *vc) ...@@ -936,10 +936,21 @@ static void flush_scrollback(struct vc_data *vc)
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
set_origin(vc); set_origin(vc);
if (vc->vc_sw->con_flush_scrollback) if (vc->vc_sw->con_flush_scrollback) {
vc->vc_sw->con_flush_scrollback(vc); vc->vc_sw->con_flush_scrollback(vc);
else } else if (con_is_visible(vc)) {
/*
* When no con_flush_scrollback method is provided then the
* legacy way for flushing the scrollback buffer is to use
* a side effect of the con_switch method. We do it only on
* the foreground console as background consoles have no
* scrollback buffers in that case and we obviously don't
* want to switch to them.
*/
hide_cursor(vc);
vc->vc_sw->con_switch(vc); vc->vc_sw->con_switch(vc);
set_cursor(vc);
}
} }
/* /*
......
...@@ -876,15 +876,20 @@ int vt_ioctl(struct tty_struct *tty, ...@@ -876,15 +876,20 @@ int vt_ioctl(struct tty_struct *tty,
return -EINVAL; return -EINVAL;
for (i = 0; i < MAX_NR_CONSOLES; i++) { for (i = 0; i < MAX_NR_CONSOLES; i++) {
struct vc_data *vcp;
if (!vc_cons[i].d) if (!vc_cons[i].d)
continue; continue;
console_lock(); console_lock();
if (v.v_vlin) vcp = vc_cons[i].d;
vc_cons[i].d->vc_scan_lines = v.v_vlin; if (vcp) {
if (v.v_clin) if (v.v_vlin)
vc_cons[i].d->vc_font.height = v.v_clin; vcp->vc_scan_lines = v.v_vlin;
vc_cons[i].d->vc_resize_user = 1; if (v.v_clin)
vc_resize(vc_cons[i].d, v.v_cols, v.v_rows); vcp->vc_font.height = v.v_clin;
vcp->vc_resize_user = 1;
vc_resize(vcp, v.v_cols, v.v_rows);
}
console_unlock(); console_unlock();
} }
break; break;
......
...@@ -225,6 +225,8 @@ struct tty_port_client_operations { ...@@ -225,6 +225,8 @@ struct tty_port_client_operations {
void (*write_wakeup)(struct tty_port *port); void (*write_wakeup)(struct tty_port *port);
}; };
extern const struct tty_port_client_operations tty_port_default_client_ops;
struct tty_port { struct tty_port {
struct tty_bufhead buf; /* Locked internally */ struct tty_bufhead buf; /* Locked internally */
struct tty_struct *tty; /* Back pointer */ struct tty_struct *tty; /* Back pointer */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册