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 + -
显示快捷键?