diff options
Diffstat (limited to 'drivers/char/cyclades.c')
-rw-r--r-- | drivers/char/cyclades.c | 771 |
1 files changed, 325 insertions, 446 deletions
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 9e0adfe27c12..e4f579c3e245 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -359,7 +359,7 @@ * * 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 @@ -662,7 +662,7 @@ 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 */ + /* 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)); - } 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 */ - 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); +} + +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; - 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. */ + /* 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); +} - /* 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); +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; - mdm_change = readb(base_addr + (CyMISR << index)); - mdm_status = readb(base_addr + (CyMSVR1 << index)); + /* 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); - 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); - } + mdm_change = readb(base_addr + (CyMISR << index)); + mdm_status = readb(base_addr + (CyMSVR1 << index)); - 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 (!info->tty) + goto end; + + 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); } @@ -1893,10 +1778,9 @@ static void cyz_poll(unsigned long arg) struct FIRM_ID __iomem *firm_id; struct ZFW_CTRL __iomem *zfw_ctrl; struct BOARD_CTRL __iomem *board_ctrl; - struct CH_CTRL __iomem *ch_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; @@ -2491,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++) @@ -2812,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); @@ -4444,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", @@ -4467,9 +4348,9 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo) { struct cyclades_port *info; u32 uninitialized_var(mailbox); - unsigned int nports; + unsigned int nports, port; unsigned short chip_number; - int uninitialized_var(index), port; + int uninitialized_var(index); spin_lock_init(&cinfo->card_lock); @@ -4502,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); @@ -5236,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 */ @@ -5480,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: @@ -5496,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); @@ -5524,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); |