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 426bfdd7f3e0..300d5bd6cd06 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) | |||
793 | { | 793 | { |
794 | int channel; | 794 | int channel; |
795 | struct isi_port *port; | 795 | struct isi_port *port; |
796 | unsigned long flags; | ||
797 | 796 | ||
798 | spin_lock_irqsave(&bp->card_lock, flags); | 797 | bp->count++; |
799 | if (bp->status & BOARD_ACTIVE) { | 798 | if (!(bp->status & BOARD_INIT)) { |
800 | spin_unlock_irqrestore(&bp->card_lock, flags); | 799 | port = bp->ports; |
801 | return; | 800 | for (channel = 0; channel < bp->port_count; channel++, port++) |
801 | drop_dtr_rts(port); | ||
802 | } | 802 | } |
803 | port = bp->ports; | 803 | bp->status |= BOARD_ACTIVE | BOARD_INIT; |
804 | bp->status |= BOARD_ACTIVE; | ||
805 | for (channel = 0; channel < bp->port_count; channel++, port++) | ||
806 | drop_dtr_rts(port); | ||
807 | spin_unlock_irqrestore(&bp->card_lock, flags); | ||
808 | } | 804 | } |
809 | 805 | ||
810 | static int isicom_setup_port(struct tty_struct *tty) | 806 | /* Activate and thus setup board are protected from races against shutdown |
807 | by the tty_port mutex */ | ||
808 | |||
809 | static int isicom_activate(struct tty_port *tport, struct tty_struct *tty) | ||
811 | { | 810 | { |
812 | struct isi_port *port = tty->driver_data; | 811 | struct isi_port *port = container_of(tport, struct isi_port, port); |
813 | struct isi_board *card = port->card; | 812 | struct isi_board *card = port->card; |
814 | unsigned long flags; | 813 | unsigned long flags; |
815 | 814 | ||
816 | if (port->port.flags & ASYNC_INITIALIZED) | 815 | if (tty_port_alloc_xmit_buf(tport) < 0) |
817 | return 0; | ||
818 | if (tty_port_alloc_xmit_buf(&port->port) < 0) | ||
819 | return -ENOMEM; | 816 | return -ENOMEM; |
820 | 817 | ||
821 | spin_lock_irqsave(&card->card_lock, flags); | 818 | spin_lock_irqsave(&card->card_lock, flags); |
822 | clear_bit(TTY_IO_ERROR, &tty->flags); | 819 | isicom_setup_board(card); |
823 | if (port->port.count == 1) | ||
824 | card->count++; | ||
825 | 820 | ||
826 | port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; | 821 | port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; |
827 | 822 | ||
@@ -832,9 +827,7 @@ static int isicom_setup_port(struct tty_struct *tty) | |||
832 | outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base); | 827 | outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base); |
833 | InterruptTheCard(card->base); | 828 | InterruptTheCard(card->base); |
834 | } | 829 | } |
835 | |||
836 | isicom_config_port(tty); | 830 | isicom_config_port(tty); |
837 | port->port.flags |= ASYNC_INITIALIZED; | ||
838 | spin_unlock_irqrestore(&card->card_lock, flags); | 831 | spin_unlock_irqrestore(&card->card_lock, flags); |
839 | 832 | ||
840 | return 0; | 833 | return 0; |
@@ -871,85 +864,37 @@ static struct tty_port *isicom_find_port(struct tty_struct *tty) | |||
871 | 864 | ||
872 | return &port->port; | 865 | return &port->port; |
873 | } | 866 | } |
874 | 867 | ||
875 | static int isicom_open(struct tty_struct *tty, struct file *filp) | 868 | static int isicom_open(struct tty_struct *tty, struct file *filp) |
876 | { | 869 | { |
877 | struct isi_port *port; | 870 | struct isi_port *port; |
878 | struct isi_board *card; | 871 | struct isi_board *card; |
879 | struct tty_port *tport; | 872 | struct tty_port *tport; |
880 | int error = 0; | ||
881 | 873 | ||
882 | tport = isicom_find_port(tty); | 874 | tport = isicom_find_port(tty); |
883 | if (tport == NULL) | 875 | if (tport == NULL) |
884 | return -ENODEV; | 876 | return -ENODEV; |
885 | port = container_of(tport, struct isi_port, port); | 877 | port = container_of(tport, struct isi_port, port); |
886 | card = &isi_card[BOARD(tty->index)]; | 878 | card = &isi_card[BOARD(tty->index)]; |
887 | isicom_setup_board(card); | ||
888 | 879 | ||
889 | /* FIXME: locking on port.count etc */ | 880 | return tty_port_open(tport, tty, filp); |
890 | port->port.count++; | ||
891 | tty->driver_data = port; | ||
892 | tty_port_tty_set(&port->port, tty); | ||
893 | /* FIXME: Locking on Initialized flag */ | ||
894 | if (!test_bit(ASYNCB_INITIALIZED, &tport->flags)) | ||
895 | error = isicom_setup_port(tty); | ||
896 | if (error == 0) | ||
897 | error = tty_port_block_til_ready(&port->port, tty, filp); | ||
898 | return error; | ||
899 | } | 881 | } |
900 | 882 | ||
901 | /* close et all */ | 883 | /* close et all */ |
902 | 884 | ||
903 | static inline void isicom_shutdown_board(struct isi_board *bp) | ||
904 | { | ||
905 | if (bp->status & BOARD_ACTIVE) | ||
906 | bp->status &= ~BOARD_ACTIVE; | ||
907 | } | ||
908 | |||
909 | /* card->lock HAS to be held */ | 885 | /* card->lock HAS to be held */ |
910 | static void isicom_shutdown_port(struct isi_port *port) | 886 | static void isicom_shutdown_port(struct isi_port *port) |
911 | { | 887 | { |
912 | struct isi_board *card = port->card; | 888 | struct isi_board *card = port->card; |
913 | struct tty_struct *tty; | ||
914 | |||
915 | tty = tty_port_tty_get(&port->port); | ||
916 | |||
917 | if (!(port->port.flags & ASYNC_INITIALIZED)) { | ||
918 | tty_kref_put(tty); | ||
919 | return; | ||
920 | } | ||
921 | |||
922 | tty_port_free_xmit_buf(&port->port); | ||
923 | port->port.flags &= ~ASYNC_INITIALIZED; | ||
924 | /* 3rd October 2000 : Vinayak P Risbud */ | ||
925 | tty_port_tty_set(&port->port, NULL); | ||
926 | |||
927 | /*Fix done by Anil .S on 30-04-2001 | ||
928 | remote login through isi port has dtr toggle problem | ||
929 | due to which the carrier drops before the password prompt | ||
930 | appears on the remote end. Now we drop the dtr only if the | ||
931 | HUPCL(Hangup on close) flag is set for the tty*/ | ||
932 | |||
933 | if (C_HUPCL(tty)) | ||
934 | /* drop dtr on this port */ | ||
935 | drop_dtr(port); | ||
936 | |||
937 | /* any other port uninits */ | ||
938 | if (tty) | ||
939 | set_bit(TTY_IO_ERROR, &tty->flags); | ||
940 | 889 | ||
941 | if (--card->count < 0) { | 890 | if (--card->count < 0) { |
942 | pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n", | 891 | pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n", |
943 | card->base, card->count); | 892 | card->base, card->count); |
944 | card->count = 0; | 893 | card->count = 0; |
945 | } | 894 | } |
946 | 895 | /* last port was closed, shutdown that board too */ | |
947 | /* last port was closed, shutdown that boad too */ | 896 | if (!card->count) |
948 | if (C_HUPCL(tty)) { | 897 | card->status &= BOARD_ACTIVE; |
949 | if (!card->count) | ||
950 | isicom_shutdown_board(card); | ||
951 | } | ||
952 | tty_kref_put(tty); | ||
953 | } | 898 | } |
954 | 899 | ||
955 | static void isicom_flush_buffer(struct tty_struct *tty) | 900 | static void isicom_flush_buffer(struct tty_struct *tty) |
@@ -968,7 +913,7 @@ static void isicom_flush_buffer(struct tty_struct *tty) | |||
968 | tty_wakeup(tty); | 913 | tty_wakeup(tty); |
969 | } | 914 | } |
970 | 915 | ||
971 | static void isicom_close_port(struct tty_port *port) | 916 | static void isicom_shutdown(struct tty_port *port) |
972 | { | 917 | { |
973 | struct isi_port *ip = container_of(port, struct isi_port, port); | 918 | struct isi_port *ip = container_of(port, struct isi_port, port); |
974 | struct isi_board *card = ip->card; | 919 | struct isi_board *card = ip->card; |
@@ -977,12 +922,11 @@ static void isicom_close_port(struct tty_port *port) | |||
977 | /* indicate to the card that no more data can be received | 922 | /* indicate to the card that no more data can be received |
978 | on this port */ | 923 | on this port */ |
979 | spin_lock_irqsave(&card->card_lock, flags); | 924 | spin_lock_irqsave(&card->card_lock, flags); |
980 | if (port->flags & ASYNC_INITIALIZED) { | 925 | card->port_status &= ~(1 << ip->channel); |
981 | card->port_status &= ~(1 << ip->channel); | 926 | outw(card->port_status, card->base + 0x02); |
982 | outw(card->port_status, card->base + 0x02); | ||
983 | } | ||
984 | isicom_shutdown_port(ip); | 927 | isicom_shutdown_port(ip); |
985 | spin_unlock_irqrestore(&card->card_lock, flags); | 928 | spin_unlock_irqrestore(&card->card_lock, flags); |
929 | tty_port_free_xmit_buf(port); | ||
986 | } | 930 | } |
987 | 931 | ||
988 | static void isicom_close(struct tty_struct *tty, struct file *filp) | 932 | 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) | |||
991 | struct tty_port *port = &ip->port; | 935 | struct tty_port *port = &ip->port; |
992 | if (isicom_paranoia_check(ip, tty->name, "isicom_close")) | 936 | if (isicom_paranoia_check(ip, tty->name, "isicom_close")) |
993 | return; | 937 | return; |
994 | 938 | tty_port_close(port, tty, filp); | |
995 | if (tty_port_close_start(port, tty, filp) == 0) | ||
996 | return; | ||
997 | isicom_close_port(port); | ||
998 | isicom_flush_buffer(tty); | ||
999 | tty_port_close_end(port, tty); | ||
1000 | } | 939 | } |
1001 | 940 | ||
1002 | /* write et all */ | 941 | /* write et all */ |
@@ -1326,15 +1265,9 @@ static void isicom_start(struct tty_struct *tty) | |||
1326 | static void isicom_hangup(struct tty_struct *tty) | 1265 | static void isicom_hangup(struct tty_struct *tty) |
1327 | { | 1266 | { |
1328 | struct isi_port *port = tty->driver_data; | 1267 | struct isi_port *port = tty->driver_data; |
1329 | unsigned long flags; | ||
1330 | 1268 | ||
1331 | if (isicom_paranoia_check(port, tty->name, "isicom_hangup")) | 1269 | if (isicom_paranoia_check(port, tty->name, "isicom_hangup")) |
1332 | return; | 1270 | return; |
1333 | |||
1334 | spin_lock_irqsave(&port->card->card_lock, flags); | ||
1335 | isicom_shutdown_port(port); | ||
1336 | spin_unlock_irqrestore(&port->card->card_lock, flags); | ||
1337 | |||
1338 | tty_port_hangup(&port->port); | 1271 | tty_port_hangup(&port->port); |
1339 | } | 1272 | } |
1340 | 1273 | ||
@@ -1367,6 +1300,8 @@ static const struct tty_operations isicom_ops = { | |||
1367 | static const struct tty_port_operations isicom_port_ops = { | 1300 | static const struct tty_port_operations isicom_port_ops = { |
1368 | .carrier_raised = isicom_carrier_raised, | 1301 | .carrier_raised = isicom_carrier_raised, |
1369 | .dtr_rts = isicom_dtr_rts, | 1302 | .dtr_rts = isicom_dtr_rts, |
1303 | .activate = isicom_activate, | ||
1304 | .shutdown = isicom_shutdown, | ||
1370 | }; | 1305 | }; |
1371 | 1306 | ||
1372 | static int __devinit reset_card(struct pci_dev *pdev, | 1307 | static int __devinit reset_card(struct pci_dev *pdev, |