diff options
Diffstat (limited to 'drivers/char/isicom.c')
-rw-r--r-- | drivers/char/isicom.c | 115 |
1 files changed, 25 insertions, 90 deletions
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 426bfdd7f3e..300d5bd6cd0 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -793,35 +793,30 @@ static inline void isicom_setup_board(struct isi_board *bp) { int channel; struct isi_port *port; - unsigned long flags; - spin_lock_irqsave(&bp->card_lock, flags); - if (bp->status & BOARD_ACTIVE) { - spin_unlock_irqrestore(&bp->card_lock, flags); - return; + bp->count++; + if (!(bp->status & BOARD_INIT)) { + port = bp->ports; + for (channel = 0; channel < bp->port_count; channel++, port++) + drop_dtr_rts(port); } - port = bp->ports; - bp->status |= BOARD_ACTIVE; - for (channel = 0; channel < bp->port_count; channel++, port++) - drop_dtr_rts(port); - spin_unlock_irqrestore(&bp->card_lock, flags); + bp->status |= BOARD_ACTIVE | BOARD_INIT; } -static int isicom_setup_port(struct tty_struct *tty) +/* Activate and thus setup board are protected from races against shutdown + by the tty_port mutex */ + +static int isicom_activate(struct tty_port *tport, struct tty_struct *tty) { - struct isi_port *port = tty->driver_data; + struct isi_port *port = container_of(tport, struct isi_port, port); struct isi_board *card = port->card; unsigned long flags; - if (port->port.flags & ASYNC_INITIALIZED) - return 0; - if (tty_port_alloc_xmit_buf(&port->port) < 0) + if (tty_port_alloc_xmit_buf(tport) < 0) return -ENOMEM; spin_lock_irqsave(&card->card_lock, flags); - clear_bit(TTY_IO_ERROR, &tty->flags); - if (port->port.count == 1) - card->count++; + isicom_setup_board(card); port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; @@ -832,9 +827,7 @@ static int isicom_setup_port(struct tty_struct *tty) outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base); InterruptTheCard(card->base); } - isicom_config_port(tty); - port->port.flags |= ASYNC_INITIALIZED; spin_unlock_irqrestore(&card->card_lock, flags); return 0; @@ -871,85 +864,37 @@ static struct tty_port *isicom_find_port(struct tty_struct *tty) return &port->port; } - + static int isicom_open(struct tty_struct *tty, struct file *filp) { struct isi_port *port; struct isi_board *card; struct tty_port *tport; - int error = 0; tport = isicom_find_port(tty); if (tport == NULL) return -ENODEV; port = container_of(tport, struct isi_port, port); card = &isi_card[BOARD(tty->index)]; - isicom_setup_board(card); - /* FIXME: locking on port.count etc */ - port->port.count++; - tty->driver_data = port; - tty_port_tty_set(&port->port, tty); - /* FIXME: Locking on Initialized flag */ - if (!test_bit(ASYNCB_INITIALIZED, &tport->flags)) - error = isicom_setup_port(tty); - if (error == 0) - error = tty_port_block_til_ready(&port->port, tty, filp); - return error; + return tty_port_open(tport, tty, filp); } /* close et all */ -static inline void isicom_shutdown_board(struct isi_board *bp) -{ - if (bp->status & BOARD_ACTIVE) - bp->status &= ~BOARD_ACTIVE; -} - /* card->lock HAS to be held */ static void isicom_shutdown_port(struct isi_port *port) { struct isi_board *card = port->card; - struct tty_struct *tty; - - tty = tty_port_tty_get(&port->port); - - if (!(port->port.flags & ASYNC_INITIALIZED)) { - tty_kref_put(tty); - return; - } - - tty_port_free_xmit_buf(&port->port); - port->port.flags &= ~ASYNC_INITIALIZED; - /* 3rd October 2000 : Vinayak P Risbud */ - tty_port_tty_set(&port->port, NULL); - - /*Fix done by Anil .S on 30-04-2001 - remote login through isi port has dtr toggle problem - due to which the carrier drops before the password prompt - appears on the remote end. Now we drop the dtr only if the - HUPCL(Hangup on close) flag is set for the tty*/ - - if (C_HUPCL(tty)) - /* drop dtr on this port */ - drop_dtr(port); - - /* any other port uninits */ - if (tty) - set_bit(TTY_IO_ERROR, &tty->flags); if (--card->count < 0) { pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n", card->base, card->count); card->count = 0; } - - /* last port was closed, shutdown that boad too */ - if (C_HUPCL(tty)) { - if (!card->count) - isicom_shutdown_board(card); - } - tty_kref_put(tty); + /* last port was closed, shutdown that board too */ + if (!card->count) + card->status &= BOARD_ACTIVE; } static void isicom_flush_buffer(struct tty_struct *tty) @@ -968,7 +913,7 @@ static void isicom_flush_buffer(struct tty_struct *tty) tty_wakeup(tty); } -static void isicom_close_port(struct tty_port *port) +static void isicom_shutdown(struct tty_port *port) { struct isi_port *ip = container_of(port, struct isi_port, port); struct isi_board *card = ip->card; @@ -977,12 +922,11 @@ static void isicom_close_port(struct tty_port *port) /* indicate to the card that no more data can be received on this port */ spin_lock_irqsave(&card->card_lock, flags); - if (port->flags & ASYNC_INITIALIZED) { - card->port_status &= ~(1 << ip->channel); - outw(card->port_status, card->base + 0x02); - } + card->port_status &= ~(1 << ip->channel); + outw(card->port_status, card->base + 0x02); isicom_shutdown_port(ip); spin_unlock_irqrestore(&card->card_lock, flags); + tty_port_free_xmit_buf(port); } static void isicom_close(struct tty_struct *tty, struct file *filp) @@ -991,12 +935,7 @@ static void isicom_close(struct tty_struct *tty, struct file *filp) struct tty_port *port = &ip->port; if (isicom_paranoia_check(ip, tty->name, "isicom_close")) return; - - if (tty_port_close_start(port, tty, filp) == 0) - return; - isicom_close_port(port); - isicom_flush_buffer(tty); - tty_port_close_end(port, tty); + tty_port_close(port, tty, filp); } /* write et all */ @@ -1326,15 +1265,9 @@ static void isicom_start(struct tty_struct *tty) static void isicom_hangup(struct tty_struct *tty) { struct isi_port *port = tty->driver_data; - unsigned long flags; if (isicom_paranoia_check(port, tty->name, "isicom_hangup")) return; - - spin_lock_irqsave(&port->card->card_lock, flags); - isicom_shutdown_port(port); - spin_unlock_irqrestore(&port->card->card_lock, flags); - tty_port_hangup(&port->port); } @@ -1367,6 +1300,8 @@ static const struct tty_operations isicom_ops = { static const struct tty_port_operations isicom_port_ops = { .carrier_raised = isicom_carrier_raised, .dtr_rts = isicom_dtr_rts, + .activate = isicom_activate, + .shutdown = isicom_shutdown, }; static int __devinit reset_card(struct pci_dev *pdev, |