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

📄 serial_sicc.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    }#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;    }    save_flags(flags); cli();    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;    restore_flags(flags);    return 0;errout:    restore_flags(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;    save_flags(flags); cli(); /* 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;    restore_flags(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) {               clockSource = 324000000;           }           else {               clockSource = 216000000;           }           clockSource = clockSource/(unsigned long)((temp&0x00FC0000)>>18);           divisor = clockSource/(16*baud) - 1;           /* divisor has only 12 bits of resolution */           if(divisor>0x00000FFF){               divisor=0x00000FFF;           }           quot = divisor;        }        if (baud == 38400 &&            ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))            quot = info->state->custom_divisor;        if (!quot && old_termios) {            info->tty->termios->c_cflag &= ~CBAUD;            info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);            old_termios = NULL;        }    } while (quot == 0 && old_termios);    /* As a last resort, if the quotient is zero, default to 9600 bps */    if (!quot)        quot = (info->port->uartclk / (16 * 9600)) - 1;    info->timeout = info->port->fifosize * HZ * bits / baud;    info->timeout += HZ/50;     /* Add .02 seconds of slop */    if (cflag & CRTSCTS)        info->flags |= ASYNC_CTS_FLOW;    else        info->flags &= ~ASYNC_CTS_FLOW;    if (cflag & CLOCAL)        info->flags &= ~ASYNC_CHECK_CD;    else        info->flags |= ASYNC_CHECK_CD;    /*     * Set up parity check flag     */#define RELEVENT_IFLAG(iflag)   ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))    info->read_status_mask = _LSR_OE_MASK;    if (I_INPCK(info->tty))        info->read_status_mask |= _LSR_FE_MASK | _LSR_PE_MASK;    if (I_BRKINT(info->tty) || I_PARMRK(info->tty))        info->read_status_mask |= _LSR_LB_MASK;    /*     * Characters to ignore     */    info->ignore_status_mask = 0;    if (I_IGNPAR(info->tty))        info->ignore_status_mask |= _LSR_FE_MASK | _LSR_PE_MASK;    if (I_IGNBRK(info->tty)) {        info->ignore_status_mask |=  _LSR_LB_MASK;        /*         * If we're ignoring parity and break indicators,         * ignore overruns to (for real raw support).         */        if (I_IGNPAR(info->tty))            info->ignore_status_mask |=  _LSR_OE_MASK;    }    /* first, disable everything */    save_flags(flags); cli();    old_rcr = readb(info->port->uart_base + BL_SICC_RCR);    old_tcr = readb(info->port->uart_base + BL_SICC_TxCR);    writeb(0, info->port->uart_base + BL_SICC_RCR);    writeb(0, info->port->uart_base + BL_SICC_TxCR);    /*RLBtrace (&ppc403Chan0, 0x2000000c, 0, 0);*/    restore_flags(flags);    /* Set baud rate */    writeb((quot & 0x00000F00)>>8, info->port->uart_base + BL_SICC_BRDH );    writeb( quot & 0x00000FF,      info->port->uart_base + BL_SICC_BRDL );    /* Set CTL2 reg to use external clock (ExtClk) and enable FIFOs. */    /* For now, do NOT use FIFOs since 403 UART did not have this    */    /* capability and this driver was inherited from 403UART.        */    writeb(_CTL2_EXTERN, info->port->uart_base + BL_SICC_CTL2);    writeb(lcr_h, info->port->uart_base + BL_SICC_LCR);    writeb(old_rcr, info->port->uart_base + BL_SICC_RCR);  // restore rcr    writeb(old_tcr, info->port->uart_base + BL_SICC_TxCR); // restore txcr}static void siccuart_put_char(struct tty_struct *tty, u_char ch){    struct SICC_info *info = tty->driver_data;    unsigned long flags;    if (!tty || !info->xmit.buf)        return;    save_flags(flags); cli();    if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SICC_XMIT_SIZE) != 0) {        info->xmit.buf[info->xmit.head] = ch;        info->xmit.head = (info->xmit.head + 1) & (SICC_XMIT_SIZE - 1);    }    restore_flags(flags);}static void siccuart_flush_chars(struct tty_struct *tty){    struct SICC_info *info = tty->driver_data;    unsigned long flags;    if (info->xmit.head == info->xmit.tail        || tty->stopped        || tty->hw_stopped        || !info->xmit.buf)        return;    save_flags(flags); cli();    siccuart_enable_tx_interrupt(info);    restore_flags(flags);}static int siccuart_write(struct tty_struct *tty, int from_user,              const u_char * buf, int count){    struct SICC_info *info = tty->driver_data;    unsigned long flags;    int c, ret = 0;    if (!tty || !info->xmit.buf || !tmp_buf)        return 0;    save_flags(flags);    if (from_user) {        down(&tmp_buf_sem);        while (1) {            int c1;            c = CIRC_SPACE_TO_END(info->xmit.head,                          info->xmit.tail,                          SICC_XMIT_SIZE);            if (count < c)                c = count;            if (c <= 0)                break;            c -= copy_from_user(tmp_buf, buf, c);            if (!c) {                if (!ret)                    ret = -EFAULT;                break;            }            cli();            c1 = CIRC_SPACE_TO_END(info->xmit.head,                           info->xmit.tail,                           SICC_XMIT_SIZE);            if (c1 < c)                c = c1;            memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);            info->xmit.head = (info->xmit.head + c) &                      (SICC_XMIT_SIZE - 1);            restore_flags(flags);            buf += c;            count -= c;            ret += c;        }        up(&tmp_buf_sem);    } else {        cli();        while (1) {            c = CIRC_SPACE_TO_END(info->xmit.head,                          info->xmit.tail,                          SICC_XMIT_SIZE);            if (count < c)                c = count;            if (c <= 0)                break;            memcpy(info->xmit.buf + info->xmit.head, buf, c);            info->xmit.head = (info->xmit.head + c) &                      (SICC_XMIT_SIZE - 1);            buf += c;            count -= c;            ret += c;        }        restore_flags(flags);    }    if (info->xmit.head != info->xmit.tail        && !tty->stopped        && !tty->hw_stopped)        siccuart_enable_tx_interrupt(info);    return ret;}static int siccuart_write_room(struct tty_struct *tty){    struct SICC_info *info = tty->driver_data;    return CIRC_SPACE(info->xmit.head, info->xmit.tail, SICC_XMIT_SIZE);}static int siccuart_chars_in_buffer(struct tty_struct *tty){

⌨️ 快捷键说明

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