diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/isicom.c | 112 |
1 files changed, 59 insertions, 53 deletions
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 55a47b33ff34..e9ebabaf8cb0 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c | |||
@@ -189,7 +189,7 @@ struct isi_board { | |||
189 | unsigned char irq; | 189 | unsigned char irq; |
190 | unsigned char port_count; | 190 | unsigned char port_count; |
191 | unsigned short status; | 191 | unsigned short status; |
192 | unsigned short port_status; /* each bit represents a single port */ | 192 | unsigned short port_status; /* each bit for each port */ |
193 | unsigned short shift_count; | 193 | unsigned short shift_count; |
194 | struct isi_port * ports; | 194 | struct isi_port * ports; |
195 | signed char count; | 195 | signed char count; |
@@ -242,7 +242,9 @@ static int lock_card(struct isi_board *card) | |||
242 | udelay(1000); /* 1ms */ | 242 | udelay(1000); /* 1ms */ |
243 | } | 243 | } |
244 | } | 244 | } |
245 | printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%lx)\n", card->base); | 245 | printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%lx)\n", |
246 | card->base); | ||
247 | |||
246 | return 0; /* Failed to aquire the card! */ | 248 | return 0; /* Failed to aquire the card! */ |
247 | } | 249 | } |
248 | 250 | ||
@@ -466,33 +468,36 @@ static void isicom_tx(unsigned long _data) | |||
466 | residue = NO; | 468 | residue = NO; |
467 | wrd = 0; | 469 | wrd = 0; |
468 | while (1) { | 470 | while (1) { |
469 | cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE - port->xmit_tail)); | 471 | cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE |
472 | - port->xmit_tail)); | ||
470 | if (residue == YES) { | 473 | if (residue == YES) { |
471 | residue = NO; | 474 | residue = NO; |
472 | if (cnt > 0) { | 475 | if (cnt > 0) { |
473 | wrd |= (port->xmit_buf[port->xmit_tail] << 8); | 476 | wrd |= (port->xmit_buf[port->xmit_tail] |
474 | port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); | 477 | << 8); |
478 | port->xmit_tail = (port->xmit_tail + 1) | ||
479 | & (SERIAL_XMIT_SIZE - 1); | ||
475 | port->xmit_cnt--; | 480 | port->xmit_cnt--; |
476 | txcount--; | 481 | txcount--; |
477 | cnt--; | 482 | cnt--; |
478 | outw(wrd, base); | 483 | outw(wrd, base); |
479 | } | 484 | } else { |
480 | else { | ||
481 | outw(wrd, base); | 485 | outw(wrd, base); |
482 | break; | 486 | break; |
483 | } | 487 | } |
484 | } | 488 | } |
485 | if (cnt <= 0) break; | 489 | if (cnt <= 0) break; |
486 | word_count = cnt >> 1; | 490 | word_count = cnt >> 1; |
487 | outsw(base, port->xmit_buf+port->xmit_tail, word_count); | 491 | outsw(base, port->xmit_buf+port->xmit_tail,word_count); |
488 | port->xmit_tail = (port->xmit_tail + (word_count << 1)) & | 492 | port->xmit_tail = (port->xmit_tail |
489 | (SERIAL_XMIT_SIZE - 1); | 493 | + (word_count << 1)) & (SERIAL_XMIT_SIZE - 1); |
490 | txcount -= (word_count << 1); | 494 | txcount -= (word_count << 1); |
491 | port->xmit_cnt -= (word_count << 1); | 495 | port->xmit_cnt -= (word_count << 1); |
492 | if (cnt & 0x0001) { | 496 | if (cnt & 0x0001) { |
493 | residue = YES; | 497 | residue = YES; |
494 | wrd = port->xmit_buf[port->xmit_tail]; | 498 | wrd = port->xmit_buf[port->xmit_tail]; |
495 | port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); | 499 | port->xmit_tail = (port->xmit_tail + 1) |
500 | & (SERIAL_XMIT_SIZE - 1); | ||
496 | port->xmit_cnt--; | 501 | port->xmit_cnt--; |
497 | txcount--; | 502 | txcount--; |
498 | } | 503 | } |
@@ -572,8 +577,8 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
572 | byte_count = header & 0xff; | 577 | byte_count = header & 0xff; |
573 | 578 | ||
574 | if (channel + 1 > card->port_count) { | 579 | if (channel + 1 > card->port_count) { |
575 | printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): %d(channel) > port_count.\n", | 580 | printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): " |
576 | base, channel+1); | 581 | "%d(channel) > port_count.\n", base, channel+1); |
577 | if (card->isa) | 582 | if (card->isa) |
578 | ClearInterrupt(base); | 583 | ClearInterrupt(base); |
579 | else | 584 | else |
@@ -611,26 +616,22 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
611 | header = inw(base); | 616 | header = inw(base); |
612 | switch(header & 0xff) { | 617 | switch(header & 0xff) { |
613 | case 0: /* Change in EIA signals */ | 618 | case 0: /* Change in EIA signals */ |
614 | |||
615 | if (port->flags & ASYNC_CHECK_CD) { | 619 | if (port->flags & ASYNC_CHECK_CD) { |
616 | if (port->status & ISI_DCD) { | 620 | if (port->status & ISI_DCD) { |
617 | if (!(header & ISI_DCD)) { | 621 | if (!(header & ISI_DCD)) { |
618 | /* Carrier has been lost */ | 622 | /* Carrier has been lost */ |
619 | pr_dbg("interrupt: DCD->low.\n"); | 623 | pr_dbg("interrupt: DCD->low.\n" |
624 | ); | ||
620 | port->status &= ~ISI_DCD; | 625 | port->status &= ~ISI_DCD; |
621 | schedule_work(&port->hangup_tq); | 626 | schedule_work(&port->hangup_tq); |
622 | } | 627 | } |
628 | } else if (header & ISI_DCD) { | ||
629 | /* Carrier has been detected */ | ||
630 | pr_dbg("interrupt: DCD->high.\n"); | ||
631 | port->status |= ISI_DCD; | ||
632 | wake_up_interruptible(&port->open_wait); | ||
623 | } | 633 | } |
624 | else { | 634 | } else { |
625 | if (header & ISI_DCD) { | ||
626 | /* Carrier has been detected */ | ||
627 | pr_dbg("interrupt: DCD->high.\n"); | ||
628 | port->status |= ISI_DCD; | ||
629 | wake_up_interruptible(&port->open_wait); | ||
630 | } | ||
631 | } | ||
632 | } | ||
633 | else { | ||
634 | if (header & ISI_DCD) | 635 | if (header & ISI_DCD) |
635 | port->status |= ISI_DCD; | 636 | port->status |= ISI_DCD; |
636 | else | 637 | else |
@@ -642,19 +643,16 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
642 | if (header & ISI_CTS) { | 643 | if (header & ISI_CTS) { |
643 | port->tty->hw_stopped = 0; | 644 | port->tty->hw_stopped = 0; |
644 | /* start tx ing */ | 645 | /* start tx ing */ |
645 | port->status |= (ISI_TXOK | ISI_CTS); | 646 | port->status |= (ISI_TXOK |
647 | | ISI_CTS); | ||
646 | schedule_work(&port->bh_tqueue); | 648 | schedule_work(&port->bh_tqueue); |
647 | } | 649 | } |
650 | } else if (!(header & ISI_CTS)) { | ||
651 | port->tty->hw_stopped = 1; | ||
652 | /* stop tx ing */ | ||
653 | port->status &= ~(ISI_TXOK | ISI_CTS); | ||
648 | } | 654 | } |
649 | else { | 655 | } else { |
650 | if (!(header & ISI_CTS)) { | ||
651 | port->tty->hw_stopped = 1; | ||
652 | /* stop tx ing */ | ||
653 | port->status &= ~(ISI_TXOK | ISI_CTS); | ||
654 | } | ||
655 | } | ||
656 | } | ||
657 | else { | ||
658 | if (header & ISI_CTS) | 656 | if (header & ISI_CTS) |
659 | port->status |= ISI_CTS; | 657 | port->status |= ISI_CTS; |
660 | else | 658 | else |
@@ -673,7 +671,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
673 | 671 | ||
674 | break; | 672 | break; |
675 | 673 | ||
676 | case 1: /* Received Break !!! */ | 674 | case 1: /* Received Break !!! */ |
677 | tty_insert_flip_char(tty, 0, TTY_BREAK); | 675 | tty_insert_flip_char(tty, 0, TTY_BREAK); |
678 | if (port->flags & ASYNC_SAK) | 676 | if (port->flags & ASYNC_SAK) |
679 | do_SAK(tty); | 677 | do_SAK(tty); |
@@ -688,8 +686,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
688 | pr_dbg("Intr: Unknown code in status packet.\n"); | 686 | pr_dbg("Intr: Unknown code in status packet.\n"); |
689 | break; | 687 | break; |
690 | } | 688 | } |
691 | } | 689 | } else { /* Data Packet */ |
692 | else { /* Data Packet */ | ||
693 | 690 | ||
694 | count = tty_prepare_flip_string(tty, &rp, byte_count & ~1); | 691 | count = tty_prepare_flip_string(tty, &rp, byte_count & ~1); |
695 | pr_dbg("Intr: Can rx %d of %d bytes.\n", count, byte_count); | 692 | pr_dbg("Intr: Can rx %d of %d bytes.\n", count, byte_count); |
@@ -697,7 +694,8 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
697 | insw(base, rp, word_count); | 694 | insw(base, rp, word_count); |
698 | byte_count -= (word_count << 1); | 695 | byte_count -= (word_count << 1); |
699 | if (count & 0x0001) { | 696 | if (count & 0x0001) { |
700 | tty_insert_flip_char(tty, inw(base) & 0xff, TTY_NORMAL); | 697 | tty_insert_flip_char(tty, inw(base) & 0xff, |
698 | TTY_NORMAL); | ||
701 | byte_count -= 2; | 699 | byte_count -= 2; |
702 | } | 700 | } |
703 | if (byte_count > 0) { | 701 | if (byte_count > 0) { |
@@ -714,6 +712,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
714 | ClearInterrupt(base); | 712 | ClearInterrupt(base); |
715 | else | 713 | else |
716 | outw(0x0000, base+0x04); /* enable interrupts */ | 714 | outw(0x0000, base+0x04); /* enable interrupts */ |
715 | |||
717 | return IRQ_HANDLED; | 716 | return IRQ_HANDLED; |
718 | } | 717 | } |
719 | 718 | ||
@@ -885,7 +884,8 @@ static int isicom_setup_port(struct isi_port *port) | |||
885 | return 0; | 884 | return 0; |
886 | } | 885 | } |
887 | 886 | ||
888 | static int block_til_ready(struct tty_struct *tty, struct file *filp, struct isi_port *port) | 887 | static int block_til_ready(struct tty_struct *tty, struct file *filp, |
888 | struct isi_port *port) | ||
889 | { | 889 | { |
890 | struct isi_board *card = port->card; | 890 | struct isi_board *card = port->card; |
891 | int do_clocal = 0, retval; | 891 | int do_clocal = 0, retval; |
@@ -905,7 +905,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, struct isi | |||
905 | 905 | ||
906 | /* if non-blocking mode is set ... */ | 906 | /* if non-blocking mode is set ... */ |
907 | 907 | ||
908 | if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { | 908 | if ((filp->f_flags & O_NONBLOCK) || |
909 | (tty->flags & (1 << TTY_IO_ERROR))) { | ||
909 | pr_dbg("block_til_ready: non-block mode.\n"); | 910 | pr_dbg("block_til_ready: non-block mode.\n"); |
910 | port->flags |= ASYNC_NORMAL_ACTIVE; | 911 | port->flags |= ASYNC_NORMAL_ACTIVE; |
911 | return 0; | 912 | return 0; |
@@ -1051,7 +1052,7 @@ static void isicom_shutdown_port(struct isi_port *port) | |||
1051 | card->count = 0; | 1052 | card->count = 0; |
1052 | } | 1053 | } |
1053 | 1054 | ||
1054 | /* last port was closed , shutdown that boad too */ | 1055 | /* last port was closed, shutdown that boad too */ |
1055 | if (C_HUPCL(tty)) { | 1056 | if (C_HUPCL(tty)) { |
1056 | if (!card->count) | 1057 | if (!card->count) |
1057 | isicom_shutdown_board(card); | 1058 | isicom_shutdown_board(card); |
@@ -1078,14 +1079,14 @@ static void isicom_close(struct tty_struct *tty, struct file *filp) | |||
1078 | } | 1079 | } |
1079 | 1080 | ||
1080 | if (tty->count == 1 && port->count != 1) { | 1081 | if (tty->count == 1 && port->count != 1) { |
1081 | printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port count" | 1082 | printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port " |
1082 | "tty->count = 1 port count = %d.\n", | 1083 | "count tty->count = 1 port count = %d.\n", |
1083 | card->base, port->count); | 1084 | card->base, port->count); |
1084 | port->count = 1; | 1085 | port->count = 1; |
1085 | } | 1086 | } |
1086 | if (--port->count < 0) { | 1087 | if (--port->count < 0) { |
1087 | printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port count for" | 1088 | printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port " |
1088 | "channel%d = %d", card->base, port->channel, | 1089 | "count for channel%d = %d", card->base, port->channel, |
1089 | port->count); | 1090 | port->count); |
1090 | port->count = 0; | 1091 | port->count = 0; |
1091 | } | 1092 | } |
@@ -1121,7 +1122,8 @@ static void isicom_close(struct tty_struct *tty, struct file *filp) | |||
1121 | spin_unlock_irqrestore(&card->card_lock, flags); | 1122 | spin_unlock_irqrestore(&card->card_lock, flags); |
1122 | if (port->close_delay) { | 1123 | if (port->close_delay) { |
1123 | pr_dbg("scheduling until time out.\n"); | 1124 | pr_dbg("scheduling until time out.\n"); |
1124 | msleep_interruptible(jiffies_to_msecs(port->close_delay)); | 1125 | msleep_interruptible( |
1126 | jiffies_to_msecs(port->close_delay)); | ||
1125 | } | 1127 | } |
1126 | spin_lock_irqsave(&card->card_lock, flags); | 1128 | spin_lock_irqsave(&card->card_lock, flags); |
1127 | wake_up_interruptible(&port->open_wait); | 1129 | wake_up_interruptible(&port->open_wait); |
@@ -1149,13 +1151,14 @@ static int isicom_write(struct tty_struct *tty, const unsigned char *buf, | |||
1149 | spin_lock_irqsave(&card->card_lock, flags); | 1151 | spin_lock_irqsave(&card->card_lock, flags); |
1150 | 1152 | ||
1151 | while(1) { | 1153 | while(1) { |
1152 | cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, | 1154 | cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt |
1153 | SERIAL_XMIT_SIZE - port->xmit_head)); | 1155 | - 1, SERIAL_XMIT_SIZE - port->xmit_head)); |
1154 | if (cnt <= 0) | 1156 | if (cnt <= 0) |
1155 | break; | 1157 | break; |
1156 | 1158 | ||
1157 | memcpy(port->xmit_buf + port->xmit_head, buf, cnt); | 1159 | memcpy(port->xmit_buf + port->xmit_head, buf, cnt); |
1158 | port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - 1); | 1160 | port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE |
1161 | - 1); | ||
1159 | port->xmit_cnt += cnt; | 1162 | port->xmit_cnt += cnt; |
1160 | buf += cnt; | 1163 | buf += cnt; |
1161 | count -= cnt; | 1164 | count -= cnt; |
@@ -1200,7 +1203,8 @@ static void isicom_flush_chars(struct tty_struct *tty) | |||
1200 | if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars")) | 1203 | if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars")) |
1201 | return; | 1204 | return; |
1202 | 1205 | ||
1203 | if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !port->xmit_buf) | 1206 | if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || |
1207 | !port->xmit_buf) | ||
1204 | return; | 1208 | return; |
1205 | 1209 | ||
1206 | /* this tells the transmitter to consider this port for | 1210 | /* this tells the transmitter to consider this port for |
@@ -1233,7 +1237,8 @@ static int isicom_chars_in_buffer(struct tty_struct *tty) | |||
1233 | } | 1237 | } |
1234 | 1238 | ||
1235 | /* ioctl et all */ | 1239 | /* ioctl et all */ |
1236 | static inline void isicom_send_break(struct isi_port *port, unsigned long length) | 1240 | static inline void isicom_send_break(struct isi_port *port, |
1241 | unsigned long length) | ||
1237 | { | 1242 | { |
1238 | struct isi_board *card = port->card; | 1243 | struct isi_board *card = port->card; |
1239 | unsigned long base = card->base; | 1244 | unsigned long base = card->base; |
@@ -1368,7 +1373,8 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp, | |||
1368 | return 0; | 1373 | return 0; |
1369 | 1374 | ||
1370 | case TIOCGSOFTCAR: | 1375 | case TIOCGSOFTCAR: |
1371 | return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp); | 1376 | return put_user(C_CLOCAL(tty) ? 1 : 0, |
1377 | (unsigned long __user *)argp); | ||
1372 | 1378 | ||
1373 | case TIOCSSOFTCAR: | 1379 | case TIOCSSOFTCAR: |
1374 | if (get_user(arg, (unsigned long __user *) argp)) | 1380 | if (get_user(arg, (unsigned long __user *) argp)) |