static irqreturn_t scc_rx_int(int irq, void *data) { unsigned char ch; struct scc_port *port = data; struct tty_struct *tty = port->gs.port.tty; SCC_ACCESS_INIT(port); ch = SCCread_NB(RX_DATA_REG); if (!tty) { printk(KERN_WARNING "scc_rx_int with NULL tty!\n"); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); return IRQ_HANDLED; } tty_insert_flip_char(tty, ch, 0); /* Check if another character is already ready; in that case, the * spcond_int() function must be used, because this character may have an * error condition that isn't signalled by the interrupt vector used! */ if (SCCread(INT_PENDING_REG) & (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) { scc_spcond_int (irq, data); return IRQ_HANDLED; } SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); tty_flip_buffer_push(tty); return IRQ_HANDLED; }
static irqreturn_t scc_stat_int(int irq, void *data) { struct scc_port *port = data; unsigned channel = port->channel; unsigned char last_sr, sr, changed; SCC_ACCESS_INIT(port); last_sr = scc_last_status_reg[channel]; sr = scc_last_status_reg[channel] = SCCread_NB(STATUS_REG); changed = last_sr ^ sr; if (changed & SR_DCD) { port->c_dcd = !!(sr & SR_DCD); if (!(port->gs.port.flags & ASYNC_CHECK_CD)) ; /* Don't report DCD changes */ else if (port->c_dcd) { wake_up_interruptible(&port->gs.port.open_wait); } else { if (port->gs.port.tty) tty_hangup (port->gs.port.tty); } } SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); return IRQ_HANDLED; }
static void scc_stat_int(int irq, void *data, struct pt_regs *fp) { struct scc_port *port = data; unsigned channel = port->channel; unsigned char last_sr, sr, changed; SCC_ACCESS_INIT(port); last_sr = scc_last_status_reg[channel]; sr = scc_last_status_reg[channel] = SCCread_NB(STATUS_REG); changed = last_sr ^ sr; if (changed & SR_DCD) { port->c_dcd = !!(sr & SR_DCD); if (!(port->gs.flags & ASYNC_CHECK_CD)) ; /* Don't report DCD changes */ else if (port->c_dcd) { if (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) { /* Are we blocking in open?*/ wake_up_interruptible(&port->gs.open_wait); } } else { if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) && (port->gs.flags & ASYNC_CALLOUT_NOHUP))) { if (port->gs.tty) tty_hangup (port->gs.tty); } } } SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); }
static void scc_rx_int(int irq, void *data, struct pt_regs *fp) { unsigned char ch; struct scc_port *port = data; struct tty_struct *tty = port->gs.tty; SCC_ACCESS_INIT(port); ch = SCCread_NB(RX_DATA_REG); if (!tty) { printk(KERN_WARNING "scc_rx_int with NULL tty!\n"); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); return; } if (tty->flip.count < TTY_FLIPBUF_SIZE) { *tty->flip.char_buf_ptr = ch; *tty->flip.flag_buf_ptr = 0; tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; } /* Check if another character is already ready; in that case, the * spcond_int() function must be used, because this character may have an * error condition that isn't signalled by the interrupt vector used! */ if (SCCread(INT_PENDING_REG) & (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) { scc_spcond_int (irq, data, fp); return; } SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); tty_flip_buffer_push(tty); }
static void scc_spcond_int(int irq, void *data, struct pt_regs *fp) { struct scc_port *port = data; struct tty_struct *tty = port->gs.tty; unsigned char stat, ch, err; int int_pending_mask = port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX; SCC_ACCESS_INIT(port); if (!tty) { printk(KERN_WARNING "scc_spcond_int with NULL tty!\n"); SCCwrite(COMMAND_REG, CR_ERROR_RESET); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); return; } do { stat = SCCread(SPCOND_STATUS_REG); ch = SCCread_NB(RX_DATA_REG); if (stat & SCSR_RX_OVERRUN) err = TTY_OVERRUN; else if (stat & SCSR_PARITY_ERR) err = TTY_PARITY; else if (stat & SCSR_CRC_FRAME_ERR) err = TTY_FRAME; else err = 0; if (tty->flip.count < TTY_FLIPBUF_SIZE) { *tty->flip.char_buf_ptr = ch; *tty->flip.flag_buf_ptr = err; tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; } /* ++TeSche: *All* errors have to be cleared manually, * else the condition persists for the next chars */ if (err) SCCwrite(COMMAND_REG, CR_ERROR_RESET); } while(SCCread(INT_PENDING_REG) & int_pending_mask); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); tty_flip_buffer_push(tty); }
static void scc_tx_int(int irq, void *data, struct pt_regs *fp) { struct scc_port *port = data; SCC_ACCESS_INIT(port); if (!port->gs.tty) { printk(KERN_WARNING "scc_tx_int with NULL tty!\n"); SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); return; } while ((SCCread_NB(STATUS_REG) & SR_TX_BUF_EMPTY)) { if (port->x_char) { SCCwrite(TX_DATA_REG, port->x_char); port->x_char = 0; } else if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped || port->gs.tty->hw_stopped) break; else { SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]); port->gs.xmit_tail = port->gs.xmit_tail & (SERIAL_XMIT_SIZE-1); if (--port->gs.xmit_cnt <= 0) break; } } if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped || port->gs.tty->hw_stopped) { /* disable tx interrupts */ SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); /* disable tx_int on next tx underrun? */ port->gs.flags &= ~GS_TX_INTEN; } if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) { if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && port->gs.tty->ldisc.write_wakeup) (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); wake_up_interruptible(&port->gs.tty->write_wait); } SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); }
static irqreturn_t scc_tx_int(int irq, void *data) { struct scc_port *port = data; SCC_ACCESS_INIT(port); if (!port->gs.port.tty) { printk(KERN_WARNING "scc_tx_int with NULL tty!\n"); SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); return IRQ_HANDLED; } while ((SCCread_NB(STATUS_REG) & SR_TX_BUF_EMPTY)) { if (port->x_char) { SCCwrite(TX_DATA_REG, port->x_char); port->x_char = 0; } else if ((port->gs.xmit_cnt <= 0) || port->gs.port.tty->stopped || port->gs.port.tty->hw_stopped) break; else { SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]); port->gs.xmit_tail = port->gs.xmit_tail & (SERIAL_XMIT_SIZE-1); if (--port->gs.xmit_cnt <= 0) break; } } if ((port->gs.xmit_cnt <= 0) || port->gs.port.tty->stopped || port->gs.port.tty->hw_stopped) { /* disable tx interrupts */ SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); /* disable tx_int on next tx underrun? */ port->gs.port.flags &= ~GS_TX_INTEN; } if (port->gs.port.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) tty_wakeup(port->gs.port.tty); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); return IRQ_HANDLED; }