patch-2.3.35 linux/net/irda/ircomm/ircomm_tty.c
Next file: linux/net/irda/ircomm/ircomm_tty_attach.c
Previous file: linux/net/irda/ircomm/ircomm_ttp.c
Back to the patch index
Back to the overall index
- Lines: 616
- Date:
Tue Dec 21 10:17:58 1999
- Orig file:
v2.3.34/linux/net/irda/ircomm/ircomm_tty.c
- Orig date:
Sun Nov 7 16:37:34 1999
diff -u --recursive --new-file v2.3.34/linux/net/irda/ircomm/ircomm_tty.c linux/net/irda/ircomm/ircomm_tty.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Jun 6 21:00:56 1999
- * Modified at: Sat Oct 30 12:49:26 1999
+ * Modified at: Thu Dec 16 22:07:37 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: serial.c and previous IrCOMM work by Takahide Higuchi
*
@@ -61,6 +61,7 @@
static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout);
static void ircomm_tty_hangup(struct tty_struct *tty);
static void ircomm_tty_do_softint(void *private_);
+static void ircomm_tty_shutdown(struct ircomm_tty_cb *self);
static int ircomm_tty_data_indication(void *instance, void *sap,
struct sk_buff *skb);
@@ -134,6 +135,20 @@
return 0;
}
+#ifdef MODULE
+static void __ircomm_tty_cleanup(struct ircomm_tty_cb *self)
+{
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+ ircomm_tty_shutdown(self);
+
+ self->magic = 0;
+ kfree(self);
+}
+
/*
* Function ircomm_tty_cleanup ()
*
@@ -144,7 +159,7 @@
{
int ret;
- IRDA_DEBUG(4, __FUNCTION__"()\n");
+ IRDA_DEBUG(4, __FUNCTION__"()\n");
ret = tty_unregister_driver(&driver);
if (ret) {
@@ -152,8 +167,9 @@
return;
}
- hashbin_delete(ircomm_tty, (FREE_FUNC) kfree);
+ hashbin_delete(ircomm_tty, (FREE_FUNC) __ircomm_tty_cleanup);
}
+#endif /* MODULE */
/*
* Function ircomm_startup (self)
@@ -166,6 +182,8 @@
notify_t notify;
int ret;
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
@@ -189,9 +207,10 @@
strncpy(notify.name, "ircomm_tty", NOTIFY_MAX_NAME);
notify.instance = self;
- if (!self->ircomm)
+ if (!self->ircomm) {
self->ircomm = ircomm_open(¬ify, self->service_type,
self->line);
+ }
if (!self->ircomm)
return -ENODEV;
@@ -224,25 +243,23 @@
unsigned long flags;
struct tty_struct *tty;
- tty = self->tty;
-
IRDA_DEBUG(2, __FUNCTION__ "()\n");
+ tty = self->tty;
+
if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
/* this is a callout device */
/* just verify that normal device is not in use */
if (self->flags & ASYNC_NORMAL_ACTIVE)
return -EBUSY;
-#if 0
if ((self->flags & ASYNC_CALLOUT_ACTIVE) &&
(self->flags & ASYNC_SESSION_LOCKOUT) &&
(self->session != current->session))
- return -EBUSY;
-#endif
+ return -EBUSY;
if ((self->flags & ASYNC_CALLOUT_ACTIVE) &&
(self->flags & ASYNC_PGRP_LOCKOUT) &&
(self->pgrp != current->pgrp))
- return -EBUSY;
+ return -EBUSY;
self->flags |= ASYNC_CALLOUT_ACTIVE;
return 0;
}
@@ -297,13 +314,13 @@
if (!(self->flags & ASYNC_CALLOUT_ACTIVE) &&
(tty->termios->c_cflag & CBAUD)) {
save_flags(flags); cli();
- self->session.dte |= IRCOMM_RTS + IRCOMM_DTR;
+ self->settings.dte |= IRCOMM_RTS + IRCOMM_DTR;
ircomm_param_request(self, IRCOMM_DTE, TRUE);
restore_flags(flags);
}
- set_current_state(TASK_INTERRUPTIBLE);
+ current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp) || !(self->flags & ASYNC_INITIALIZED)){
retval = (self->flags & ASYNC_HUP_NOTIFY) ?
@@ -318,7 +335,7 @@
*/
if (!(self->flags & ASYNC_CALLOUT_ACTIVE) &&
!(self->flags & ASYNC_CLOSING) &&
- (do_clocal || (self->session.dce & IRCOMM_CD)) &&
+ (do_clocal || (self->settings.dce & IRCOMM_CD)) &&
self->state == IRCOMM_TTY_READY)
{
break;
@@ -386,6 +403,8 @@
memset(self, 0, sizeof(struct ircomm_tty_cb));
self->magic = IRCOMM_TTY_MAGIC;
+ self->flow = FLOW_STOP;
+
self->line = line;
self->tqueue.routine = ircomm_tty_do_softint;
self->tqueue.data = self;
@@ -397,7 +416,7 @@
/* Init some important stuff */
init_timer(&self->watchdog_timer);
init_waitqueue_head(&self->open_wait);
- init_waitqueue_head(&self->close_wait);
+ init_waitqueue_head(&self->close_wait);
/*
* Force TTY into raw mode by default which is usually what
@@ -453,15 +472,14 @@
ret = ircomm_tty_block_til_ready(self, filp);
if (ret) {
/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
- IRDA_DEBUG(0, __FUNCTION__
+ IRDA_DEBUG(2, __FUNCTION__
"(), returning after block_til_ready with %d\n",
ret);
return ret;
}
-#if 0
+
self->session = current->session;
-#endif
self->pgrp = current->pgrp;
return 0;
@@ -478,14 +496,11 @@
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
unsigned long flags;
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
if (!tty)
return;
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
save_flags(flags);
cli();
@@ -493,10 +508,27 @@
MOD_DEC_USE_COUNT;
restore_flags(flags);
- IRDA_DEBUG(2, __FUNCTION__ "(), returning 1\n");
+ IRDA_DEBUG(0, __FUNCTION__ "(), returning 1\n");
return;
}
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, 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, __FUNCTION__ "(), bad serial port count; "
+ "tty->count is 1, state->count is %d\n",
+ self->open_count);
+ self->open_count = 1;
+ }
+
if (--self->open_count < 0) {
ERROR(__FUNCTION__
"(), bad serial port count for ttys%d: %d\n",
@@ -507,7 +539,7 @@
MOD_DEC_USE_COUNT;
restore_flags(flags);
- IRDA_DEBUG(2, __FUNCTION__ "(), open count > 0\n");
+ IRDA_DEBUG(0, __FUNCTION__ "(), open count > 0\n");
return;
}
self->flags |= ASYNC_CLOSING;
@@ -520,7 +552,7 @@
if (self->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, self->closing_wait);
- self->flags &= ~ASYNC_INITIALIZED;
+ ircomm_tty_shutdown(self);
if (tty->driver.flush_buffer)
tty->driver.flush_buffer(tty);
@@ -543,34 +575,7 @@
wake_up_interruptible(&self->close_wait);
MOD_DEC_USE_COUNT;
-
- del_timer(&self->watchdog_timer);
-
- /* Free parameter buffer */
- if (self->ctrl_skb) {
- dev_kfree_skb(self->ctrl_skb);
- self->ctrl_skb = NULL;
- }
-
- /* Free transmit buffer */
- if (self->tx_skb) {
- dev_kfree_skb(self->tx_skb);
- self->tx_skb = NULL;
- }
-
restore_flags(flags);
-
- ircomm_tty_detach_cable(self);
- ircomm_close(self->ircomm);
- self->ircomm = NULL;
-
-#if IRCOMM_TTY_CLOSE_WILL_DEALLOC
- self->magic = 0;
-
- hashbin_remove(ircomm_tty, self->line, NULL);
-
- kfree(self);
-#endif
}
/*
@@ -606,7 +611,9 @@
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) private_;
struct tty_struct *tty;
unsigned long flags;
- struct sk_buff *skb;
+ struct sk_buff *skb, *ctrl_skb;
+
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
if (!self || self->magic != IRCOMM_TTY_MAGIC)
return;
@@ -615,6 +622,19 @@
if (!tty)
return;
+ /* Unlink control buffer */
+ save_flags(flags);
+ cli();
+
+ ctrl_skb = self->ctrl_skb;
+ self->ctrl_skb = NULL;
+
+ restore_flags(flags);
+
+ /* Flush control buffer if any */
+ if (ctrl_skb && self->flow == FLOW_START)
+ ircomm_control_request(self->ircomm, ctrl_skb);
+
if (tty->hw_stopped)
return;
@@ -625,7 +645,7 @@
skb = self->tx_skb;
self->tx_skb = NULL;
- restore_flags(flags);
+ restore_flags(flags);
/* Flush transmit buffer if any */
if (skb)
@@ -658,7 +678,7 @@
int len = 0;
int size;
- IRDA_DEBUG(3, __FUNCTION__ "(), count=%d, hw_stopped=%d\n", count,
+ IRDA_DEBUG(2, __FUNCTION__ "(), count=%d, hw_stopped=%d\n", count,
tty->hw_stopped);
ASSERT(self != NULL, return -1;);
@@ -788,7 +808,7 @@
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
unsigned long orig_jiffies, poll_time;
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -831,8 +851,8 @@
/* Hardware flow control? */
if (tty->termios->c_cflag & CRTSCTS) {
- self->session.dte &= ~IRCOMM_RTS;
- self->session.dte |= IRCOMM_DELTA_RTS;
+ self->settings.dte &= ~IRCOMM_RTS;
+ self->settings.dte |= IRCOMM_DELTA_RTS;
ircomm_param_request(self, IRCOMM_DTE, TRUE);
}
@@ -863,7 +883,7 @@
/* Using hardware flow control? */
if (tty->termios->c_cflag & CRTSCTS) {
- self->session.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
+ self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
ircomm_param_request(self, IRCOMM_DTE, TRUE);
IRDA_DEBUG(1, __FUNCTION__"(), FLOW_START\n");
@@ -897,6 +917,46 @@
return len;
}
+static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
+{
+ unsigned long flags;
+
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ if (!(self->flags & ASYNC_INITIALIZED))
+ return;
+
+ save_flags(flags);
+ cli();
+
+ del_timer(&self->watchdog_timer);
+
+ /* Free parameter buffer */
+ if (self->ctrl_skb) {
+ dev_kfree_skb(self->ctrl_skb);
+ self->ctrl_skb = NULL;
+ }
+
+ /* Free transmit buffer */
+ if (self->tx_skb) {
+ dev_kfree_skb(self->tx_skb);
+ self->tx_skb = NULL;
+ }
+
+ ircomm_tty_detach_cable(self);
+
+ if (self->ircomm) {
+ ircomm_close(self->ircomm);
+ self->ircomm = NULL;
+ }
+ self->flags &= ~ASYNC_INITIALIZED;
+
+ restore_flags(flags);
+}
+
/*
* Function ircomm_tty_hangup (tty)
*
@@ -908,7 +968,7 @@
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- IRDA_DEBUG(2, __FUNCTION__"()\n");
+ IRDA_DEBUG(0, __FUNCTION__"()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -917,17 +977,11 @@
return;
/* ircomm_tty_flush_buffer(tty); */
- ircomm_tty_detach_cable(self);
- ircomm_close(self->ircomm);
+ ircomm_tty_shutdown(self);
- self->ircomm = NULL;
-
- self->flags &= ~ASYNC_INITIALIZED;
-
- self->open_count = 0;
self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
self->tty = 0;
-
+ self->open_count = 0;
wake_up_interruptible(&self->open_wait);
}
@@ -983,19 +1037,21 @@
struct tty_struct *tty;
int status;
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
tty = self->tty;
- status = self->session.dce;
+ 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)) {
IRDA_DEBUG(2, __FUNCTION__
- "(), ttys%d CD now %s...\n", self->line,
+ "(), ircomm%d CD now %s...\n", self->line,
(status & IRCOMM_CD) ? "on" : "off");
if (status & IRCOMM_CD) {
@@ -1003,27 +1059,30 @@
} else if (!((self->flags & ASYNC_CALLOUT_ACTIVE) &&
(self->flags & ASYNC_CALLOUT_NOHUP)))
{
- IRDA_DEBUG(2, __FUNCTION__ "(), Doing serial hangup..\n");
-
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), Doing serial hangup..\n");
if (tty)
tty_hangup(tty);
+
+ /* Hangup will remote the tty, so better break out */
+ return;
}
}
if (self->flags & ASYNC_CTS_FLOW) {
if (tty->hw_stopped) {
if (status & IRCOMM_CTS) {
- IRDA_DEBUG(2, __FUNCTION__ "(), CTS tx start...\n");
-
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), CTS tx start...\n");
tty->hw_stopped = 0;
-
+
queue_task(&self->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
return;
}
} else {
if (!(status & IRCOMM_CTS)) {
- IRDA_DEBUG(2, __FUNCTION__ "(), CTS tx stop...\n");
-
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), CTS tx stop...\n");
tty->hw_stopped = 1;
}
}
@@ -1047,8 +1106,20 @@
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
ASSERT(skb != NULL, return -1;);
- if (!self->tty)
+ if (!self->tty) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), no tty!\n");
+ dev_kfree_skb(skb);
return 0;
+ }
+
+ /*
+ * If we receive data when hardware is stopped then something is wrong.
+ * We try to poll the peers line settings to check if we are up todate.
+ */
+ if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), polling for line settings!\n");
+ ircomm_param_request(self, IRCOMM_POLL, TRUE);
+ }
/*
* Just give it over to the line discipline. There is no need to
@@ -1113,15 +1184,15 @@
/* ircomm_tty_do_softint will take care of the rest */
queue_task(&self->tqueue, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
+ mark_bh(IMMEDIATE_BH);
break;
- default:
- /* If we get here, something is very wrong, better stop */
+ default: /* If we get here, something is very wrong, better stop */
case FLOW_STOP:
IRDA_DEBUG(2, __FUNCTION__ "(), hw stopped!\n");
tty->hw_stopped = 1;
break;
}
+ self->flow = cmd;
}
static int ircomm_tty_line_info(struct ircomm_tty_cb *self, char *buf)
@@ -1141,57 +1212,57 @@
ret += sprintf(buf+ret, "No common service type!\n");
ret += sprintf(buf+ret, "\n");
- ret += sprintf(buf+ret, "Port name: %s\n", self->session.port_name);
+ ret += sprintf(buf+ret, "Port name: %s\n", self->settings.port_name);
ret += sprintf(buf+ret, "DTE status: ");
- if (self->session.dte & IRCOMM_RTS)
+ if (self->settings.dte & IRCOMM_RTS)
ret += sprintf(buf+ret, "RTS|");
- if (self->session.dte & IRCOMM_DTR)
+ if (self->settings.dte & IRCOMM_DTR)
ret += sprintf(buf+ret, "DTR|");
- if (self->session.dte)
+ if (self->settings.dte)
ret--; /* remove the last | */
ret += sprintf(buf+ret, "\n");
ret += sprintf(buf+ret, "DCE status: ");
- if (self->session.dce & IRCOMM_CTS)
+ if (self->settings.dce & IRCOMM_CTS)
ret += sprintf(buf+ret, "CTS|");
- if (self->session.dce & IRCOMM_DSR)
+ if (self->settings.dce & IRCOMM_DSR)
ret += sprintf(buf+ret, "DSR|");
- if (self->session.dce & IRCOMM_CD)
+ if (self->settings.dce & IRCOMM_CD)
ret += sprintf(buf+ret, "CD|");
- if (self->session.dce & IRCOMM_RI)
+ if (self->settings.dce & IRCOMM_RI)
ret += sprintf(buf+ret, "RI|");
- if (self->session.dce)
+ if (self->settings.dce)
ret--; /* remove the last | */
ret += sprintf(buf+ret, "\n");
ret += sprintf(buf+ret, "Configuration: ");
- if (!self->session.null_modem)
+ if (!self->settings.null_modem)
ret += sprintf(buf+ret, "DTE <-> DCE\n");
else
ret += sprintf(buf+ret,
"DTE <-> DTE (null modem emulation)\n");
- ret += sprintf(buf+ret, "Data rate: %d\n", self->session.data_rate);
+ ret += sprintf(buf+ret, "Data rate: %d\n", self->settings.data_rate);
ret += sprintf(buf+ret, "Flow control: ");
- if (self->session.flow_control & IRCOMM_XON_XOFF_IN)
+ if (self->settings.flow_control & IRCOMM_XON_XOFF_IN)
ret += sprintf(buf+ret, "XON_XOFF_IN|");
- if (self->session.flow_control & IRCOMM_XON_XOFF_OUT)
+ if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT)
ret += sprintf(buf+ret, "XON_XOFF_OUT|");
- if (self->session.flow_control & IRCOMM_RTS_CTS_IN)
+ if (self->settings.flow_control & IRCOMM_RTS_CTS_IN)
ret += sprintf(buf+ret, "RTS_CTS_IN|");
- if (self->session.flow_control & IRCOMM_RTS_CTS_OUT)
+ if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT)
ret += sprintf(buf+ret, "RTS_CTS_OUT|");
- if (self->session.flow_control & IRCOMM_DSR_DTR_IN)
+ if (self->settings.flow_control & IRCOMM_DSR_DTR_IN)
ret += sprintf(buf+ret, "DSR_DTR_IN|");
- if (self->session.flow_control & IRCOMM_DSR_DTR_OUT)
+ if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT)
ret += sprintf(buf+ret, "DSR_DTR_OUT|");
- if (self->session.flow_control & IRCOMM_ENQ_ACK_IN)
+ if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN)
ret += sprintf(buf+ret, "ENQ_ACK_IN|");
- if (self->session.flow_control & IRCOMM_ENQ_ACK_OUT)
+ if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT)
ret += sprintf(buf+ret, "ENQ_ACK_OUT|");
- if (self->session.flow_control)
+ if (self->settings.flow_control)
ret--; /* remove the last | */
ret += sprintf(buf+ret, "\n");
@@ -1214,7 +1285,12 @@
ret--; /* remove the last | */
ret += sprintf(buf+ret, "\n");
+ ret += sprintf(buf+ret, "Role: %s\n", self->client ?
+ "client" : "server");
ret += sprintf(buf+ret, "Open count: %d\n", self->open_count);
+ ret += sprintf(buf+ret, "Max data size: %d\n", self->max_data_size);
+ ret += sprintf(buf+ret, "Max header size: %d\n", self->max_header_size);
+
if (self->tty)
ret += sprintf(buf+ret, "Hardware: %s\n",
self->tty->hw_stopped ? "Stopped" : "Running");
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)