aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@redhat.com>2009-01-02 08:46:10 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-02 13:19:39 -0500
commit36c621d82b956ff6ff72273f848af53e6c581aba (patch)
treeedd387d8275a8f25277d264ffed94e8d1c2ba048
parent3b6826b250633361f08a6427a4ac0035e5d88c72 (diff)
tty: Introduce a tty_port generic block_til_ready
Start sucking more commonality out of the drivers into a single piece of core code. Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/char/isicom.c79
-rw-r--r--drivers/char/mxser.c71
-rw-r--r--drivers/char/riscom8.c86
-rw-r--r--drivers/char/synclink.c1
-rw-r--r--drivers/char/tty_port.c105
-rw-r--r--drivers/char/vme_scc.c6
-rw-r--r--include/linux/tty.h2
7 files changed, 115 insertions, 235 deletions
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index db53db91ae4a..bac55cf44243 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -838,82 +838,6 @@ static int isicom_carrier_raised(struct tty_port *port)
838 return (ip->status & ISI_DCD)?1 : 0; 838 return (ip->status & ISI_DCD)?1 : 0;
839} 839}
840 840
841static int block_til_ready(struct tty_struct *tty, struct file *filp,
842 struct isi_port *ip)
843{
844 struct tty_port *port = &ip->port;
845 int do_clocal = 0, retval;
846 unsigned long flags;
847 DECLARE_WAITQUEUE(wait, current);
848 int cd;
849
850 /* block if port is in the process of being closed */
851
852 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
853 pr_dbg("block_til_ready: close in progress.\n");
854 interruptible_sleep_on(&port->close_wait);
855 if (port->flags & ASYNC_HUP_NOTIFY)
856 return -EAGAIN;
857 else
858 return -ERESTARTSYS;
859 }
860
861 /* if non-blocking mode is set ... */
862
863 if ((filp->f_flags & O_NONBLOCK) ||
864 (tty->flags & (1 << TTY_IO_ERROR))) {
865 pr_dbg("block_til_ready: non-block mode.\n");
866 port->flags |= ASYNC_NORMAL_ACTIVE;
867 return 0;
868 }
869
870 if (C_CLOCAL(tty))
871 do_clocal = 1;
872
873 /* block waiting for DCD to be asserted, and while
874 callout dev is busy */
875 retval = 0;
876 add_wait_queue(&port->open_wait, &wait);
877
878 spin_lock_irqsave(&port->lock, flags);
879 if (!tty_hung_up_p(filp))
880 port->count--;
881 port->blocked_open++;
882 spin_unlock_irqrestore(&port->lock, flags);
883
884 while (1) {
885 tty_port_raise_dtr_rts(port);
886
887 set_current_state(TASK_INTERRUPTIBLE);
888 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
889 if (port->flags & ASYNC_HUP_NOTIFY)
890 retval = -EAGAIN;
891 else
892 retval = -ERESTARTSYS;
893 break;
894 }
895 cd = tty_port_carrier_raised(port);
896 if (!(port->flags & ASYNC_CLOSING) &&
897 (do_clocal || cd))
898 break;
899 if (signal_pending(current)) {
900 retval = -ERESTARTSYS;
901 break;
902 }
903 schedule();
904 }
905 set_current_state(TASK_RUNNING);
906 remove_wait_queue(&port->open_wait, &wait);
907 spin_lock_irqsave(&port->lock, flags);
908 if (!tty_hung_up_p(filp))
909 port->count++;
910 port->blocked_open--;
911 if (retval == 0)
912 port->flags |= ASYNC_NORMAL_ACTIVE;
913 spin_unlock_irqrestore(&port->lock, flags);
914 return 0;
915}
916
917static int isicom_open(struct tty_struct *tty, struct file *filp) 841static int isicom_open(struct tty_struct *tty, struct file *filp)
918{ 842{
919 struct isi_port *port; 843 struct isi_port *port;
@@ -940,12 +864,13 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
940 864
941 isicom_setup_board(card); 865 isicom_setup_board(card);
942 866
867 /* FIXME: locking on port.count etc */
943 port->port.count++; 868 port->port.count++;
944 tty->driver_data = port; 869 tty->driver_data = port;
945 tty_port_tty_set(&port->port, tty); 870 tty_port_tty_set(&port->port, tty);
946 error = isicom_setup_port(tty); 871 error = isicom_setup_port(tty);
947 if (error == 0) 872 if (error == 0)
948 error = block_til_ready(tty, filp, port); 873 error = tty_port_block_til_ready(&port->port, tty, filp);
949 return error; 874 return error;
950} 875}
951 876
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index e2471cf1ee95..08ba6eb1a380 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -558,75 +558,6 @@ static void mxser_raise_dtr_rts(struct tty_port *port)
558 spin_unlock_irqrestore(&mp->slock, flags); 558 spin_unlock_irqrestore(&mp->slock, flags);
559} 559}
560 560
561static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
562 struct mxser_port *mp)
563{
564 DECLARE_WAITQUEUE(wait, current);
565 int retval;
566 int do_clocal = 0;
567 unsigned long flags;
568 int cd;
569 struct tty_port *port = &mp->port;
570
571 /*
572 * If non-blocking mode is set, or the port is not enabled,
573 * then make the check up front and then exit.
574 */
575 if ((filp->f_flags & O_NONBLOCK) ||
576 test_bit(TTY_IO_ERROR, &tty->flags)) {
577 port->flags |= ASYNC_NORMAL_ACTIVE;
578 return 0;
579 }
580
581 if (tty->termios->c_cflag & CLOCAL)
582 do_clocal = 1;
583
584 /*
585 * Block waiting for the carrier detect and the line to become
586 * free (i.e., not in use by the callout). While we are in
587 * this loop, port->count is dropped by one, so that
588 * mxser_close() knows when to free things. We restore it upon
589 * exit, either normal or abnormal.
590 */
591 retval = 0;
592 add_wait_queue(&port->open_wait, &wait);
593
594 spin_lock_irqsave(&port->lock, flags);
595 if (!tty_hung_up_p(filp))
596 port->count--;
597 port->blocked_open++;
598 spin_unlock_irqrestore(&port->lock, flags);
599 while (1) {
600 tty_port_raise_dtr_rts(port);
601 set_current_state(TASK_INTERRUPTIBLE);
602 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
603 if (port->flags & ASYNC_HUP_NOTIFY)
604 retval = -EAGAIN;
605 else
606 retval = -ERESTARTSYS;
607 break;
608 }
609 cd = tty_port_carrier_raised(port);
610 if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd))
611 break;
612 if (signal_pending(current)) {
613 retval = -ERESTARTSYS;
614 break;
615 }
616 schedule();
617 }
618 set_current_state(TASK_RUNNING);
619 remove_wait_queue(&port->open_wait, &wait);
620 spin_lock_irqsave(&port->lock, flags);
621 if (!tty_hung_up_p(filp))
622 port->count++;
623 port->blocked_open--;
624 if (retval == 0)
625 port->flags |= ASYNC_NORMAL_ACTIVE;
626 spin_unlock_irqrestore(&port->lock, flags);
627 return 0;
628}
629
630static int mxser_set_baud(struct tty_struct *tty, long newspd) 561static int mxser_set_baud(struct tty_struct *tty, long newspd)
631{ 562{
632 struct mxser_port *info = tty->driver_data; 563 struct mxser_port *info = tty->driver_data;
@@ -1110,7 +1041,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
1110 if (retval) 1041 if (retval)
1111 return retval; 1042 return retval;
1112 1043
1113 retval = mxser_block_til_ready(tty, filp, info); 1044 retval = tty_port_block_til_ready(&info->port, tty, filp);
1114 if (retval) 1045 if (retval)
1115 return retval; 1046 return retval;
1116 1047
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 14662d7aa628..af34c2054a09 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -874,90 +874,6 @@ static int carrier_raised(struct tty_port *port)
874 return CD; 874 return CD;
875} 875}
876 876
877static int block_til_ready(struct tty_struct *tty, struct file *filp,
878 struct riscom_port *rp)
879{
880 DECLARE_WAITQUEUE(wait, current);
881 int retval;
882 int do_clocal = 0;
883 int CD;
884 unsigned long flags;
885 struct tty_port *port = &rp->port;
886
887 /*
888 * If the device is in the middle of being closed, then block
889 * until it's done, and then try again.
890 */
891 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
892 interruptible_sleep_on(&port->close_wait);
893 if (port->flags & ASYNC_HUP_NOTIFY)
894 return -EAGAIN;
895 else
896 return -ERESTARTSYS;
897 }
898
899 /*
900 * If non-blocking mode is set, or the port is not enabled,
901 * then make the check up front and then exit.
902 */
903 if ((filp->f_flags & O_NONBLOCK) ||
904 (tty->flags & (1 << TTY_IO_ERROR))) {
905 port->flags |= ASYNC_NORMAL_ACTIVE;
906 return 0;
907 }
908
909 if (C_CLOCAL(tty))
910 do_clocal = 1;
911
912 /*
913 * Block waiting for the carrier detect and the line to become
914 * free (i.e., not in use by the callout). While we are in
915 * this loop, info->count is dropped by one, so that
916 * rs_close() knows when to free things. We restore it upon
917 * exit, either normal or abnormal.
918 */
919 retval = 0;
920 add_wait_queue(&port->open_wait, &wait);
921
922 spin_lock_irqsave(&port->lock, flags);
923 if (!tty_hung_up_p(filp))
924 port->count--;
925 port->blocked_open++;
926 spin_unlock_irqrestore(&port->lock, flags);
927
928 while (1) {
929
930 CD = tty_port_carrier_raised(port);
931 set_current_state(TASK_INTERRUPTIBLE);
932 if (tty_hung_up_p(filp) ||
933 !(port->flags & ASYNC_INITIALIZED)) {
934 if (port->flags & ASYNC_HUP_NOTIFY)
935 retval = -EAGAIN;
936 else
937 retval = -ERESTARTSYS;
938 break;
939 }
940 if (!(port->flags & ASYNC_CLOSING) &&
941 (do_clocal || CD))
942 break;
943 if (signal_pending(current)) {
944 retval = -ERESTARTSYS;
945 break;
946 }
947 schedule();
948 }
949 __set_current_state(TASK_RUNNING);
950 remove_wait_queue(&port->open_wait, &wait);
951 spin_lock_irqsave(&port->lock, flags);
952 if (!tty_hung_up_p(filp))
953 port->count++;
954 port->blocked_open--;
955 if (retval == 0)
956 port->flags |= ASYNC_NORMAL_ACTIVE;
957 spin_unlock_irqrestore(&port->lock, flags);
958 return 0;
959}
960
961static int rc_open(struct tty_struct *tty, struct file *filp) 877static int rc_open(struct tty_struct *tty, struct file *filp)
962{ 878{
963 int board; 879 int board;
@@ -984,7 +900,7 @@ static int rc_open(struct tty_struct *tty, struct file *filp)
984 900
985 error = rc_setup_port(bp, port); 901 error = rc_setup_port(bp, port);
986 if (error == 0) 902 if (error == 0)
987 error = block_til_ready(tty, filp, port); 903 error = tty_port_block_til_ready(&port->port, tty, filp);
988 return error; 904 return error;
989} 905}
990 906
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index ac9f21e18c3f..0ded4ed3da3c 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -3401,6 +3401,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
3401 set_current_state(TASK_RUNNING); 3401 set_current_state(TASK_RUNNING);
3402 remove_wait_queue(&port->open_wait, &wait); 3402 remove_wait_queue(&port->open_wait, &wait);
3403 3403
3404 /* FIXME: Racy on hangup during close wait */
3404 if (extra_count) 3405 if (extra_count)
3405 port->count++; 3406 port->count++;
3406 port->blocked_open--; 3407 port->blocked_open--;
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
index 9f418bca4a22..ff94182b3813 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/char/tty_port.c
@@ -151,3 +151,108 @@ void tty_port_raise_dtr_rts(struct tty_port *port)
151 port->ops->raise_dtr_rts(port); 151 port->ops->raise_dtr_rts(port);
152} 152}
153EXPORT_SYMBOL(tty_port_raise_dtr_rts); 153EXPORT_SYMBOL(tty_port_raise_dtr_rts);
154
155/**
156 * tty_port_block_til_ready - Waiting logic for tty open
157 * @port: the tty port being opened
158 * @tty: the tty device being bound
159 * @filp: the file pointer of the opener
160 *
161 * Implement the core POSIX/SuS tty behaviour when opening a tty device.
162 * Handles:
163 * - hangup (both before and during)
164 * - non blocking open
165 * - rts/dtr/dcd
166 * - signals
167 * - port flags and counts
168 *
169 * The passed tty_port must implement the carrier_raised method if it can
170 * do carrier detect and the raise_dtr_rts method if it supports software
171 * management of these lines. Note that the dtr/rts raise is done each
172 * iteration as a hangup may have previously dropped them while we wait.
173 */
174
175int tty_port_block_til_ready(struct tty_port *port,
176 struct tty_struct *tty, struct file *filp)
177{
178 int do_clocal = 0, retval;
179 unsigned long flags;
180 DECLARE_WAITQUEUE(wait, current);
181 int cd;
182
183 /* block if port is in the process of being closed */
184 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
185 interruptible_sleep_on(&port->close_wait);
186 if (port->flags & ASYNC_HUP_NOTIFY)
187 return -EAGAIN;
188 else
189 return -ERESTARTSYS;
190 }
191
192 /* if non-blocking mode is set we can pass directly to open unless
193 the port has just hung up or is in another error state */
194 if ((filp->f_flags & O_NONBLOCK) ||
195 (tty->flags & (1 << TTY_IO_ERROR))) {
196 port->flags |= ASYNC_NORMAL_ACTIVE;
197 return 0;
198 }
199
200 if (C_CLOCAL(tty))
201 do_clocal = 1;
202
203 /* Block waiting until we can proceed. We may need to wait for the
204 carrier, but we must also wait for any close that is in progress
205 before the next open may complete */
206
207 retval = 0;
208 add_wait_queue(&port->open_wait, &wait);
209
210 /* The port lock protects the port counts */
211 spin_lock_irqsave(&port->lock, flags);
212 if (!tty_hung_up_p(filp))
213 port->count--;
214 port->blocked_open++;
215 spin_unlock_irqrestore(&port->lock, flags);
216
217 while (1) {
218 /* Indicate we are open */
219 tty_port_raise_dtr_rts(port);
220
221 set_current_state(TASK_INTERRUPTIBLE);
222 /* Check for a hangup or uninitialised port. Return accordingly */
223 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
224 if (port->flags & ASYNC_HUP_NOTIFY)
225 retval = -EAGAIN;
226 else
227 retval = -ERESTARTSYS;
228 break;
229 }
230 /* Probe the carrier. For devices with no carrier detect this
231 will always return true */
232 cd = tty_port_carrier_raised(port);
233 if (!(port->flags & ASYNC_CLOSING) &&
234 (do_clocal || cd))
235 break;
236 if (signal_pending(current)) {
237 retval = -ERESTARTSYS;
238 break;
239 }
240 schedule();
241 }
242 set_current_state(TASK_RUNNING);
243 remove_wait_queue(&port->open_wait, &wait);
244
245 /* Update counts. A parallel hangup will have set count to zero and
246 we must not mess that up further */
247 spin_lock_irqsave(&port->lock, flags);
248 if (!tty_hung_up_p(filp))
249 port->count++;
250 port->blocked_open--;
251 if (retval == 0)
252 port->flags |= ASYNC_NORMAL_ACTIVE;
253 spin_unlock_irqrestore(&port->lock, flags);
254 return 0;
255
256}
257EXPORT_SYMBOL(tty_port_block_til_ready);
258
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index d4e1534c0e03..2d9242a45a0d 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -631,8 +631,8 @@ static void scc_enable_rx_interrupts(void *ptr)
631 631
632static int scc_carrier_raised(struct tty_port *port) 632static int scc_carrier_raised(struct tty_port *port)
633{ 633{
634 struct scc_port *scc = container_of(port, struct scc_port, gs.port); 634 struct scc_port *sc = container_of(port, struct scc_port, gs.port);
635 unsigned channel = port->channel; 635 unsigned channel = sc->channel;
636 636
637 return !!(scc_last_status_reg[channel] & SR_DCD); 637 return !!(scc_last_status_reg[channel] & SR_DCD);
638} 638}
@@ -643,7 +643,7 @@ static void scc_shutdown_port(void *ptr)
643 struct scc_port *port = ptr; 643 struct scc_port *port = ptr;
644 644
645 port->gs.port.flags &= ~ GS_ACTIVE; 645 port->gs.port.flags &= ~ GS_ACTIVE;
646 if (port->gs.port.tty && port->gs.port.tty->termios->c_cflag & HUPCL) { 646 if (port->gs.port.tty && (port->gs.port.tty->termios->c_cflag & HUPCL)) {
647 scc_setsignals (port, 0, 0); 647 scc_setsignals (port, 0, 0);
648 } 648 }
649} 649}
diff --git a/include/linux/tty.h b/include/linux/tty.h
index a1a93140e6e4..61a0ab32cf11 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -439,6 +439,8 @@ extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
439extern int tty_port_carrier_raised(struct tty_port *port); 439extern int tty_port_carrier_raised(struct tty_port *port);
440extern void tty_port_raise_dtr_rts(struct tty_port *port); 440extern void tty_port_raise_dtr_rts(struct tty_port *port);
441extern void tty_port_hangup(struct tty_port *port); 441extern void tty_port_hangup(struct tty_port *port);
442extern int tty_port_block_til_ready(struct tty_port *port,
443 struct tty_struct *tty, struct file *filp);
442 444
443extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); 445extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
444extern int tty_unregister_ldisc(int disc); 446extern int tty_unregister_ldisc(int disc);