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;
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
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);
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
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;
}