Commit 266794eb authored by Alan Cox's avatar Alan Cox Committed by Greg Kroah-Hartman

nozomi: Add tty_port usage

The Nozomi tty handling is very broken on the open/close side (See
http://bugzilla.kernel.org/show_bug.cgi?id=13024 for one example). In
particular it marks the tty as closed on the first close() not on the last.

Most of the logic is pretty solid except for the open/close path so switch
to the tty_port helpers and let them do all the heavy lifting. This is also
fixes all the POSIX behaviour violations in the open/close paths.

Begin by adding the tty port usage
Signed-off-by: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 8b197a5c
...@@ -371,6 +371,8 @@ struct port { ...@@ -371,6 +371,8 @@ struct port {
struct mutex tty_sem; struct mutex tty_sem;
wait_queue_head_t tty_wait; wait_queue_head_t tty_wait;
struct async_icount tty_icount; struct async_icount tty_icount;
struct nozomi *dc;
}; };
/* Private data one for each card in the system */ /* Private data one for each card in the system */
...@@ -414,6 +416,8 @@ MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl); ...@@ -414,6 +416,8 @@ MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl);
static struct nozomi *ndevs[NOZOMI_MAX_CARDS]; static struct nozomi *ndevs[NOZOMI_MAX_CARDS];
static struct tty_driver *ntty_driver; static struct tty_driver *ntty_driver;
static const struct tty_port_operations noz_tty_port_ops;
/* /*
* find card by tty_index * find card by tty_index
*/ */
...@@ -1473,9 +1477,11 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, ...@@ -1473,9 +1477,11 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
for (i = 0; i < MAX_PORT; i++) { for (i = 0; i < MAX_PORT; i++) {
struct device *tty_dev; struct device *tty_dev;
struct port *port = &dc->port[i];
mutex_init(&dc->port[i].tty_sem); port->dc = dc;
tty_port_init(&dc->port[i].port); mutex_init(&port->tty_sem);
tty_port_init(&port->port);
port->port.ops = &noz_tty_port_ops;
tty_dev = tty_register_device(ntty_driver, dc->index_start + i, tty_dev = tty_register_device(ntty_driver, dc->index_start + i,
&pdev->dev); &pdev->dev);
...@@ -1600,67 +1606,74 @@ static void set_dtr(const struct tty_struct *tty, int dtr) ...@@ -1600,67 +1606,74 @@ static void set_dtr(const struct tty_struct *tty, int dtr)
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/* Called when the userspace process opens the tty, /dev/noz*. */ static int ntty_install(struct tty_driver *driver, struct tty_struct *tty)
static int ntty_open(struct tty_struct *tty, struct file *file)
{ {
struct port *port = get_port_by_tty(tty); struct port *port = get_port_by_tty(tty);
struct nozomi *dc = get_dc_by_tty(tty); struct nozomi *dc = get_dc_by_tty(tty);
unsigned long flags; int ret;
if (!port || !dc || dc->state != NOZOMI_STATE_READY) if (!port || !dc || dc->state != NOZOMI_STATE_READY)
return -ENODEV; return -ENODEV;
ret = tty_init_termios(tty);
if (ret == 0) {
tty_driver_kref_get(driver);
driver->ttys[tty->index] = tty;
}
return ret;
}
if (mutex_lock_interruptible(&port->tty_sem)) static void ntty_cleanup(struct tty_struct *tty)
return -ERESTARTSYS; {
tty->driver_data = NULL;
}
port->port.count++; static int ntty_activate(struct tty_port *tport, struct tty_struct *tty)
dc->open_ttys++; {
struct port *port = container_of(tport, struct port, port);
struct nozomi *dc = port->dc;
unsigned long flags;
/* Enable interrupt downlink for channel */
if (port->port.count == 1) {
tty->driver_data = port;
tty_port_tty_set(&port->port, tty);
DBG1("open: %d", port->token_dl); DBG1("open: %d", port->token_dl);
spin_lock_irqsave(&dc->spin_mutex, flags); spin_lock_irqsave(&dc->spin_mutex, flags);
dc->last_ier = dc->last_ier | port->token_dl; dc->last_ier = dc->last_ier | port->token_dl;
writew(dc->last_ier, dc->reg_ier); writew(dc->last_ier, dc->reg_ier);
dc->open_ttys++;
spin_unlock_irqrestore(&dc->spin_mutex, flags); spin_unlock_irqrestore(&dc->spin_mutex, flags);
} printk("noz: activated %d: %p\n", tty->index, tport);
mutex_unlock(&port->tty_sem);
return 0; return 0;
} }
/* Called when the userspace process close the tty, /dev/noz*. Also static int ntty_open(struct tty_struct *tty, struct file *filp)
called immediately if ntty_open fails in which case tty->driver_data {
will be NULL an we exit by the first return */ struct port *port = get_port_by_tty(tty);
return tty_port_open(&port->port, tty, filp);
}
static void ntty_close(struct tty_struct *tty, struct file *file) static void ntty_shutdown(struct tty_port *tport)
{ {
struct nozomi *dc = get_dc_by_tty(tty); struct port *port = container_of(tport, struct port, port);
struct port *nport = tty->driver_data; struct nozomi *dc = port->dc;
struct tty_port *port = &nport->port;
unsigned long flags; unsigned long flags;
if (!dc || !nport) DBG1("close: %d", port->token_dl);
return;
/* Users cannot interrupt a close */
mutex_lock(&nport->tty_sem);
WARN_ON(!port->count);
dc->open_ttys--;
port->count--;
if (port->count == 0) {
DBG1("close: %d", nport->token_dl);
tty_port_tty_set(port, NULL);
spin_lock_irqsave(&dc->spin_mutex, flags); spin_lock_irqsave(&dc->spin_mutex, flags);
dc->last_ier &= ~(nport->token_dl); dc->last_ier &= ~(port->token_dl);
writew(dc->last_ier, dc->reg_ier); writew(dc->last_ier, dc->reg_ier);
dc->open_ttys--;
spin_unlock_irqrestore(&dc->spin_mutex, flags); spin_unlock_irqrestore(&dc->spin_mutex, flags);
} printk("noz: shutdown %p\n", tport);
mutex_unlock(&nport->tty_sem); }
static void ntty_close(struct tty_struct *tty, struct file *filp)
{
struct port *port = tty->driver_data;
if (port)
tty_port_close(&port->port, tty, filp);
}
static void ntty_hangup(struct tty_struct *tty)
{
struct port *port = tty->driver_data;
tty_port_hangup(&port->port);
} }
/* /*
...@@ -1906,10 +1919,16 @@ exit_in_buffer: ...@@ -1906,10 +1919,16 @@ exit_in_buffer:
return rval; return rval;
} }
static const struct tty_port_operations noz_tty_port_ops = {
.activate = ntty_activate,
.shutdown = ntty_shutdown,
};
static const struct tty_operations tty_ops = { static const struct tty_operations tty_ops = {
.ioctl = ntty_ioctl, .ioctl = ntty_ioctl,
.open = ntty_open, .open = ntty_open,
.close = ntty_close, .close = ntty_close,
.hangup = ntty_hangup,
.write = ntty_write, .write = ntty_write,
.write_room = ntty_write_room, .write_room = ntty_write_room,
.unthrottle = ntty_unthrottle, .unthrottle = ntty_unthrottle,
...@@ -1917,6 +1936,8 @@ static const struct tty_operations tty_ops = { ...@@ -1917,6 +1936,8 @@ static const struct tty_operations tty_ops = {
.chars_in_buffer = ntty_chars_in_buffer, .chars_in_buffer = ntty_chars_in_buffer,
.tiocmget = ntty_tiocmget, .tiocmget = ntty_tiocmget,
.tiocmset = ntty_tiocmset, .tiocmset = ntty_tiocmset,
.install = ntty_install,
.cleanup = ntty_cleanup,
}; };
/* Module initialization */ /* Module initialization */
......
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