diff options
-rw-r--r-- | drivers/char/epca.c | 172 | ||||
-rw-r--r-- | drivers/char/tty_port.c | 3 |
2 files changed, 26 insertions, 149 deletions
diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 7a697055e4f6..71225d1af9ee 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c | |||
@@ -432,58 +432,15 @@ static void pc_close(struct tty_struct *tty, struct file *filp) | |||
432 | return; | 432 | return; |
433 | port = &ch->port; | 433 | port = &ch->port; |
434 | 434 | ||
435 | spin_lock_irqsave(&port->lock, flags); | 435 | if (tty_port_close_start(port, tty, filp) == 0) |
436 | if (tty_hung_up_p(filp)) { | ||
437 | spin_unlock_irqrestore(&port->lock, flags); | ||
438 | return; | ||
439 | } | ||
440 | if (port->count-- > 1) { | ||
441 | /* Begin channel is open more than once */ | ||
442 | /* | ||
443 | * Return without doing anything. Someone might still | ||
444 | * be using the channel. | ||
445 | */ | ||
446 | spin_unlock_irqrestore(&port->lock, flags); | ||
447 | return; | 436 | return; |
448 | } | ||
449 | /* Port open only once go ahead with shutdown & reset */ | ||
450 | WARN_ON(port->count < 0); | ||
451 | 437 | ||
452 | /* | ||
453 | * Let the rest of the driver know the channel is being closed. | ||
454 | * This becomes important if an open is attempted before close | ||
455 | * is finished. | ||
456 | */ | ||
457 | port->flags |= ASYNC_CLOSING; | ||
458 | tty->closing = 1; | ||
459 | |||
460 | spin_unlock_irqrestore(&port->lock, flags); | ||
461 | |||
462 | if (port->flags & ASYNC_INITIALIZED) { | ||
463 | /* Setup an event to indicate when the | ||
464 | transmit buffer empties */ | ||
465 | setup_empty_event(tty, ch); | ||
466 | /* 30 seconds timeout */ | ||
467 | tty_wait_until_sent(tty, 3000); | ||
468 | } | ||
469 | pc_flush_buffer(tty); | 438 | pc_flush_buffer(tty); |
470 | tty_ldisc_flush(tty); | ||
471 | shutdown(ch, tty); | 439 | shutdown(ch, tty); |
472 | 440 | ||
473 | spin_lock_irqsave(&port->lock, flags); | 441 | tty_port_close_end(port, tty); |
474 | tty->closing = 0; | 442 | ch->event = 0; /* FIXME: review ch->event locking */ |
475 | ch->event = 0; | ||
476 | tty_port_tty_set(port, NULL); | 443 | tty_port_tty_set(port, NULL); |
477 | spin_unlock_irqrestore(&port->lock, flags); | ||
478 | |||
479 | if (port->blocked_open) { | ||
480 | if (ch->close_delay) | ||
481 | msleep_interruptible(jiffies_to_msecs(ch->close_delay)); | ||
482 | wake_up_interruptible(&port->open_wait); | ||
483 | } | ||
484 | port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | | ||
485 | ASYNC_CLOSING); | ||
486 | wake_up_interruptible(&port->close_wait); | ||
487 | } | 444 | } |
488 | 445 | ||
489 | static void shutdown(struct channel *ch, struct tty_struct *tty) | 446 | static void shutdown(struct channel *ch, struct tty_struct *tty) |
@@ -527,7 +484,6 @@ static void shutdown(struct channel *ch, struct tty_struct *tty) | |||
527 | static void pc_hangup(struct tty_struct *tty) | 484 | static void pc_hangup(struct tty_struct *tty) |
528 | { | 485 | { |
529 | struct channel *ch; | 486 | struct channel *ch; |
530 | struct tty_port *port; | ||
531 | 487 | ||
532 | /* | 488 | /* |
533 | * verifyChannel returns the channel from the tty struct if it is | 489 | * verifyChannel returns the channel from the tty struct if it is |
@@ -536,19 +492,13 @@ static void pc_hangup(struct tty_struct *tty) | |||
536 | ch = verifyChannel(tty); | 492 | ch = verifyChannel(tty); |
537 | if (ch != NULL) { | 493 | if (ch != NULL) { |
538 | unsigned long flags; | 494 | unsigned long flags; |
539 | port = &ch->port; | ||
540 | 495 | ||
541 | pc_flush_buffer(tty); | 496 | pc_flush_buffer(tty); |
542 | tty_ldisc_flush(tty); | 497 | tty_ldisc_flush(tty); |
543 | shutdown(ch, tty); | 498 | shutdown(ch, tty); |
544 | 499 | ||
545 | spin_lock_irqsave(&port->lock, flags); | ||
546 | port->tty = NULL; | ||
547 | ch->event = 0; /* FIXME: review locking of ch->event */ | 500 | ch->event = 0; /* FIXME: review locking of ch->event */ |
548 | port->count = 0; | 501 | tty_port_hangup(&ch->port); |
549 | port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED); | ||
550 | spin_unlock_irqrestore(&port->lock, flags); | ||
551 | wake_up_interruptible(&port->open_wait); | ||
552 | } | 502 | } |
553 | } | 503 | } |
554 | 504 | ||
@@ -792,98 +742,18 @@ static void pc_flush_chars(struct tty_struct *tty) | |||
792 | } | 742 | } |
793 | } | 743 | } |
794 | 744 | ||
795 | static int block_til_ready(struct tty_struct *tty, | 745 | static int epca_carrier_raised(struct tty_port *port) |
796 | struct file *filp, struct channel *ch) | ||
797 | { | 746 | { |
798 | DECLARE_WAITQUEUE(wait, current); | 747 | struct channel *ch = container_of(port, struct channel, port); |
799 | int retval, do_clocal = 0; | 748 | if (ch->imodem & ch->dcd) |
800 | unsigned long flags; | 749 | return 1; |
801 | struct tty_port *port = &ch->port; | ||
802 | |||
803 | if (tty_hung_up_p(filp)) { | ||
804 | if (port->flags & ASYNC_HUP_NOTIFY) | ||
805 | retval = -EAGAIN; | ||
806 | else | ||
807 | retval = -ERESTARTSYS; | ||
808 | return retval; | ||
809 | } | ||
810 | |||
811 | /* | ||
812 | * If the device is in the middle of being closed, then block until | ||
813 | * it's done, and then try again. | ||
814 | */ | ||
815 | if (port->flags & ASYNC_CLOSING) { | ||
816 | interruptible_sleep_on(&port->close_wait); | ||
817 | |||
818 | if (port->flags & ASYNC_HUP_NOTIFY) | ||
819 | return -EAGAIN; | ||
820 | else | ||
821 | return -ERESTARTSYS; | ||
822 | } | ||
823 | |||
824 | if (filp->f_flags & O_NONBLOCK) { | ||
825 | /* | ||
826 | * If non-blocking mode is set, then make the check up front | ||
827 | * and then exit. | ||
828 | */ | ||
829 | port->flags |= ASYNC_NORMAL_ACTIVE; | ||
830 | return 0; | ||
831 | } | ||
832 | if (tty->termios->c_cflag & CLOCAL) | ||
833 | do_clocal = 1; | ||
834 | /* Block waiting for the carrier detect and the line to become free */ | ||
835 | |||
836 | retval = 0; | ||
837 | add_wait_queue(&port->open_wait, &wait); | ||
838 | |||
839 | spin_lock_irqsave(&port->lock, flags); | ||
840 | /* We dec count so that pc_close will know when to free things */ | ||
841 | if (!tty_hung_up_p(filp)) | ||
842 | port->count--; | ||
843 | port->blocked_open++; | ||
844 | while (1) { | ||
845 | set_current_state(TASK_INTERRUPTIBLE); | ||
846 | if (tty_hung_up_p(filp) || | ||
847 | !(port->flags & ASYNC_INITIALIZED)) { | ||
848 | if (port->flags & ASYNC_HUP_NOTIFY) | ||
849 | retval = -EAGAIN; | ||
850 | else | ||
851 | retval = -ERESTARTSYS; | ||
852 | break; | ||
853 | } | ||
854 | if (!(port->flags & ASYNC_CLOSING) && | ||
855 | (do_clocal || (ch->imodem & ch->dcd))) | ||
856 | break; | ||
857 | if (signal_pending(current)) { | ||
858 | retval = -ERESTARTSYS; | ||
859 | break; | ||
860 | } | ||
861 | spin_unlock_irqrestore(&port->lock, flags); | ||
862 | /* | ||
863 | * Allow someone else to be scheduled. We will occasionally go | ||
864 | * through this loop until one of the above conditions change. | ||
865 | * The below schedule call will allow other processes to enter | ||
866 | * and prevent this loop from hogging the cpu. | ||
867 | */ | ||
868 | schedule(); | ||
869 | spin_lock_irqsave(&port->lock, flags); | ||
870 | } | ||
871 | |||
872 | __set_current_state(TASK_RUNNING); | ||
873 | remove_wait_queue(&port->open_wait, &wait); | ||
874 | if (!tty_hung_up_p(filp)) | ||
875 | port->count++; | ||
876 | port->blocked_open--; | ||
877 | |||
878 | spin_unlock_irqrestore(&port->lock, flags); | ||
879 | |||
880 | if (retval) | ||
881 | return retval; | ||
882 | |||
883 | port->flags |= ASYNC_NORMAL_ACTIVE; | ||
884 | return 0; | 750 | return 0; |
885 | } | 751 | } |
886 | 752 | ||
753 | static void epca_raise_dtr_rts(struct tty_port *port0 | ||
754 | { | ||
755 | } | ||
756 | |||
887 | static int pc_open(struct tty_struct *tty, struct file *filp) | 757 | static int pc_open(struct tty_struct *tty, struct file *filp) |
888 | { | 758 | { |
889 | struct channel *ch; | 759 | struct channel *ch; |
@@ -978,7 +848,7 @@ static int pc_open(struct tty_struct *tty, struct file *filp) | |||
978 | port->flags |= ASYNC_INITIALIZED; | 848 | port->flags |= ASYNC_INITIALIZED; |
979 | spin_unlock_irqrestore(&port->lock, flags); | 849 | spin_unlock_irqrestore(&port->lock, flags); |
980 | 850 | ||
981 | retval = block_til_ready(tty, filp, ch); | 851 | retval = tty_port_block_til_ready(port, tty, filp); |
982 | if (retval) | 852 | if (retval) |
983 | return retval; | 853 | return retval; |
984 | /* | 854 | /* |
@@ -1058,6 +928,11 @@ static const struct tty_operations pc_ops = { | |||
1058 | .break_ctl = pc_send_break | 928 | .break_ctl = pc_send_break |
1059 | }; | 929 | }; |
1060 | 930 | ||
931 | static const struct tty_port_operations epca_port_ops = { | ||
932 | .carrier_raised = epca_carrier_raised, | ||
933 | .raise_dtr_rts = epca_raise_dtr_rts, | ||
934 | }; | ||
935 | |||
1061 | static int info_open(struct tty_struct *tty, struct file *filp) | 936 | static int info_open(struct tty_struct *tty, struct file *filp) |
1062 | { | 937 | { |
1063 | return 0; | 938 | return 0; |
@@ -1393,6 +1268,7 @@ static void post_fep_init(unsigned int crd) | |||
1393 | u16 tseg, rseg; | 1268 | u16 tseg, rseg; |
1394 | 1269 | ||
1395 | tty_port_init(&ch->port); | 1270 | tty_port_init(&ch->port); |
1271 | ch->port.ops - &epca_port_ops; | ||
1396 | ch->brdchan = bc; | 1272 | ch->brdchan = bc; |
1397 | ch->mailbox = gd; | 1273 | ch->mailbox = gd; |
1398 | INIT_WORK(&ch->tqueue, do_softint); | 1274 | INIT_WORK(&ch->tqueue, do_softint); |
@@ -1526,7 +1402,7 @@ static void post_fep_init(unsigned int crd) | |||
1526 | ch->fepstartca = 0; | 1402 | ch->fepstartca = 0; |
1527 | ch->fepstopca = 0; | 1403 | ch->fepstopca = 0; |
1528 | 1404 | ||
1529 | ch->close_delay = 50; | 1405 | ch->port.close_delay = 50; |
1530 | 1406 | ||
1531 | spin_unlock_irqrestore(&epca_lock, flags); | 1407 | spin_unlock_irqrestore(&epca_lock, flags); |
1532 | } | 1408 | } |
@@ -1647,7 +1523,7 @@ static void doevent(int crd) | |||
1647 | if (event & MODEMCHG_IND) { | 1523 | if (event & MODEMCHG_IND) { |
1648 | /* A modem signal change has been indicated */ | 1524 | /* A modem signal change has been indicated */ |
1649 | ch->imodem = mstat; | 1525 | ch->imodem = mstat; |
1650 | if (ch->port.flags & ASYNC_CHECK_CD) { | 1526 | if (test_bit(ASYNC_CHECK_CD, &ch->port.flags)) { |
1651 | /* We are now receiving dcd */ | 1527 | /* We are now receiving dcd */ |
1652 | if (mstat & ch->dcd) | 1528 | if (mstat & ch->dcd) |
1653 | wake_up_interruptible(&ch->port.open_wait); | 1529 | wake_up_interruptible(&ch->port.open_wait); |
@@ -1894,9 +1770,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) | |||
1894 | * that the driver will wait on carrier detect. | 1770 | * that the driver will wait on carrier detect. |
1895 | */ | 1771 | */ |
1896 | if (ts->c_cflag & CLOCAL) | 1772 | if (ts->c_cflag & CLOCAL) |
1897 | ch->port.flags &= ~ASYNC_CHECK_CD; | 1773 | clear_bit(ASYNC_CHECK_CD, &ch->port.flags); |
1898 | else | 1774 | else |
1899 | ch->port.flags |= ASYNC_CHECK_CD; | 1775 | set_bit(ASYNC_CHECK_CD, &ch->port.flags); |
1900 | mval = ch->m_dtr | ch->m_rts; | 1776 | mval = ch->m_dtr | ch->m_rts; |
1901 | } /* End CBAUD not detected */ | 1777 | } /* End CBAUD not detected */ |
1902 | iflag = termios2digi_i(ch, ts->c_iflag); | 1778 | iflag = termios2digi_i(ch, ts->c_iflag); |
@@ -2373,7 +2249,7 @@ static void do_softint(struct work_struct *work) | |||
2373 | if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { | 2249 | if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { |
2374 | tty_hangup(tty); | 2250 | tty_hangup(tty); |
2375 | wake_up_interruptible(&ch->port.open_wait); | 2251 | wake_up_interruptible(&ch->port.open_wait); |
2376 | ch->port.flags &= ~ASYNC_NORMAL_ACTIVE; | 2252 | clear_bit(ASYNC_NORMAL_ACTIVE, &ch->port.flags); |
2377 | } | 2253 | } |
2378 | } | 2254 | } |
2379 | tty_kref_put(tty); | 2255 | tty_kref_put(tty); |
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c index b3175f54fe05..b580fcf629f8 100644 --- a/drivers/char/tty_port.c +++ b/drivers/char/tty_port.c | |||
@@ -286,7 +286,8 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f | |||
286 | port->flags |= ASYNC_CLOSING; | 286 | port->flags |= ASYNC_CLOSING; |
287 | tty->closing = 1; | 287 | tty->closing = 1; |
288 | spin_unlock_irqrestore(&port->lock, flags); | 288 | spin_unlock_irqrestore(&port->lock, flags); |
289 | if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) | 289 | if (port->flags & ASYNC_INITIALIZED && |
290 | port->closing_wait != ASYNC_CLOSING_WAIT_NONE) | ||
290 | tty_wait_until_sent(tty, port->closing_wait); | 291 | tty_wait_until_sent(tty, port->closing_wait); |
291 | return 1; | 292 | return 1; |
292 | } | 293 | } |