⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial_sicc.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 5 页
字号:
        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 + -