aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 12:26:52 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 12:26:52 -0700
commit3498d13b8090c0b0ef911409fbc503a7c4cca6ef (patch)
tree254ca00276e863d9fba25707690c66b2a04c49e9 /net
parentdef7cb8cd4e3258db88050eaaca5438bcc3dafca (diff)
parent0c57dfcc6c1d037243c2f8fbf62eab3633326ec0 (diff)
Merge tag 'tty-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull TTY changes from Greg Kroah-Hartman: "As we skipped the merge window for 3.6-rc1 for the tty tree, everything is now settled down and working properly, so we are ready for 3.7-rc1. Here's the patchset, it's big, but the large changes are removing a firmware file and adding a staging tty driver (it depended on the tty core changes, so it's going through this tree instead of the staging tree.) All of these patches have been in the linux-next tree for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" Fix up more-or-less trivial conflicts in - drivers/char/pcmcia/synclink_cs.c: tty NULL dereference fix vs tty_port_cts_enabled() helper function - drivers/staging/{Kconfig,Makefile}: add-add conflict (dgrp driver added close to other staging drivers) - drivers/staging/ipack/devices/ipoctal.c: "split ipoctal_channel from iopctal" vs "TTY: use tty_port_register_device" * tag 'tty-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (235 commits) tty/serial: Add kgdb_nmi driver tty/serial/amba-pl011: Quiesce interrupts in poll_get_char tty/serial/amba-pl011: Implement poll_init callback tty/serial/core: Introduce poll_init callback kdb: Turn KGDB_KDB=n stubs into static inlines kdb: Implement disable_nmi command kernel/debug: Mask KGDB NMI upon entry serial: pl011: handle corruption at high clock speeds serial: sccnxp: Make 'default' choice in switch last serial: sccnxp: Remove mask termios caps for SW flow control serial: sccnxp: Report actual baudrate back to core serial: samsung: Add poll_get_char & poll_put_char Powerpc 8xx CPM_UART setting MAXIDL register proportionaly to baud rate Powerpc 8xx CPM_UART maxidl should not depend on fifo size Powerpc 8xx CPM_UART too many interrupts Powerpc 8xx CPM_UART desynchronisation serial: set correct baud_base for EXSYS EX-41092 Dual 16950 serial: omap: fix the reciever line error case 8250: blacklist Winbond CIR port 8250_pnp: do pnp probe before legacy probe ...
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/rfcomm/tty.c10
-rw-r--r--net/irda/ircomm/ircomm_param.c5
-rw-r--r--net/irda/ircomm/ircomm_tty.c320
-rw-r--r--net/irda/ircomm/ircomm_tty_attach.c40
-rw-r--r--net/irda/ircomm/ircomm_tty_ioctl.c33
5 files changed, 205 insertions, 203 deletions
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 56f182393c4..ccc248791d5 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -278,8 +278,8 @@ out:
if (err < 0)
goto free;
- dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL);
-
+ dev->tty_dev = tty_port_register_device(&dev->port, rfcomm_tty_driver,
+ dev->id, NULL);
if (IS_ERR(dev->tty_dev)) {
err = PTR_ERR(dev->tty_dev);
list_del(&dev->list);
@@ -705,9 +705,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
break;
}
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->wait, &wait);
@@ -861,7 +861,7 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned l
static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
{
- struct ktermios *new = tty->termios;
+ struct ktermios *new = &tty->termios;
int old_baud_rate = tty_termios_baud_rate(old);
int new_baud_rate = tty_termios_baud_rate(new);
diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c
index 8b915f3ac3b..30893912835 100644
--- a/net/irda/ircomm/ircomm_param.c
+++ b/net/irda/ircomm/ircomm_param.c
@@ -99,7 +99,6 @@ pi_param_info_t ircomm_param_info = { pi_major_call_table, 3, 0x0f, 4 };
*/
int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
{
- struct tty_struct *tty;
unsigned long flags;
struct sk_buff *skb;
int count;
@@ -109,10 +108,6 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
- tty = self->tty;
- if (!tty)
- return 0;
-
/* Make sure we don't send parameters for raw mode */
if (self->service_type == IRCOMM_3_WIRE_RAW)
return 0;
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index 6b9d5a0e42f..95a3a7a336b 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -52,6 +52,8 @@
#include <net/irda/ircomm_tty_attach.h>
#include <net/irda/ircomm_tty.h>
+static int ircomm_tty_install(struct tty_driver *driver,
+ struct tty_struct *tty);
static int ircomm_tty_open(struct tty_struct *tty, struct file *filp);
static void ircomm_tty_close(struct tty_struct * tty, struct file *filp);
static int ircomm_tty_write(struct tty_struct * tty,
@@ -82,6 +84,7 @@ static struct tty_driver *driver;
static hashbin_t *ircomm_tty = NULL;
static const struct tty_operations ops = {
+ .install = ircomm_tty_install,
.open = ircomm_tty_open,
.close = ircomm_tty_close,
.write = ircomm_tty_write,
@@ -104,6 +107,35 @@ static const struct tty_operations ops = {
#endif /* CONFIG_PROC_FS */
};
+static void ircomm_port_raise_dtr_rts(struct tty_port *port, int raise)
+{
+ struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb,
+ port);
+ /*
+ * Here, we use to lock those two guys, but as ircomm_param_request()
+ * does it itself, I don't see the point (and I see the deadlock).
+ * Jean II
+ */
+ if (raise)
+ self->settings.dte |= IRCOMM_RTS | IRCOMM_DTR;
+ else
+ self->settings.dte &= ~(IRCOMM_RTS | IRCOMM_DTR);
+
+ ircomm_param_request(self, IRCOMM_DTE, TRUE);
+}
+
+static int ircomm_port_carrier_raised(struct tty_port *port)
+{
+ struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb,
+ port);
+ return self->settings.dce & IRCOMM_CD;
+}
+
+static const struct tty_port_operations ircomm_port_ops = {
+ .dtr_rts = ircomm_port_raise_dtr_rts,
+ .carrier_raised = ircomm_port_carrier_raised,
+};
+
/*
* Function ircomm_tty_init()
*
@@ -194,7 +226,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
/* Check if already open */
- if (test_and_set_bit(ASYNC_B_INITIALIZED, &self->flags)) {
+ if (test_and_set_bit(ASYNCB_INITIALIZED, &self->port.flags)) {
IRDA_DEBUG(2, "%s(), already open so break out!\n", __func__ );
return 0;
}
@@ -231,7 +263,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
return 0;
err:
- clear_bit(ASYNC_B_INITIALIZED, &self->flags);
+ clear_bit(ASYNCB_INITIALIZED, &self->port.flags);
return ret;
}
@@ -242,72 +274,62 @@ err:
*
*/
static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
- struct file *filp)
+ struct tty_struct *tty, struct file *filp)
{
+ struct tty_port *port = &self->port;
DECLARE_WAITQUEUE(wait, current);
int retval;
int do_clocal = 0, extra_count = 0;
unsigned long flags;
- struct tty_struct *tty;
IRDA_DEBUG(2, "%s()\n", __func__ );
- tty = self->tty;
-
/*
* If non-blocking mode is set, or the port is not enabled,
* then make the check up front and then exit.
*/
if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
/* nonblock mode is set or port is not enabled */
- self->flags |= ASYNC_NORMAL_ACTIVE;
+ port->flags |= ASYNC_NORMAL_ACTIVE;
IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __func__ );
return 0;
}
- if (tty->termios->c_cflag & CLOCAL) {
+ if (tty->termios.c_cflag & CLOCAL) {
IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __func__ );
do_clocal = 1;
}
/* Wait for carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in
- * this loop, self->open_count is dropped by one, so that
+ * this loop, port->count is dropped by one, so that
* mgsl_close() knows when to free things. We restore it upon
* exit, either normal or abnormal.
*/
retval = 0;
- add_wait_queue(&self->open_wait, &wait);
+ add_wait_queue(&port->open_wait, &wait);
IRDA_DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n",
- __FILE__,__LINE__, tty->driver->name, self->open_count );
+ __FILE__, __LINE__, tty->driver->name, port->count);
- /* As far as I can see, we protect open_count - Jean II */
- spin_lock_irqsave(&self->spinlock, flags);
+ spin_lock_irqsave(&port->lock, flags);
if (!tty_hung_up_p(filp)) {
extra_count = 1;
- self->open_count--;
+ port->count--;
}
- spin_unlock_irqrestore(&self->spinlock, flags);
- self->blocked_open++;
+ spin_unlock_irqrestore(&port->lock, flags);
+ port->blocked_open++;
while (1) {
- if (tty->termios->c_cflag & CBAUD) {
- /* Here, we use to lock those two guys, but
- * as ircomm_param_request() does it itself,
- * I don't see the point (and I see the deadlock).
- * Jean II */
- self->settings.dte |= IRCOMM_RTS + IRCOMM_DTR;
-
- ircomm_param_request(self, IRCOMM_DTE, TRUE);
- }
+ if (tty->termios.c_cflag & CBAUD)
+ tty_port_raise_dtr_rts(port);
current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp) ||
- !test_bit(ASYNC_B_INITIALIZED, &self->flags)) {
- retval = (self->flags & ASYNC_HUP_NOTIFY) ?
+ !test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+ retval = (port->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS;
break;
}
@@ -317,8 +339,8 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
* specified, we cannot return before the IrCOMM link is
* ready
*/
- if (!test_bit(ASYNC_B_CLOSING, &self->flags) &&
- (do_clocal || (self->settings.dce & IRCOMM_CD)) &&
+ if (!test_bit(ASYNCB_CLOSING, &port->flags) &&
+ (do_clocal || tty_port_carrier_raised(port)) &&
self->state == IRCOMM_TTY_READY)
{
break;
@@ -330,46 +352,36 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
}
IRDA_DEBUG(1, "%s(%d):block_til_ready blocking on %s open_count=%d\n",
- __FILE__,__LINE__, tty->driver->name, self->open_count );
+ __FILE__, __LINE__, tty->driver->name, port->count);
schedule();
}
__set_current_state(TASK_RUNNING);
- remove_wait_queue(&self->open_wait, &wait);
+ remove_wait_queue(&port->open_wait, &wait);
if (extra_count) {
/* ++ is not atomic, so this should be protected - Jean II */
- spin_lock_irqsave(&self->spinlock, flags);
- self->open_count++;
- spin_unlock_irqrestore(&self->spinlock, flags);
+ spin_lock_irqsave(&port->lock, flags);
+ port->count++;
+ spin_unlock_irqrestore(&port->lock, flags);
}
- self->blocked_open--;
+ port->blocked_open--;
IRDA_DEBUG(1, "%s(%d):block_til_ready after blocking on %s open_count=%d\n",
- __FILE__,__LINE__, tty->driver->name, self->open_count);
+ __FILE__, __LINE__, tty->driver->name, port->count);
if (!retval)
- self->flags |= ASYNC_NORMAL_ACTIVE;
+ port->flags |= ASYNC_NORMAL_ACTIVE;
return retval;
}
-/*
- * Function ircomm_tty_open (tty, filp)
- *
- * This routine is called when a particular tty device is opened. This
- * routine is mandatory; if this routine is not filled in, the attempted
- * open will fail with ENODEV.
- */
-static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
+
+static int ircomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct ircomm_tty_cb *self;
unsigned int line = tty->index;
- unsigned long flags;
- int ret;
-
- IRDA_DEBUG(2, "%s()\n", __func__ );
/* Check if instance already exists */
self = hashbin_lock_find(ircomm_tty, line, NULL);
@@ -381,6 +393,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
return -ENOMEM;
}
+ tty_port_init(&self->port);
+ self->port.ops = &ircomm_port_ops;
self->magic = IRCOMM_TTY_MAGIC;
self->flow = FLOW_STOP;
@@ -388,13 +402,9 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
INIT_WORK(&self->tqueue, ircomm_tty_do_softint);
self->max_header_size = IRCOMM_TTY_HDR_UNINITIALISED;
self->max_data_size = IRCOMM_TTY_DATA_UNINITIALISED;
- self->close_delay = 5*HZ/10;
- self->closing_wait = 30*HZ;
/* Init some important stuff */
init_timer(&self->watchdog_timer);
- init_waitqueue_head(&self->open_wait);
- init_waitqueue_head(&self->close_wait);
spin_lock_init(&self->spinlock);
/*
@@ -404,31 +414,48 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
*
* Note this is completely usafe and doesn't work properly
*/
- tty->termios->c_iflag = 0;
- tty->termios->c_oflag = 0;
+ tty->termios.c_iflag = 0;
+ tty->termios.c_oflag = 0;
/* Insert into hash */
hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL);
}
- /* ++ is not atomic, so this should be protected - Jean II */
- spin_lock_irqsave(&self->spinlock, flags);
- self->open_count++;
- tty->driver_data = self;
- self->tty = tty;
- spin_unlock_irqrestore(&self->spinlock, flags);
+ return tty_port_install(&self->port, driver, tty);
+}
+
+/*
+ * Function ircomm_tty_open (tty, filp)
+ *
+ * This routine is called when a particular tty device is opened. This
+ * routine is mandatory; if this routine is not filled in, the attempted
+ * open will fail with ENODEV.
+ */
+static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
+{
+ struct ircomm_tty_cb *self = tty->driver_data;
+ unsigned long flags;
+ int ret;
+
+ IRDA_DEBUG(2, "%s()\n", __func__ );
+
+ /* ++ is not atomic, so this should be protected - Jean II */
+ spin_lock_irqsave(&self->port.lock, flags);
+ self->port.count++;
+ spin_unlock_irqrestore(&self->port.lock, flags);
+ tty_port_tty_set(&self->port, tty);
IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __func__ , tty->driver->name,
- self->line, self->open_count);
+ self->line, self->port.count);
/* Not really used by us, but lets do it anyway */
- self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ tty->low_latency = (self->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
/*
* If the port is the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) ||
- test_bit(ASYNC_B_CLOSING, &self->flags)) {
+ test_bit(ASYNCB_CLOSING, &self->port.flags)) {
/* Hm, why are we blocking on ASYNC_CLOSING if we
* do return -EAGAIN/-ERESTARTSYS below anyway?
@@ -438,14 +465,15 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
* probably better sleep uninterruptible?
*/
- if (wait_event_interruptible(self->close_wait, !test_bit(ASYNC_B_CLOSING, &self->flags))) {
+ if (wait_event_interruptible(self->port.close_wait,
+ !test_bit(ASYNCB_CLOSING, &self->port.flags))) {
IRDA_WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n",
__func__);
return -ERESTARTSYS;
}
#ifdef SERIAL_DO_RESTART
- return (self->flags & ASYNC_HUP_NOTIFY) ?
+ return (self->port.flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS;
#else
return -EAGAIN;
@@ -453,7 +481,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
}
/* Check if this is a "normal" ircomm device, or an irlpt device */
- if (line < 0x10) {
+ if (self->line < 0x10) {
self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */
/* Jan Kiszka -> add DSR/RI -> Conform to IrCOMM spec */
@@ -469,7 +497,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
if (ret)
return ret;
- ret = ircomm_tty_block_til_ready(self, filp);
+ ret = ircomm_tty_block_til_ready(self, tty, filp);
if (ret) {
IRDA_DEBUG(2,
"%s(), returning after block_til_ready with %d\n", __func__ ,
@@ -489,81 +517,22 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- unsigned long flags;
+ struct tty_port *port = &self->port;
IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- spin_lock_irqsave(&self->spinlock, flags);
-
- if (tty_hung_up_p(filp)) {
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- IRDA_DEBUG(0, "%s(), returning 1\n", __func__ );
- return;
- }
-
- if ((tty->count == 1) && (self->open_count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. state->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- IRDA_DEBUG(0, "%s(), bad serial port count; "
- "tty->count is 1, state->count is %d\n", __func__ ,
- self->open_count);
- self->open_count = 1;
- }
-
- if (--self->open_count < 0) {
- IRDA_ERROR("%s(), bad serial port count for ttys%d: %d\n",
- __func__, self->line, self->open_count);
- self->open_count = 0;
- }
- if (self->open_count) {
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- IRDA_DEBUG(0, "%s(), open count > 0\n", __func__ );
+ if (tty_port_close_start(port, tty, filp) == 0)
return;
- }
-
- /* Hum... Should be test_and_set_bit ??? - Jean II */
- set_bit(ASYNC_B_CLOSING, &self->flags);
-
- /* We need to unlock here (we were unlocking at the end of this
- * function), because tty_wait_until_sent() may schedule.
- * I don't know if the rest should be protected somehow,
- * so someone should check. - Jean II */
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- if (self->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent_from_close(tty, self->closing_wait);
ircomm_tty_shutdown(self);
tty_driver_flush_buffer(tty);
- tty_ldisc_flush(tty);
-
- tty->closing = 0;
- self->tty = NULL;
- if (self->blocked_open) {
- if (self->close_delay)
- schedule_timeout_interruptible(self->close_delay);
- wake_up_interruptible(&self->open_wait);
- }
-
- self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- wake_up_interruptible(&self->close_wait);
+ tty_port_close_end(port, tty);
+ tty_port_tty_set(port, NULL);
}
/*
@@ -606,7 +575,7 @@ static void ircomm_tty_do_softint(struct work_struct *work)
if (!self || self->magic != IRCOMM_TTY_MAGIC)
return;
- tty = self->tty;
+ tty = tty_port_tty_get(&self->port);
if (!tty)
return;
@@ -627,7 +596,7 @@ static void ircomm_tty_do_softint(struct work_struct *work)
}
if (tty->hw_stopped)
- return;
+ goto put;
/* Unlink transmit buffer */
spin_lock_irqsave(&self->spinlock, flags);
@@ -646,6 +615,8 @@ static void ircomm_tty_do_softint(struct work_struct *work)
/* Check if user (still) wants to be waken up */
tty_wakeup(tty);
+put:
+ tty_kref_put(tty);
}
/*
@@ -880,7 +851,7 @@ static void ircomm_tty_throttle(struct tty_struct *tty)
ircomm_tty_send_xchar(tty, STOP_CHAR(tty));
/* Hardware flow control? */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
self->settings.dte &= ~IRCOMM_RTS;
self->settings.dte |= IRCOMM_DELTA_RTS;
@@ -912,7 +883,7 @@ static void ircomm_tty_unthrottle(struct tty_struct *tty)
}
/* Using hardware flow control? */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
ircomm_param_request(self, IRCOMM_DTE, TRUE);
@@ -955,7 +926,7 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
IRDA_DEBUG(0, "%s()\n", __func__ );
- if (!test_and_clear_bit(ASYNC_B_INITIALIZED, &self->flags))
+ if (!test_and_clear_bit(ASYNCB_INITIALIZED, &self->port.flags))
return;
ircomm_tty_detach_cable(self);
@@ -994,6 +965,7 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
static void ircomm_tty_hangup(struct tty_struct *tty)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+ struct tty_port *port = &self->port;
unsigned long flags;
IRDA_DEBUG(0, "%s()\n", __func__ );
@@ -1004,14 +976,17 @@ static void ircomm_tty_hangup(struct tty_struct *tty)
/* ircomm_tty_flush_buffer(tty); */
ircomm_tty_shutdown(self);
- /* I guess we need to lock here - Jean II */
- spin_lock_irqsave(&self->spinlock, flags);
- self->flags &= ~ASYNC_NORMAL_ACTIVE;
- self->tty = NULL;
- self->open_count = 0;
- spin_unlock_irqrestore(&self->spinlock, flags);
+ spin_lock_irqsave(&port->lock, flags);
+ port->flags &= ~ASYNC_NORMAL_ACTIVE;
+ if (port->tty) {
+ set_bit(TTY_IO_ERROR, &port->tty->flags);
+ tty_kref_put(port->tty);
+ }
+ port->tty = NULL;
+ port->count = 0;
+ spin_unlock_irqrestore(&port->lock, flags);
- wake_up_interruptible(&self->open_wait);
+ wake_up_interruptible(&port->open_wait);
}
/*
@@ -1071,20 +1046,20 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- tty = self->tty;
+ tty = tty_port_tty_get(&self->port);
status = self->settings.dce;
if (status & IRCOMM_DCE_DELTA_ANY) {
/*wake_up_interruptible(&self->delta_msr_wait);*/
}
- if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
+ if ((self->port.flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
IRDA_DEBUG(2,
"%s(), ircomm%d CD now %s...\n", __func__ , self->line,
(status & IRCOMM_CD) ? "on" : "off");
if (status & IRCOMM_CD) {
- wake_up_interruptible(&self->open_wait);
+ wake_up_interruptible(&self->port.open_wait);
} else {
IRDA_DEBUG(2,
"%s(), Doing serial hangup..\n", __func__ );
@@ -1092,10 +1067,10 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
tty_hangup(tty);
/* Hangup will remote the tty, so better break out */
- return;
+ goto put;
}
}
- if (self->flags & ASYNC_CTS_FLOW) {
+ if (tty && tty_port_cts_enabled(&self->port)) {
if (tty->hw_stopped) {
if (status & IRCOMM_CTS) {
IRDA_DEBUG(2,
@@ -1103,10 +1078,10 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
tty->hw_stopped = 0;
/* Wake up processes blocked on open */
- wake_up_interruptible(&self->open_wait);
+ wake_up_interruptible(&self->port.open_wait);
schedule_work(&self->tqueue);
- return;
+ goto put;
}
} else {
if (!(status & IRCOMM_CTS)) {
@@ -1116,6 +1091,8 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
}
}
}
+put:
+ tty_kref_put(tty);
}
/*
@@ -1128,6 +1105,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
struct sk_buff *skb)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+ struct tty_struct *tty;
IRDA_DEBUG(2, "%s()\n", __func__ );
@@ -1135,7 +1113,8 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
IRDA_ASSERT(skb != NULL, return -1;);
- if (!self->tty) {
+ tty = tty_port_tty_get(&self->port);
+ if (!tty) {
IRDA_DEBUG(0, "%s(), no tty!\n", __func__ );
return 0;
}
@@ -1146,7 +1125,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
* Devices like WinCE can do this, and since they don't send any
* params, we can just as well declare the hardware for running.
*/
- if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
+ if (tty->hw_stopped && (self->flow == FLOW_START)) {
IRDA_DEBUG(0, "%s(), polling for line settings!\n", __func__ );
ircomm_param_request(self, IRCOMM_POLL, TRUE);
@@ -1159,8 +1138,9 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
* Use flip buffer functions since the code may be called from interrupt
* context
*/
- tty_insert_flip_string(self->tty, skb->data, skb->len);
- tty_flip_buffer_push(self->tty);
+ tty_insert_flip_string(tty, skb->data, skb->len);
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
/* No need to kfree_skb - see ircomm_ttp_data_indication() */
@@ -1211,12 +1191,13 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- tty = self->tty;
+ tty = tty_port_tty_get(&self->port);
switch (cmd) {
case FLOW_START:
IRDA_DEBUG(2, "%s(), hw start!\n", __func__ );
- tty->hw_stopped = 0;
+ if (tty)
+ tty->hw_stopped = 0;
/* ircomm_tty_do_softint will take care of the rest */
schedule_work(&self->tqueue);
@@ -1224,15 +1205,19 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
default: /* If we get here, something is very wrong, better stop */
case FLOW_STOP:
IRDA_DEBUG(2, "%s(), hw stopped!\n", __func__ );
- tty->hw_stopped = 1;
+ if (tty)
+ tty->hw_stopped = 1;
break;
}
+
+ tty_kref_put(tty);
self->flow = cmd;
}
#ifdef CONFIG_PROC_FS
static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
{
+ struct tty_struct *tty;
char sep;
seq_printf(m, "State: %s\n", ircomm_tty_state[self->state]);
@@ -1328,40 +1313,43 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
seq_puts(m, "Flags:");
sep = ' ';
- if (self->flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(&self->port)) {
seq_printf(m, "%cASYNC_CTS_FLOW", sep);
sep = '|';
}
- if (self->flags & ASYNC_CHECK_CD) {
+ if (self->port.flags & ASYNC_CHECK_CD) {
seq_printf(m, "%cASYNC_CHECK_CD", sep);
sep = '|';
}
- if (self->flags & ASYNC_INITIALIZED) {
+ if (self->port.flags & ASYNC_INITIALIZED) {
seq_printf(m, "%cASYNC_INITIALIZED", sep);
sep = '|';
}
- if (self->flags & ASYNC_LOW_LATENCY) {
+ if (self->port.flags & ASYNC_LOW_LATENCY) {
seq_printf(m, "%cASYNC_LOW_LATENCY", sep);
sep = '|';
}
- if (self->flags & ASYNC_CLOSING) {
+ if (self->port.flags & ASYNC_CLOSING) {
seq_printf(m, "%cASYNC_CLOSING", sep);
sep = '|';
}
- if (self->flags & ASYNC_NORMAL_ACTIVE) {
+ if (self->port.flags & ASYNC_NORMAL_ACTIVE) {
seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep);
sep = '|';
}
seq_putc(m, '\n');
seq_printf(m, "Role: %s\n", self->client ? "client" : "server");
- seq_printf(m, "Open count: %d\n", self->open_count);
+ seq_printf(m, "Open count: %d\n", self->port.count);
seq_printf(m, "Max data size: %d\n", self->max_data_size);
seq_printf(m, "Max header size: %d\n", self->max_header_size);
- if (self->tty)
+ tty = tty_port_tty_get(&self->port);
+ if (tty) {
seq_printf(m, "Hardware: %s\n",
- self->tty->hw_stopped ? "Stopped" : "Running");
+ tty->hw_stopped ? "Stopped" : "Running");
+ tty_kref_put(tty);
+ }
}
static int ircomm_tty_proc_show(struct seq_file *m, void *v)
diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c
index b65d66e0d81..edab393e0c8 100644
--- a/net/irda/ircomm/ircomm_tty_attach.c
+++ b/net/irda/ircomm/ircomm_tty_attach.c
@@ -130,6 +130,8 @@ static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
*/
int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
{
+ struct tty_struct *tty;
+
IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
@@ -142,7 +144,11 @@ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
}
/* Make sure nobody tries to write before the link is up */
- self->tty->hw_stopped = 1;
+ tty = tty_port_tty_get(&self->port);
+ if (tty) {
+ tty->hw_stopped = 1;
+ tty_kref_put(tty);
+ }
ircomm_tty_ias_register(self);
@@ -398,23 +404,26 @@ void ircomm_tty_disconnect_indication(void *instance, void *sap,
struct sk_buff *skb)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+ struct tty_struct *tty;
IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- if (!self->tty)
+ tty = tty_port_tty_get(&self->port);
+ if (!tty)
return;
/* This will stop control data transfers */
self->flow = FLOW_STOP;
/* Stop data transfers */
- self->tty->hw_stopped = 1;
+ tty->hw_stopped = 1;
ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL,
NULL);
+ tty_kref_put(tty);
}
/*
@@ -550,12 +559,15 @@ void ircomm_tty_connect_indication(void *instance, void *sap,
*/
void ircomm_tty_link_established(struct ircomm_tty_cb *self)
{
+ struct tty_struct *tty;
+
IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- if (!self->tty)
+ tty = tty_port_tty_get(&self->port);
+ if (!tty)
return;
del_timer(&self->watchdog_timer);
@@ -566,19 +578,22 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self)
* will have to wait for the peer device (DCE) to raise the CTS
* line.
*/
- if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {
+ if (tty_port_cts_enabled(&self->port) &&
+ ((self->settings.dce & IRCOMM_CTS) == 0)) {
IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ );
- return;
+ goto put;
} else {
IRDA_DEBUG(1, "%s(), starting hardware!\n", __func__ );
- self->tty->hw_stopped = 0;
+ tty->hw_stopped = 0;
/* Wake up processes blocked on open */
- wake_up_interruptible(&self->open_wait);
+ wake_up_interruptible(&self->port.open_wait);
}
schedule_work(&self->tqueue);
+put:
+ tty_kref_put(tty);
}
/*
@@ -977,14 +992,17 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
ircomm_tty_start_watchdog_timer(self, 3*HZ);
- if (self->flags & ASYNC_CHECK_CD) {
+ if (self->port.flags & ASYNC_CHECK_CD) {
/* Drop carrier */
self->settings.dce = IRCOMM_DELTA_CD;
ircomm_tty_check_modem_status(self);
} else {
+ struct tty_struct *tty = tty_port_tty_get(&self->port);
IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ );
- if (self->tty)
- tty_hangup(self->tty);
+ if (tty) {
+ tty_hangup(tty);
+ tty_kref_put(tty);
+ }
}
break;
default:
diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c
index d0667d68351..b343f50dc8d 100644
--- a/net/irda/ircomm/ircomm_tty_ioctl.c
+++ b/net/irda/ircomm/ircomm_tty_ioctl.c
@@ -52,17 +52,18 @@
* Change speed of the driver. If the remote device is a DCE, then this
* should make it change the speed of its serial port
*/
-static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
+static void ircomm_tty_change_speed(struct ircomm_tty_cb *self,
+ struct tty_struct *tty)
{
unsigned int cflag, cval;
int baud;
IRDA_DEBUG(2, "%s()\n", __func__ );
- if (!self->tty || !self->tty->termios || !self->ircomm)
+ if (!self->ircomm)
return;
- cflag = self->tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
/* byte size and parity */
switch (cflag & CSIZE) {
@@ -81,7 +82,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
cval |= IRCOMM_PARITY_EVEN;
/* Determine divisor based on baud rate */
- baud = tty_get_baud_rate(self->tty);
+ baud = tty_get_baud_rate(tty);
if (!baud)
baud = 9600; /* B0 transition handled in rs_set_termios */
@@ -90,19 +91,19 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
/* CTS flow control flag and modem status interrupts */
if (cflag & CRTSCTS) {
- self->flags |= ASYNC_CTS_FLOW;
+ self->port.flags |= ASYNC_CTS_FLOW;
self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
/* This got me. Bummer. Jean II */
if (self->service_type == IRCOMM_3_WIRE_RAW)
IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __func__);
} else {
- self->flags &= ~ASYNC_CTS_FLOW;
+ self->port.flags &= ~ASYNC_CTS_FLOW;
self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
}
if (cflag & CLOCAL)
- self->flags &= ~ASYNC_CHECK_CD;
+ self->port.flags &= ~ASYNC_CHECK_CD;
else
- self->flags |= ASYNC_CHECK_CD;
+ self->port.flags |= ASYNC_CHECK_CD;
#if 0
/*
* Set up parity check flag
@@ -148,18 +149,18 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
IRDA_DEBUG(2, "%s()\n", __func__ );
if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(tty->termios->c_iflag) ==
+ (RELEVANT_IFLAG(tty->termios.c_iflag) ==
RELEVANT_IFLAG(old_termios->c_iflag)))
{
return;
}
- ircomm_tty_change_speed(self);
+ ircomm_tty_change_speed(self, tty);
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) &&
@@ -172,7 +173,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
if (!(old_termios->c_cflag & CBAUD) &&
(cflag & CBAUD)) {
self->settings.dte |= IRCOMM_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
self->settings.dte |= IRCOMM_RTS;
}
@@ -181,7 +182,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS))
+ !(tty->termios.c_cflag & CRTSCTS))
{
tty->hw_stopped = 0;
ircomm_tty_start(tty);
@@ -270,10 +271,10 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
memset(&info, 0, sizeof(info));
info.line = self->line;
- info.flags = self->flags;
+ info.flags = self->port.flags;
info.baud_base = self->settings.data_rate;
- info.close_delay = self->close_delay;
- info.closing_wait = self->closing_wait;
+ info.close_delay = self->port.close_delay;
+ info.closing_wait = self->port.closing_wait;
/* For compatibility */
info.type = PORT_16550A;