Пример #1
0
/* Reprogram the Zilog channel HW registers with the copies found in the
 * software state struct.  If the transmitter is busy, we defer this update
 * until the next TX complete interrupt.  Else, we do it right now.
 *
 * The UART port lock must be held and local interrupts disabled.
 */
static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up,
				       struct zilog_channel *channel)
{
	if (!ZS_REGS_HELD(up)) {
		if (ZS_TX_ACTIVE(up)) {
			up->flags |= IP22ZILOG_FLAG_REGS_HELD;
		} else {
			__load_zsregs(channel, up->curregs);
		}
	}
}
Пример #2
0
static void __ip22zilog_startup(struct uart_ip22zilog_port *up)
{
	struct zilog_channel *channel;

	channel = ZILOG_CHANNEL_FROM_PORT(&up->port);

	__ip22zilog_reset(up);

	__load_zsregs(channel, up->curregs);
	/* set master interrupt enable */
	write_zsreg(channel, R9, up->curregs[R9]);
	up->prev_status = readb(&channel->control);

	/* Enable receiver and transmitter.  */
	up->curregs[R3] |= RxENAB;
	up->curregs[R5] |= TxENAB;

	up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
	ip22zilog_maybe_update_regs(up, channel);
}
Пример #3
0
static void __init ip22zilog_init_hw(void)
{
	int i;

	for (i = 0; i < NUM_CHANNELS; i++) {
		struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
		struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
		unsigned long flags;
		int baud, brg;

		spin_lock_irqsave(&up->port.lock, flags);

		if (ZS_IS_CHANNEL_A(up)) {
			write_zsreg(channel, R9, FHWRES);
			ZSDELAY_LONG();
			(void) read_zsreg(channel, R0);
		}

		/* Normal serial TTY. */
		up->parity_mask = 0xff;
		up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
		up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
		up->curregs[R3] = RxENAB | Rx8;
		up->curregs[R5] = TxENAB | Tx8;
		up->curregs[R9] = NV | MIE;
		up->curregs[R10] = NRZ;
		up->curregs[R11] = TCBR | RCBR;
		baud = 9600;
		brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
		up->curregs[R12] = (brg & 0xff);
		up->curregs[R13] = (brg >> 8) & 0xff;
		up->curregs[R14] = BRENAB;
		__load_zsregs(channel, up->curregs);
	        /* set master interrupt enable */
	        write_zsreg(channel, R9, up->curregs[R9]);

		spin_unlock_irqrestore(&up->port.lock, flags);
	}
}
Пример #4
0
static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
				    struct zilog_channel *channel)
{
	struct circ_buf *xmit;

	if (ZS_IS_CONS(up)) {
		unsigned char status = readb(&channel->control);
		ZSDELAY();

		/* TX still busy?  Just wait for the next TX done interrupt.
		 *
		 * It can occur because of how we do serial console writes.  It would
		 * be nice to transmit console writes just like we normally would for
		 * a TTY line. (ie. buffered and TX interrupt driven).  That is not
		 * easy because console writes cannot sleep.  One solution might be
		 * to poll on enough port->xmit space becoming free.  -DaveM
		 */
		if (!(status & Tx_BUF_EMP))
			return;
	}

	up->flags &= ~IP22ZILOG_FLAG_TX_ACTIVE;

	if (ZS_REGS_HELD(up)) {
		__load_zsregs(channel, up->curregs);
		up->flags &= ~IP22ZILOG_FLAG_REGS_HELD;
	}

	if (ZS_TX_STOPPED(up)) {
		up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED;
		goto ack_tx_int;
	}

	if (up->port.x_char) {
		up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
		writeb(up->port.x_char, &channel->data);
		ZSDELAY();
		ZS_WSYNC(channel);

		up->port.icount.tx++;
		up->port.x_char = 0;
		return;
	}

	if (up->port.state == NULL)
		goto ack_tx_int;
	xmit = &up->port.state->xmit;
	if (uart_circ_empty(xmit))
		goto ack_tx_int;
	if (uart_tx_stopped(&up->port))
		goto ack_tx_int;

	up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
	writeb(xmit->buf[xmit->tail], &channel->data);
	ZSDELAY();
	ZS_WSYNC(channel);

	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
	up->port.icount.tx++;

	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
		uart_write_wakeup(&up->port);

	return;

ack_tx_int:
	writeb(RES_Tx_P, &channel->control);
	ZSDELAY();
	ZS_WSYNC(channel);
}