ip22zilog.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,308 行 · 第 1/3 页

C
1,308
字号
		goto ack_tx_int;	xmit = &up->port.info->xmit;	if (uart_circ_empty(xmit)) {		uart_write_wakeup(&up->port);		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);}static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct uart_ip22zilog_port *up = dev_id;	while (up) {		struct zilog_channel *channel			= ZILOG_CHANNEL_FROM_PORT(&up->port);		unsigned char r3;		spin_lock(&up->port.lock);		r3 = read_zsreg(channel, R3);		/* Channel A */		if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {			writeb(RES_H_IUS, &channel->control);			ZSDELAY();			ZS_WSYNC(channel);			if (r3 & CHARxIP)				ip22zilog_receive_chars(up, channel, regs);			if (r3 & CHAEXT)				ip22zilog_status_handle(up, channel, regs);			if (r3 & CHATxIP)				ip22zilog_transmit_chars(up, channel);		}		spin_unlock(&up->port.lock);		/* Channel B */		up = up->next;		channel = ZILOG_CHANNEL_FROM_PORT(&up->port);		spin_lock(&up->port.lock);		if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {			writeb(RES_H_IUS, &channel->control);			ZSDELAY();			ZS_WSYNC(channel);			if (r3 & CHBRxIP)				ip22zilog_receive_chars(up, channel, regs);			if (r3 & CHBEXT)				ip22zilog_status_handle(up, channel, regs);			if (r3 & CHBTxIP)				ip22zilog_transmit_chars(up, channel);		}		spin_unlock(&up->port.lock);		up = up->next;	}	return IRQ_HANDLED;}/* A convenient way to quickly get R0 status.  The caller must _not_ hold the * port lock, it is acquired here. */static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port){	struct zilog_channel *channel;	unsigned long flags;	unsigned char status;	spin_lock_irqsave(&port->lock, flags);	channel = ZILOG_CHANNEL_FROM_PORT(port);	status = readb(&channel->control);	ZSDELAY();	spin_unlock_irqrestore(&port->lock, flags);	return status;}/* The port lock is not held.  */static unsigned int ip22zilog_tx_empty(struct uart_port *port){	unsigned char status;	unsigned int ret;	status = ip22zilog_read_channel_status(port);	if (status & Tx_BUF_EMP)		ret = TIOCSER_TEMT;	else		ret = 0;	return ret;}/* The port lock is not held.  */static unsigned int ip22zilog_get_mctrl(struct uart_port *port){	unsigned char status;	unsigned int ret;	status = ip22zilog_read_channel_status(port);	ret = 0;	if (status & DCD)		ret |= TIOCM_CAR;	if (status & SYNC)		ret |= TIOCM_DSR;	if (status & CTS)		ret |= TIOCM_CTS;	return ret;}/* The port lock is held and interrupts are disabled.  */static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl){	struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;	struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);	unsigned char set_bits, clear_bits;	set_bits = clear_bits = 0;	if (mctrl & TIOCM_RTS)		set_bits |= RTS;	else		clear_bits |= RTS;	if (mctrl & TIOCM_DTR)		set_bits |= DTR;	else		clear_bits |= DTR;	/* NOTE: Not subject to 'transmitter active' rule.  */ 	up->curregs[R5] |= set_bits;	up->curregs[R5] &= ~clear_bits;	write_zsreg(channel, R5, up->curregs[R5]);}/* The port lock is held and interrupts are disabled.  */static void ip22zilog_stop_tx(struct uart_port *port, unsigned int tty_stop){	struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;	up->flags |= IP22ZILOG_FLAG_TX_STOPPED;}/* The port lock is held and interrupts are disabled.  */static void ip22zilog_start_tx(struct uart_port *port, unsigned int tty_start){	struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;	struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);	unsigned char status;	up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;	up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED;	status = readb(&channel->control);	ZSDELAY();	/* TX busy?  Just wait for the TX done interrupt.  */	if (!(status & Tx_BUF_EMP))		return;	/* Send the first character to jump-start the TX done	 * IRQ sending engine.	 */	if (port->x_char) {		writeb(port->x_char, &channel->data);		ZSDELAY();		ZS_WSYNC(channel);		port->icount.tx++;		port->x_char = 0;	} else {		struct circ_buf *xmit = &port->info->xmit;		writeb(xmit->buf[xmit->tail], &channel->data);		ZSDELAY();		ZS_WSYNC(channel);		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);		port->icount.tx++;		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)			uart_write_wakeup(&up->port);	}}/* The port lock is not held.  */static void ip22zilog_stop_rx(struct uart_port *port){	struct uart_ip22zilog_port *up = UART_ZILOG(port);	struct zilog_channel *channel;	unsigned long flags;	if (ZS_IS_CONS(up))		return;	spin_lock_irqsave(&port->lock, flags);	channel = ZILOG_CHANNEL_FROM_PORT(port);	/* Disable all RX interrupts.  */	up->curregs[R1] &= ~RxINT_MASK;	ip22zilog_maybe_update_regs(up, channel);	spin_unlock_irqrestore(&port->lock, flags);}/* The port lock is not held.  */static void ip22zilog_enable_ms(struct uart_port *port){	struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;	struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);	unsigned char new_reg;	unsigned long flags;	spin_lock_irqsave(&port->lock, flags);	new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);	if (new_reg != up->curregs[R15]) {		up->curregs[R15] = new_reg;		/* NOTE: Not subject to 'transmitter active' rule.  */ 		write_zsreg(channel, R15, up->curregs[R15]);	}	spin_unlock_irqrestore(&port->lock, flags);}/* The port lock is not held.  */static void ip22zilog_break_ctl(struct uart_port *port, int break_state){	struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;	struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);	unsigned char set_bits, clear_bits, new_reg;	unsigned long flags;	set_bits = clear_bits = 0;	if (break_state)		set_bits |= SND_BRK;	else		clear_bits |= SND_BRK;	spin_lock_irqsave(&port->lock, flags);	new_reg = (up->curregs[R5] | set_bits) & ~clear_bits;	if (new_reg != up->curregs[R5]) {		up->curregs[R5] = new_reg;		/* NOTE: Not subject to 'transmitter active' rule.  */ 		write_zsreg(channel, R5, up->curregs[R5]);	}	spin_unlock_irqrestore(&port->lock, flags);}static void __ip22zilog_startup(struct uart_ip22zilog_port *up){	struct zilog_channel *channel;	channel = ZILOG_CHANNEL_FROM_PORT(&up->port);	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);}static int ip22zilog_startup(struct uart_port *port){	struct uart_ip22zilog_port *up = UART_ZILOG(port);	unsigned long flags;	if (ZS_IS_CONS(up))		return 0;	spin_lock_irqsave(&port->lock, flags);	__ip22zilog_startup(up);	spin_unlock_irqrestore(&port->lock, flags);	return 0;}/* * The test for ZS_IS_CONS is explained by the following e-mail: ***** * From: Russell King <rmk@arm.linux.org.uk> * Date: Sun, 8 Dec 2002 10:18:38 +0000 * * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote: * > I boot my 2.5 boxes using "console=ttyS0,9600" argument, * > and I noticed that something is not right with reference * > counting in this case. It seems that when the console * > is open by kernel initially, this is not accounted * > as an open, and uart_startup is not called. * * That is correct.  We are unable to call uart_startup when the serial * console is initialised because it may need to allocate memory (as * request_irq does) and the memory allocators may not have been * initialised. * * 1. initialise the port into a state where it can send characters in the *    console write method. * * 2. don't do the actual hardware shutdown in your shutdown() method (but *    do the normal software shutdown - ie, free irqs etc) ***** */static void ip22zilog_shutdown(struct uart_port *port){	struct uart_ip22zilog_port *up = UART_ZILOG(port);	struct zilog_channel *channel;	unsigned long flags;	if (ZS_IS_CONS(up))		return;	spin_lock_irqsave(&port->lock, flags);	channel = ZILOG_CHANNEL_FROM_PORT(port);	/* Disable receiver and transmitter.  */	up->curregs[R3] &= ~RxENAB;	up->curregs[R5] &= ~TxENAB;	/* Disable all interrupts and BRK assertion.  */	up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);	up->curregs[R5] &= ~SND_BRK;	ip22zilog_maybe_update_regs(up, channel);	spin_unlock_irqrestore(&port->lock, flags);}/* Shared by TTY driver and serial console setup.  The port lock is held * and local interrupts are disabled. */static voidip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag,		       unsigned int iflag, int brg){	up->curregs[R10] = NRZ;	up->curregs[R11] = TCBR | RCBR;	/* Program BAUD and clock source. */	up->curregs[R4] &= ~XCLK_MASK;	up->curregs[R4] |= X16CLK;	up->curregs[R12] = brg & 0xff;	up->curregs[R13] = (brg >> 8) & 0xff;	up->curregs[R14] = BRSRC | BRENAB;	/* Character size, stop bits, and parity. */	up->curregs[3] &= ~RxN_MASK;	up->curregs[5] &= ~TxN_MASK;	switch (cflag & CSIZE) {	case CS5:		up->curregs[3] |= Rx5;		up->curregs[5] |= Tx5;		up->parity_mask = 0x1f;		break;	case CS6:		up->curregs[3] |= Rx6;		up->curregs[5] |= Tx6;		up->parity_mask = 0x3f;		break;	case CS7:		up->curregs[3] |= Rx7;		up->curregs[5] |= Tx7;		up->parity_mask = 0x7f;		break;	case CS8:	default:		up->curregs[3] |= Rx8;		up->curregs[5] |= Tx8;		up->parity_mask = 0xff;		break;	};	up->curregs[4] &= ~0x0c;	if (cflag & CSTOPB)		up->curregs[4] |= SB2;	else		up->curregs[4] |= SB1;	if (cflag & PARENB)		up->curregs[4] |= PAR_ENAB;	else		up->curregs[4] &= ~PAR_ENAB;	if (!(cflag & PARODD))		up->curregs[4] |= PAR_EVEN;	else		up->curregs[4] &= ~PAR_EVEN;	up->port.read_status_mask = Rx_OVR;	if (iflag & INPCK)		up->port.read_status_mask |= CRC_ERR | PAR_ERR;	if (iflag & (BRKINT | PARMRK))		up->port.read_status_mask |= BRK_ABRT;	up->port.ignore_status_mask = 0;	if (iflag & IGNPAR)		up->port.ignore_status_mask |= CRC_ERR | PAR_ERR;	if (iflag & IGNBRK) {		up->port.ignore_status_mask |= BRK_ABRT;		if (iflag & IGNPAR)			up->port.ignore_status_mask |= Rx_OVR;	}	if ((cflag & CREAD) == 0)		up->port.ignore_status_mask = 0xff;}/* The port lock is not held.  */static void

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?