tty: The big operations rework

- Operations are now a shared const function block as with most other Linux
  objects

- Introduce wrappers for some optional functions to get consistent behaviour

- Wrap put_char which used to be patched by the tty layer

- Document which functions are needed/optional

- Make put_char report success/fail

- Cache the driver->ops pointer in the tty as tty->ops

- Remove various surplus lock calls we no longer need

- Remove proc_write method as noted by Alexey Dobriyan

- Introduce some missing sanity checks where certain driver/ldisc
  combinations would oops as they didn't check needed methods were present

[[email protected]: fix fs/compat_ioctl.c build]
[[email protected]: fix isicom]
[[email protected]: fix arch/ia64/hp/sim/simserial.c build]
[[email protected]: fix kgdb]
Signed-off-by: Alan Cox <[email protected]>
Acked-by: Greg Kroah-Hartman <[email protected]>
Cc: Jason Wessel <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
Alan Cox 2008-04-30 00:54:13 -07:00 • committed by Linus Torvalds
commit f34d7a5b70
30 changed files with 537 additions and 664 deletions

View file

@ -96,12 +96,14 @@ static void cleanup_kgdboc(void)
static int kgdboc_get_char(void)
{
return kgdb_tty_driver->poll_get_char(kgdb_tty_driver, kgdb_tty_line);
return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
kgdb_tty_line);
}
static void kgdboc_put_char(u8 chr)
{
kgdb_tty_driver->poll_put_char(kgdb_tty_driver, kgdb_tty_line, chr);
kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
kgdb_tty_line, chr);
}
static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)

View file

@ -532,15 +532,25 @@ uart_write(struct tty_struct *tty, const unsigned char *buf, int count)
static int uart_write_room(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
unsigned long flags;
int ret;
return uart_circ_chars_free(&state->info->xmit);
spin_lock_irqsave(&state->port->lock, flags);
ret = uart_circ_chars_free(&state->info->xmit);
spin_unlock_irqrestore(&state->port->lock, flags);
return ret;
}
static int uart_chars_in_buffer(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
unsigned long flags;
int ret;
return uart_circ_chars_pending(&state->info->xmit);
spin_lock_irqsave(&state->port->lock, flags);
ret = uart_circ_chars_pending(&state->info->xmit);
spin_unlock_irqrestore(&state->port->lock, flags);
return ret;
}
static void uart_flush_buffer(struct tty_struct *tty)
@ -622,6 +632,11 @@ static int uart_get_info(struct uart_state *state,
struct serial_struct tmp;
memset(&tmp, 0, sizeof(tmp));
/* Ensure the state we copy is consistent and no hardware changes
occur as we go */
mutex_lock(&state->mutex);
tmp.type = port->type;
tmp.line = port->line;
tmp.port = port->iobase;
@ -641,6 +656,8 @@ static int uart_get_info(struct uart_state *state,
tmp.iomem_reg_shift = port->regshift;
tmp.iomem_base = (void *)(unsigned long)port->mapbase;
mutex_unlock(&state->mutex);
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
return 0;
@ -918,14 +935,12 @@ static void uart_break_ctl(struct tty_struct *tty, int break_state)
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->port;
lock_kernel();
mutex_lock(&state->mutex);
if (port->type != PORT_UNKNOWN)
port->ops->break_ctl(port, break_state);
mutex_unlock(&state->mutex);
unlock_kernel();
}
static int uart_do_autoconfig(struct uart_state *state)
@ -1074,7 +1089,6 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
int ret = -ENOIOCTLCMD;
lock_kernel();
/*
* These ioctls don't rely on the hardware to be present.
*/
@ -1144,10 +1158,9 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
break;
}
}
out_up:
out_up:
mutex_unlock(&state->mutex);
out:
unlock_kernel();
out:
return ret;
}
@ -1173,7 +1186,6 @@ static void uart_set_termios(struct tty_struct *tty,
return;
}
lock_kernel();
uart_change_speed(state, old_termios);
/* Handle transition to B0 status */
@ -1206,7 +1218,6 @@ static void uart_set_termios(struct tty_struct *tty,
}
spin_unlock_irqrestore(&state->port->lock, flags);
}
unlock_kernel();
#if 0
/*
* No need to wake up processes in open wait, since they
@ -1322,11 +1333,11 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
struct uart_port *port = state->port;
unsigned long char_time, expire;
BUG_ON(!kernel_locked());
if (port->type == PORT_UNKNOWN || port->fifosize == 0)
return;
lock_kernel();
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
@ -1372,6 +1383,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
break;
}
set_current_state(TASK_RUNNING); /* might not be needed */
unlock_kernel();
}
/*
@ -2085,7 +2097,9 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
int ret;
uart_change_pm(state, 0);
spin_lock_irq(&port->lock);
ops->set_mctrl(port, 0);
spin_unlock_irq(&port->lock);
ret = ops->startup(port);
if (ret == 0) {
uart_change_speed(state, NULL);