Merge git://git.infradead.org/mtd-2.6
[pandora-kernel.git] / drivers / char / cyclades.c
index b9bd4f6..e4f579c 100644 (file)
  *
  * Revision 1.36.3.8  1996/06/07 16:29:00  bentson
  * starting minor number at zero; added missing verify_area
- * as noted by Heiko Eissfeldt <heiko@colossus.escape.de>
+ * as noted by Heiko Eißfeldt <heiko@colossus.escape.de>
  *
  * Revision 1.36.3.7  1996/04/19 21:06:18  bentson
  * remove unneeded boot message & fix CLOCAL hardware flow
 static void cy_throttle(struct tty_struct *tty);
 static void cy_send_xchar(struct tty_struct *tty, char ch);
 
-#define IS_CYC_Z(card) ((card).num_chips == -1)
+#define IS_CYC_Z(card) ((card).num_chips == (unsigned int)-1)
 
 #define Z_FPGA_CHECK(card) \
        ((readl(&((struct RUNTIME_9060 __iomem *) \
@@ -727,8 +727,6 @@ static struct tty_driver *cy_serial_driver;
    driver to probe addresses at a different address, add it to
    this table.  If the driver is probing some other board and
    causing problems, remove the offending address from this table.
-   The cy_setup function extracts additional addresses from the
-   boot options line.  The form is "cyclades=address,address..."
 */
 
 static unsigned int cy_isa_addresses[] = {
@@ -897,71 +895,6 @@ static inline int serial_paranoia_check(struct cyclades_port *info,
        return 0;
 }                              /* serial_paranoia_check */
 
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver
- * (also known as the "bottom half").  This can be called any
- * number of times for any channel without harm.
- */
-static inline void cy_sched_event(struct cyclades_port *info, int event)
-{
-       info->event |= 1 << event; /* remember what kind of event and who */
-       schedule_work(&info->tqueue);
-}                              /* cy_sched_event */
-
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using cy_sched_event(), and they get done here.
- *
- * This is done through one level of indirection--the task queue.
- * When a hardware interrupt service routine wants service by the
- * driver's bottom half, it enqueues the appropriate tq_struct (one
- * per port) to the keventd work queue and sets a request flag
- * that the work queue be processed.
- *
- * Although this may seem unwieldy, it gives the system a way to
- * pass an argument (in this case the pointer to the cyclades_port
- * structure) to the bottom half of the driver.  Previous kernels
- * had to poll every port to see if that port needed servicing.
- */
-static void
-do_softint(struct work_struct *work)
-{
-       struct cyclades_port *info =
-               container_of(work, struct cyclades_port, tqueue);
-       struct tty_struct    *tty;
-
-       tty = info->tty;
-       if (!tty)
-               return;
-
-       if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
-               tty_hangup(info->tty);
-               wake_up_interruptible(&info->open_wait);
-                       info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       }
-       if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event))
-               wake_up_interruptible(&info->open_wait);
-#ifdef CONFIG_CYZ_INTR
-       if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event) &&
-                       !timer_pending(&cyz_rx_full_timer[info->line]))
-               mod_timer(&cyz_rx_full_timer[info->line], jiffies + 1);
-#endif
-       if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event))
-               wake_up_interruptible(&info->delta_msr_wait);
-       tty_wakeup(tty);
-#ifdef Z_WAKE
-       if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event))
-               complete(&info->shutdown_wait);
-#endif
-} /* do_softint */
-
-
 /***********************************************************/
 /********* Start of block of Cyclom-Y specific code ********/
 
@@ -1045,382 +978,332 @@ static unsigned detect_isa_irq(void __iomem * address)
 }
 #endif                         /* CONFIG_ISA */
 
-static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
-                       void __iomem * base_addr, int status, int index)
+static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
+               void __iomem *base_addr)
 {
        struct cyclades_port *info;
        struct tty_struct *tty;
-       int char_count;
-       int j, len, mdm_change, mdm_status, outch;
-       int save_xir, channel, save_car;
-       char data;
+       int len, index = cinfo->bus_index;
+       u8 save_xir, channel, save_car, data, char_count;
 
-       if (status & CySRReceive) {     /* reception interrupt */
 #ifdef CY_DEBUG_INTERRUPTS
-               printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
+       printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
 #endif
-               /* determine the channel & change to that context */
-               spin_lock(&cinfo->card_lock);
-               save_xir = (u_char) readb(base_addr + (CyRIR << index));
-               channel = (u_short) (save_xir & CyIRChannel);
-               info = &cinfo->ports[channel + chip * 4];
-               save_car = readb(base_addr + (CyCAR << index));
-               cy_writeb(base_addr + (CyCAR << index), save_xir);
-
-               /* if there is nowhere to put the data, discard it */
-               if (info->tty == NULL) {
-                       j = (readb(base_addr + (CyRIVR << index)) &
-                               CyIVRMask);
-                       if (j == CyIVRRxEx) {   /* exception */
-                               data = readb(base_addr + (CyRDSR << index));
-                       } else {        /* normal character reception */
-                               char_count = readb(base_addr +
-                                               (CyRDCR << index));
-                               while (char_count--) {
-                                       data = readb(base_addr +
-                                               (CyRDSR << index));
-                               }
-                       }
-               } else {        /* there is an open port for this data */
-                       tty = info->tty;
-                       j = (readb(base_addr + (CyRIVR << index)) &
-                                       CyIVRMask);
-                       if (j == CyIVRRxEx) {   /* exception */
+       /* determine the channel & change to that context */
+       save_xir = readb(base_addr + (CyRIR << index));
+       channel = save_xir & CyIRChannel;
+       info = &cinfo->ports[channel + chip * 4];
+       save_car = readb(base_addr + (CyCAR << index));
+       cy_writeb(base_addr + (CyCAR << index), save_xir);
+
+       /* if there is nowhere to put the data, discard it */
+       if (info->tty == NULL) {
+               if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
+                               CyIVRRxEx) {    /* exception */
+                       data = readb(base_addr + (CyRDSR << index));
+               } else {        /* normal character reception */
+                       char_count = readb(base_addr + (CyRDCR << index));
+                       while (char_count--)
                                data = readb(base_addr + (CyRDSR << index));
-
-                               /* For statistics only */
-                               if (data & CyBREAK)
-                                       info->icount.brk++;
-                               else if (data & CyFRAME)
-                                       info->icount.frame++;
-                               else if (data & CyPARITY)
-                                       info->icount.parity++;
-                               else if (data & CyOVERRUN)
-                                       info->icount.overrun++;
-
-                               if (data & info->ignore_status_mask) {
+               }
+               goto end;
+       }
+       /* there is an open port for this data */
+       tty = info->tty;
+       if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
+                       CyIVRRxEx) {    /* exception */
+               data = readb(base_addr + (CyRDSR << index));
+
+               /* For statistics only */
+               if (data & CyBREAK)
+                       info->icount.brk++;
+               else if (data & CyFRAME)
+                       info->icount.frame++;
+               else if (data & CyPARITY)
+                       info->icount.parity++;
+               else if (data & CyOVERRUN)
+                       info->icount.overrun++;
+
+               if (data & info->ignore_status_mask) {
+                       info->icount.rx++;
+                       return;
+               }
+               if (tty_buffer_request_room(tty, 1)) {
+                       if (data & info->read_status_mask) {
+                               if (data & CyBREAK) {
+                                       tty_insert_flip_char(tty,
+                                               readb(base_addr + (CyRDSR <<
+                                                       index)), TTY_BREAK);
+                                       info->icount.rx++;
+                                       if (info->flags & ASYNC_SAK)
+                                               do_SAK(tty);
+                               } else if (data & CyFRAME) {
+                                       tty_insert_flip_char( tty,
+                                               readb(base_addr + (CyRDSR <<
+                                                       index)), TTY_FRAME);
+                                       info->icount.rx++;
+                                       info->idle_stats.frame_errs++;
+                               } else if (data & CyPARITY) {
+                                       /* Pieces of seven... */
+                                       tty_insert_flip_char(tty,
+                                               readb(base_addr + (CyRDSR <<
+                                                       index)), TTY_PARITY);
+                                       info->icount.rx++;
+                                       info->idle_stats.parity_errs++;
+                               } else if (data & CyOVERRUN) {
+                                       tty_insert_flip_char(tty, 0,
+                                                       TTY_OVERRUN);
+                                       info->icount.rx++;
+                                       /* If the flip buffer itself is
+                                          overflowing, we still lose
+                                          the next incoming character.
+                                        */
+                                       tty_insert_flip_char(tty,
+                                               readb(base_addr + (CyRDSR <<
+                                                       index)), TTY_FRAME);
                                        info->icount.rx++;
-                                       spin_unlock(&cinfo->card_lock);
-                                       return;
-                               }
-                               if (tty_buffer_request_room(tty, 1)) {
-                                       if (data & info->read_status_mask) {
-                                               if (data & CyBREAK) {
-                                                       tty_insert_flip_char(
-                                                               tty,
-                                                               readb(
-                                                               base_addr +
-                                                               (CyRDSR <<
-                                                                       index)),
-                                                               TTY_BREAK);
-                                                       info->icount.rx++;
-                                                       if (info->flags &
-                                                           ASYNC_SAK) {
-                                                               do_SAK(tty);
-                                                       }
-                                               } else if (data & CyFRAME) {
-                                                       tty_insert_flip_char(
-                                                               tty,
-                                                               readb(
-                                                               base_addr +
-                                                               (CyRDSR <<
-                                                                       index)),
-                                                               TTY_FRAME);
-                                                       info->icount.rx++;
-                                                       info->idle_stats.
-                                                               frame_errs++;
-                                               } else if (data & CyPARITY) {
-                                                       /* Pieces of seven... */
-                                                       tty_insert_flip_char(
-                                                               tty,
-                                                               readb(
-                                                               base_addr +
-                                                               (CyRDSR <<
-                                                                       index)),
-                                                               TTY_PARITY);
-                                                       info->icount.rx++;
-                                                       info->idle_stats.
-                                                               parity_errs++;
-                                               } else if (data & CyOVERRUN) {
-                                                       tty_insert_flip_char(
-                                                               tty, 0,
-                                                               TTY_OVERRUN);
-                                                       info->icount.rx++;
-                                               /* If the flip buffer itself is
-                                                  overflowing, we still lose
-                                                  the next incoming character.
-                                                */
-                                                       tty_insert_flip_char(
-                                                               tty,
-                                                               readb(
-                                                               base_addr +
-                                                               (CyRDSR <<
-                                                                       index)),
-                                                               TTY_FRAME);
-                                                       info->icount.rx++;
-                                                       info->idle_stats.
-                                                               overruns++;
-                                       /* These two conditions may imply */
-                                       /* a normal read should be done. */
-                                       /* }else if(data & CyTIMEOUT){ */
-                                       /* }else if(data & CySPECHAR){ */
-                                               } else {
-                                                       tty_insert_flip_char(
-                                                               tty, 0,
-                                                               TTY_NORMAL);
-                                                       info->icount.rx++;
-                                               }
-                                       } else {
-                                               tty_insert_flip_char(tty, 0,
-                                                               TTY_NORMAL);
-                                               info->icount.rx++;
-                                       }
-                               } else {
-                                       /* there was a software buffer
-                                          overrun and nothing could be
-                                          done about it!!! */
-                                       info->icount.buf_overrun++;
                                        info->idle_stats.overruns++;
+                               /* These two conditions may imply */
+                               /* a normal read should be done. */
+                               /* } else if(data & CyTIMEOUT) { */
+                               /* } else if(data & CySPECHAR) { */
+                               } else {
+                                       tty_insert_flip_char(tty, 0,
+                                                       TTY_NORMAL);
+                                       info->icount.rx++;
                                }
-                       } else {        /* normal character reception */
-                               /* load # chars available from the chip */
-                               char_count = readb(base_addr +
-                                               (CyRDCR << index));
+                       } else {
+                               tty_insert_flip_char(tty, 0, TTY_NORMAL);
+                               info->icount.rx++;
+                       }
+               } else {
+                       /* there was a software buffer overrun and nothing
+                        * could be done about it!!! */
+                       info->icount.buf_overrun++;
+                       info->idle_stats.overruns++;
+               }
+       } else {        /* normal character reception */
+               /* load # chars available from the chip */
+               char_count = readb(base_addr + (CyRDCR << index));
 
 #ifdef CY_ENABLE_MONITORING
-                               ++info->mon.int_count;
-                               info->mon.char_count += char_count;
-                               if (char_count > info->mon.char_max)
-                                       info->mon.char_max = char_count;
-                               info->mon.char_last = char_count;
+               ++info->mon.int_count;
+               info->mon.char_count += char_count;
+               if (char_count > info->mon.char_max)
+                       info->mon.char_max = char_count;
+               info->mon.char_last = char_count;
 #endif
-                               len = tty_buffer_request_room(tty, char_count);
-                               while (len--) {
-                                       data = readb(base_addr +
-                                                       (CyRDSR << index));
-                                       tty_insert_flip_char(tty, data,
-                                                       TTY_NORMAL);
-                                       info->idle_stats.recv_bytes++;
-                                       info->icount.rx++;
+               len = tty_buffer_request_room(tty, char_count);
+               while (len--) {
+                       data = readb(base_addr + (CyRDSR << index));
+                       tty_insert_flip_char(tty, data, TTY_NORMAL);
+                       info->idle_stats.recv_bytes++;
+                       info->icount.rx++;
 #ifdef CY_16Y_HACK
-                                       udelay(10L);
+                       udelay(10L);
 #endif
-                               }
-                               info->idle_stats.recv_idle = jiffies;
-                       }
-                       tty_schedule_flip(tty);
                }
-               /* end of service */
-               cy_writeb(base_addr + (CyRIR << index), (save_xir & 0x3f));
-               cy_writeb(base_addr + (CyCAR << index), (save_car));
-               spin_unlock(&cinfo->card_lock);
+               info->idle_stats.recv_idle = jiffies;
        }
+       tty_schedule_flip(tty);
+end:
+       /* end of service */
+       cy_writeb(base_addr + (CyRIR << index), save_xir & 0x3f);
+       cy_writeb(base_addr + (CyCAR << index), save_car);
+}
 
-       if (status & CySRTransmit) {    /* transmission interrupt */
-               /* Since we only get here when the transmit buffer
-                  is empty, we know we can always stuff a dozen
-                  characters. */
+static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
+               void __iomem *base_addr)
+{
+       struct cyclades_port *info;
+       int char_count, index = cinfo->bus_index;
+       u8 save_xir, channel, save_car, outch;
+
+       /* Since we only get here when the transmit buffer
+          is empty, we know we can always stuff a dozen
+          characters. */
 #ifdef CY_DEBUG_INTERRUPTS
-               printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
+       printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
 #endif
 
-               /* determine the channel & change to that context */
-               spin_lock(&cinfo->card_lock);
-               save_xir = (u_char) readb(base_addr + (CyTIR << index));
-               channel = (u_short) (save_xir & CyIRChannel);
-               save_car = readb(base_addr + (CyCAR << index));
-               cy_writeb(base_addr + (CyCAR << index), save_xir);
+       /* determine the channel & change to that context */
+       save_xir = readb(base_addr + (CyTIR << index));
+       channel = save_xir & CyIRChannel;
+       save_car = readb(base_addr + (CyCAR << index));
+       cy_writeb(base_addr + (CyCAR << index), save_xir);
 
-               /* validate the port# (as configured and open) */
-               if (channel + chip * 4 >= cinfo->nports) {
-                       cy_writeb(base_addr + (CySRER << index),
-                                 readb(base_addr + (CySRER << index)) &
-                                 ~CyTxRdy);
-                       goto txend;
-               }
-               info = &cinfo->ports[channel + chip * 4];
-               if (info->tty == NULL) {
-                       cy_writeb(base_addr + (CySRER << index),
-                                 readb(base_addr + (CySRER << index)) &
-                                 ~CyTxRdy);
-                       goto txdone;
-               }
+       /* validate the port# (as configured and open) */
+       if (channel + chip * 4 >= cinfo->nports) {
+               cy_writeb(base_addr + (CySRER << index),
+                         readb(base_addr + (CySRER << index)) & ~CyTxRdy);
+               goto end;
+       }
+       info = &cinfo->ports[channel + chip * 4];
+       if (info->tty == NULL) {
+               cy_writeb(base_addr + (CySRER << index),
+                         readb(base_addr + (CySRER << index)) & ~CyTxRdy);
+               goto end;
+       }
 
-               /* load the on-chip space for outbound data */
-               char_count = info->xmit_fifo_size;
+       /* load the on-chip space for outbound data */
+       char_count = info->xmit_fifo_size;
 
-               if (info->x_char) {     /* send special char */
-                       outch = info->x_char;
-                       cy_writeb(base_addr + (CyTDR << index), outch);
-                       char_count--;
-                       info->icount.tx++;
-                       info->x_char = 0;
-               }
+       if (info->x_char) {     /* send special char */
+               outch = info->x_char;
+               cy_writeb(base_addr + (CyTDR << index), outch);
+               char_count--;
+               info->icount.tx++;
+               info->x_char = 0;
+       }
 
-               if (info->breakon || info->breakoff) {
-                       if (info->breakon) {
-                               cy_writeb(base_addr + (CyTDR << index), 0);
-                               cy_writeb(base_addr + (CyTDR << index), 0x81);
-                               info->breakon = 0;
-                               char_count -= 2;
-                       }
-                       if (info->breakoff) {
-                               cy_writeb(base_addr + (CyTDR << index), 0);
-                               cy_writeb(base_addr + (CyTDR << index), 0x83);
-                               info->breakoff = 0;
-                               char_count -= 2;
-                       }
+       if (info->breakon || info->breakoff) {
+               if (info->breakon) {
+                       cy_writeb(base_addr + (CyTDR << index), 0);
+                       cy_writeb(base_addr + (CyTDR << index), 0x81);
+                       info->breakon = 0;
+                       char_count -= 2;
+               }
+               if (info->breakoff) {
+                       cy_writeb(base_addr + (CyTDR << index), 0);
+                       cy_writeb(base_addr + (CyTDR << index), 0x83);
+                       info->breakoff = 0;
+                       char_count -= 2;
                }
+       }
 
-               while (char_count-- > 0) {
-                       if (!info->xmit_cnt) {
-                               if (readb(base_addr + (CySRER << index)) &
-                                               CyTxMpty) {
-                                       cy_writeb(base_addr + (CySRER << index),
-                                               readb(base_addr +
-                                                       (CySRER << index)) &
+       while (char_count-- > 0) {
+               if (!info->xmit_cnt) {
+                       if (readb(base_addr + (CySRER << index)) & CyTxMpty) {
+                               cy_writeb(base_addr + (CySRER << index),
+                                       readb(base_addr + (CySRER << index)) &
                                                ~CyTxMpty);
-                               } else {
-                                       cy_writeb(base_addr + (CySRER << index),
-                                               (readb(base_addr +
-                                                       (CySRER << index)) &
+                       } else {
+                               cy_writeb(base_addr + (CySRER << index),
+                                       (readb(base_addr + (CySRER << index)) &
                                                ~CyTxRdy) | CyTxMpty);
-                               }
-                               goto txdone;
                        }
-                       if (info->xmit_buf == NULL) {
-                               cy_writeb(base_addr + (CySRER << index),
-                                       readb(base_addr + (CySRER << index)) &
+                       goto done;
+               }
+               if (info->xmit_buf == NULL) {
+                       cy_writeb(base_addr + (CySRER << index),
+                               readb(base_addr + (CySRER << index)) &
                                        ~CyTxRdy);
-                               goto txdone;
-                       }
-                       if (info->tty->stopped || info->tty->hw_stopped) {
-                               cy_writeb(base_addr + (CySRER << index),
-                                       readb(base_addr + (CySRER << index)) &
+                       goto done;
+               }
+               if (info->tty->stopped || info->tty->hw_stopped) {
+                       cy_writeb(base_addr + (CySRER << index),
+                               readb(base_addr + (CySRER << index)) &
                                        ~CyTxRdy);
-                               goto txdone;
-                       }
-                       /* Because the Embedded Transmit Commands have
-                          been enabled, we must check to see if the
-                          escape character, NULL, is being sent.  If it
-                          is, we must ensure that there is room for it
-                          to be doubled in the output stream.  Therefore
-                          we no longer advance the pointer when the
-                          character is fetched, but rather wait until
-                          after the check for a NULL output character.
-                          This is necessary because there may not be
-                          room for the two chars needed to send a NULL.)
-                        */
-                       outch = info->xmit_buf[info->xmit_tail];
-                       if (outch) {
+                       goto done;
+               }
+               /* Because the Embedded Transmit Commands have been enabled,
+                * we must check to see if the escape character, NULL, is being
+                * sent. If it is, we must ensure that there is room for it to
+                * be doubled in the output stream.  Therefore we no longer
+                * advance the pointer when the character is fetched, but
+                * rather wait until after the check for a NULL output
+                * character. This is necessary because there may not be room
+                * for the two chars needed to send a NULL.)
+                */
+               outch = info->xmit_buf[info->xmit_tail];
+               if (outch) {
+                       info->xmit_cnt--;
+                       info->xmit_tail = (info->xmit_tail + 1) &
+                                       (SERIAL_XMIT_SIZE - 1);
+                       cy_writeb(base_addr + (CyTDR << index), outch);
+                       info->icount.tx++;
+               } else {
+                       if (char_count > 1) {
                                info->xmit_cnt--;
                                info->xmit_tail = (info->xmit_tail + 1) &
-                                               (SERIAL_XMIT_SIZE - 1);
+                                       (SERIAL_XMIT_SIZE - 1);
                                cy_writeb(base_addr + (CyTDR << index), outch);
+                               cy_writeb(base_addr + (CyTDR << index), 0);
                                info->icount.tx++;
-                       } else {
-                               if (char_count > 1) {
-                                       info->xmit_cnt--;
-                                       info->xmit_tail = (info->xmit_tail + 1)&
-                                               (SERIAL_XMIT_SIZE - 1);
-                                       cy_writeb(base_addr + (CyTDR << index),
-                                               outch);
-                                       cy_writeb(base_addr + (CyTDR << index),
-                                               0);
-                                       info->icount.tx++;
-                                       char_count--;
-                               }
+                               char_count--;
                        }
                }
-
-txdone:
-               if (info->xmit_cnt < WAKEUP_CHARS) {
-                       cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
-               }
-txend:
-               /* end of service */
-               cy_writeb(base_addr + (CyTIR << index), (save_xir & 0x3f));
-               cy_writeb(base_addr + (CyCAR << index), (save_car));
-               spin_unlock(&cinfo->card_lock);
        }
 
-       if (status & CySRModem) {       /* modem interrupt */
+done:
+       tty_wakeup(info->tty);
+end:
+       /* end of service */
+       cy_writeb(base_addr + (CyTIR << index), save_xir & 0x3f);
+       cy_writeb(base_addr + (CyCAR << index), save_car);
+}
+
+static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
+               void __iomem *base_addr)
+{
+       struct cyclades_port *info;
+       int index = cinfo->bus_index;
+       u8 save_xir, channel, save_car, mdm_change, mdm_status;
 
-               /* determine the channel & change to that context */
-               spin_lock(&cinfo->card_lock);
-               save_xir = (u_char) readb(base_addr + (CyMIR << index));
-               channel = (u_short) (save_xir & CyIRChannel);
-               info = &cinfo->ports[channel + chip * 4];
-               save_car = readb(base_addr + (CyCAR << index));
-               cy_writeb(base_addr + (CyCAR << index), save_xir);
+       /* determine the channel & change to that context */
+       save_xir = readb(base_addr + (CyMIR << index));
+       channel = save_xir & CyIRChannel;
+       info = &cinfo->ports[channel + chip * 4];
+       save_car = readb(base_addr + (CyCAR << index));
+       cy_writeb(base_addr + (CyCAR << index), save_xir);
 
-               mdm_change = readb(base_addr + (CyMISR << index));
-               mdm_status = readb(base_addr + (CyMSVR1 << index));
+       mdm_change = readb(base_addr + (CyMISR << index));
+       mdm_status = readb(base_addr + (CyMSVR1 << index));
 
-               if (info->tty) {
-                       if (mdm_change & CyANY_DELTA) {
-                               /* For statistics only */
-                               if (mdm_change & CyDCD)
-                                       info->icount.dcd++;
-                               if (mdm_change & CyCTS)
-                                       info->icount.cts++;
-                               if (mdm_change & CyDSR)
-                                       info->icount.dsr++;
-                               if (mdm_change & CyRI)
-                                       info->icount.rng++;
-
-                               cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
-                       }
+       if (!info->tty)
+               goto end;
 
-                       if ((mdm_change & CyDCD) &&
-                                       (info->flags & ASYNC_CHECK_CD)) {
-                               if (mdm_status & CyDCD) {
-                                       cy_sched_event(info,
-                                                       Cy_EVENT_OPEN_WAKEUP);
-                               } else {
-                                       cy_sched_event(info, Cy_EVENT_HANGUP);
-                               }
-                       }
-                       if ((mdm_change & CyCTS) &&
-                                       (info->flags & ASYNC_CTS_FLOW)) {
-                               if (info->tty->hw_stopped) {
-                                       if (mdm_status & CyCTS) {
-                                               /* cy_start isn't used
-                                                  because... !!! */
-                                               info->tty->hw_stopped = 0;
-                                               cy_writeb(base_addr +
-                                                       (CySRER << index),
-                                                       readb(base_addr +
-                                                               (CySRER <<
-                                                                       index))|
-                                                       CyTxRdy);
-                                               cy_sched_event(info,
-                                                       Cy_EVENT_WRITE_WAKEUP);
-                                       }
-                               } else {
-                                       if (!(mdm_status & CyCTS)) {
-                                               /* cy_stop isn't used
-                                                  because ... !!! */
-                                               info->tty->hw_stopped = 1;
-                                               cy_writeb(base_addr +
-                                                       (CySRER << index),
-                                                       readb(base_addr +
-                                                               (CySRER <<
-                                                               index)) &
-                                                       ~CyTxRdy);
-                                       }
-                               }
+       if (mdm_change & CyANY_DELTA) {
+               /* For statistics only */
+               if (mdm_change & CyDCD)
+                       info->icount.dcd++;
+               if (mdm_change & CyCTS)
+                       info->icount.cts++;
+               if (mdm_change & CyDSR)
+                       info->icount.dsr++;
+               if (mdm_change & CyRI)
+                       info->icount.rng++;
+
+               wake_up_interruptible(&info->delta_msr_wait);
+       }
+
+       if ((mdm_change & CyDCD) && (info->flags & ASYNC_CHECK_CD)) {
+               if (!(mdm_status & CyDCD)) {
+                       tty_hangup(info->tty);
+                       info->flags &= ~ASYNC_NORMAL_ACTIVE;
+               }
+               wake_up_interruptible(&info->open_wait);
+       }
+       if ((mdm_change & CyCTS) && (info->flags & ASYNC_CTS_FLOW)) {
+               if (info->tty->hw_stopped) {
+                       if (mdm_status & CyCTS) {
+                               /* cy_start isn't used
+                                  because... !!! */
+                               info->tty->hw_stopped = 0;
+                               cy_writeb(base_addr + (CySRER << index),
+                                       readb(base_addr + (CySRER << index)) |
+                                               CyTxRdy);
+                               tty_wakeup(info->tty);
                        }
-/*                     if (mdm_change & CyDSR) {
+               } else {
+                       if (!(mdm_status & CyCTS)) {
+                               /* cy_stop isn't used
+                                  because ... !!! */
+                               info->tty->hw_stopped = 1;
+                               cy_writeb(base_addr + (CySRER << index),
+                                       readb(base_addr + (CySRER << index)) &
+                                               ~CyTxRdy);
                        }
-                       if (mdm_change & CyRI) {
-                       }*/
                }
-               /* end of service */
-               cy_writeb(base_addr + (CyMIR << index), (save_xir & 0x3f));
-               cy_writeb(base_addr + (CyCAR << index), save_car);
-               spin_unlock(&cinfo->card_lock);
        }
+/*     if (mdm_change & CyDSR) {
+       }
+       if (mdm_change & CyRI) {
+       }*/
+end:
+       /* end of service */
+       cy_writeb(base_addr + (CyMIR << index), save_xir & 0x3f);
+       cy_writeb(base_addr + (CyCAR << index), save_car);
 }
 
 /* The real interrupt service routine is called
@@ -1432,10 +1315,8 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
        int status;
        struct cyclades_card *cinfo = dev_id;
        void __iomem *base_addr, *card_base_addr;
-       int chip;
+       unsigned int chip, too_many, had_work;
        int index;
-       int too_many;
-       int had_work;
 
        if (unlikely(cinfo == NULL)) {
 #ifdef CY_DEBUG_INTERRUPTS
@@ -1470,11 +1351,16 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
                           chips to be checked in a round-robin fashion (after
                           draining each of a bunch (1000) of characters).
                         */
-                               if (1000 < too_many++) {
+                               if (1000 < too_many++)
                                        break;
-                               }
-                               cyy_intr_chip(cinfo, chip, base_addr, status,
-                                               index);
+                               spin_lock(&cinfo->card_lock);
+                               if (status & CySRReceive) /* rx intr */
+                                       cyy_chip_rx(cinfo, chip, base_addr);
+                               if (status & CySRTransmit) /* tx intr */
+                                       cyy_chip_tx(cinfo, chip, base_addr);
+                               if (status & CySRModem) /* modem intr */
+                                       cyy_chip_modem(cinfo, chip, base_addr);
+                               spin_unlock(&cinfo->card_lock);
                        }
                }
        } while (had_work);
@@ -1529,7 +1415,7 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
        struct ZFW_CTRL __iomem *zfw_ctrl;
        struct BOARD_CTRL __iomem *board_ctrl;
        __u32 __iomem *pci_doorbell;
-       int index;
+       unsigned int index;
 
        firm_id = cinfo->base_addr + ID_ADDRESS;
        if (!ISZLOADED(*cinfo)) {
@@ -1554,13 +1440,12 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
        return 0;
 }                              /* cyz_issue_cmd */
 
-static void
-cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
+static void cyz_handle_rx(struct cyclades_port *info,
                struct BUF_CTRL __iomem *buf_ctrl)
 {
        struct cyclades_card *cinfo = info->card;
        struct tty_struct *tty = info->tty;
-       int char_count;
+       unsigned int char_count;
        int len;
 #ifdef BLOCKMOVE
        unsigned char *buf;
@@ -1633,9 +1518,11 @@ cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
                                char_count = rx_put - rx_get;
                        else
                                char_count = rx_put - rx_get + rx_bufsize;
-                       if (char_count >= (int)readl(&buf_ctrl->rx_threshold)) {
-                               cy_sched_event(info, Cy_EVENT_Z_RX_FULL);
-                       }
+                       if (char_count >= readl(&buf_ctrl->rx_threshold) &&
+                                       !timer_pending(&cyz_rx_full_timer[
+                                                       info->line]))
+                               mod_timer(&cyz_rx_full_timer[info->line],
+                                               jiffies + 1);
 #endif
                        info->idle_stats.recv_idle = jiffies;
                        tty_schedule_flip(tty);
@@ -1645,14 +1532,13 @@ cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
        }
 }
 
-static void
-cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
+static void cyz_handle_tx(struct cyclades_port *info,
                struct BUF_CTRL __iomem *buf_ctrl)
 {
        struct cyclades_card *cinfo = info->card;
        struct tty_struct *tty = info->tty;
-       char data;
-       int char_count;
+       u8 data;
+       unsigned int char_count;
 #ifdef BLOCKMOVE
        int small_count;
 #endif
@@ -1716,10 +1602,8 @@ cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
                        info->icount.tx++;
                }
 #endif
+               tty_wakeup(tty);
 ztxdone:
-               if (info->xmit_cnt < WAKEUP_CHARS) {
-                       cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
-               }
                /* Update tx_put */
                cy_writel(&buf_ctrl->tx_put, tx_put);
        }
@@ -1781,10 +1665,11 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
                                if ((fw_ver > 241 ? ((u_long) param) :
                                                readl(&ch_ctrl->rs_status)) &
                                                C_RS_DCD) {
-                                       cy_sched_event(info,
-                                                       Cy_EVENT_OPEN_WAKEUP);
+                                       wake_up_interruptible(&info->open_wait);
                                } else {
-                                       cy_sched_event(info, Cy_EVENT_HANGUP);
+                                       tty_hangup(info->tty);
+                                       wake_up_interruptible(&info->open_wait);
+                                       info->flags &= ~ASYNC_NORMAL_ACTIVE;
                                }
                        }
                        break;
@@ -1802,7 +1687,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
                        break;
 #ifdef Z_WAKE
                case C_CM_IOCTLW:
-                       cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
+                       complete(&info->shutdown_wait);
                        break;
 #endif
 #ifdef CONFIG_CYZ_INTR
@@ -1814,7 +1699,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
                        printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
                                        "port %ld\n", info->card, channel);
 #endif
-                       cyz_handle_rx(info, ch_ctrl, buf_ctrl);
+                       cyz_handle_rx(info, buf_ctrl);
                        break;
                case C_CM_TXBEMPTY:
                case C_CM_TXLOWWM:
@@ -1824,7 +1709,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
                        printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
                                        "port %ld\n", info->card, channel);
 #endif
-                       cyz_handle_tx(info, ch_ctrl, buf_ctrl);
+                       cyz_handle_tx(info, buf_ctrl);
                        break;
 #endif                         /* CONFIG_CYZ_INTR */
                case C_CM_FATAL:
@@ -1834,7 +1719,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
                        break;
                }
                if (delta_count)
-                       cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
+                       wake_up_interruptible(&info->delta_msr_wait);
                if (special_count)
                        tty_schedule_flip(tty);
        }
@@ -1890,13 +1775,12 @@ static void cyz_poll(unsigned long arg)
        struct cyclades_card *cinfo;
        struct cyclades_port *info;
        struct tty_struct *tty;
-       static struct FIRM_ID *firm_id;
-       static struct ZFW_CTRL *zfw_ctrl;
-       static struct BOARD_CTRL *board_ctrl;
-       static struct CH_CTRL *ch_ctrl;
-       static struct BUF_CTRL *buf_ctrl;
+       struct FIRM_ID __iomem *firm_id;
+       struct ZFW_CTRL __iomem *zfw_ctrl;
+       struct BOARD_CTRL __iomem *board_ctrl;
+       struct BUF_CTRL __iomem *buf_ctrl;
        unsigned long expires = jiffies + HZ;
-       int card, port;
+       unsigned int port, card;
 
        for (card = 0; card < NR_CARDS; card++) {
                cinfo = &cy_card[card];
@@ -1923,12 +1807,11 @@ static void cyz_poll(unsigned long arg)
                for (port = 0; port < cinfo->nports; port++) {
                        info = &cinfo->ports[port];
                        tty = info->tty;
-                       ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
                        buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
 
                        if (!info->throttle)
-                               cyz_handle_rx(info, ch_ctrl, buf_ctrl);
-                       cyz_handle_tx(info, ch_ctrl, buf_ctrl);
+                               cyz_handle_rx(info, buf_ctrl);
+                       cyz_handle_tx(info, buf_ctrl);
                }
                /* poll every 'cyz_polling_cycle' period */
                expires = jiffies + cyz_polling_cycle;
@@ -2038,7 +1921,6 @@ static int startup(struct cyclades_port *info)
                struct ZFW_CTRL __iomem *zfw_ctrl;
                struct BOARD_CTRL __iomem *board_ctrl;
                struct CH_CTRL __iomem *ch_ctrl;
-               int retval;
 
                base_addr = card->base_addr;
 
@@ -2410,7 +2292,6 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
                struct ZFW_CTRL __iomem *zfw_ctrl;
                struct BOARD_CTRL __iomem *board_ctrl;
                struct CH_CTRL __iomem *ch_ctrl;
-               int retval;
 
                base_addr = cinfo->base_addr;
                firm_id = base_addr + ID_ADDRESS;
@@ -2493,11 +2374,11 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
 static int cy_open(struct tty_struct *tty, struct file *filp)
 {
        struct cyclades_port *info;
-       unsigned int i;
-       int retval, line;
+       unsigned int i, line;
+       int retval;
 
        line = tty->index;
-       if ((line < 0) || (NR_PORTS <= line)) {
+       if ((tty->index < 0) || (NR_PORTS <= line)) {
                return -ENODEV;
        }
        for (i = 0; i < NR_CARDS; i++)
@@ -2814,7 +2695,6 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
        spin_lock_irqsave(&card->card_lock, flags);
 
        tty->closing = 0;
-       info->event = 0;
        info->tty = NULL;
        if (info->blocked_open) {
                spin_unlock_irqrestore(&card->card_lock, flags);
@@ -4446,7 +4326,6 @@ static void cy_hangup(struct tty_struct *tty)
 
        cy_flush_buffer(tty);
        shutdown(info);
-       info->event = 0;
        info->count = 0;
 #ifdef CY_DEBUG_COUNT
        printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n",
@@ -4468,10 +4347,10 @@ static void cy_hangup(struct tty_struct *tty)
 static int __devinit cy_init_card(struct cyclades_card *cinfo)
 {
        struct cyclades_port *info;
-       u32 mailbox;
-       unsigned int nports;
+       u32 uninitialized_var(mailbox);
+       unsigned int nports, port;
        unsigned short chip_number;
-       int index, port;
+       int uninitialized_var(index);
 
        spin_lock_init(&cinfo->card_lock);
 
@@ -4504,7 +4383,6 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
                info->closing_wait = CLOSING_WAIT_DELAY;
                info->close_delay = 5 * HZ / 10;
 
-               INIT_WORK(&info->tqueue, do_softint);
                init_waitqueue_head(&info->open_wait);
                init_waitqueue_head(&info->close_wait);
                init_completion(&info->shutdown_wait);
@@ -4902,7 +4780,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
        struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
        struct CUSTOM_REG __iomem *cust = base_addr;
        struct ZFW_CTRL __iomem *pt_zfwctrl;
-       u8 *tmp;
+       void __iomem *tmp;
        u32 mailbox, status;
        unsigned int i;
        int retval;
@@ -4964,13 +4842,13 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
        udelay(100);
 
        /* clear memory */
-       for (tmp = base_addr; (void *)tmp < base_addr + RAM_SIZE; tmp++)
+       for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
                cy_writeb(tmp, 255);
        if (mailbox != 0) {
                /* set window to last 512K of RAM */
                cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
                //sleep(1);
-               for (tmp = base_addr; (void *)tmp < base_addr + RAM_SIZE; tmp++)
+               for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
                        cy_writeb(tmp, 255);
                /* set window to beginning of RAM */
                cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
@@ -5238,7 +5116,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                        }
                }
 #endif                         /* CONFIG_CYZ_INTR */
-               cy_card[card_no].num_chips = -1;
+               cy_card[card_no].num_chips = (unsigned int)-1;
        }
 
        /* set cy_card */
@@ -5482,13 +5360,13 @@ static int __init cy_init(void)
 #ifdef CONFIG_PCI
        /* look for pci boards */
        retval = pci_register_driver(&cy_pci_driver);
-       if (retval && !nboards)
-               goto err_unr;
+       if (retval && !nboards) {
+               tty_unregister_driver(cy_serial_driver);
+               goto err_frtty;
+       }
 #endif
 
        return 0;
-err_unr:
-       tty_unregister_driver(cy_serial_driver);
 err_frtty:
        put_tty_driver(cy_serial_driver);
 err:
@@ -5498,7 +5376,7 @@ err:
 static void __exit cy_cleanup_module(void)
 {
        struct cyclades_card *card;
-       int i, e1;
+       unsigned int i, e1;
 
 #ifndef CONFIG_CYZ_INTR
        del_timer_sync(&cyz_timerlist);
@@ -5526,8 +5404,7 @@ static void __exit cy_cleanup_module(void)
 #endif /* CONFIG_CYZ_INTR */
                                )
                                free_irq(card->irq, card);
-                       for (e1 = card->first_line;
-                                       e1 < card->first_line +
+                       for (e1 = card->first_line; e1 < card->first_line +
                                        card->nports; e1++)
                                tty_unregister_device(cy_serial_driver, e1);
                        kfree(card->ports);