zs.c

来自「linux 内核源代码」· C语言 代码 · 共 1,288 行 · 第 1/3 页

C
1,288
字号
	spin_lock(&scc->zlock);	zs_raw_stop_tx(zport);	spin_unlock(&scc->zlock);}static void zs_raw_transmit_chars(struct zs_port *);static void zs_start_tx(struct uart_port *uport){	struct zs_port *zport = to_zport(uport);	struct zs_scc *scc = zport->scc;	spin_lock(&scc->zlock);	if (zport->tx_stopped) {		zs_transmit_drain(zport, 0);		zport->tx_stopped = 0;		zs_raw_transmit_chars(zport);	}	spin_unlock(&scc->zlock);}static void zs_stop_rx(struct uart_port *uport){	struct zs_port *zport = to_zport(uport);	struct zs_scc *scc = zport->scc;	struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];	spin_lock(&scc->zlock);	zport->regs[15] &= ~BRKIE;	zport->regs[1] &= ~(RxINT_MASK | TxINT_ENAB);	zport->regs[1] |= RxINT_DISAB;	if (zport != zport_a) {		/* A-side DCD tracks RI and SYNC tracks DSR.  */		zport_a->regs[15] &= ~(DCDIE | SYNCIE);		write_zsreg(zport_a, R15, zport_a->regs[15]);		if (!(zport_a->regs[15] & BRKIE)) {			zport_a->regs[1] &= ~EXT_INT_ENAB;			write_zsreg(zport_a, R1, zport_a->regs[1]);		}		/* This-side DCD tracks DCD and CTS tracks CTS.  */		zport->regs[15] &= ~(DCDIE | CTSIE);		zport->regs[1] &= ~EXT_INT_ENAB;	} else {		/* DCD tracks RI and SYNC tracks DSR for the B side.  */		if (!(zport->regs[15] & (DCDIE | SYNCIE)))			zport->regs[1] &= ~EXT_INT_ENAB;	}	write_zsreg(zport, R15, zport->regs[15]);	write_zsreg(zport, R1, zport->regs[1]);	spin_unlock(&scc->zlock);}static void zs_enable_ms(struct uart_port *uport){	struct zs_port *zport = to_zport(uport);	struct zs_scc *scc = zport->scc;	struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];	if (zport == zport_a)		return;	spin_lock(&scc->zlock);	/* Clear Ext interrupts if not being handled already.  */	if (!(zport_a->regs[1] & EXT_INT_ENAB))		write_zsreg(zport_a, R0, RES_EXT_INT);	/* A-side DCD tracks RI and SYNC tracks DSR.  */	zport_a->regs[1] |= EXT_INT_ENAB;	zport_a->regs[15] |= DCDIE | SYNCIE;	/* This-side DCD tracks DCD and CTS tracks CTS.  */	zport->regs[15] |= DCDIE | CTSIE;	zs_raw_xor_mctrl(zport);	write_zsreg(zport_a, R1, zport_a->regs[1]);	write_zsreg(zport_a, R15, zport_a->regs[15]);	write_zsreg(zport, R15, zport->regs[15]);	spin_unlock(&scc->zlock);}static void zs_break_ctl(struct uart_port *uport, int break_state){	struct zs_port *zport = to_zport(uport);	struct zs_scc *scc = zport->scc;	unsigned long flags;	spin_lock_irqsave(&scc->zlock, flags);	if (break_state == -1)		zport->regs[5] |= SND_BRK;	else		zport->regs[5] &= ~SND_BRK;	write_zsreg(zport, R5, zport->regs[5]);	spin_unlock_irqrestore(&scc->zlock, flags);}/* * Interrupt handling routines. */#define Rx_BRK 0x0100			/* BREAK event software flag.  */#define Rx_SYS 0x0200			/* SysRq event software flag.  */static void zs_receive_chars(struct zs_port *zport){	struct uart_port *uport = &zport->port;	struct zs_scc *scc = zport->scc;	struct uart_icount *icount;	unsigned int avail, status, ch, flag;	int count;	for (count = 16; count; count--) {		spin_lock(&scc->zlock);		avail = read_zsreg(zport, R0) & Rx_CH_AV;		spin_unlock(&scc->zlock);		if (!avail)			break;		spin_lock(&scc->zlock);		status = read_zsreg(zport, R1) & (Rx_OVR | FRM_ERR | PAR_ERR);		ch = read_zsdata(zport);		spin_unlock(&scc->zlock);		flag = TTY_NORMAL;		icount = &uport->icount;		icount->rx++;		/* Handle the null char got when BREAK is removed.  */		if (!ch)			status |= zport->tty_break;		if (unlikely(status &			     (Rx_OVR | FRM_ERR | PAR_ERR | Rx_SYS | Rx_BRK))) {			zport->tty_break = 0;			/* Reset the error indication.  */			if (status & (Rx_OVR | FRM_ERR | PAR_ERR)) {				spin_lock(&scc->zlock);				write_zsreg(zport, R0, ERR_RES);				spin_unlock(&scc->zlock);			}			if (status & (Rx_SYS | Rx_BRK)) {				icount->brk++;				/* SysRq discards the null char.  */				if (status & Rx_SYS)					continue;			} else if (status & FRM_ERR)				icount->frame++;			else if (status & PAR_ERR)				icount->parity++;			if (status & Rx_OVR)				icount->overrun++;			status &= uport->read_status_mask;			if (status & Rx_BRK)				flag = TTY_BREAK;			else if (status & FRM_ERR)				flag = TTY_FRAME;			else if (status & PAR_ERR)				flag = TTY_PARITY;		}		if (uart_handle_sysrq_char(uport, ch))			continue;		uart_insert_char(uport, status, Rx_OVR, ch, flag);	}	tty_flip_buffer_push(uport->info->tty);}static void zs_raw_transmit_chars(struct zs_port *zport){	struct circ_buf *xmit = &zport->port.info->xmit;	/* XON/XOFF chars.  */	if (zport->port.x_char) {		write_zsdata(zport, zport->port.x_char);		zport->port.icount.tx++;		zport->port.x_char = 0;		return;	}	/* If nothing to do or stopped or hardware stopped.  */	if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) {		zs_raw_stop_tx(zport);		return;	}	/* Send char.  */	write_zsdata(zport, xmit->buf[xmit->tail]);	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);	zport->port.icount.tx++;	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)		uart_write_wakeup(&zport->port);	/* Are we are done?  */	if (uart_circ_empty(xmit))		zs_raw_stop_tx(zport);}static void zs_transmit_chars(struct zs_port *zport){	struct zs_scc *scc = zport->scc;	spin_lock(&scc->zlock);	zs_raw_transmit_chars(zport);	spin_unlock(&scc->zlock);}static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a){	struct uart_port *uport = &zport->port;	struct zs_scc *scc = zport->scc;	unsigned int delta;	u8 status, brk;	spin_lock(&scc->zlock);	/* Get status from Read Register 0.  */	status = read_zsreg(zport, R0);	if (zport->regs[15] & BRKIE) {		brk = status & BRK_ABRT;		if (brk && !zport->brk) {			spin_unlock(&scc->zlock);			if (uart_handle_break(uport))				zport->tty_break = Rx_SYS;			else				zport->tty_break = Rx_BRK;			spin_lock(&scc->zlock);		}		zport->brk = brk;	}	if (zport != zport_a) {		delta = zs_raw_xor_mctrl(zport);		spin_unlock(&scc->zlock);		if (delta & TIOCM_CTS)			uart_handle_cts_change(uport,					       zport->mctrl & TIOCM_CTS);		if (delta & TIOCM_CAR)			uart_handle_dcd_change(uport,					       zport->mctrl & TIOCM_CAR);		if (delta & TIOCM_RNG)			uport->icount.dsr++;		if (delta & TIOCM_DSR)			uport->icount.rng++;		if (delta)			wake_up_interruptible(&uport->info->delta_msr_wait);		spin_lock(&scc->zlock);	}	/* Clear the status condition...  */	write_zsreg(zport, R0, RES_EXT_INT);	spin_unlock(&scc->zlock);}/* * This is the Z85C30 driver's generic interrupt routine. */static irqreturn_t zs_interrupt(int irq, void *dev_id){	struct zs_scc *scc = dev_id;	struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];	struct zs_port *zport_b = &scc->zport[ZS_CHAN_B];	irqreturn_t status = IRQ_NONE;	u8 zs_intreg;	int count;	/*	 * NOTE: The read register 3, which holds the irq status,	 *       does so for both channels on each chip.  Although	 *       the status value itself must be read from the A	 *       channel and is only valid when read from channel A.	 *       Yes... broken hardware...	 */	for (count = 16; count; count--) {		spin_lock(&scc->zlock);		zs_intreg = read_zsreg(zport_a, R3);		spin_unlock(&scc->zlock);		if (!zs_intreg)			break;		/*		 * We do not like losing characters, so we prioritise		 * interrupt sources a little bit differently than		 * the SCC would, was it allowed to.		 */		if (zs_intreg & CHBRxIP)			zs_receive_chars(zport_b);		if (zs_intreg & CHARxIP)			zs_receive_chars(zport_a);		if (zs_intreg & CHBEXT)			zs_status_handle(zport_b, zport_a);		if (zs_intreg & CHAEXT)			zs_status_handle(zport_a, zport_a);		if (zs_intreg & CHBTxIP)			zs_transmit_chars(zport_b);		if (zs_intreg & CHATxIP)			zs_transmit_chars(zport_a);		status = IRQ_HANDLED;	}	return status;}/* * Finally, routines used to initialize the serial port. */static int zs_startup(struct uart_port *uport){	struct zs_port *zport = to_zport(uport);	struct zs_scc *scc = zport->scc;	unsigned long flags;	int irq_guard;	int ret;	irq_guard = atomic_add_return(1, &scc->irq_guard);	if (irq_guard == 1) {		ret = request_irq(zport->port.irq, zs_interrupt,				  IRQF_SHARED, "scc", scc);		if (ret) {			atomic_add(-1, &scc->irq_guard);			printk(KERN_ERR "zs: can't get irq %d\n",			       zport->port.irq);			return ret;		}	}	spin_lock_irqsave(&scc->zlock, flags);	/* Clear the receive FIFO.  */	zs_receive_drain(zport);	/* Clear the interrupt registers.  */	write_zsreg(zport, R0, ERR_RES);	write_zsreg(zport, R0, RES_Tx_P);	/* But Ext only if not being handled already.  */	if (!(zport->regs[1] & EXT_INT_ENAB))		write_zsreg(zport, R0, RES_EXT_INT);	/* Finally, enable sequencing and interrupts.  */	zport->regs[1] &= ~RxINT_MASK;	zport->regs[1] |= RxINT_ALL | TxINT_ENAB | EXT_INT_ENAB;	zport->regs[3] |= RxENABLE;	zport->regs[5] |= TxENAB;	zport->regs[15] |= BRKIE;	write_zsreg(zport, R1, zport->regs[1]);	write_zsreg(zport, R3, zport->regs[3]);	write_zsreg(zport, R5, zport->regs[5]);	write_zsreg(zport, R15, zport->regs[15]);	/* Record the current state of RR0.  */	zport->mctrl = zs_raw_get_mctrl(zport);	zport->brk = read_zsreg(zport, R0) & BRK_ABRT;	zport->tx_stopped = 1;	spin_unlock_irqrestore(&scc->zlock, flags);	return 0;}static void zs_shutdown(struct uart_port *uport){	struct zs_port *zport = to_zport(uport);	struct zs_scc *scc = zport->scc;	unsigned long flags;	int irq_guard;	spin_lock_irqsave(&scc->zlock, flags);	zport->regs[5] &= ~TxENAB;	zport->regs[3] &= ~RxENABLE;	write_zsreg(zport, R5, zport->regs[5]);	write_zsreg(zport, R3, zport->regs[3]);	spin_unlock_irqrestore(&scc->zlock, flags);	irq_guard = atomic_add_return(-1, &scc->irq_guard);	if (!irq_guard)		free_irq(zport->port.irq, scc);}static void zs_reset(struct zs_port *zport){	struct zs_scc *scc = zport->scc;	int irq;	unsigned long flags;	spin_lock_irqsave(&scc->zlock, flags);	irq = !irqs_disabled_flags(flags);	if (!scc->initialised) {		/* Reset the pointer first, just in case...  */		read_zsreg(zport, R0);		/* And let the current transmission finish.  */		zs_line_drain(zport, irq);		write_zsreg(zport, R9, FHWRES);		udelay(10);		write_zsreg(zport, R9, 0);		scc->initialised = 1;	}	load_zsregs(zport, zport->regs, irq);	spin_unlock_irqrestore(&scc->zlock, flags);}static void zs_set_termios(struct uart_port *uport, struct ktermios *termios,			   struct ktermios *old_termios){	struct zs_port *zport = to_zport(uport);	struct zs_scc *scc = zport->scc;	struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];	int irq;	unsigned int baud, brg;	unsigned long flags;

⌨️ 快捷键说明

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