|
@@ -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 @@ start:
|
|
|
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);
|
|
|
-
|
|
|
- if (!info->count)
|
|
|
- return;
|
|
|
+ __FILE__,__LINE__, info->device_name, port->count);
|
|
|
|
|
|
- if (tty_hung_up_p(filp))
|
|
|
- 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;
|
|
|
- }
|
|
|
+ WARN_ON(!port->count);
|
|
|
|
|
|
- info->count--;
|
|
|
-
|
|
|
- /* if at least one open remaining, leave hardware active */
|
|
|
- if (info->count)
|
|
|
+ if (tty_port_close_start(port, tty, filp) == 0)
|
|
|
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->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);
|
|
|
-
|
|
|
+ shutdown(info, tty);
|
|
|
+
|
|
|
+ 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;
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- if (debug_level >= DEBUG_LEVEL_INFO)
|
|
|
- printk("%s(%d):block_til_ready on %s\n",
|
|
|
- __FILE__,__LINE__, tty->driver->name );
|
|
|
-
|
|
|
- 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;
|
|
|
- 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++;
|
|
|
-
|
|
|
- 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);
|
|
|
+ MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
- if (extra_count)
|
|
|
- info->count++;
|
|
|
- info->blocked_open--;
|
|
|
+ spin_lock_irqsave(&info->lock,flags);
|
|
|
+ get_signals(info);
|
|
|
+ spin_unlock_irqrestore(&info->lock,flags);
|
|
|
|
|
|
- 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 (info->serial_signals & SerialSignal_DCD)
|
|
|
+ return 1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- if (!retval)
|
|
|
- info->flags |= ASYNC_NORMAL_ACTIVE;
|
|
|
+static void raise_dtr_rts(struct tty_port *port)
|
|
|
+{
|
|
|
+ MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
- return retval;
|
|
|
+ spin_lock_irqsave(&info->lock,flags);
|
|
|
+ info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
|
|
|
+ set_signals(info);
|
|
|
+ spin_unlock_irqrestore(&info->lock,flags);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
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:
|