patch-2.3.19 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: 686
- Date:
Wed Sep 29 15:32:15 1999
- Orig file:
v2.3.18/linux/net/irda/ircomm/ircomm_tty.c
- Orig date:
Tue Aug 31 17:29:15 1999
diff -u --recursive --new-file v2.3.18/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: Wed Aug 25 15:12:18 1999
+ * Modified at: Tue Sep 21 11:46:59 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: serial.c and previous IrCOMM work by Takahide Higuchi
*
@@ -60,11 +60,8 @@
static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch);
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_break(struct tty_struct *tty, int break_state);
static void ircomm_tty_do_softint(void *private_);
-static void ircomm_tty_disconnect_indication(void *instance, void *sap,
- LM_REASON reason,
- struct sk_buff *skb);
+
static int ircomm_tty_data_indication(void *instance, void *sap,
struct sk_buff *skb);
static int ircomm_tty_control_indication(void *instance, void *sap,
@@ -127,7 +124,6 @@
driver.stop = ircomm_tty_stop;
driver.start = ircomm_tty_start;
driver.hangup = ircomm_tty_hangup;
- driver.break_ctl = ircomm_tty_break;
driver.wait_until_sent = ircomm_tty_wait_until_sent;
driver.read_proc = ircomm_tty_read_proc;
@@ -170,9 +166,12 @@
notify_t notify;
int ret;
+ ASSERT(self != NULL, return -1;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
/* Already open */
if (self->flags & ASYNC_INITIALIZED) {
- DEBUG(0, __FUNCTION__ "(), already open so break out!\n");
+ DEBUG(2, __FUNCTION__ "(), already open so break out!\n");
return 0;
}
@@ -181,10 +180,10 @@
/* These callbacks we must handle ourselves */
notify.data_indication = ircomm_tty_data_indication;
notify.udata_indication = ircomm_tty_control_indication;
- notify.disconnect_indication = ircomm_tty_disconnect_indication;
notify.flow_indication = ircomm_tty_flow_indication;
/* Use the ircomm_tty interface for these ones */
+ notify.disconnect_indication = ircomm_tty_disconnect_indication;
notify.connect_confirm = ircomm_tty_connect_confirm;
notify.connect_indication = ircomm_tty_connect_indication;
strncpy(notify.name, "ircomm_tty", NOTIFY_MAX_NAME);
@@ -201,7 +200,7 @@
/* Connect IrCOMM link with remote device */
ret = ircomm_tty_attach_cable(self);
if (ret < 0) {
- DEBUG(0, __FUNCTION__ "(), error attaching cable!\n");
+ ERROR(__FUNCTION__ "(), error attaching cable!\n");
return ret;
}
@@ -227,7 +226,7 @@
tty = self->tty;
- DEBUG(1, __FUNCTION__ "()\n");
+ DEBUG(2, __FUNCTION__ "()\n");
if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
/* this is a callout device */
@@ -283,7 +282,7 @@
retval = 0;
add_wait_queue(&self->open_wait, &wait);
- DEBUG(1, "%s(%d):block_til_ready before block on %s open_count=%d\n",
+ DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n",
__FILE__,__LINE__, tty->driver.name, self->open_count );
save_flags(flags); cli();
@@ -391,16 +390,25 @@
self->tqueue.routine = ircomm_tty_do_softint;
self->tqueue.data = self;
self->max_header_size = 5;
- self->max_data_size = 2048-self->max_header_size;
+ self->max_data_size = 64-self->max_header_size;
+ 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);
- skb_queue_head_init(&self->tx_queue);
+ init_waitqueue_head(&self->close_wait);
+
+ /*
+ * Force TTY into raw mode by default which is usually what
+ * we want for IrCOMM and IrLPT. This way applications will
+ * not have to twiddle with printcap etc.
+ */
+ tty->termios->c_iflag = 0;
+ tty->termios->c_oflag = 0;
/* Insert into hash */
hashbin_insert(ircomm_tty, (QUEUE *) self, line, NULL);
-
}
self->open_count++;
@@ -413,12 +421,28 @@
/* Not really used by us, but lets do it anyway */
self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ /*
+ * If the port is the middle of closing, bail out now
+ */
+ if (tty_hung_up_p(filp) ||
+ (self->flags & ASYNC_CLOSING)) {
+ if (self->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&self->close_wait);
+ /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
+#ifdef SERIAL_DO_RESTART
+ return ((self->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+#else
+ return -EAGAIN;
+#endif
+ }
+
/* Check if this is a "normal" ircomm device, or an irlpt device */
if (line < 0x10) {
self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
- DEBUG(0, __FUNCTION__ "(), IrCOMM device\n");
+ DEBUG(2, __FUNCTION__ "(), IrCOMM device\n");
} else {
- DEBUG(0, __FUNCTION__ "(), IrLPT device\n");
+ DEBUG(2, __FUNCTION__ "(), IrLPT device\n");
self->service_type = IRCOMM_3_WIRE_RAW;
}
@@ -452,7 +476,6 @@
static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- struct sk_buff *skb;
unsigned long flags;
DEBUG(2, __FUNCTION__ "()\n");
@@ -484,7 +507,7 @@
MOD_DEC_USE_COUNT;
restore_flags(flags);
- DEBUG(2, __FUNCTION__ "(), returning 2\n");
+ DEBUG(2, __FUNCTION__ "(), open count > 0\n");
return;
}
self->flags |= ASYNC_CLOSING;
@@ -494,6 +517,10 @@
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
+ if (self->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, self->closing_wait);
+
+ self->flags &= ~ASYNC_INITIALIZED;
if (tty->driver.flush_buffer)
tty->driver.flush_buffer(tty);
@@ -503,35 +530,47 @@
tty->closing = 0;
self->tty = 0;
- wake_up_interruptible(&self->open_wait);
-
+ if (self->blocked_open) {
+ if (self->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(self->close_delay);
+ }
+ wake_up_interruptible(&self->open_wait);
+ }
+
self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
ASYNC_CLOSING);
+ wake_up_interruptible(&self->close_wait);
MOD_DEC_USE_COUNT;
- restore_flags(flags);
del_timer(&self->watchdog_timer);
- /* Free frames queued for transmission */
- while ((skb = skb_dequeue(&self->tx_queue)) != NULL)
- dev_kfree_skb(skb);
-
/* 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
}
/*
@@ -544,18 +583,15 @@
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- DEBUG(2, __FUNCTION__ "()\n");
-
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- /* Flush transmit buffer if any */
- if ((self->tx_skb) && (!tty->hw_stopped)) {
- DEBUG(0, __FUNCTION__ "(), flushing!\n");
- ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST,
- self->tx_skb, NULL);
- self->tx_skb = NULL;
- }
+ /*
+ * Let do_softint() do this to avoid race condition with
+ * do_softint() ;-)
+ */
+ queue_task(&self->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
}
/*
@@ -569,28 +605,31 @@
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) private_;
struct tty_struct *tty;
+ unsigned long flags;
+ struct sk_buff *skb;
- DEBUG(2, __FUNCTION__ "()\n");
-
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+ if (!self || self->magic != IRCOMM_TTY_MAGIC)
+ return;
tty = self->tty;
if (!tty)
return;
- if (tty->hw_stopped) {
- DEBUG(2, __FUNCTION__ "(), hw stopped!\n");
+ if (tty->hw_stopped)
return;
- }
+
+ /* Unlink transmit buffer */
+ save_flags(flags);
+ cli();
+
+ skb = self->tx_skb;
+ self->tx_skb = NULL;
+
+ restore_flags(flags);
/* Flush transmit buffer if any */
- if (self->tx_skb) {
- DEBUG(1, __FUNCTION__ "(), flushing!\n");
- ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST,
- self->tx_skb, NULL);
- self->tx_skb = NULL;
- }
+ if (skb)
+ ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL);
/* Check if user (still) wants to be waken up */
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
@@ -625,9 +664,9 @@
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-/* save_flags(flags);
+ save_flags(flags);
cli();
-*/
+
/* Fetch current transmit buffer */
skb = self->tx_skb;
@@ -637,20 +676,19 @@
* max data size. The normal case however is just the opposite, and
* this function may be called multiple times, and will then actually
* defragment the data and send it out as one packet as soon as
- * possible, but at a safer point in time
+ * possible, but at a safer point in time
*/
- while (count && !tty->hw_stopped) {
+ while (count) {
size = count;
/* Adjust data size to the max data size */
- if (size > self->max_data_size) {
- DEBUG(1, __FUNCTION__
- "(), size %d to big, clipping to %d!\n",
- size, self->max_data_size);
+ if (size > self->max_data_size)
size = self->max_data_size;
- }
- /* Do we already have a buffer ready for transmit? */
+ /*
+ * Do we already have a buffer ready for transmit, or do
+ * we need to allocate a new frame
+ */
if (skb) {
/*
* Any room for more data at the end of the current
@@ -663,25 +701,18 @@
if (size > tailroom)
size = tailroom;
} else {
- /* Current transmit frame is full */
- DEBUG(1, __FUNCTION__ "(), flushing!\n");
- ircomm_tty_do_event(self,
- IRCOMM_TTY_DATA_REQUEST,
- skb, NULL);
- skb = self->tx_skb = NULL;
+ /*
+ * Current transmit frame is full, so break
+ * out, so we can send it as soon as possible
+ */
+ break;
}
- }
-
- /* Check if we need to allocate a new frame */
- if (!skb) {
- DEBUG(3, __FUNCTION__
- "(), allocating new buffer of size %d!\n",
- self->max_data_size+self->max_header_size);
+ } else {
/* Prepare a full sized frame */
skb = dev_alloc_skb(self->max_data_size+
self->max_header_size);
if (!skb) {
- /*restore_flags(flags);*/
+ restore_flags(flags);
return -ENOBUFS;
}
skb_reserve(skb, self->max_header_size);
@@ -694,12 +725,12 @@
else
memcpy(skb_put(skb,size), buf+len, size);
- DEBUG(1, __FUNCTION__ "(), size=%d\n", size);
-
count -= size;
len += size;
}
+ restore_flags(flags);
+
/*
* Schedule a new thread which will transmit the frame as soon
* as possible, but at a safe point in time. We do this so the
@@ -710,8 +741,6 @@
queue_task(&self->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
- /*restore_flags(flags);*/
-
return len;
}
@@ -725,6 +754,7 @@
static int ircomm_tty_write_room(struct tty_struct *tty)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+ unsigned long flags;
int ret;
ASSERT(self != NULL, return -1;);
@@ -734,10 +764,13 @@
if (tty->hw_stopped)
ret = 0;
else {
+ save_flags(flags);
+ cli();
if (self->tx_skb)
ret = self->max_data_size - self->tx_skb->len;
else
ret = self->max_data_size;
+ restore_flags(flags);
}
DEBUG(2, __FUNCTION__ "(), ret=%d\n", ret);
@@ -753,8 +786,27 @@
static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+ unsigned long orig_jiffies, poll_time;
+
+ DEBUG(0, __FUNCTION__ "()\n");
+
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- DEBUG(2, __FUNCTION__ "(), not impl\n");
+ orig_jiffies = jiffies;
+
+ /* Set poll time to 200 ms */
+ poll_time = MIN(timeout, MSECS_TO_JIFFIES(200));
+
+ while (self->tx_skb && self->tx_skb->len) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(poll_time);
+ if (signal_pending(current))
+ break;
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
+ break;
+ }
+ current->state = TASK_RUNNING;
}
/*
@@ -785,7 +837,6 @@
ircomm_param_request(self, IRCOMM_DTE, TRUE);
}
- DEBUG(1, __FUNCTION__"(), FLOW_STOP\n");
ircomm_flow_request(self->ircomm, FLOW_STOP);
}
@@ -829,10 +880,21 @@
static int ircomm_tty_chars_in_buffer(struct tty_struct *tty)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+ unsigned long flags;
+ int len = 0;
- DEBUG(4, __FUNCTION__ "()\n");
+ ASSERT(self != NULL, return -1;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
- return 0; /* We don't have any "buffer" */
+ save_flags(flags);
+ cli();
+
+ if (self->tx_skb)
+ len = self->tx_skb->len;
+
+ restore_flags(flags);
+
+ return len;
}
/*
@@ -846,7 +908,10 @@
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- DEBUG(0, __FUNCTION__"()\n");
+ DEBUG(2, __FUNCTION__"()\n");
+
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
if (!tty)
return;
@@ -889,8 +954,6 @@
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- DEBUG(2, __FUNCTION__"()\n");
-
ircomm_flow_request(self->ircomm, FLOW_START);
}
@@ -904,25 +967,13 @@
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- DEBUG(2, __FUNCTION__"()\n");
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
ircomm_flow_request(self->ircomm, FLOW_STOP);
}
/*
- * Function ircomm_tty_break (tty, break_state)
- *
- *
- *
- */
-static void ircomm_tty_break(struct tty_struct *tty, int break_state)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
-
- DEBUG(0, __FUNCTION__"(), not impl\n");
-}
-
-/*
* Function ircomm_check_modem_status (self)
*
* Check for any changes in the DCE's line settings. This function should
@@ -934,8 +985,6 @@
struct tty_struct *tty;
int status;
- DEBUG(4, __FUNCTION__ "()\n");
-
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -967,13 +1016,9 @@
DEBUG(2, __FUNCTION__ "(), CTS tx start...\n");
tty->hw_stopped = 0;
-
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
- && tty->ldisc.write_wakeup)
- {
- (tty->ldisc.write_wakeup)(tty);
- }
- wake_up_interruptible(&tty->write_wait);
+
+ queue_task(&self->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
return;
}
} else {
@@ -1045,35 +1090,6 @@
}
/*
- * Function ircomm_tty_disconnect_indication (instance, sap, reason, skb)
- *
- * Link disconnected
- *
- */
-static void ircomm_tty_disconnect_indication(void *instance, void *sap,
- LM_REASON reason,
- struct sk_buff *skb)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
-
- DEBUG(2, __FUNCTION__ "()\n");
-
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- if (!self->tty)
- return;
-
- /* Drop carrier */
- self->session.dce = IRCOMM_DELTA_CD;
- ircomm_tty_check_modem_status(self);
-#if 0
- /* Disconnect */
- tty_hangup(self->tty);
-#endif
-}
-
-/*
* Function ircomm_tty_flow_indication (instance, sap, cmd)
*
* This function is called by IrTTP when it wants us to slow down the
@@ -1093,18 +1109,17 @@
switch (cmd) {
case FLOW_START:
- DEBUG(1, __FUNCTION__ "(), hw start!\n");
+ DEBUG(2, __FUNCTION__ "(), hw start!\n");
tty->hw_stopped = 0;
-
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
- && tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
- wake_up_interruptible(&tty->write_wait);
+
+ /* ircomm_tty_do_softint will take care of the rest */
+ queue_task(&self->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
break;
default:
/* If we get here, something is very wrong, better stop */
case FLOW_STOP:
- DEBUG(1, __FUNCTION__ "(), hw stopped!\n");
+ DEBUG(2, __FUNCTION__ "(), hw stopped!\n");
tty->hw_stopped = 1;
break;
}
@@ -1114,6 +1129,8 @@
{
int ret=0;
+ ret += sprintf(buf+ret, "State: %s\n", ircomm_tty_state[self->state]);
+
ret += sprintf(buf+ret, "Service type: ");
if (self->service_type & IRCOMM_9_WIRE)
ret += sprintf(buf+ret, "9_WIRE");
@@ -1125,12 +1142,15 @@
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, "DTE status: ");
if (self->session.dte & IRCOMM_RTS)
ret += sprintf(buf+ret, "RTS|");
if (self->session.dte & IRCOMM_DTR)
ret += sprintf(buf+ret, "DTR|");
- ret--; /* remove the last | */
+ if (self->session.dte)
+ ret--; /* remove the last | */
ret += sprintf(buf+ret, "\n");
ret += sprintf(buf+ret, "DCE status: ");
@@ -1142,7 +1162,8 @@
ret += sprintf(buf+ret, "CD|");
if (self->session.dce & IRCOMM_RI)
ret += sprintf(buf+ret, "RI|");
- ret--; /* remove the last | */
+ if (self->session.dce)
+ ret--; /* remove the last | */
ret += sprintf(buf+ret, "\n");
ret += sprintf(buf+ret, "Configuration: ");
@@ -1171,7 +1192,8 @@
ret += sprintf(buf+ret, "ENQ_ACK_IN|");
if (self->session.flow_control & IRCOMM_ENQ_ACK_OUT)
ret += sprintf(buf+ret, "ENQ_ACK_OUT|");
- ret--; /* remove the last | */
+ if (self->session.flow_control)
+ ret--; /* remove the last | */
ret += sprintf(buf+ret, "\n");
ret += sprintf(buf+ret, "Flags: ");
@@ -1189,7 +1211,8 @@
ret += sprintf(buf+ret, "ASYNC_NORMAL_ACTIVE|");
if (self->flags & ASYNC_CALLOUT_ACTIVE)
ret += sprintf(buf+ret, "ASYNC_CALLOUT_ACTIVE|");
- ret--; /* remove the last | */
+ if (self->flags)
+ ret--; /* remove the last | */
ret += sprintf(buf+ret, "\n");
ret += sprintf(buf+ret, "Open count: %d\n", self->open_count);
@@ -1197,7 +1220,6 @@
ret += sprintf(buf+ret, "Hardware: %s\n",
self->tty->hw_stopped ? "Stopped" : "Running");
- exit:
ret += sprintf(buf+ret, "\n");
return ret;
}
@@ -1213,7 +1235,7 @@
int *eof, void *unused)
{
struct ircomm_tty_cb *self;
- int i, count = 0, l;
+ int count = 0, l;
off_t begin = 0;
self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)