From 7ca0ff9ab3218ec443a7a9ad247e4650373ed41e Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 19 Sep 2009 13:13:20 -0700 Subject: tty: Add a full port_close function Now we are extracting out methods for shutdown and the like we can add a proper tty_port_close method that knows all the innards of the tty closing process and hides the lot from the caller. At some point in the future this will be paired with a similar open() helper and the drivers can stick to hardware management. Signed-off-by: Alan Cox Cc: stable Signed-off-by: Greg Kroah-Hartman --- include/linux/tty.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'include/linux/tty.h') diff --git a/include/linux/tty.h b/include/linux/tty.h index a916a318004e..ecb3d1ba3017 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -187,7 +187,12 @@ struct tty_port; struct tty_port_operations { /* Return 1 if the carrier is raised */ int (*carrier_raised)(struct tty_port *port); + /* Control the DTR line */ void (*dtr_rts)(struct tty_port *port, int raise); + /* Called when the last close completes or a hangup finishes + IFF the port was initialized. Do not use to free resources */ + void (*shutdown)(struct tty_port *port); + void (*drop)(struct tty_port *port); }; struct tty_port { @@ -459,7 +464,8 @@ extern int tty_port_block_til_ready(struct tty_port *port, extern int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp); extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); - +extern void tty_port_close(struct tty_port *port, + struct tty_struct *tty, struct file *filp); extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); extern int tty_unregister_ldisc(int disc); extern int tty_set_ldisc(struct tty_struct *tty, int ldisc); -- cgit v1.2.3 From 5e99df561fc830730d63672d795a0b02ef8cdd6f Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 19 Sep 2009 13:13:28 -0700 Subject: serial: Fold closing_* fields into the tty_port ones Remove some more serial specific use Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/serial/serial_core.c | 26 +++++++++++++------------- include/linux/serial_core.h | 2 -- include/linux/tty.h | 4 ++-- 3 files changed, 15 insertions(+), 17 deletions(-) (limited to 'include/linux/tty.h') diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index ea53b6f224b0..2d63b13e2f7e 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -651,10 +651,10 @@ static int uart_get_info(struct uart_state *state, tmp.flags = port->flags; tmp.xmit_fifo_size = port->fifosize; tmp.baud_base = port->uartclk / 16; - tmp.close_delay = state->close_delay / 10; - tmp.closing_wait = state->closing_wait == USF_CLOSING_WAIT_NONE ? + tmp.close_delay = state->port.close_delay / 10; + tmp.closing_wait = state->port.closing_wait == USF_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : - state->closing_wait / 10; + state->port.closing_wait / 10; tmp.custom_divisor = port->custom_divisor; tmp.hub6 = port->hub6; tmp.io_type = port->iotype; @@ -724,8 +724,8 @@ static int uart_set_info(struct uart_state *state, retval = -EPERM; if (change_irq || change_port || (new_serial.baud_base != port->uartclk / 16) || - (close_delay != state->close_delay) || - (closing_wait != state->closing_wait) || + (close_delay != state->port.close_delay) || + (closing_wait != state->port.closing_wait) || (new_serial.xmit_fifo_size && new_serial.xmit_fifo_size != port->fifosize) || (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0)) @@ -834,8 +834,8 @@ static int uart_set_info(struct uart_state *state, port->flags = (port->flags & ~UPF_CHANGE_MASK) | (new_flags & UPF_CHANGE_MASK); port->custom_divisor = new_serial.custom_divisor; - state->close_delay = close_delay; - state->closing_wait = closing_wait; + state->port.close_delay = close_delay; + state->port.closing_wait = closing_wait; if (new_serial.xmit_fifo_size) port->fifosize = new_serial.xmit_fifo_size; if (state->port.tty) @@ -1297,8 +1297,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp) */ tty->closing = 1; - if (state->closing_wait != USF_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, msecs_to_jiffies(state->closing_wait)); + if (state->port.closing_wait != USF_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, msecs_to_jiffies(state->port.closing_wait)); /* * At this point, we stop accepting input. To do this, we @@ -1326,8 +1326,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp) state->port.tty = NULL; if (state->port.blocked_open) { - if (state->close_delay) - msleep_interruptible(state->close_delay); + if (state->port.close_delay) + msleep_interruptible(state->port.close_delay); } else if (!uart_console(port)) { uart_change_pm(state, 3); } @@ -2358,11 +2358,11 @@ int uart_register_driver(struct uart_driver *drv) for (i = 0; i < drv->nr; i++) { struct uart_state *state = drv->state + i; - state->close_delay = 500; /* .5 seconds */ - state->closing_wait = 30000; /* 30 seconds */ mutex_init(&state->mutex); tty_port_init(&state->port); + state->port.close_delay = 500; /* .5 seconds */ + state->port.closing_wait = 30000; /* 30 seconds */ init_waitqueue_head(&state->delta_msr_wait); tasklet_init(&state->tlet, uart_tasklet_action, (unsigned long)state); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index c1542703fbab..fd11d4d5a571 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -350,8 +350,6 @@ typedef unsigned int __bitwise__ uif_t; */ struct uart_state { struct tty_port port; - unsigned int close_delay; /* msec */ - unsigned int closing_wait; /* msec */ #define USF_CLOSING_WAIT_INF (0) #define USF_CLOSING_WAIT_NONE (~0U) diff --git a/include/linux/tty.h b/include/linux/tty.h index ecb3d1ba3017..9fdc3d84baad 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -206,8 +206,8 @@ struct tty_port { unsigned long flags; /* TTY flags ASY_*/ struct mutex mutex; /* Locking */ unsigned char *xmit_buf; /* Optional buffer */ - int close_delay; /* Close port delay */ - int closing_wait; /* Delay for output */ + unsigned int close_delay; /* Close port delay */ + unsigned int closing_wait; /* Delay for output */ int drain_delay; /* Set to zero if no pure time based drain is needed else set to size of fifo */ -- cgit v1.2.3 From bdc04e3174e18f475289fa8f4144f66686326b7e Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 19 Sep 2009 13:13:31 -0700 Subject: serial: move delta_msr_wait into the tty_port This is used by various drivers not just serial and can be extracted as commonality Signed-off-by: Alan Cox --- drivers/char/cyclades.c | 9 ++++----- drivers/char/esp.c | 7 +++---- drivers/char/mxser.c | 8 +++----- drivers/char/tty_port.c | 2 ++ drivers/serial/8250.c | 2 +- drivers/serial/amba-pl010.c | 2 +- drivers/serial/amba-pl011.c | 2 +- drivers/serial/atmel_serial.c | 2 +- drivers/serial/icom.c | 2 +- drivers/serial/imx.c | 4 ++-- drivers/serial/ioc3_serial.c | 8 ++++---- drivers/serial/ioc4_serial.c | 8 ++++---- drivers/serial/ip22zilog.c | 2 +- drivers/serial/msm_serial.c | 2 +- drivers/serial/pmac_zilog.c | 2 +- drivers/serial/pnx8xxx_uart.c | 2 +- drivers/serial/pxa.c | 2 +- drivers/serial/sa1100.c | 2 +- drivers/serial/sb1250-duart.c | 2 +- drivers/serial/serial_core.c | 18 +++++++++++------- drivers/serial/serial_ks8695.c | 2 +- drivers/serial/serial_lh7a40x.c | 2 +- drivers/serial/sunsab.c | 2 +- drivers/serial/sunsu.c | 2 +- drivers/serial/sunzilog.c | 2 +- drivers/serial/timbuart.c | 2 +- drivers/serial/vr41xx_siu.c | 2 +- drivers/serial/zs.c | 2 +- include/linux/cyclades.h | 1 - include/linux/hayesesp.h | 1 - include/linux/serial_core.h | 1 - include/linux/tty.h | 1 + 32 files changed, 54 insertions(+), 54 deletions(-) (limited to 'include/linux/tty.h') diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 70bd61b2a7d7..df5038bbcbc2 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -729,7 +729,7 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, if (mdm_change & CyRI) info->icount.rng++; - wake_up_interruptible(&info->delta_msr_wait); + wake_up_interruptible(&info->port.delta_msr_wait); } if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) { @@ -1197,7 +1197,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) break; } if (delta_count) - wake_up_interruptible(&info->delta_msr_wait); + wake_up_interruptible(&info->port.delta_msr_wait); if (special_count) tty_schedule_flip(tty); tty_kref_put(tty); @@ -1464,7 +1464,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) spin_lock_irqsave(&card->card_lock, flags); /* Clear delta_msr_wait queue to avoid mem leaks. */ - wake_up_interruptible(&info->delta_msr_wait); + wake_up_interruptible(&info->port.delta_msr_wait); if (info->port.xmit_buf) { unsigned char *temp; @@ -2788,7 +2788,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, /* note the counters on entry */ cnow = info->icount; spin_unlock_irqrestore(&info->card->card_lock, flags); - ret_val = wait_event_interruptible(info->delta_msr_wait, + ret_val = wait_event_interruptible(info->port.delta_msr_wait, cy_cflags_changed(info, arg, &cnow)); break; @@ -3153,7 +3153,6 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo) info->port.close_delay = 5 * HZ / 10; info->port.flags = STD_COM_FLAGS; init_completion(&info->shutdown_wait); - init_waitqueue_head(&info->delta_msr_wait); if (cy_is_Z(cinfo)) { struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS; diff --git a/drivers/char/esp.c b/drivers/char/esp.c index a5c59fc2b0ff..b19d43cd9542 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -572,7 +572,7 @@ static void check_modem_status(struct esp_struct *info) info->icount.dcd++; if (status & UART_MSR_DCTS) info->icount.cts++; - wake_up_interruptible(&info->delta_msr_wait); + wake_up_interruptible(&info->port.delta_msr_wait); } if ((info->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { @@ -927,7 +927,7 @@ static void shutdown(struct esp_struct *info) * clear delta_msr_wait queue to avoid mem leaks: we may free the irq * here so the queue might never be waken up */ - wake_up_interruptible(&info->delta_msr_wait); + wake_up_interruptible(&info->port.delta_msr_wait); wake_up_interruptible(&info->break_wait); /* stop a DMA transfer on the port being closed */ @@ -1800,7 +1800,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file *file, spin_unlock_irqrestore(&info->lock, flags); while (1) { /* FIXME: convert to new style wakeup */ - interruptible_sleep_on(&info->delta_msr_wait); + interruptible_sleep_on(&info->port.delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; @@ -2452,7 +2452,6 @@ static int __init espserial_init(void) info->config.flow_off = flow_off; info->config.pio_threshold = pio_threshold; info->next_port = ports; - init_waitqueue_head(&info->delta_msr_wait); init_waitqueue_head(&info->break_wait); ports = info; printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ", diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 30544ca5e956..37058ff7da7d 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -258,7 +258,6 @@ struct mxser_port { struct mxser_mon mon_data; spinlock_t slock; - wait_queue_head_t delta_msr_wait; }; struct mxser_board { @@ -818,7 +817,7 @@ static void mxser_check_modem_status(struct tty_struct *tty, if (status & UART_MSR_DCTS) port->icount.cts++; port->mon_data.modem_status = status; - wake_up_interruptible(&port->delta_msr_wait); + wake_up_interruptible(&port->port.delta_msr_wait); if ((port->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { if (status & UART_MSR_DCD) @@ -973,7 +972,7 @@ static void mxser_shutdown(struct tty_struct *tty) * clear delta_msr_wait queue to avoid mem leaks: we may free the irq * here so the queue might never be waken up */ - wake_up_interruptible(&info->delta_msr_wait); + wake_up_interruptible(&info->port.delta_msr_wait); /* * Free the IRQ, if necessary @@ -1762,7 +1761,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, cnow = info->icount; /* note the counters on entry */ spin_unlock_irqrestore(&info->slock, flags); - return wait_event_interruptible(info->delta_msr_wait, + return wait_event_interruptible(info->port.delta_msr_wait, mxser_cflags_changed(info, arg, &cnow)); /* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) @@ -2414,7 +2413,6 @@ static int __devinit mxser_initbrd(struct mxser_board *brd, info->port.close_delay = 5 * HZ / 10; info->port.closing_wait = 30 * HZ; info->normal_termios = mxvar_sdriver->init_termios; - init_waitqueue_head(&info->delta_msr_wait); memset(&info->mon_data, 0, sizeof(struct mxser_mon)); info->err_shadow = 0; spin_lock_init(&info->slock); diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c index 549bd0fa8bb6..c767e30a1425 100644 --- a/drivers/char/tty_port.c +++ b/drivers/char/tty_port.c @@ -23,6 +23,7 @@ void tty_port_init(struct tty_port *port) memset(port, 0, sizeof(*port)); init_waitqueue_head(&port->open_wait); init_waitqueue_head(&port->close_wait); + init_waitqueue_head(&port->delta_msr_wait); mutex_init(&port->mutex); spin_lock_init(&port->lock); port->close_delay = (50 * HZ) / 100; @@ -124,6 +125,7 @@ void tty_port_hangup(struct tty_port *port) port->tty = NULL; spin_unlock_irqrestore(&port->lock, flags); wake_up_interruptible(&port->open_wait); + wake_up_interruptible(&port->delta_msr_wait); tty_port_shutdown(port); } EXPORT_SYMBOL(tty_port_hangup); diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index e415c5eca599..2209620d2349 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1510,7 +1510,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up) if (status & UART_MSR_DCTS) uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - wake_up_interruptible(&up->port.state->delta_msr_wait); + wake_up_interruptible(&up->port.state->port.delta_msr_wait); } return status; diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index 39032413d4a1..429a8ae86933 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -225,7 +225,7 @@ static void pl010_modem_status(struct uart_amba_port *uap) if (delta & UART01x_FR_CTS) uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); - wake_up_interruptible(&uap->port.state->delta_msr_wait); + wake_up_interruptible(&uap->port.state->port.delta_msr_wait); } static irqreturn_t pl010_int(int irq, void *dev_id) diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index ef82a34baf0f..ef7adc8135dd 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -226,7 +226,7 @@ static void pl011_modem_status(struct uart_amba_port *uap) if (delta & UART01x_FR_CTS) uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); - wake_up_interruptible(&uap->port.state->delta_msr_wait); + wake_up_interruptible(&uap->port.state->port.delta_msr_wait); } static irqreturn_t pl011_int(int irq, void *dev_id) diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 963e3c12af41..3551c5cb7094 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -776,7 +776,7 @@ static void atmel_tasklet_func(unsigned long data) if (status_change & ATMEL_US_CTS) uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); - wake_up_interruptible(&port->state->delta_msr_wait); + wake_up_interruptible(&port->state->port.delta_msr_wait); atmel_port->irq_status_prev = status; } diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index f86c47e08a06..2d7feecaf492 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c @@ -695,7 +695,7 @@ static inline void check_modem_status(struct icom_port *icom_port) delta_status & ICOM_CTS); wake_up_interruptible(&icom_port->uart_port.state-> - delta_msr_wait); + port.delta_msr_wait); old_status = status; } spin_unlock(&icom_port->uart_port.lock); diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 1febeafcb97a..18130f11238e 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -224,7 +224,7 @@ static void imx_mctrl_check(struct imx_port *sport) if (changed & TIOCM_CTS) uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - wake_up_interruptible(&sport->port.state->delta_msr_wait); + wake_up_interruptible(&sport->port.state->port.delta_msr_wait); } /* @@ -388,7 +388,7 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id) writel(USR1_RTSD, sport->port.membase + USR1); uart_handle_cts_change(&sport->port, !!val); - wake_up_interruptible(&sport->port.state->delta_msr_wait); + wake_up_interruptible(&sport->port.state->port.delta_msr_wait); spin_unlock_irqrestore(&sport->port.lock, flags); return IRQ_HANDLED; diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c index de4ab1bfee8d..d8983dd5c4b2 100644 --- a/drivers/serial/ioc3_serial.c +++ b/drivers/serial/ioc3_serial.c @@ -1287,7 +1287,7 @@ static inline int do_read(struct uart_port *the_port, char *buf, int len) (port->ip_port, 0); wake_up_interruptible (&the_port->state-> - delta_msr_wait); + port.delta_msr_wait); } /* If we had any data to return, we @@ -1491,7 +1491,7 @@ ioc3uart_intr_one(struct ioc3_submodule *is, uart_handle_dcd_change(the_port, shadow & SHADOW_DCD); wake_up_interruptible - (&the_port->state->delta_msr_wait); + (&the_port->state->port.delta_msr_wait); } else if ((port->ip_notify & N_DDCD) && !(shadow & SHADOW_DCD)) { /* Flag delta DCD/no DCD */ @@ -1511,7 +1511,7 @@ ioc3uart_intr_one(struct ioc3_submodule *is, uart_handle_cts_change(the_port, shadow & SHADOW_CTS); wake_up_interruptible - (&the_port->state->delta_msr_wait); + (&the_port->state->port.delta_msr_wait); } } @@ -1728,7 +1728,7 @@ static void ic3_shutdown(struct uart_port *the_port) return; state = the_port->state; - wake_up_interruptible(&state->delta_msr_wait); + wake_up_interruptible(&state->port.delta_msr_wait); spin_lock_irqsave(&the_port->lock, port_flags); set_notification(port, N_ALL, 0); diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index 2055d323f15f..2e02c3026d24 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -1882,7 +1882,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) the_port = port->ip_port; the_port->icount.dcd = 1; wake_up_interruptible - (&the_port->state->delta_msr_wait); + (&the_port->state->port.delta_msr_wait); } else if ((port->ip_notify & N_DDCD) && !(shadow & IOC4_SHADOW_DCD)) { /* Flag delta DCD/no DCD */ @@ -1904,7 +1904,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) the_port->icount.cts = (shadow & IOC4_SHADOW_CTS) ? 1 : 0; wake_up_interruptible - (&the_port->state->delta_msr_wait); + (&the_port->state->port.delta_msr_wait); } } @@ -2237,7 +2237,7 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf, the_port->icount.dcd = 0; wake_up_interruptible (&the_port->state-> - delta_msr_wait); + port.delta_msr_wait); } /* If we had any data to return, we @@ -2439,7 +2439,7 @@ static void ic4_shutdown(struct uart_port *the_port) state = the_port->state; port->ip_port = NULL; - wake_up_interruptible(&state->delta_msr_wait); + wake_up_interruptible(&state->port.delta_msr_wait); if (state->port.tty) set_bit(TTY_IO_ERROR, &state->port.tty->flags); diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c index 2e847deb41dc..ebff4a1d4bcc 100644 --- a/drivers/serial/ip22zilog.c +++ b/drivers/serial/ip22zilog.c @@ -354,7 +354,7 @@ static void ip22zilog_status_handle(struct uart_ip22zilog_port *up, uart_handle_cts_change(&up->port, (status & CTS)); - wake_up_interruptible(&up->port.state->delta_msr_wait); + wake_up_interruptible(&up->port.state->port.delta_msr_wait); } up->prev_status = status; diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c index ff18d50c99c1..b05c5aa02cb4 100644 --- a/drivers/serial/msm_serial.c +++ b/drivers/serial/msm_serial.c @@ -169,7 +169,7 @@ static void handle_delta_cts(struct uart_port *port) { msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); port->icount.cts++; - wake_up_interruptible(&port->state->delta_msr_wait); + wake_up_interruptible(&port->state->port.delta_msr_wait); } static irqreturn_t msm_irq(int irq, void *dev_id) diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index 0dc786835dca..0700cd10b97c 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -369,7 +369,7 @@ static void pmz_status_handle(struct uart_pmac_port *uap) uart_handle_cts_change(&uap->port, !(status & CTS)); - wake_up_interruptible(&uap->port.state->delta_msr_wait); + wake_up_interruptible(&uap->port.state->port.delta_msr_wait); } if (status & BRK_ABRT) diff --git a/drivers/serial/pnx8xxx_uart.c b/drivers/serial/pnx8xxx_uart.c index 2da747635275..0aa75a97531c 100644 --- a/drivers/serial/pnx8xxx_uart.c +++ b/drivers/serial/pnx8xxx_uart.c @@ -100,7 +100,7 @@ static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport) if (changed & TIOCM_CTS) uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - wake_up_interruptible(&sport->port.state->delta_msr_wait); + wake_up_interruptible(&sport->port.state->port.delta_msr_wait); } /* diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index ad48919c0415..6443b7ff274a 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -220,7 +220,7 @@ static inline void check_modem_status(struct uart_pxa_port *up) if (status & UART_MSR_DCTS) uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - wake_up_interruptible(&up->port.state->delta_msr_wait); + wake_up_interruptible(&up->port.state->port.delta_msr_wait); } /* diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index 61ef3ae24927..7f5e26873220 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -117,7 +117,7 @@ static void sa1100_mctrl_check(struct sa1100_port *sport) if (changed & TIOCM_CTS) uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - wake_up_interruptible(&sport->port.state->delta_msr_wait); + wake_up_interruptible(&sport->port.state->port.delta_msr_wait); } /* diff --git a/drivers/serial/sb1250-duart.c b/drivers/serial/sb1250-duart.c index fa5f303b36d3..a2f2b3254499 100644 --- a/drivers/serial/sb1250-duart.c +++ b/drivers/serial/sb1250-duart.c @@ -440,7 +440,7 @@ static void sbd_status_handle(struct sbd_port *sport) if (delta & ((M_DUART_IN_PIN2_VAL | M_DUART_IN_PIN0_VAL) << S_DUART_IN_PIN_CHNG)) - wake_up_interruptible(&uport->state->delta_msr_wait); + wake_up_interruptible(&uport->state->port.delta_msr_wait); } static irqreturn_t sbd_interrupt(int irq, void *dev_id) diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 9d42e57e1971..e16d15343dfd 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -215,7 +215,8 @@ static int uart_startup(struct uart_state *state, int init_hw) static void uart_shutdown(struct uart_state *state) { struct uart_port *uport = state->uart_port; - struct tty_struct *tty = state->port.tty; + struct tty_port *port = &state->port; + struct tty_struct *tty = port->tty; /* * Set the TTY IO error marker @@ -223,7 +224,7 @@ static void uart_shutdown(struct uart_state *state) if (tty) set_bit(TTY_IO_ERROR, &tty->flags); - if (test_and_clear_bit(ASYNCB_INITIALIZED, &state->port.flags)) { + if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) { /* * Turn off DTR and RTS early. */ @@ -237,7 +238,7 @@ static void uart_shutdown(struct uart_state *state) * any outstanding file descriptors should be pointing at * hung_up_tty_fops now. */ - wake_up_interruptible(&state->delta_msr_wait); + wake_up_interruptible(&port->delta_msr_wait); /* * Free the IRQ and disable the port. @@ -1004,11 +1005,15 @@ static int uart_do_autoconfig(struct uart_state *state) * - mask passed in arg for lines of interest * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) * Caller should use TIOCGICOUNT to see which one it was + * + * FIXME: This wants extracting into a common all driver implementation + * of TIOCMWAIT using tty_port. */ static int uart_wait_modem_status(struct uart_state *state, unsigned long arg) { struct uart_port *uport = state->uart_port; + struct tty_port *port = &state->port; DECLARE_WAITQUEUE(wait, current); struct uart_icount cprev, cnow; int ret; @@ -1025,7 +1030,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) uport->ops->enable_ms(uport); spin_unlock_irq(&uport->lock); - add_wait_queue(&state->delta_msr_wait, &wait); + add_wait_queue(&port->delta_msr_wait, &wait); for (;;) { spin_lock_irq(&uport->lock); memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); @@ -1053,7 +1058,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) } current->state = TASK_RUNNING; - remove_wait_queue(&state->delta_msr_wait, &wait); + remove_wait_queue(&port->delta_msr_wait, &wait); return ret; } @@ -1430,7 +1435,7 @@ static void uart_hangup(struct tty_struct *tty) clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); port->tty = NULL; wake_up_interruptible(&port->open_wait); - wake_up_interruptible(&state->delta_msr_wait); + wake_up_interruptible(&port->delta_msr_wait); } mutex_unlock(&port->mutex); } @@ -2378,7 +2383,6 @@ int uart_register_driver(struct uart_driver *drv) tty_port_init(port); port->close_delay = 500; /* .5 seconds */ port->closing_wait = 30000; /* 30 seconds */ - init_waitqueue_head(&state->delta_msr_wait); tasklet_init(&state->tlet, uart_tasklet_action, (unsigned long)state); } diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c index 4560b2e70685..2e71bbc04dac 100644 --- a/drivers/serial/serial_ks8695.c +++ b/drivers/serial/serial_ks8695.c @@ -266,7 +266,7 @@ static irqreturn_t ks8695uart_modem_status(int irq, void *dev_id) if (status & URMS_URTERI) port->icount.rng++; - wake_up_interruptible(&port->state->delta_msr_wait); + wake_up_interruptible(&port->state->port.delta_msr_wait); return IRQ_HANDLED; } diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c index 057fc5e8cc8d..ea744707c4d6 100644 --- a/drivers/serial/serial_lh7a40x.c +++ b/drivers/serial/serial_lh7a40x.c @@ -241,7 +241,7 @@ static void lh7a40xuart_modem_status (struct uart_port* port) if (delta & CTS) uart_handle_cts_change (port, status & CTS); - wake_up_interruptible (&port->state->delta_msr_wait); + wake_up_interruptible (&port->state->port.delta_msr_wait); } static irqreturn_t lh7a40xuart_int (int irq, void* dev_id) diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 7c4f2fe8e246..d1ad34128635 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -297,7 +297,7 @@ static void check_status(struct uart_sunsab_port *up, up->port.icount.dsr++; } - wake_up_interruptible(&up->port.state->delta_msr_wait); + wake_up_interruptible(&up->port.state->port.delta_msr_wait); } static irqreturn_t sunsab_interrupt(int irq, void *dev_id) diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 5a32365b58ad..68d262b15749 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -441,7 +441,7 @@ static void check_modem_status(struct uart_sunsu_port *up) if (status & UART_MSR_DCTS) uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - wake_up_interruptible(&up->port.state->delta_msr_wait); + wake_up_interruptible(&up->port.state->port.delta_msr_wait); } static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id) diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 055034d12b1c..ef693ae22e7f 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -451,7 +451,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up, uart_handle_cts_change(&up->port, (status & CTS)); - wake_up_interruptible(&up->port.state->delta_msr_wait); + wake_up_interruptible(&up->port.state->port.delta_msr_wait); } up->prev_status = status; diff --git a/drivers/serial/timbuart.c b/drivers/serial/timbuart.c index 3d40be6f389f..34b31da01d09 100644 --- a/drivers/serial/timbuart.c +++ b/drivers/serial/timbuart.c @@ -231,7 +231,7 @@ static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier) iowrite32(CTS_DELTA, port->membase + TIMBUART_ISR); cts = timbuart_get_mctrl(port); uart_handle_cts_change(port, cts & TIOCM_CTS); - wake_up_interruptible(&port->state->delta_msr_wait); + wake_up_interruptible(&port->state->port.delta_msr_wait); } *ier |= CTS_DELTA; diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index cf4410e6d53b..3beb6ab4fa68 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -386,7 +386,7 @@ static inline void check_modem_status(struct uart_port *port) if (msr & UART_MSR_DCTS) uart_handle_cts_change(port, msr & UART_MSR_CTS); - wake_up_interruptible(&port->state->delta_msr_wait); + wake_up_interruptible(&port->state->port.delta_msr_wait); } static inline void transmit_chars(struct uart_port *port) diff --git a/drivers/serial/zs.c b/drivers/serial/zs.c index b9c9fb9198d6..1a7fd3e70315 100644 --- a/drivers/serial/zs.c +++ b/drivers/serial/zs.c @@ -686,7 +686,7 @@ static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a) uport->icount.rng++; if (delta) - wake_up_interruptible(&uport->state->delta_msr_wait); + wake_up_interruptible(&uport->state->port.delta_msr_wait); spin_lock(&scc->zlock); } diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h index bbebef7713b3..a5049eaf782d 100644 --- a/include/linux/cyclades.h +++ b/include/linux/cyclades.h @@ -578,7 +578,6 @@ struct cyclades_port { struct cyclades_idle_stats idle_stats; struct cyclades_icount icount; struct completion shutdown_wait; - wait_queue_head_t delta_msr_wait; int throttle; }; diff --git a/include/linux/hayesesp.h b/include/linux/hayesesp.h index 940aeb51d53f..92b08cfe4a75 100644 --- a/include/linux/hayesesp.h +++ b/include/linux/hayesesp.h @@ -96,7 +96,6 @@ struct esp_struct { int xmit_head; int xmit_tail; int xmit_cnt; - wait_queue_head_t delta_msr_wait; wait_queue_head_t break_wait; struct async_icount icount; /* kernel counters for the 4 input interrupts */ struct hayes_esp_config config; /* port configuration */ diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 27767ea5fa29..bcafecd3b7c1 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -349,7 +349,6 @@ struct uart_state { struct circ_buf xmit; struct tasklet_struct tlet; - wait_queue_head_t delta_msr_wait; struct uart_port *uart_port; }; diff --git a/include/linux/tty.h b/include/linux/tty.h index 9fdc3d84baad..0daa8a72b176 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -203,6 +203,7 @@ struct tty_port { int count; /* Usage count */ wait_queue_head_t open_wait; /* Open waiters */ wait_queue_head_t close_wait; /* Close waiters */ + wait_queue_head_t delta_msr_wait; /* Modem status change */ unsigned long flags; /* TTY flags ASY_*/ struct mutex mutex; /* Locking */ unsigned char *xmit_buf; /* Optional buffer */ -- cgit v1.2.3 From b58d13a0216d4e0753668214f23e1d2c24c30f8c Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 19 Sep 2009 13:13:32 -0700 Subject: serial: move port users helper This little helper is now tty_port specific and useful generally so move it Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/serial/serial_core.c | 6 ++---- include/linux/tty.h | 5 +++++ 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'include/linux/tty.h') diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index e16d15343dfd..3c45a8d7eb7f 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -52,8 +52,6 @@ static struct lock_class_key port_lock_key; #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) -#define uart_users(state) ((state)->port.count + (state)->port.blocked_open) - #ifdef CONFIG_SERIAL_CORE_CONSOLE #define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) #else @@ -758,7 +756,7 @@ static int uart_set_info(struct uart_state *state, /* * Make sure that we are the sole user of this port. */ - if (uart_users(state) > 1) + if (tty_port_users(port) > 1) goto exit; /* @@ -974,7 +972,7 @@ static int uart_do_autoconfig(struct uart_state *state) return -ERESTARTSYS; ret = -EBUSY; - if (uart_users(state) == 1) { + if (tty_port_users(port) == 1) { uart_shutdown(state); /* diff --git a/include/linux/tty.h b/include/linux/tty.h index 0daa8a72b176..a0e03309a379 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -467,6 +467,11 @@ extern int tty_port_close_start(struct tty_port *port, extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); extern void tty_port_close(struct tty_port *port, struct tty_struct *tty, struct file *filp); +extern inline int tty_port_users(struct tty_port *port) +{ + return port->count + port->blocked_open; +} + extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); extern int tty_unregister_ldisc(int disc); extern int tty_set_ldisc(struct tty_struct *tty, int ldisc); -- cgit v1.2.3 From e92166517e3ca9bfb416f91e69cf0373b55b6ede Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 6 Aug 2009 15:09:28 +0200 Subject: tty: handle VT specific compat ioctls in vt driver The VT specific compat_ioctl handlers are the only ones in common code that require the BKL. Moving them into the vt driver lets us remove the BKL from the other handlers and cleans up the code. Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/char/vt.c | 3 + drivers/char/vt_ioctl.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/tty.h | 3 + 3 files changed, 209 insertions(+) (limited to 'include/linux/tty.h') diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 33214d92ca4c..5dfbfa7d7606 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -2910,6 +2910,9 @@ static const struct tty_operations con_ops = { .flush_chars = con_flush_chars, .chars_in_buffer = con_chars_in_buffer, .ioctl = vt_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = vt_compat_ioctl, +#endif .stop = con_stop, .start = con_start, .throttle = con_throttle, diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 0fceb8f4d6f2..30b5d128037c 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -1376,6 +1377,208 @@ void vc_SAK(struct work_struct *work) release_console_sem(); } +#ifdef CONFIG_COMPAT + +struct compat_consolefontdesc { + unsigned short charcount; /* characters in font (256 or 512) */ + unsigned short charheight; /* scan lines per character (1-32) */ + compat_caddr_t chardata; /* font data in expanded form */ +}; + +static inline int +compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd, + int perm, struct console_font_op *op) +{ + struct compat_consolefontdesc cfdarg; + int i; + + if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc))) + return -EFAULT; + + switch (cmd) { + case PIO_FONTX: + if (!perm) + return -EPERM; + op->op = KD_FONT_OP_SET; + op->flags = KD_FONT_FLAG_OLD; + op->width = 8; + op->height = cfdarg.charheight; + op->charcount = cfdarg.charcount; + op->data = compat_ptr(cfdarg.chardata); + return con_font_op(vc_cons[fg_console].d, op); + case GIO_FONTX: + op->op = KD_FONT_OP_GET; + op->flags = KD_FONT_FLAG_OLD; + op->width = 8; + op->height = cfdarg.charheight; + op->charcount = cfdarg.charcount; + op->data = compat_ptr(cfdarg.chardata); + i = con_font_op(vc_cons[fg_console].d, op); + if (i) + return i; + cfdarg.charheight = op->height; + cfdarg.charcount = op->charcount; + if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc))) + return -EFAULT; + return 0; + } + return -EINVAL; +} + +struct compat_console_font_op { + compat_uint_t op; /* operation code KD_FONT_OP_* */ + compat_uint_t flags; /* KD_FONT_FLAG_* */ + compat_uint_t width, height; /* font size */ + compat_uint_t charcount; + compat_caddr_t data; /* font data with height fixed to 32 */ +}; + +static inline int +compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop, + int perm, struct console_font_op *op, struct vc_data *vc) +{ + int i; + + if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op))) + return -EFAULT; + if (!perm && op->op != KD_FONT_OP_GET) + return -EPERM; + op->data = compat_ptr(((struct compat_console_font_op *)op)->data); + op->flags |= KD_FONT_FLAG_OLD; + i = con_font_op(vc, op); + if (i) + return i; + ((struct compat_console_font_op *)op)->data = (unsigned long)op->data; + if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op))) + return -EFAULT; + return 0; +} + +struct compat_unimapdesc { + unsigned short entry_ct; + compat_caddr_t entries; +}; + +static inline int +compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud, + int perm, struct vc_data *vc) +{ + struct compat_unimapdesc tmp; + struct unipair __user *tmp_entries; + + if (copy_from_user(&tmp, user_ud, sizeof tmp)) + return -EFAULT; + tmp_entries = compat_ptr(tmp.entries); + if (tmp_entries) + if (!access_ok(VERIFY_WRITE, tmp_entries, + tmp.entry_ct*sizeof(struct unipair))) + return -EFAULT; + switch (cmd) { + case PIO_UNIMAP: + if (!perm) + return -EPERM; + return con_set_unimap(vc, tmp.entry_ct, tmp_entries); + case GIO_UNIMAP: + if (!perm && fg_console != vc->vc_num) + return -EPERM; + return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries); + } + return 0; +} + +long vt_compat_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct vc_data *vc = tty->driver_data; + struct console_font_op op; /* used in multiple places here */ + struct kbd_struct *kbd; + unsigned int console; + void __user *up = (void __user *)arg; + int perm; + int ret = 0; + + console = vc->vc_num; + + lock_kernel(); + + if (!vc_cons_allocated(console)) { /* impossible? */ + ret = -ENOIOCTLCMD; + goto out; + } + + /* + * To have permissions to do most of the vt ioctls, we either have + * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. + */ + perm = 0; + if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) + perm = 1; + + kbd = kbd_table + console; + switch (cmd) { + /* + * these need special handlers for incompatible data structures + */ + case PIO_FONTX: + case GIO_FONTX: + ret = compat_fontx_ioctl(cmd, up, perm, &op); + break; + + case KDFONTOP: + ret = compat_kdfontop_ioctl(up, perm, &op, vc); + break; + + case PIO_UNIMAP: + case GIO_UNIMAP: + ret = do_unimap_ioctl(cmd, up, perm, vc); + break; + + /* + * all these treat 'arg' as an integer + */ + case KIOCSOUND: + case KDMKTONE: +#ifdef CONFIG_X86 + case KDADDIO: + case KDDELIO: +#endif + case KDSETMODE: + case KDMAPDISP: + case KDUNMAPDISP: + case KDSKBMODE: + case KDSKBMETA: + case KDSKBLED: + case KDSETLED: + case KDSIGACCEPT: + case VT_ACTIVATE: + case VT_WAITACTIVE: + case VT_RELDISP: + case VT_DISALLOCATE: + case VT_RESIZE: + case VT_RESIZEX: + goto fallback; + + /* + * the rest has a compatible data structure behind arg, + * but we have to convert it to a proper 64 bit pointer. + */ + default: + arg = (unsigned long)compat_ptr(arg); + goto fallback; + } +out: + unlock_kernel(); + return ret; + +fallback: + unlock_kernel(); + return vt_ioctl(tty, file, cmd, arg); +} + + +#endif /* CONFIG_COMPAT */ + + /* * Performs the back end of a vt switch. Called under the console * semaphore. diff --git a/include/linux/tty.h b/include/linux/tty.h index a0e03309a379..f0f43d08d8b8 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -536,5 +536,8 @@ extern int pcxe_open(struct tty_struct *tty, struct file *filp); extern int vt_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); +extern long vt_compat_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg); + #endif /* __KERNEL__ */ #endif -- cgit v1.2.3