aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/isicom.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/isicom.c')
-rw-r--r--drivers/char/isicom.c175
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
810static 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
813static 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
875static int isicom_open(struct tty_struct *tty, struct file *filp) 872static 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
903static 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 */
910static void isicom_shutdown_port(struct isi_port *port) 890static 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
955static void isicom_flush_buffer(struct tty_struct *tty) 904static 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
971static void isicom_close_port(struct tty_port *port) 920static 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
988static void isicom_close(struct tty_struct *tty, struct file *filp) 936static 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)
1326static void isicom_hangup(struct tty_struct *tty) 1274static 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 = {
1367static const struct tty_port_operations isicom_port_ops = { 1309static 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
1372static int __devinit reset_card(struct pci_dev *pdev, 1316static 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);
1782MODULE_AUTHOR("MultiTech"); 1726MODULE_AUTHOR("MultiTech");
1783MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech"); 1727MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
1784MODULE_LICENSE("GPL"); 1728MODULE_LICENSE("GPL");
1729MODULE_FIRMWARE("isi608.bin");
1730MODULE_FIRMWARE("isi608em.bin");
1731MODULE_FIRMWARE("isi616em.bin");
1732MODULE_FIRMWARE("isi4608.bin");
1733MODULE_FIRMWARE("isi4616.bin");