diff options
Diffstat (limited to 'drivers/char/isicom.c')
-rw-r--r-- | drivers/char/isicom.c | 175 |
1 files changed, 62 insertions, 113 deletions
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 426bfdd7f3e0..c1ab303455cf 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c | |||
@@ -113,6 +113,8 @@ | |||
113 | * 64-bit verification | 113 | * 64-bit verification |
114 | */ | 114 | */ |
115 | 115 | ||
116 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
117 | |||
116 | #include <linux/module.h> | 118 | #include <linux/module.h> |
117 | #include <linux/firmware.h> | 119 | #include <linux/firmware.h> |
118 | #include <linux/kernel.h> | 120 | #include <linux/kernel.h> |
@@ -128,6 +130,7 @@ | |||
128 | #include <linux/timer.h> | 130 | #include <linux/timer.h> |
129 | #include <linux/delay.h> | 131 | #include <linux/delay.h> |
130 | #include <linux/ioport.h> | 132 | #include <linux/ioport.h> |
133 | #include <linux/slab.h> | ||
131 | 134 | ||
132 | #include <linux/uaccess.h> | 135 | #include <linux/uaccess.h> |
133 | #include <linux/io.h> | 136 | #include <linux/io.h> |
@@ -140,7 +143,6 @@ | |||
140 | #define InterruptTheCard(base) outw(0, (base) + 0xc) | 143 | #define InterruptTheCard(base) outw(0, (base) + 0xc) |
141 | #define ClearInterrupt(base) inw((base) + 0x0a) | 144 | #define ClearInterrupt(base) inw((base) + 0x0a) |
142 | 145 | ||
143 | #define pr_dbg(str...) pr_debug("ISICOM: " str) | ||
144 | #ifdef DEBUG | 146 | #ifdef DEBUG |
145 | #define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c)) | 147 | #define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c)) |
146 | #else | 148 | #else |
@@ -249,8 +251,7 @@ static int lock_card(struct isi_board *card) | |||
249 | spin_unlock_irqrestore(&card->card_lock, card->flags); | 251 | spin_unlock_irqrestore(&card->card_lock, card->flags); |
250 | msleep(10); | 252 | msleep(10); |
251 | } | 253 | } |
252 | printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%lx)\n", | 254 | pr_warning("Failed to lock Card (0x%lx)\n", card->base); |
253 | card->base); | ||
254 | 255 | ||
255 | return 0; /* Failed to acquire the card! */ | 256 | return 0; /* Failed to acquire the card! */ |
256 | } | 257 | } |
@@ -379,13 +380,13 @@ static inline int __isicom_paranoia_check(struct isi_port const *port, | |||
379 | char *name, const char *routine) | 380 | char *name, const char *routine) |
380 | { | 381 | { |
381 | if (!port) { | 382 | if (!port) { |
382 | printk(KERN_WARNING "ISICOM: Warning: bad isicom magic for " | 383 | pr_warning("Warning: bad isicom magic for dev %s in %s.\n", |
383 | "dev %s in %s.\n", name, routine); | 384 | name, routine); |
384 | return 1; | 385 | return 1; |
385 | } | 386 | } |
386 | if (port->magic != ISICOM_MAGIC) { | 387 | if (port->magic != ISICOM_MAGIC) { |
387 | printk(KERN_WARNING "ISICOM: Warning: NULL isicom port for " | 388 | pr_warning("Warning: NULL isicom port for dev %s in %s.\n", |
388 | "dev %s in %s.\n", name, routine); | 389 | name, routine); |
389 | return 1; | 390 | return 1; |
390 | } | 391 | } |
391 | 392 | ||
@@ -450,8 +451,8 @@ static void isicom_tx(unsigned long _data) | |||
450 | if (!(inw(base + 0x02) & (1 << port->channel))) | 451 | if (!(inw(base + 0x02) & (1 << port->channel))) |
451 | continue; | 452 | continue; |
452 | 453 | ||
453 | pr_dbg("txing %d bytes, port%d.\n", txcount, | 454 | pr_debug("txing %d bytes, port%d.\n", |
454 | port->channel + 1); | 455 | txcount, port->channel + 1); |
455 | outw((port->channel << isi_card[card].shift_count) | txcount, | 456 | outw((port->channel << isi_card[card].shift_count) | txcount, |
456 | base); | 457 | base); |
457 | residue = NO; | 458 | residue = NO; |
@@ -547,8 +548,8 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) | |||
547 | byte_count = header & 0xff; | 548 | byte_count = header & 0xff; |
548 | 549 | ||
549 | if (channel + 1 > card->port_count) { | 550 | if (channel + 1 > card->port_count) { |
550 | printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): " | 551 | pr_warning("%s(0x%lx): %d(channel) > port_count.\n", |
551 | "%d(channel) > port_count.\n", base, channel+1); | 552 | __func__, base, channel+1); |
552 | outw(0x0000, base+0x04); /* enable interrupts */ | 553 | outw(0x0000, base+0x04); /* enable interrupts */ |
553 | spin_unlock(&card->card_lock); | 554 | spin_unlock(&card->card_lock); |
554 | return IRQ_HANDLED; | 555 | return IRQ_HANDLED; |
@@ -582,14 +583,15 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) | |||
582 | if (port->status & ISI_DCD) { | 583 | if (port->status & ISI_DCD) { |
583 | if (!(header & ISI_DCD)) { | 584 | if (!(header & ISI_DCD)) { |
584 | /* Carrier has been lost */ | 585 | /* Carrier has been lost */ |
585 | pr_dbg("interrupt: DCD->low.\n" | 586 | pr_debug("%s: DCD->low.\n", |
586 | ); | 587 | __func__); |
587 | port->status &= ~ISI_DCD; | 588 | port->status &= ~ISI_DCD; |
588 | tty_hangup(tty); | 589 | tty_hangup(tty); |
589 | } | 590 | } |
590 | } else if (header & ISI_DCD) { | 591 | } else if (header & ISI_DCD) { |
591 | /* Carrier has been detected */ | 592 | /* Carrier has been detected */ |
592 | pr_dbg("interrupt: DCD->high.\n"); | 593 | pr_debug("%s: DCD->high.\n", |
594 | __func__); | ||
593 | port->status |= ISI_DCD; | 595 | port->status |= ISI_DCD; |
594 | wake_up_interruptible(&port->port.open_wait); | 596 | wake_up_interruptible(&port->port.open_wait); |
595 | } | 597 | } |
@@ -641,17 +643,19 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) | |||
641 | break; | 643 | break; |
642 | 644 | ||
643 | case 2: /* Statistics */ | 645 | case 2: /* Statistics */ |
644 | pr_dbg("isicom_interrupt: stats!!!.\n"); | 646 | pr_debug("%s: stats!!!\n", __func__); |
645 | break; | 647 | break; |
646 | 648 | ||
647 | default: | 649 | default: |
648 | pr_dbg("Intr: Unknown code in status packet.\n"); | 650 | pr_debug("%s: Unknown code in status packet.\n", |
651 | __func__); | ||
649 | break; | 652 | break; |
650 | } | 653 | } |
651 | } else { /* Data Packet */ | 654 | } else { /* Data Packet */ |
652 | 655 | ||
653 | count = tty_prepare_flip_string(tty, &rp, byte_count & ~1); | 656 | count = tty_prepare_flip_string(tty, &rp, byte_count & ~1); |
654 | pr_dbg("Intr: Can rx %d of %d bytes.\n", count, byte_count); | 657 | pr_debug("%s: Can rx %d of %d bytes.\n", |
658 | __func__, count, byte_count); | ||
655 | word_count = count >> 1; | 659 | word_count = count >> 1; |
656 | insw(base, rp, word_count); | 660 | insw(base, rp, word_count); |
657 | byte_count -= (word_count << 1); | 661 | byte_count -= (word_count << 1); |
@@ -661,8 +665,8 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) | |||
661 | byte_count -= 2; | 665 | byte_count -= 2; |
662 | } | 666 | } |
663 | if (byte_count > 0) { | 667 | if (byte_count > 0) { |
664 | pr_dbg("Intr(0x%lx:%d): Flip buffer overflow! dropping " | 668 | pr_debug("%s(0x%lx:%d): Flip buffer overflow! dropping bytes...\n", |
665 | "bytes...\n", base, channel + 1); | 669 | __func__, base, channel + 1); |
666 | /* drain out unread xtra data */ | 670 | /* drain out unread xtra data */ |
667 | while (byte_count > 0) { | 671 | while (byte_count > 0) { |
668 | inw(base); | 672 | inw(base); |
@@ -793,35 +797,30 @@ static inline void isicom_setup_board(struct isi_board *bp) | |||
793 | { | 797 | { |
794 | int channel; | 798 | int channel; |
795 | struct isi_port *port; | 799 | struct isi_port *port; |
796 | unsigned long flags; | ||
797 | 800 | ||
798 | spin_lock_irqsave(&bp->card_lock, flags); | 801 | bp->count++; |
799 | if (bp->status & BOARD_ACTIVE) { | 802 | if (!(bp->status & BOARD_INIT)) { |
800 | spin_unlock_irqrestore(&bp->card_lock, flags); | 803 | port = bp->ports; |
801 | return; | 804 | for (channel = 0; channel < bp->port_count; channel++, port++) |
805 | drop_dtr_rts(port); | ||
802 | } | 806 | } |
803 | port = bp->ports; | 807 | 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 | } | 808 | } |
809 | 809 | ||
810 | static int isicom_setup_port(struct tty_struct *tty) | 810 | /* Activate and thus setup board are protected from races against shutdown |
811 | by the tty_port mutex */ | ||
812 | |||
813 | static int isicom_activate(struct tty_port *tport, struct tty_struct *tty) | ||
811 | { | 814 | { |
812 | struct isi_port *port = tty->driver_data; | 815 | struct isi_port *port = container_of(tport, struct isi_port, port); |
813 | struct isi_board *card = port->card; | 816 | struct isi_board *card = port->card; |
814 | unsigned long flags; | 817 | unsigned long flags; |
815 | 818 | ||
816 | if (port->port.flags & ASYNC_INITIALIZED) | 819 | if (tty_port_alloc_xmit_buf(tport) < 0) |
817 | return 0; | ||
818 | if (tty_port_alloc_xmit_buf(&port->port) < 0) | ||
819 | return -ENOMEM; | 820 | return -ENOMEM; |
820 | 821 | ||
821 | spin_lock_irqsave(&card->card_lock, flags); | 822 | spin_lock_irqsave(&card->card_lock, flags); |
822 | clear_bit(TTY_IO_ERROR, &tty->flags); | 823 | isicom_setup_board(card); |
823 | if (port->port.count == 1) | ||
824 | card->count++; | ||
825 | 824 | ||
826 | port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; | 825 | port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; |
827 | 826 | ||
@@ -832,9 +831,7 @@ static int isicom_setup_port(struct tty_struct *tty) | |||
832 | outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base); | 831 | outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base); |
833 | InterruptTheCard(card->base); | 832 | InterruptTheCard(card->base); |
834 | } | 833 | } |
835 | |||
836 | isicom_config_port(tty); | 834 | isicom_config_port(tty); |
837 | port->port.flags |= ASYNC_INITIALIZED; | ||
838 | spin_unlock_irqrestore(&card->card_lock, flags); | 835 | spin_unlock_irqrestore(&card->card_lock, flags); |
839 | 836 | ||
840 | return 0; | 837 | return 0; |
@@ -871,85 +868,37 @@ static struct tty_port *isicom_find_port(struct tty_struct *tty) | |||
871 | 868 | ||
872 | return &port->port; | 869 | return &port->port; |
873 | } | 870 | } |
874 | 871 | ||
875 | static int isicom_open(struct tty_struct *tty, struct file *filp) | 872 | static int isicom_open(struct tty_struct *tty, struct file *filp) |
876 | { | 873 | { |
877 | struct isi_port *port; | 874 | struct isi_port *port; |
878 | struct isi_board *card; | 875 | struct isi_board *card; |
879 | struct tty_port *tport; | 876 | struct tty_port *tport; |
880 | int error = 0; | ||
881 | 877 | ||
882 | tport = isicom_find_port(tty); | 878 | tport = isicom_find_port(tty); |
883 | if (tport == NULL) | 879 | if (tport == NULL) |
884 | return -ENODEV; | 880 | return -ENODEV; |
885 | port = container_of(tport, struct isi_port, port); | 881 | port = container_of(tport, struct isi_port, port); |
886 | card = &isi_card[BOARD(tty->index)]; | ||
887 | isicom_setup_board(card); | ||
888 | 882 | ||
889 | /* FIXME: locking on port.count etc */ | ||
890 | port->port.count++; | ||
891 | tty->driver_data = port; | 883 | tty->driver_data = port; |
892 | tty_port_tty_set(&port->port, tty); | 884 | return tty_port_open(tport, tty, filp); |
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 | } | 885 | } |
900 | 886 | ||
901 | /* close et all */ | 887 | /* close et all */ |
902 | 888 | ||
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 */ | 889 | /* card->lock HAS to be held */ |
910 | static void isicom_shutdown_port(struct isi_port *port) | 890 | static void isicom_shutdown_port(struct isi_port *port) |
911 | { | 891 | { |
912 | struct isi_board *card = port->card; | 892 | 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 | 893 | ||
941 | if (--card->count < 0) { | 894 | if (--card->count < 0) { |
942 | pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n", | 895 | pr_debug("%s: bad board(0x%lx) count %d.\n", |
943 | card->base, card->count); | 896 | __func__, card->base, card->count); |
944 | card->count = 0; | 897 | card->count = 0; |
945 | } | 898 | } |
946 | 899 | /* last port was closed, shutdown that board too */ | |
947 | /* last port was closed, shutdown that boad too */ | 900 | if (!card->count) |
948 | if (C_HUPCL(tty)) { | 901 | card->status &= BOARD_ACTIVE; |
949 | if (!card->count) | ||
950 | isicom_shutdown_board(card); | ||
951 | } | ||
952 | tty_kref_put(tty); | ||
953 | } | 902 | } |
954 | 903 | ||
955 | static void isicom_flush_buffer(struct tty_struct *tty) | 904 | static void isicom_flush_buffer(struct tty_struct *tty) |
@@ -968,7 +917,7 @@ static void isicom_flush_buffer(struct tty_struct *tty) | |||
968 | tty_wakeup(tty); | 917 | tty_wakeup(tty); |
969 | } | 918 | } |
970 | 919 | ||
971 | static void isicom_close_port(struct tty_port *port) | 920 | static void isicom_shutdown(struct tty_port *port) |
972 | { | 921 | { |
973 | struct isi_port *ip = container_of(port, struct isi_port, port); | 922 | struct isi_port *ip = container_of(port, struct isi_port, port); |
974 | struct isi_board *card = ip->card; | 923 | struct isi_board *card = ip->card; |
@@ -977,26 +926,25 @@ static void isicom_close_port(struct tty_port *port) | |||
977 | /* indicate to the card that no more data can be received | 926 | /* indicate to the card that no more data can be received |
978 | on this port */ | 927 | on this port */ |
979 | spin_lock_irqsave(&card->card_lock, flags); | 928 | spin_lock_irqsave(&card->card_lock, flags); |
980 | if (port->flags & ASYNC_INITIALIZED) { | 929 | card->port_status &= ~(1 << ip->channel); |
981 | card->port_status &= ~(1 << ip->channel); | 930 | outw(card->port_status, card->base + 0x02); |
982 | outw(card->port_status, card->base + 0x02); | ||
983 | } | ||
984 | isicom_shutdown_port(ip); | 931 | isicom_shutdown_port(ip); |
985 | spin_unlock_irqrestore(&card->card_lock, flags); | 932 | spin_unlock_irqrestore(&card->card_lock, flags); |
933 | tty_port_free_xmit_buf(port); | ||
986 | } | 934 | } |
987 | 935 | ||
988 | static void isicom_close(struct tty_struct *tty, struct file *filp) | 936 | static void isicom_close(struct tty_struct *tty, struct file *filp) |
989 | { | 937 | { |
990 | struct isi_port *ip = tty->driver_data; | 938 | struct isi_port *ip = tty->driver_data; |
991 | struct tty_port *port = &ip->port; | 939 | struct tty_port *port; |
992 | if (isicom_paranoia_check(ip, tty->name, "isicom_close")) | 940 | |
941 | if (ip == NULL) | ||
993 | return; | 942 | return; |
994 | 943 | ||
995 | if (tty_port_close_start(port, tty, filp) == 0) | 944 | port = &ip->port; |
945 | if (isicom_paranoia_check(ip, tty->name, "isicom_close")) | ||
996 | return; | 946 | return; |
997 | isicom_close_port(port); | 947 | tty_port_close(port, tty, filp); |
998 | isicom_flush_buffer(tty); | ||
999 | tty_port_close_end(port, tty); | ||
1000 | } | 948 | } |
1001 | 949 | ||
1002 | /* write et all */ | 950 | /* write et all */ |
@@ -1326,15 +1274,9 @@ static void isicom_start(struct tty_struct *tty) | |||
1326 | static void isicom_hangup(struct tty_struct *tty) | 1274 | static void isicom_hangup(struct tty_struct *tty) |
1327 | { | 1275 | { |
1328 | struct isi_port *port = tty->driver_data; | 1276 | struct isi_port *port = tty->driver_data; |
1329 | unsigned long flags; | ||
1330 | 1277 | ||
1331 | if (isicom_paranoia_check(port, tty->name, "isicom_hangup")) | 1278 | if (isicom_paranoia_check(port, tty->name, "isicom_hangup")) |
1332 | return; | 1279 | 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); | 1280 | tty_port_hangup(&port->port); |
1339 | } | 1281 | } |
1340 | 1282 | ||
@@ -1367,6 +1309,8 @@ static const struct tty_operations isicom_ops = { | |||
1367 | static const struct tty_port_operations isicom_port_ops = { | 1309 | static const struct tty_port_operations isicom_port_ops = { |
1368 | .carrier_raised = isicom_carrier_raised, | 1310 | .carrier_raised = isicom_carrier_raised, |
1369 | .dtr_rts = isicom_dtr_rts, | 1311 | .dtr_rts = isicom_dtr_rts, |
1312 | .activate = isicom_activate, | ||
1313 | .shutdown = isicom_shutdown, | ||
1370 | }; | 1314 | }; |
1371 | 1315 | ||
1372 | static int __devinit reset_card(struct pci_dev *pdev, | 1316 | static int __devinit reset_card(struct pci_dev *pdev, |
@@ -1746,13 +1690,13 @@ static int __init isicom_init(void) | |||
1746 | 1690 | ||
1747 | retval = tty_register_driver(isicom_normal); | 1691 | retval = tty_register_driver(isicom_normal); |
1748 | if (retval) { | 1692 | if (retval) { |
1749 | pr_dbg("Couldn't register the dialin driver\n"); | 1693 | pr_debug("Couldn't register the dialin driver\n"); |
1750 | goto err_puttty; | 1694 | goto err_puttty; |
1751 | } | 1695 | } |
1752 | 1696 | ||
1753 | retval = pci_register_driver(&isicom_driver); | 1697 | retval = pci_register_driver(&isicom_driver); |
1754 | if (retval < 0) { | 1698 | if (retval < 0) { |
1755 | printk(KERN_ERR "ISICOM: Unable to register pci driver.\n"); | 1699 | pr_err("Unable to register pci driver.\n"); |
1756 | goto err_unrtty; | 1700 | goto err_unrtty; |
1757 | } | 1701 | } |
1758 | 1702 | ||
@@ -1782,3 +1726,8 @@ module_exit(isicom_exit); | |||
1782 | MODULE_AUTHOR("MultiTech"); | 1726 | MODULE_AUTHOR("MultiTech"); |
1783 | MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech"); | 1727 | MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech"); |
1784 | MODULE_LICENSE("GPL"); | 1728 | MODULE_LICENSE("GPL"); |
1729 | MODULE_FIRMWARE("isi608.bin"); | ||
1730 | MODULE_FIRMWARE("isi608em.bin"); | ||
1731 | MODULE_FIRMWARE("isi616em.bin"); | ||
1732 | MODULE_FIRMWARE("isi4608.bin"); | ||
1733 | MODULE_FIRMWARE("isi4616.bin"); | ||