patch-2.4.8 linux/drivers/s390/net/ctctty.c
Next file: linux/drivers/s390/net/ctctty.h
Previous file: linux/drivers/s390/net/ctcmain.c
Back to the patch index
Back to the overall index
- Lines: 736
- Date:
Wed Jul 25 14:12:02 2001
- Orig file:
v2.4.7/linux/drivers/s390/net/ctctty.c
- Orig date:
Wed Apr 11 19:02:28 2001
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/net/ctctty.c linux/drivers/s390/net/ctctty.c
@@ -1,5 +1,5 @@
/*
- * $Id: ctctty.c,v 1.1 2001/01/23 14:23:51 felfert Exp $
+ * $Id: ctctty.c,v 1.8 2001/05/16 16:28:31 felfert Exp $
*
* CTC / ESCON network driver, tty interface.
*
@@ -33,7 +33,23 @@
# include <linux/devfs_fs_kernel.h>
#endif
#include "ctctty.h"
-#include <net/dst.h>
+
+#if LINUX_VERSION_CODE < 0x020212
+typedef struct wait_queue wait_queue_t;
+typedef struct wait_queue *wait_queue_head_t;
+#define DECLARE_WAITQUEUE(wait, current) \
+ struct wait_queue wait = { current, NULL }
+#define init_waitqueue_head(x) *(x)=NULL
+#define __set_current_state(state_value) \
+ do { current->state = state_value; } while (0)
+#ifdef __SMP__
+#define set_current_state(state_value) \
+ do { __set_current_state(state_value); mb(); } while (0)
+#else
+#define set_current_state(state_value) __set_current_state(state_value)
+#endif
+#define init_MUTEX(x) *(x)=MUTEX
+#endif
#define CTC_TTY_MAJOR 43
#define CTC_TTY_MAX_DEVICES 64
@@ -45,6 +61,8 @@
#define CTC_ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */
#define CTC_ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */
#define CTC_ASYNC_HUP_NOTIFY 0x0001 /* Notify tty on hangups/closes */
+#define CTC_ASYNC_NETDEV_OPEN 0x0002 /* Underlying netdev is open */
+#define CTC_ASYNC_TX_LINESTAT 0x0004 /* Must send line status */
#define CTC_ASYNC_SPLIT_TERMIOS 0x0008 /* Sep. termios for dialin/out */
#define CTC_TTY_XMIT_SIZE 1024 /* Default bufsize for write */
#define CTC_SERIAL_XMIT_MAX 4000 /* Maximum bufsize for write */
@@ -54,14 +72,13 @@
typedef struct {
int magic;
int flags; /* defined in tty.h */
- int x_char; /* xon/xoff character */
int mcr; /* Modem control register */
int msr; /* Modem status register */
int lsr; /* Line status register */
int line;
int count; /* # of fd on device */
int blocked_open; /* # of blocked opens */
- net_device *netdev;
+ net_device *netdev;
struct sk_buff_head tx_queue; /* transmit queue */
struct sk_buff_head rx_queue; /* receive queue */
struct tty_struct *tty; /* Pointer to corresponding tty */
@@ -69,7 +86,8 @@
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
struct semaphore write_sem;
- struct tq_struct tq;
+ struct tq_struct tq;
+ struct timer_list stoptimer;
} ctc_tty_info;
/* Description of one CTC-tty */
@@ -88,7 +106,7 @@
#define MODEM_PARANOIA_CHECK
#define MODEM_DO_RESTART
-#define CTC_TTY_NAME "ttyZ"
+#define CTC_TTY_NAME "ctctty"
#ifdef CONFIG_DEVFS_FS
static char *ctc_ttyname = "ctc/" CTC_TTY_NAME "%d";
@@ -96,7 +114,12 @@
static char *ctc_ttyname = CTC_TTY_NAME;
#endif
-char *ctc_tty_revision = "$Revision: 1.1 $";
+char *ctc_tty_revision = "$Revision: 1.8 $";
+
+static __u32 ctc_tty_magic = CTC_ASYNC_MAGIC;
+static int ctc_tty_shuttingdown = 0;
+
+static spinlock_t ctc_tty_lock;
/* ctc_tty_try_read() is called from within ctc_tty_rcv_skb()
* to stuff incoming data directly into a tty's flip-buffer. If the
@@ -120,11 +143,11 @@
len = skb->len;
if (c >= len) {
memcpy(tty->flip.char_buf_ptr, skb->data, len);
+ memset(tty->flip.flag_buf_ptr, 0, len);
tty->flip.count += len;
tty->flip.char_buf_ptr += len;
- memset(tty->flip.flag_buf_ptr, 0, len);
tty->flip.flag_buf_ptr += len;
- queue_task(&tty->flip.tqueue, &tq_timer);
+ tty_flip_buffer_push(tty);
kfree_skb(skb);
return 1;
}
@@ -140,7 +163,7 @@
static int
ctc_tty_readmodem(ctc_tty_info *info)
{
- int ret = 0;
+ int ret = 1;
struct tty_struct *tty;
if ((tty = info->tty)) {
@@ -152,16 +175,19 @@
int len = skb->len;
if (len > c)
len = c;
- memcpy(tty->flip.char_buf_ptr, skb_pull(skb, len), len);
- tty->flip.count += len;
+ memcpy(tty->flip.char_buf_ptr, skb->data, len);
+ skb_pull(skb, len);
memset(tty->flip.flag_buf_ptr, 0, len);
+ tty->flip.count += len;
+ tty->flip.char_buf_ptr += len;
tty->flip.flag_buf_ptr += len;
- queue_task(&tty->flip.tqueue, &tq_timer);
- if (skb->len) {
+ tty_flip_buffer_push(tty);
+ if (skb->len > 0)
skb_queue_head(&info->rx_queue, skb);
- ret = 1;
- } else
+ else {
kfree_skb(skb);
+ ret = skb_queue_len(&info->rx_queue);
+ }
}
}
}
@@ -169,6 +195,25 @@
}
void
+ctc_tty_setcarrier(net_device *netdev, int on)
+{
+ int i;
+
+ if ((!driver) || ctc_tty_shuttingdown)
+ return;
+ for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
+ if (driver->info[i].netdev == netdev) {
+ ctc_tty_info *info = &driver->info[i];
+ if (on)
+ info->msr |= UART_MSR_DCD;
+ else
+ info->msr &= ~UART_MSR_DCD;
+ if ((info->flags & CTC_ASYNC_CHECK_CD) && (!on))
+ tty_hangup(info->tty);
+ }
+}
+
+void
ctc_tty_netif_rx(struct sk_buff *skb)
{
int i;
@@ -176,7 +221,7 @@
if (!skb)
return;
- if (!skb->dev) {
+ if ((!skb->dev) || (!driver) || ctc_tty_shuttingdown) {
dev_kfree_skb(skb);
return;
}
@@ -189,7 +234,35 @@
dev_kfree_skb(skb);
return;
}
- skb_pull(skb, sizeof(int));
+ if (skb->len < 6) {
+ dev_kfree_skb(skb);
+ return;
+ }
+ if (memcmp(skb->data, &ctc_tty_magic, sizeof(__u32))) {
+ dev_kfree_skb(skb);
+ return;
+ }
+ skb_pull(skb, sizeof(__u32));
+
+ i = *((int *)skb->data);
+ skb_pull(skb, sizeof(info->mcr));
+ if (i & UART_MCR_RTS) {
+ info->msr |= UART_MSR_CTS;
+ if (info->flags & CTC_ASYNC_CTS_FLOW)
+ info->tty->hw_stopped = 0;
+ } else {
+ info->msr &= ~UART_MSR_CTS;
+ if (info->flags & CTC_ASYNC_CTS_FLOW)
+ info->tty->hw_stopped = 1;
+ }
+ if (i & UART_MCR_DTR)
+ info->msr |= UART_MSR_DSR;
+ else
+ info->msr &= ~UART_MSR_DSR;
+ if (skb->len <= 0) {
+ kfree_skb(skb);
+ return;
+ }
/* Try to deliver directly via tty-flip-buf if queue is empty */
if (skb_queue_empty(&info->rx_queue))
if (ctc_tty_try_read(info, skb))
@@ -203,46 +276,70 @@
mark_bh(IMMEDIATE_BH);
}
-static void
-ctc_tty_dstfail(struct sk_buff *skb) {
- if (!skb)
- return;
- dev_kfree_skb(skb);
- return;
-}
-
-static struct dst_entry dst_e;
-static struct dst_ops dst_o;
-
static int
ctc_tty_tint(ctc_tty_info * info)
{
struct sk_buff *skb = skb_dequeue(&info->tx_queue);
+ int stopped = (info->tty->hw_stopped || info->tty->stopped);
+ int wake = 1;
int rc;
- int l;
- char c;
- if (!skb)
- return 0;
if (!info->netdev) {
- kfree(skb);
+ if (skb)
+ kfree(skb);
return 0;
}
- skb->dst = &dst_e;
- l = skb->len;
- c = *(skb->data);
- rc = info->netdev->hard_start_xmit(skb, info->netdev);
-printk(KERN_DEBUG "xmit: l=%d rc=%d '%02x'\n", l, rc, c);
- if (rc) {
+ if (info->flags & CTC_ASYNC_TX_LINESTAT) {
+ int skb_res = info->netdev->hard_header_len +
+ sizeof(info->mcr) + sizeof(__u32);
+ /* If we must update line status,
+ * create an empty dummy skb and insert it.
+ */
+ if (skb)
+ skb_queue_head(&info->tx_queue, skb);
+
+ skb = dev_alloc_skb(skb_res);
+ if (!skb) {
+ printk(KERN_WARNING
+ "ctc_tty: Out of memory in %s%d tint\n",
+ CTC_TTY_NAME, info->line);
+ return 1;
+ }
+ skb_reserve(skb, skb_res);
+ stopped = 0;
+ wake = 0;
+ }
+ if (!skb)
+ return 0;
+ if (stopped) {
skb_queue_head(&info->tx_queue, skb);
return 1;
+ }
+#if 0
+ if (skb->len > 0)
+ printk(KERN_DEBUG "tint: %d %02x\n", skb->len, *(skb->data));
+ else
+ printk(KERN_DEBUG "tint: %d STAT\n", skb->len);
+#endif
+ memcpy(skb_push(skb, sizeof(info->mcr)), &info->mcr, sizeof(info->mcr));
+ memcpy(skb_push(skb, sizeof(__u32)), &ctc_tty_magic, sizeof(__u32));
+ rc = info->netdev->hard_start_xmit(skb, info->netdev);
+ if (rc) {
+ skb_pull(skb, sizeof(info->mcr) + sizeof(__u32));
+ if (skb->len > 0)
+ skb_queue_head(&info->tx_queue, skb);
+ else
+ kfree_skb(skb);
} else {
struct tty_struct *tty = info->tty;
- info->lsr |= UART_LSR_TEMT;
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
- wake_up_interruptible(&tty->write_wait);
+
+ info->flags &= ~CTC_ASYNC_TX_LINESTAT;
+ if (tty) {
+ if (wake && (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+ }
}
return (skb_queue_empty(&info->tx_queue) ? 0 : 1);
}
@@ -274,6 +371,40 @@
}
static void
+ctc_tty_inject(ctc_tty_info *info, char c)
+{
+ int skb_res;
+ struct sk_buff *skb;
+
+ if (ctc_tty_shuttingdown)
+ return;
+ skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
+ sizeof(__u32) + 1;
+ skb = dev_alloc_skb(skb_res);
+ if (!skb) {
+ printk(KERN_WARNING
+ "ctc_tty: Out of memory in %s%d tx_inject\n",
+ CTC_TTY_NAME, info->line);
+ return;
+ }
+ skb_reserve(skb, skb_res);
+ *(skb_put(skb, 1)) = c;
+ skb_queue_head(&info->tx_queue, skb);
+ queue_task(&info->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static void
+ctc_tty_transmit_status(ctc_tty_info *info)
+{
+ if (ctc_tty_shuttingdown)
+ return;
+ info->flags |= CTC_ASYNC_TX_LINESTAT;
+ queue_task(&info->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static void
ctc_tty_change_speed(ctc_tty_info * info)
{
unsigned int cflag;
@@ -294,8 +425,12 @@
}
if (quot) {
info->mcr |= UART_MCR_DTR;
+ info->mcr |= UART_MCR_RTS;
+ ctc_tty_transmit_status(info);
} else {
info->mcr &= ~UART_MCR_DTR;
+ info->mcr &= ~UART_MCR_RTS;
+ ctc_tty_transmit_status(info);
return;
}
@@ -331,11 +466,24 @@
ctc_tty_change_speed(info);
info->flags |= CTC_ASYNC_INITIALIZED;
- info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
- info->netdev->open(info->netdev);
+ if (!(info->flags & CTC_ASYNC_NETDEV_OPEN))
+ info->netdev->open(info->netdev);
+ info->flags |= CTC_ASYNC_NETDEV_OPEN;
return 0;
}
+static void
+ctc_tty_stopdev(unsigned long data)
+{
+ ctc_tty_info *info = (ctc_tty_info *)data;
+
+ if ((!info) || (!info->netdev) ||
+ (info->flags & CTC_ASYNC_INITIALIZED))
+ return;
+ info->netdev->stop(info->netdev);
+ info->flags &= ~CTC_ASYNC_NETDEV_OPEN;
+}
+
/*
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
@@ -349,12 +497,11 @@
printk(KERN_DEBUG "Shutting down %s%d ....\n", CTC_TTY_NAME, info->line);
#endif
info->msr &= ~UART_MSR_RI;
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
- }
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- info->netdev->stop(info->netdev);
+ mod_timer(&info->stoptimer, jiffies + (10 * HZ));
skb_queue_purge(&info->tx_queue);
skb_queue_purge(&info->rx_queue);
info->flags &= ~CTC_ASYNC_INITIALIZED;
@@ -376,6 +523,8 @@
int total = 0;
ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+ if (ctc_tty_shuttingdown)
+ return 0;
if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_write"))
return 0;
if (!tty)
@@ -392,7 +541,8 @@
if (c <= 0)
break;
- skb_res = info->netdev->hard_header_len + sizeof(int);
+ skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
+ + sizeof(__u32);
skb = dev_alloc_skb(skb_res + c);
if (!skb) {
printk(KERN_WARNING
@@ -411,6 +561,7 @@
count -= c;
}
if (skb_queue_len(&info->tx_queue)) {
+ info->lsr &= ~UART_LSR_TEMT;
queue_task(&info->tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
@@ -457,6 +608,7 @@
return;
}
skb_queue_purge(&info->tx_queue);
+ info->lsr |= UART_LSR_TEMT;
restore_flags(flags);
wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
@@ -469,12 +621,14 @@
{
ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+ if (ctc_tty_shuttingdown)
+ return;
if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_flush_chars"))
return;
- if (skb_queue_len(&info->tx_queue)) {
- queue_task(&info->tq, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
- }
+ if (tty->stopped || tty->hw_stopped || (!skb_queue_len(&info->tx_queue)))
+ return;
+ queue_task(&info->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
}
/*
@@ -492,9 +646,10 @@
if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_throttle"))
return;
- if (I_IXOFF(tty))
- info->x_char = STOP_CHAR(tty);
info->mcr &= ~UART_MCR_RTS;
+ if (I_IXOFF(tty))
+ ctc_tty_inject(info, STOP_CHAR(tty));
+ ctc_tty_transmit_status(info);
}
static void
@@ -504,13 +659,10 @@
if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_unthrottle"))
return;
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- info->x_char = START_CHAR(tty);
- }
info->mcr |= UART_MCR_RTS;
+ if (I_IXOFF(tty))
+ ctc_tty_inject(info, START_CHAR(tty));
+ ctc_tty_transmit_status(info);
}
/*
@@ -573,6 +725,7 @@
ctc_tty_set_ctc_tty_info(ctc_tty_info * info, uint cmd, uint * value)
{
uint arg;
+ int old_mcr = info->mcr & (UART_MCR_RTS | UART_MCR_DTR);
get_user(arg, (uint *) value);
switch (cmd) {
@@ -581,24 +734,20 @@
printk(KERN_DEBUG "%s%d ioctl TIOCMBIS\n", CTC_TTY_NAME,
info->line);
#endif
- if (arg & TIOCM_RTS) {
+ if (arg & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
- }
- if (arg & TIOCM_DTR) {
+ if (arg & TIOCM_DTR)
info->mcr |= UART_MCR_DTR;
- }
break;
case TIOCMBIC:
#ifdef CTC_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "%s%d ioctl TIOCMBIC\n", CTC_TTY_NAME,
info->line);
#endif
- if (arg & TIOCM_RTS) {
+ if (arg & TIOCM_RTS)
info->mcr &= ~UART_MCR_RTS;
- }
- if (arg & TIOCM_DTR) {
+ if (arg & TIOCM_DTR)
info->mcr &= ~UART_MCR_DTR;
- }
break;
case TIOCMSET:
#ifdef CTC_DEBUG_MODEM_IOCTL
@@ -612,6 +761,8 @@
default:
return -EINVAL;
}
+ if ((info->mcr & (UART_MCR_RTS | UART_MCR_DTR)) != old_mcr)
+ ctc_tty_transmit_status(info);
return 0;
}
@@ -709,18 +860,30 @@
ctc_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
{
ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+ unsigned int cflag = tty->termios->c_cflag;
- if (!old_termios)
- ctc_tty_change_speed(info);
- else {
- if (tty->termios->c_cflag == old_termios->c_cflag)
- return;
- ctc_tty_change_speed(info);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- }
+ ctc_tty_change_speed(info);
+
+ /* Handle transition to B0 */
+ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) {
+ info->mcr &= ~(UART_MCR_DTR|UART_MCR_RTS);
+ ctc_tty_transmit_status(info);
+ }
+
+ /* Handle transition from B0 to other */
+ if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+ info->mcr |= UART_MCR_DTR;
+ if (!(tty->termios->c_cflag & CRTSCTS) ||
+ !test_bit(TTY_THROTTLED, &tty->flags)) {
+ info->mcr |= UART_MCR_RTS;
+ }
+ ctc_tty_transmit_status(info);
}
+
+ /* Handle turning off CRTSCTS */
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS))
+ tty->hw_stopped = 0;
}
/*
@@ -836,6 +999,7 @@
ctc_tty_open(struct tty_struct *tty, struct file *filp)
{
ctc_tty_info *info;
+ unsigned long saveflags;
int retval,
line;
@@ -851,9 +1015,11 @@
printk(KERN_DEBUG "ctc_tty_open %s%d, count = %d\n", tty->driver.name,
info->line, info->count);
#endif
+ spin_lock_irqsave(&ctc_tty_lock, saveflags);
info->count++;
tty->driver_data = info;
info->tty = tty;
+ spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
/*
* Start up serial port
*/
@@ -885,6 +1051,7 @@
ctc_tty_close(struct tty_struct *tty, struct file *filp)
{
ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+ unsigned long saveflags;
ulong flags;
ulong timeout;
@@ -958,7 +1125,9 @@
tty->driver.flush_buffer(tty);
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
+ spin_lock_irqsave(&ctc_tty_lock, saveflags);
info->tty = 0;
+ spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
tty->closing = 0;
if (info->blocked_open) {
set_current_state(TASK_INTERRUPTIBLE);
@@ -980,13 +1149,16 @@
ctc_tty_hangup(struct tty_struct *tty)
{
ctc_tty_info *info = (ctc_tty_info *)tty->driver_data;
+ unsigned long saveflags;
if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_hangup"))
return;
ctc_tty_shutdown(info);
info->count = 0;
info->flags &= ~CTC_ASYNC_NORMAL_ACTIVE;
+ spin_lock_irqsave(&ctc_tty_lock, saveflags);
info->tty = 0;
+ spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
wake_up_interruptible(&info->open_wait);
}
@@ -998,14 +1170,21 @@
static void
ctc_tty_task(ctc_tty_info *info)
{
+ unsigned long saveflags;
int again;
- again = ctc_tty_tint(info);
- again |= ctc_tty_readmodem(info);
- if (again) {
- queue_task(&info->tq, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
+ spin_lock_irqsave(&ctc_tty_lock, saveflags);
+ if ((!ctc_tty_shuttingdown) && info) {
+ again = ctc_tty_tint(info);
+ if (!again)
+ info->lsr |= UART_LSR_TEMT;
+ again |= ctc_tty_readmodem(info);
+ if (again) {
+ queue_task(&info->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
}
+ spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
}
int
@@ -1015,8 +1194,6 @@
ctc_tty_info *info;
struct tty_driver *device;
- dst_e.ops = &dst_o;
- dst_o.link_failure = ctc_tty_dstfail;
driver = kmalloc(sizeof(ctc_tty_driver), GFP_KERNEL);
if (driver == NULL) {
printk(KERN_WARNING "Out of memory in ctc_tty_modem_init\n");
@@ -1064,14 +1241,17 @@
for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) {
info = &driver->info[i];
init_MUTEX(&info->write_sem);
+#if LINUX_VERSION_CODE >= 0x020400
INIT_LIST_HEAD(&info->tq.list);
+#else
+ info->tq.next = NULL;
+#endif
info->tq.sync = 0;
info->tq.routine = (void *)(void *)ctc_tty_task;
info->tq.data = info;
info->magic = CTC_ASYNC_MAGIC;
info->line = i;
info->tty = 0;
- info->x_char = 0;
info->count = 0;
info->blocked_open = 0;
info->normal_termios = device->init_termios;
@@ -1079,6 +1259,10 @@
init_waitqueue_head(&info->close_wait);
skb_queue_head_init(&info->tx_queue);
skb_queue_head_init(&info->rx_queue);
+ init_timer(&info->stoptimer);
+ info->stoptimer.function = ctc_tty_stopdev;
+ info->stoptimer.data = (unsigned long)info;
+ info->mcr = UART_MCR_RTS;
}
return 0;
}
@@ -1118,8 +1302,10 @@
void
ctc_tty_unregister_netdev(net_device *dev) {
int i;
+ unsigned long saveflags;
ctc_tty_info *info = NULL;
+ spin_lock_irqsave(&ctc_tty_lock, saveflags);
for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
if (driver->info[i].netdev == dev) {
info = &driver->info[i];
@@ -1130,10 +1316,24 @@
skb_queue_purge(&info->tx_queue);
skb_queue_purge(&info->rx_queue);
}
+ spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
}
void
-ctc_tty_cleanup(void) {
- tty_unregister_driver(&driver->ctc_tty_device);
- kfree(driver);
+ctc_tty_cleanup(int final) {
+ unsigned long saveflags;
+
+ spin_lock_irqsave(&ctc_tty_lock, saveflags);
+ ctc_tty_shuttingdown = 1;
+ if (final) {
+ kfree(driver);
+ driver = NULL;
+ } else {
+ int i;
+
+ for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
+ driver->info[i].tq.routine = NULL;
+ tty_unregister_driver(&driver->ctc_tty_device);
+ }
+ spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)