Commit eeb46134 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

synclink_cs: Convert to tty_port

Use the tty port operations, add refcounting, and refactor a bit to make the
refcounting work cleanly.
Signed-off-by: default avatarAlan Cox <alan@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent fba85e01
......@@ -138,20 +138,15 @@ struct _input_signal_events {
*/
typedef struct _mgslpc_info {
struct tty_port port;
void *if_ptr; /* General purpose pointer (used by SPPP) */
int magic;
int flags;
int count; /* count of opens */
int line;
unsigned short close_delay;
unsigned short closing_wait; /* time to wait before closing */
struct mgsl_icount icount;
struct tty_struct *tty;
int timeout;
int x_char; /* xon/xoff character */
int blocked_open; /* # of blocked opens */
unsigned char read_status_mask;
unsigned char ignore_status_mask;
......@@ -170,9 +165,6 @@ typedef struct _mgslpc_info {
int rx_buf_count; /* total number of rx buffers */
int rx_frame_count; /* number of full rx buffers */
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
wait_queue_head_t status_event_wait_q;
wait_queue_head_t event_wait_q;
struct timer_list tx_timer; /* HDLC transmit timeout timer */
......@@ -375,7 +367,7 @@ static void irq_enable(MGSLPC_INFO *info, unsigned char channel, unsigned short
static void rx_start(MGSLPC_INFO *info);
static void rx_stop(MGSLPC_INFO *info);
static void tx_start(MGSLPC_INFO *info);
static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty);
static void tx_stop(MGSLPC_INFO *info);
static void tx_set_idle(MGSLPC_INFO *info);
......@@ -389,7 +381,8 @@ static void async_mode(MGSLPC_INFO *info);
static void tx_timeout(unsigned long context);
static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg);
static int carrier_raised(struct tty_port *port);
static void raise_dtr_rts(struct tty_port *port);
#if SYNCLINK_GENERIC_HDLC
#define dev_to_port(D) (dev_to_hdlc(D)->priv)
......@@ -410,7 +403,7 @@ static void release_resources(MGSLPC_INFO *info);
static void mgslpc_add_device(MGSLPC_INFO *info);
static void mgslpc_remove_device(MGSLPC_INFO *info);
static bool rx_get_frame(MGSLPC_INFO *info);
static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty);
static void rx_reset_buffers(MGSLPC_INFO *info);
static int rx_alloc_buffers(MGSLPC_INFO *info);
static void rx_free_buffers(MGSLPC_INFO *info);
......@@ -421,7 +414,7 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id);
* Bottom half interrupt handlers
*/
static void bh_handler(struct work_struct *work);
static void bh_transmit(MGSLPC_INFO *info);
static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty);
static void bh_status(MGSLPC_INFO *info);
/*
......@@ -432,10 +425,10 @@ static int tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
static int get_stats(MGSLPC_INFO *info, struct mgsl_icount __user *user_icount);
static int get_params(MGSLPC_INFO *info, MGSL_PARAMS __user *user_params);
static int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params);
static int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params, struct tty_struct *tty);
static int get_txidle(MGSLPC_INFO *info, int __user *idle_mode);
static int set_txidle(MGSLPC_INFO *info, int idle_mode);
static int set_txenable(MGSLPC_INFO *info, int enable);
static int set_txenable(MGSLPC_INFO *info, int enable, struct tty_struct *tty);
static int tx_abort(MGSLPC_INFO *info);
static int set_rxenable(MGSLPC_INFO *info, int enable);
static int wait_events(MGSLPC_INFO *info, int __user *mask);
......@@ -474,7 +467,7 @@ static struct tty_driver *serial_driver;
/* number of characters left in xmit buffer before we ask for more */
#define WAKEUP_CHARS 256
static void mgslpc_change_params(MGSLPC_INFO *info);
static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty);
static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout);
/* PCMCIA prototypes */
......@@ -517,6 +510,11 @@ static void ldisc_receive_buf(struct tty_struct *tty,
}
}
static const struct tty_port_operations mgslpc_port_ops = {
.carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts
};
static int mgslpc_probe(struct pcmcia_device *link)
{
MGSLPC_INFO *info;
......@@ -532,12 +530,12 @@ static int mgslpc_probe(struct pcmcia_device *link)
}
info->magic = MGSLPC_MAGIC;
tty_port_init(&info->port);
info->port.ops = &mgslpc_port_ops;
INIT_WORK(&info->task, bh_handler);
info->max_frame_size = 4096;
info->close_delay = 5*HZ/10;
info->closing_wait = 30*HZ;
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
info->port.close_delay = 5*HZ/10;
info->port.closing_wait = 30*HZ;
init_waitqueue_head(&info->status_event_wait_q);
init_waitqueue_head(&info->event_wait_q);
spin_lock_init(&info->lock);
......@@ -784,7 +782,7 @@ static void tx_release(struct tty_struct *tty)
spin_lock_irqsave(&info->lock,flags);
if (!info->tx_enabled)
tx_start(info);
tx_start(info, tty);
spin_unlock_irqrestore(&info->lock,flags);
}
......@@ -823,6 +821,7 @@ static int bh_action(MGSLPC_INFO *info)
static void bh_handler(struct work_struct *work)
{
MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task);
struct tty_struct *tty;
int action;
if (!info)
......@@ -833,6 +832,7 @@ static void bh_handler(struct work_struct *work)
__FILE__,__LINE__,info->device_name);
info->bh_running = true;
tty = tty_port_tty_get(&info->port);
while((action = bh_action(info)) != 0) {
......@@ -844,10 +844,10 @@ static void bh_handler(struct work_struct *work)
switch (action) {
case BH_RECEIVE:
while(rx_get_frame(info));
while(rx_get_frame(info, tty));
break;
case BH_TRANSMIT:
bh_transmit(info);
bh_transmit(info, tty);
break;
case BH_STATUS:
bh_status(info);
......@@ -859,14 +859,14 @@ static void bh_handler(struct work_struct *work)
}
}
tty_kref_put(tty);
if (debug_level >= DEBUG_LEVEL_BH)
printk( "%s(%d):bh_handler(%s) exit\n",
__FILE__,__LINE__,info->device_name);
}
static void bh_transmit(MGSLPC_INFO *info)
static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty)
{
struct tty_struct *tty = info->tty;
if (debug_level >= DEBUG_LEVEL_BH)
printk("bh_transmit() entry on %s\n", info->device_name);
......@@ -945,12 +945,11 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
issue_command(info, CHA, CMD_RXFIFO);
}
static void rx_ready_async(MGSLPC_INFO *info, int tcd)
static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty)
{
unsigned char data, status, flag;
int fifo_count;
int work = 0;
struct tty_struct *tty = info->tty;
struct mgsl_icount *icount = &info->icount;
if (tcd) {
......@@ -1013,7 +1012,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd)
}
static void tx_done(MGSLPC_INFO *info)
static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty)
{
if (!info->tx_active)
return;
......@@ -1042,7 +1041,7 @@ static void tx_done(MGSLPC_INFO *info)
else
#endif
{
if (info->tty->stopped || info->tty->hw_stopped) {
if (tty->stopped || tty->hw_stopped) {
tx_stop(info);
return;
}
......@@ -1050,7 +1049,7 @@ static void tx_done(MGSLPC_INFO *info)
}
}
static void tx_ready(MGSLPC_INFO *info)
static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty)
{
unsigned char fifo_count = 32;
int c;
......@@ -1062,7 +1061,7 @@ static void tx_ready(MGSLPC_INFO *info)
if (!info->tx_active)
return;
} else {
if (info->tty->stopped || info->tty->hw_stopped) {
if (tty->stopped || tty->hw_stopped) {
tx_stop(info);
return;
}
......@@ -1099,7 +1098,7 @@ static void tx_ready(MGSLPC_INFO *info)
}
}
static void cts_change(MGSLPC_INFO *info)
static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty)
{
get_signals(info);
if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
......@@ -1112,14 +1111,14 @@ static void cts_change(MGSLPC_INFO *info)
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
if (info->flags & ASYNC_CTS_FLOW) {
if (info->tty->hw_stopped) {
if (info->port.flags & ASYNC_CTS_FLOW) {
if (tty->hw_stopped) {
if (info->serial_signals & SerialSignal_CTS) {
if (debug_level >= DEBUG_LEVEL_ISR)
printk("CTS tx start...");
if (info->tty)
info->tty->hw_stopped = 0;
tx_start(info);
if (tty)
tty->hw_stopped = 0;
tx_start(info, tty);
info->pending_bh |= BH_TRANSMIT;
return;
}
......@@ -1127,8 +1126,8 @@ static void cts_change(MGSLPC_INFO *info)
if (!(info->serial_signals & SerialSignal_CTS)) {
if (debug_level >= DEBUG_LEVEL_ISR)
printk("CTS tx stop...");
if (info->tty)
info->tty->hw_stopped = 1;
if (tty)
tty->hw_stopped = 1;
tx_stop(info);
}
}
......@@ -1136,7 +1135,7 @@ static void cts_change(MGSLPC_INFO *info)
info->pending_bh |= BH_STATUS;
}
static void dcd_change(MGSLPC_INFO *info)
static void dcd_change(MGSLPC_INFO *info, struct tty_struct *tty)
{
get_signals(info);
if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
......@@ -1158,17 +1157,17 @@ static void dcd_change(MGSLPC_INFO *info)
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
if (info->flags & ASYNC_CHECK_CD) {
if (info->port.flags & ASYNC_CHECK_CD) {
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s CD now %s...", info->device_name,
(info->serial_signals & SerialSignal_DCD) ? "on" : "off");
if (info->serial_signals & SerialSignal_DCD)
wake_up_interruptible(&info->open_wait);
wake_up_interruptible(&info->port.open_wait);
else {
if (debug_level >= DEBUG_LEVEL_ISR)
printk("doing serial hangup...");
if (info->tty)
tty_hangup(info->tty);
if (tty)
tty_hangup(tty);
}
}
info->pending_bh |= BH_STATUS;
......@@ -1214,6 +1213,7 @@ static void ri_change(MGSLPC_INFO *info)
static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
{
MGSLPC_INFO *info = dev_id;
struct tty_struct *tty;
unsigned short isr;
unsigned char gis, pis;
int count=0;
......@@ -1224,6 +1224,8 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
if (!(info->p_dev->_locked))
return IRQ_HANDLED;
tty = tty_port_tty_get(&info->port);
spin_lock(&info->lock);
while ((gis = read_reg(info, CHA + GIS))) {
......@@ -1239,9 +1241,9 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
if (gis & (BIT1 + BIT0)) {
isr = read_reg16(info, CHB + ISR);
if (isr & IRQ_DCD)
dcd_change(info);
dcd_change(info, tty);
if (isr & IRQ_CTS)
cts_change(info);
cts_change(info, tty);
}
if (gis & (BIT3 + BIT2))
{
......@@ -1258,8 +1260,8 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
}
if (isr & IRQ_BREAK_ON) {
info->icount.brk++;
if (info->flags & ASYNC_SAK)
do_SAK(info->tty);
if (info->port.flags & ASYNC_SAK)
do_SAK(tty);
}
if (isr & IRQ_RXTIME) {
issue_command(info, CHA, CMD_RXFIFO_READ);
......@@ -1268,7 +1270,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
if (info->params.mode == MGSL_MODE_HDLC)
rx_ready_hdlc(info, isr & IRQ_RXEOM);
else
rx_ready_async(info, isr & IRQ_RXEOM);
rx_ready_async(info, isr & IRQ_RXEOM, tty);
}
/* transmit IRQs */
......@@ -1277,14 +1279,14 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
info->icount.txabort++;
else
info->icount.txunder++;
tx_done(info);
tx_done(info, tty);
}
else if (isr & IRQ_ALLSENT) {
info->icount.txok++;
tx_done(info);
tx_done(info, tty);
}
else if (isr & IRQ_TXFIFO)
tx_ready(info);
tx_ready(info, tty);
}
if (gis & BIT7) {
pis = read_reg(info, CHA + PIS);
......@@ -1308,6 +1310,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
}
spin_unlock(&info->lock);
tty_kref_put(tty);
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):mgslpc_isr(%d)exit.\n",
......@@ -1318,14 +1321,14 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
/* Initialize and start device.
*/
static int startup(MGSLPC_INFO * info)
static int startup(MGSLPC_INFO * info, struct tty_struct *tty)
{
int retval = 0;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):startup(%s)\n",__FILE__,__LINE__,info->device_name);
if (info->flags & ASYNC_INITIALIZED)
if (info->port.flags & ASYNC_INITIALIZED)
return 0;
if (!info->tx_buf) {
......@@ -1352,30 +1355,30 @@ static int startup(MGSLPC_INFO * info)
retval = adapter_test(info);
if ( retval ) {
if (capable(CAP_SYS_ADMIN) && info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
if (capable(CAP_SYS_ADMIN) && tty)
set_bit(TTY_IO_ERROR, &tty->flags);
release_resources(info);
return retval;
}
/* program hardware for current parameters */
mgslpc_change_params(info);
mgslpc_change_params(info, tty);
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
if (tty)
clear_bit(TTY_IO_ERROR, &tty->flags);
info->flags |= ASYNC_INITIALIZED;
info->port.flags |= ASYNC_INITIALIZED;
return 0;
}
/* Called by mgslpc_close() and mgslpc_hangup() to shutdown hardware
*/
static void shutdown(MGSLPC_INFO * info)
static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
{
unsigned long flags;
if (!(info->flags & ASYNC_INITIALIZED))
if (!(info->port.flags & ASYNC_INITIALIZED))
return;
if (debug_level >= DEBUG_LEVEL_INFO)
......@@ -1402,7 +1405,7 @@ static void shutdown(MGSLPC_INFO * info)
/* TODO:disable interrupts instead of reset to preserve signal states */
reset_device(info);
if (!info->tty || info->tty->termios->c_cflag & HUPCL) {
if (!tty || tty->termios->c_cflag & HUPCL) {
info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
set_signals(info);
}
......@@ -1411,13 +1414,13 @@ static void shutdown(MGSLPC_INFO * info)
release_resources(info);
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);
info->flags &= ~ASYNC_INITIALIZED;
info->port.flags &= ~ASYNC_INITIALIZED;
}
static void mgslpc_program_hw(MGSLPC_INFO *info)
static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
{
unsigned long flags;
......@@ -1443,7 +1446,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info)
port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI);
get_signals(info);
if (info->netcount || info->tty->termios->c_cflag & CREAD)
if (info->netcount || (tty && (tty->termios->c_cflag & CREAD)))
rx_start(info);
spin_unlock_irqrestore(&info->lock,flags);
......@@ -1451,19 +1454,19 @@ static void mgslpc_program_hw(MGSLPC_INFO *info)
/* Reconfigure adapter based on new parameters
*/
static void mgslpc_change_params(MGSLPC_INFO *info)
static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
{
unsigned cflag;
int bits_per_char;
if (!info->tty || !info->tty->termios)
if (!tty || !tty->termios)
return;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_change_params(%s)\n",
__FILE__,__LINE__, info->device_name );
cflag = info->tty->termios->c_cflag;
cflag = tty->termios->c_cflag;
/* if B0 rate (hangup) specified then negate DTR and RTS */
/* otherwise assert DTR and RTS */
......@@ -1510,7 +1513,7 @@ static void mgslpc_change_params(MGSLPC_INFO *info)
* current data rate.
*/
if (info->params.data_rate <= 460800) {
info->params.data_rate = tty_get_baud_rate(info->tty);
info->params.data_rate = tty_get_baud_rate(tty);
}
if ( info->params.data_rate ) {
......@@ -1520,24 +1523,24 @@ static void mgslpc_change_params(MGSLPC_INFO *info)
info->timeout += HZ/50; /* Add .02 seconds of slop */
if (cflag & CRTSCTS)
info->flags |= ASYNC_CTS_FLOW;
info->port.flags |= ASYNC_CTS_FLOW;
else
info->flags &= ~ASYNC_CTS_FLOW;
info->port.flags &= ~ASYNC_CTS_FLOW;
if (cflag & CLOCAL)
info->flags &= ~ASYNC_CHECK_CD;
info->port.flags &= ~ASYNC_CHECK_CD;
else
info->flags |= ASYNC_CHECK_CD;
info->port.flags |= ASYNC_CHECK_CD;
/* process tty input control flags */
info->read_status_mask = 0;
if (I_INPCK(info->tty))
if (I_INPCK(tty))
info->read_status_mask |= BIT7 | BIT6;
if (I_IGNPAR(info->tty))
if (I_IGNPAR(tty))
info->ignore_status_mask |= BIT7 | BIT6;
mgslpc_program_hw(info);
mgslpc_program_hw(info, tty);
}
/* Add a character to the transmit buffer
......@@ -1597,7 +1600,7 @@ static void mgslpc_flush_chars(struct tty_struct *tty)
spin_lock_irqsave(&info->lock,flags);
if (!info->tx_active)
tx_start(info);
tx_start(info, tty);
spin_unlock_irqrestore(&info->lock,flags);
}
......@@ -1659,7 +1662,7 @@ static int mgslpc_write(struct tty_struct * tty,
if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
spin_lock_irqsave(&info->lock,flags);
if (!info->tx_active)
tx_start(info);
tx_start(info, tty);
spin_unlock_irqrestore(&info->lock,flags);
}
cleanup:
......@@ -1764,7 +1767,7 @@ static void mgslpc_send_xchar(struct tty_struct *tty, char ch)
if (ch) {
spin_lock_irqsave(&info->lock,flags);
if (!info->tx_enabled)
tx_start(info);
tx_start(info, tty);
spin_unlock_irqrestore(&info->lock,flags);
}
}
......@@ -1862,7 +1865,7 @@ static int get_params(MGSLPC_INFO * info, MGSL_PARAMS __user *user_params)
*
* Returns: 0 if success, otherwise error code
*/
static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params)
static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params, struct tty_struct *tty)
{
unsigned long flags;
MGSL_PARAMS tmp_params;
......@@ -1883,7 +1886,7 @@ static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params)
memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS));
spin_unlock_irqrestore(&info->lock,flags);
mgslpc_change_params(info);
mgslpc_change_params(info, tty);
return 0;
}
......@@ -1944,7 +1947,7 @@ static int set_interface(MGSLPC_INFO * info, int if_mode)
return 0;
}
static int set_txenable(MGSLPC_INFO * info, int enable)
static int set_txenable(MGSLPC_INFO * info, int enable, struct tty_struct *tty)
{
unsigned long flags;
......@@ -1954,7 +1957,7 @@ static int set_txenable(MGSLPC_INFO * info, int enable)
spin_lock_irqsave(&info->lock,flags);
if (enable) {
if (!info->tx_enabled)
tx_start(info);
tx_start(info, tty);
} else {
if (info->tx_enabled)
tx_stop(info);
......@@ -2263,6 +2266,11 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
int error;
struct mgsl_icount cnow; /* kernel counter temps */
struct serial_icounter_struct __user *p_cuser; /* user space */
void __user *argp = (void __user *)arg;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
......@@ -2277,22 +2285,11 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
return -EIO;
}
return ioctl_common(info, cmd, arg);
}
static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg)
{
int error;
struct mgsl_icount cnow; /* kernel counter temps */
struct serial_icounter_struct __user *p_cuser; /* user space */
void __user *argp = (void __user *)arg;
unsigned long flags;
switch (cmd) {
case MGSL_IOCGPARAMS:
return get_params(info, argp);
case MGSL_IOCSPARAMS:
return set_params(info, argp);
return set_params(info, argp, tty);
case MGSL_IOCGTXIDLE:
return get_txidle(info, argp);
case MGSL_IOCSTXIDLE:
......@@ -2302,7 +2299,7 @@ static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg)
case MGSL_IOCSIF:
return set_interface(info,(int)arg);
case MGSL_IOCTXENABLE:
return set_txenable(info,(int)arg);
return set_txenable(info,(int)arg, tty);
case MGSL_IOCRXENABLE:
return set_rxenable(info,(int)arg);
case MGSL_IOCTXABORT:
......@@ -2369,7 +2366,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
== RELEVANT_IFLAG(old_termios->c_iflag)))
return;
mgslpc_change_params(info);
mgslpc_change_params(info, tty);
/* Handle transition to B0 status */
if (old_termios->c_cflag & CBAUD &&
......@@ -2404,81 +2401,34 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
static void mgslpc_close(struct tty_struct *tty, struct file * filp)
{
MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
struct tty_port *port = &info->port;
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_close"))
return;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_close(%s) entry, count=%d\n",
__FILE__,__LINE__, info->device_name, info->count);
__FILE__,__LINE__, info->device_name, port->count);
if (!info->count)
return;
WARN_ON(!port->count);
if (tty_hung_up_p(filp))
if (tty_port_close_start(port, tty, filp) == 0)
goto cleanup;
if ((tty->count == 1) && (info->count != 1)) {
/*
* tty->count is 1 and the tty structure will be freed.
* info->count should be one in this case.
* if it's not, correct it so that the port is shutdown.
*/
printk("mgslpc_close: bad refcount; tty->count is 1, "
"info->count is %d\n", info->count);
info->count = 1;
}
info->count--;
/* if at least one open remaining, leave hardware active */
if (info->count)
goto cleanup;
info->flags |= ASYNC_CLOSING;
/* set tty->closing to notify line discipline to
* only process XON/XOFF characters. Only the N_TTY
* discipline appears to use this (ppp does not).
*/
tty->closing = 1;
/* wait for transmit data to clear all layers */
if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_close(%s) calling tty_wait_until_sent\n",
__FILE__,__LINE__, info->device_name );
tty_wait_until_sent(tty, info->closing_wait);
}
if (info->flags & ASYNC_INITIALIZED)
if (port->flags & ASYNC_INITIALIZED)
mgslpc_wait_until_sent(tty, info->timeout);
mgslpc_flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(info, tty);
shutdown(info);
tty->closing = 0;
info->tty = NULL;
if (info->blocked_open) {
if (info->close_delay) {
msleep_interruptible(jiffies_to_msecs(info->close_delay));
}
wake_up_interruptible(&info->open_wait);
}
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&info->close_wait);
tty_port_close_end(port, tty);
tty_port_tty_set(port, NULL);
cleanup:
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_close(%s) exit, count=%d\n", __FILE__,__LINE__,
tty->driver->name, info->count);
tty->driver->name, port->count);
}
/* Wait until the transmitter is empty.
......@@ -2498,7 +2448,7 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout)
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent"))
return;
if (!(info->flags & ASYNC_INITIALIZED))
if (!(info->port.flags & ASYNC_INITIALIZED))
goto exit;
orig_jiffies = jiffies;
......@@ -2559,120 +2509,40 @@ static void mgslpc_hangup(struct tty_struct *tty)
return;
mgslpc_flush_buffer(tty);
shutdown(info);
info->count = 0;
info->flags &= ~ASYNC_NORMAL_ACTIVE;
info->tty = NULL;
wake_up_interruptible(&info->open_wait);
shutdown(info, tty);
tty_port_hangup(&info->port);
}
/* Block the current process until the specified port
* is ready to be opened.
*/
static int block_til_ready(struct tty_struct *tty, struct file *filp,
MGSLPC_INFO *info)
static int carrier_raised(struct tty_port *port)
{
DECLARE_WAITQUEUE(wait, current);
int retval;
bool do_clocal = false;
bool extra_count = false;
MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready on %s\n",
__FILE__,__LINE__, tty->driver->name );
spin_lock_irqsave(&info->lock,flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
/* nonblock mode is set or port is not enabled */
/* just verify that callout device is not active */
info->flags |= ASYNC_NORMAL_ACTIVE;
if (info->serial_signals & SerialSignal_DCD)
return 1;
return 0;
}
if (tty->termios->c_cflag & CLOCAL)
do_clocal = true;
/* Wait for carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in
* this loop, info->count is dropped by one, so that
* mgslpc_close() knows when to free things. We restore it upon
* exit, either normal or abnormal.
*/
retval = 0;
add_wait_queue(&info->open_wait, &wait);
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready before block on %s count=%d\n",
__FILE__,__LINE__, tty->driver->name, info->count );
}
spin_lock_irqsave(&info->lock, flags);
if (!tty_hung_up_p(filp)) {
extra_count = true;
info->count--;
}
spin_unlock_irqrestore(&info->lock, flags);
info->blocked_open++;
static void raise_dtr_rts(struct tty_port *port)
{
MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
unsigned long flags;
while (1) {
if ((tty->termios->c_cflag & CBAUD)) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){
retval = (info->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS;
break;
}
spin_lock_irqsave(&info->lock,flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
if (!(info->flags & ASYNC_CLOSING) &&
(do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
break;
}
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready blocking on %s count=%d\n",
__FILE__,__LINE__, tty->driver->name, info->count );
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
if (extra_count)
info->count++;
info->blocked_open--;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready after blocking on %s count=%d\n",
__FILE__,__LINE__, tty->driver->name, info->count );
if (!retval)
info->flags |= ASYNC_NORMAL_ACTIVE;
return retval;
}
static int mgslpc_open(struct tty_struct *tty, struct file * filp)
{
MGSLPC_INFO *info;
struct tty_port *port;
int retval, line;
unsigned long flags;
......@@ -2691,23 +2561,24 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open"))
return -ENODEV;
port = &info->port;
tty->driver_data = info;
info->tty = tty;
tty_port_tty_set(port, tty);
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_open(%s), old ref count = %d\n",
__FILE__,__LINE__,tty->driver->name, info->count);
__FILE__,__LINE__,tty->driver->name, port->count);
/* If port is closing, signal caller to try again */
if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){
if (info->flags & ASYNC_CLOSING)
interruptible_sleep_on(&info->close_wait);
retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING){
if (port->flags & ASYNC_CLOSING)
interruptible_sleep_on(&port->close_wait);
retval = ((port->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
goto cleanup;
}
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
spin_lock_irqsave(&info->netlock, flags);
if (info->netcount) {
......@@ -2715,17 +2586,19 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
spin_unlock_irqrestore(&info->netlock, flags);
goto cleanup;
}
info->count++;
spin_lock(&port->lock);
port->count++;
spin_unlock(&port->lock);
spin_unlock_irqrestore(&info->netlock, flags);
if (info->count == 1) {
if (port->count == 1) {
/* 1st open on this device, init hardware */
retval = startup(info);
retval = startup(info, tty);
if (retval < 0)
goto cleanup;
}
retval = block_til_ready(tty, filp, info);
retval = tty_port_block_til_ready(&info->port, tty, filp);
if (retval) {
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready(%s) returned %d\n",
......@@ -2739,13 +2612,6 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
retval = 0;
cleanup:
if (retval) {
if (tty->count == 1)
info->tty = NULL; /* tty layer will release tty struct */
if(info->count)
info->count--;
}
return retval;
}
......@@ -3500,7 +3366,7 @@ static void rx_start(MGSLPC_INFO *info)
info->rx_enabled = true;
}
static void tx_start(MGSLPC_INFO *info)
static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty)
{
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):tx_start(%s)\n",
......@@ -3524,11 +3390,11 @@ static void tx_start(MGSLPC_INFO *info)
if (info->params.mode == MGSL_MODE_ASYNC) {
if (!info->tx_active) {
info->tx_active = true;
tx_ready(info);
tx_ready(info, tty);
}
} else {
info->tx_active = true;
tx_ready(info);
tx_ready(info, tty);
mod_timer(&info->tx_timer, jiffies +
msecs_to_jiffies(5000));
}
......@@ -3849,13 +3715,12 @@ static void rx_reset_buffers(MGSLPC_INFO *info)
*
* Returns true if frame returned, otherwise false
*/
static bool rx_get_frame(MGSLPC_INFO *info)
static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty)
{
unsigned short status;
RXBUF *buf;
unsigned int framesize = 0;
unsigned long flags;
struct tty_struct *tty = info->tty;
bool return_frame = false;
if (info->rx_frame_count == 0)
......@@ -4075,7 +3940,11 @@ static void tx_timeout(unsigned long context)
hdlcdev_tx_done(info);
else
#endif
bh_transmit(info);
{
struct tty_struct *tty = tty_port_tty_get(&info->port);
bh_transmit(info, tty);
tty_kref_put(tty);
}
}
#if SYNCLINK_GENERIC_HDLC
......@@ -4094,11 +3963,12 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
unsigned short parity)
{
MGSLPC_INFO *info = dev_to_port(dev);
struct tty_struct *tty;
unsigned char new_encoding;
unsigned short new_crctype;
/* return error if TTY interface open */
if (info->count)
if (info->port.count)
return -EBUSY;
switch (encoding)
......@@ -4123,8 +3993,11 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
info->params.crc_type = new_crctype;
/* if network interface up, reprogram hardware */
if (info->netcount)
mgslpc_program_hw(info);
if (info->netcount) {
tty = tty_port_tty_get(&info->port);
mgslpc_program_hw(info, tty);
tty_kref_put(tty);
}
return 0;
}
......@@ -4165,8 +4038,11 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
/* start hardware transmitter if necessary */
spin_lock_irqsave(&info->lock,flags);
if (!info->tx_active)
tx_start(info);
if (!info->tx_active) {
struct tty_struct *tty = tty_port_tty_get(&info->port);
tx_start(info, tty);
tty_kref_put(tty);
}
spin_unlock_irqrestore(&info->lock,flags);
return 0;
......@@ -4183,6 +4059,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
static int hdlcdev_open(struct net_device *dev)
{
MGSLPC_INFO *info = dev_to_port(dev);
struct tty_struct *tty;
int rc;
unsigned long flags;
......@@ -4195,7 +4072,7 @@ static int hdlcdev_open(struct net_device *dev)
/* arbitrate between network and tty opens */
spin_lock_irqsave(&info->netlock, flags);
if (info->count != 0 || info->netcount != 0) {
if (info->port.count != 0 || info->netcount != 0) {
printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name);
spin_unlock_irqrestore(&info->netlock, flags);
return -EBUSY;
......@@ -4203,17 +4080,19 @@ static int hdlcdev_open(struct net_device *dev)
info->netcount=1;
spin_unlock_irqrestore(&info->netlock, flags);
tty = tty_port_tty_get(&info->port);
/* claim resources and init adapter */
if ((rc = startup(info)) != 0) {
if ((rc = startup(info, tty)) != 0) {
tty_kref_put(tty);
spin_lock_irqsave(&info->netlock, flags);
info->netcount=0;
spin_unlock_irqrestore(&info->netlock, flags);
return rc;
}
/* assert DTR and RTS, apply hardware settings */
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
mgslpc_program_hw(info);
mgslpc_program_hw(info, tty);
tty_kref_put(tty);
/* enable network layer transmit */
dev->trans_start = jiffies;
......@@ -4241,6 +4120,7 @@ static int hdlcdev_open(struct net_device *dev)
static int hdlcdev_close(struct net_device *dev)
{
MGSLPC_INFO *info = dev_to_port(dev);
struct tty_struct *tty = tty_port_tty_get(&info->port);
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
......@@ -4249,8 +4129,8 @@ static int hdlcdev_close(struct net_device *dev)
netif_stop_queue(dev);
/* shutdown adapter and release resources */
shutdown(info);
shutdown(info, tty);
tty_kref_put(tty);
hdlc_close(dev);
spin_lock_irqsave(&info->netlock, flags);
......@@ -4281,7 +4161,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name);
/* return error if TTY interface open */
if (info->count)
if (info->port.count)
return -EBUSY;
if (cmd != SIOCWANDEV)
......@@ -4354,8 +4234,11 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
info->params.clock_speed = 0;
/* if network interface up, reprogram hardware */
if (info->netcount)
mgslpc_program_hw(info);
if (info->netcount) {
struct tty_struct *tty = tty_port_tty_get(&info->port);
mgslpc_program_hw(info, tty);
tty_kref_put(tty);
}
return 0;
default:
......
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