📄 serial_sicc.c
字号:
siccuart_enable_tx_interrupt(info); spin_unlock_irqrestore(&info->state->sicc_lock,flags);}/* * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. */static void siccuart_event(struct SICC_info *info, int event){ info->event |= 1 << event; tasklet_schedule(&info->tlet);}static voidsiccuart_rx_chars(struct SICC_info *info, struct pt_regs *regs){ struct tty_struct *tty = info->tty; unsigned int status, ch, rsr, flg, ignored = 0; struct SICC_icount *icount = &info->state->icount; struct SICC_port *port = info->port; status = readb(port->uart_base+BL_SICC_LSR ); while (status & _LSR_RBR_FULL) { ch = readb(port->uart_base+BL_SICC_RBR); if (tty->flip.count >= TTY_FLIPBUF_SIZE) goto ignore_char; icount->rx++; flg = TTY_NORMAL; /* * Note that the error handling code is * out of the main execution path */ rsr = readb(port->uart_base+BL_SICC_LSR); if (rsr & _LSR_RX_ERR) goto handle_error;#ifdef SUPPORT_SYSRQ if (info->sysrq) { if (ch && time_before(jiffies, info->sysrq)) { handle_sysrq(ch, regs, NULL); info->sysrq = 0; goto ignore_char; } info->sysrq = 0; }#endif error_return: *tty->flip.flag_buf_ptr++ = flg; *tty->flip.char_buf_ptr++ = ch; tty->flip.count++; ignore_char: status = readb(port->uart_base+BL_SICC_LSR ); }out: tty_flip_buffer_push(tty); return;handle_error: if (rsr & _LSR_LB_BREAK) { rsr &= ~(_LSR_FE_MASK | _LSR_PE_MASK); icount->brk++;#ifdef SUPPORT_SYSRQ if (info->state->line == siccuart_cons.index) { if (!info->sysrq) { info->sysrq = jiffies + HZ*5; goto ignore_char; } }#endif } else if (rsr & _LSR_PE_MASK) icount->parity++; else if (rsr & _LSR_FE_MASK) icount->frame++; if (rsr & _LSR_OE_MASK) icount->overrun++; if (rsr & info->ignore_status_mask) { if (++ignored > 100) goto out; goto ignore_char; } rsr &= info->read_status_mask; if (rsr & _LSR_LB_BREAK) flg = TTY_BREAK; else if (rsr & _LSR_PE_MASK) flg = TTY_PARITY; else if (rsr & _LSR_FE_MASK) flg = TTY_FRAME; if (rsr & _LSR_OE_MASK) { /* * CHECK: does overrun affect the current character? * ASSUMPTION: it does not. */ *tty->flip.flag_buf_ptr++ = flg; *tty->flip.char_buf_ptr++ = ch; tty->flip.count++; if (tty->flip.count >= TTY_FLIPBUF_SIZE) goto ignore_char; ch = 0; flg = TTY_OVERRUN; }#ifdef SUPPORT_SYSRQ info->sysrq = 0;#endif goto error_return;}static void siccuart_tx_chars(struct SICC_info *info){ struct SICC_port *port = info->port; int count; unsigned char status; if (info->x_char) { writeb(info->x_char, port->uart_base+ BL_SICC_TBR); info->state->icount.tx++; info->x_char = 0; return; } if (info->xmit.head == info->xmit.tail || info->tty->stopped || info->tty->hw_stopped) { siccuart_disable_tx_interrupt(info); writeb(status&(~_LSR_RBR_MASK),port->uart_base+BL_SICC_LSR); return; } count = port->fifosize; do { writeb(info->xmit.buf[info->xmit.tail], port->uart_base+ BL_SICC_TBR); info->xmit.tail = (info->xmit.tail + 1) & (SICC_XMIT_SIZE - 1); info->state->icount.tx++; if (info->xmit.head == info->xmit.tail) break; } while (--count > 0); if (CIRC_CNT(info->xmit.head, info->xmit.tail, SICC_XMIT_SIZE) < WAKEUP_CHARS) siccuart_event(info, EVT_WRITE_WAKEUP); if (info->xmit.head == info->xmit.tail) { siccuart_disable_tx_interrupt(info); }}static irqreturn_t siccuart_int_rx(int irq, void *dev_id, struct pt_regs *regs){ struct SICC_info *info = dev_id; siccuart_rx_chars(info, regs); return IRQ_HANDLED;}static irqreturn_t siccuart_int_tx(int irq, void *dev_id, struct pt_regs *regs){ struct SICC_info *info = dev_id; siccuart_tx_chars(info); return IRQ_HANDLED;}static void siccuart_tasklet_action(unsigned long data){ struct SICC_info *info = (struct SICC_info *)data; struct tty_struct *tty; tty = info->tty; if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event)) return; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait);}static int siccuart_startup(struct SICC_info *info){ unsigned long flags; unsigned long page; int retval = 0; if (info->flags & ASYNC_INITIALIZED) { return 0; } page = get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; if (info->port->uart_base == 0) info->port->uart_base = (int)ioremap(info->port->uart_base_phys, PAGE_SIZE); if (info->port->uart_base == 0) { free_page(page); return -ENOMEM; } /* lock access to info while doing setup */ spin_lock_irqsave(&info->state->sicc_lock,flags); if (info->xmit.buf) free_page(page); else info->xmit.buf = (unsigned char *) page; info->mctrl = 0; if (info->tty->termios->c_cflag & CBAUD) info->mctrl = TIOCM_RTS | TIOCM_DTR; info->port->set_mctrl(info->port, info->mctrl); /* * initialise the old status of the modem signals */ info->old_status = 0; // UART_GET_FR(info->port) & AMBA_UARTFR_MODEM_ANY; if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit.head = info->xmit.tail = 0; /* * Set up the tty->alt_speed kludge */ if (info->tty) { if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) info->tty->alt_speed = 57600; if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) info->tty->alt_speed = 115200; if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) info->tty->alt_speed = 230400; if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) info->tty->alt_speed = 460800; } writeb( 0x00, info->port->uart_base + BL_SICC_IrCR ); // disable IrDA /* * and set the speed of the serial port */ siccuart_change_speed(info, 0); // enable rx/tx ports writeb(_RCR_ER_ENABLE /*| _RCR_PME_HARD*/, info->port->uart_base + BL_SICC_RCR); writeb(_TxCR_ET_ENABLE , info->port->uart_base + BL_SICC_TxCR); readb(info->port->uart_base + BL_SICC_RBR); // clear rx port writeb(0xf8, info->port->uart_base + BL_SICC_LSR); /* reset bits 0-4 of LSR */ /* * Finally, enable interrupts */ /* * Allocate the IRQ */ retval = request_irq(info->port->irqrx, siccuart_int_rx, 0, "SICC rx", info); if (retval) { if (capable(CAP_SYS_ADMIN)) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); retval = 0; } goto errout; } retval = request_irq(info->port->irqtx, siccuart_int_tx, 0, "SICC tx", info); if (retval) { if (capable(CAP_SYS_ADMIN)) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); retval = 0; } free_irq(info->port->irqrx, info); goto errout; } siccuart_enable_rx_interrupt(info); info->flags |= ASYNC_INITIALIZED; spin_unlock_irqrestore(&info->state->sicc_lock,flags); return 0;errout: spin_unlock_irqrestore(&info->state->sicc_lock,flags); return retval;}/* * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */static void siccuart_shutdown(struct SICC_info *info){ unsigned long flags; if (!(info->flags & ASYNC_INITIALIZED)) return; /* lock while shutting down port */ spin_lock_irqsave(&info->state->sicc_lock,flags); /* Disable interrupts */ /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq * here so the queue might never be woken up */ wake_up_interruptible(&info->delta_msr_wait); /* * disable all interrupts, disable the port */ siccuart_disable_rx_interrupt(info); siccuart_disable_tx_interrupt(info); /* * Free the IRQ */ free_irq(info->port->irqtx, info); free_irq(info->port->irqrx, info); if (info->xmit.buf) { unsigned long pg = (unsigned long) info->xmit.buf; info->xmit.buf = NULL; free_page(pg); } if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) info->mctrl &= ~(TIOCM_DTR|TIOCM_RTS); info->port->set_mctrl(info->port, info->mctrl); /* kill off our tasklet */ tasklet_kill(&info->tlet); if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&info->state->sicc_lock,flags);}static void siccuart_change_speed(struct SICC_info *info, struct termios *old_termios){ unsigned int lcr_h, baud, quot, cflag, old_rcr, old_tcr, bits; unsigned long flags; if (!info->tty || !info->tty->termios) return; cflag = info->tty->termios->c_cflag; pr_debug("siccuart_set_cflag(0x%x) called\n", cflag); /* byte size and parity */ switch (cflag & CSIZE) { case CS7: lcr_h = _LCR_PE_DISABLE | _LCR_DB_7_BITS | _LCR_SB_1_BIT; bits = 9; break; default: lcr_h = _LCR_PE_DISABLE | _LCR_DB_8_BITS | _LCR_SB_1_BIT; bits = 10; break; // CS8 } if (cflag & CSTOPB) { lcr_h |= _LCR_SB_2_BIT; bits ++; } if (cflag & PARENB) { lcr_h |= _LCR_PE_ENABLE; bits++; if (!(cflag & PARODD)) lcr_h |= _LCR_PTY_ODD; else lcr_h |= _LCR_PTY_EVEN; } do { /* Determine divisor based on baud rate */ baud = tty_get_baud_rate(info->tty); if (!baud) baud = 9600; { // here is ppc403SetBaud(com_port, baud); unsigned long divisor, clockSource, temp; /* Ensure CICCR[7] is 0 to select Internal Baud Clock */ powerpcMtcic_cr((unsigned long)(powerpcMfcic_cr() & 0xFEFFFFFF)); /* Determine Internal Baud Clock Frequency */ /* powerpcMfclkgpcr() reads DCR 0x120 - the*/ /* SCCR (Serial Clock Control Register) on Vesta */ temp = powerpcMfclkgpcr(); if(temp & 0x00000080) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -