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

📄 serial_sicc.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 5 页
字号:
               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;    }    /* disable interrupts while reading and clearing registers */    spin_lock_irqsave(&info->state->sicc_lock,flags);    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);*/    spin_unlock_irqrestore(&info->state->sicc_lock,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;    /* lock info->xmit while adding character to tx buffer */    spin_lock_irqsave(&info->state->sicc_lock,flags);    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);    }    spin_unlock_irqrestore(&info->state->sicc_lock,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;    /* disable interrupts while transmitting characters */    spin_lock_irqsave(&info->state->sicc_lock,flags);    siccuart_enable_tx_interrupt(info);    spin_unlock_irqrestore(&info->state->sicc_lock,flags);}static int siccuart_write(struct tty_struct *tty,              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;    /* lock info->xmit while removing characters from buffer */    spin_lock_irqsave(&info->state->sicc_lock,flags);    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;    }    if (info->xmit.head != info->xmit.tail        && !tty->stopped        && !tty->hw_stopped)        siccuart_enable_tx_interrupt(info);    spin_unlock_irqrestore(&info->state->sicc_lock,flags);    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){    struct SICC_info *info = tty->driver_data;    return CIRC_CNT(info->xmit.head, info->xmit.tail, SICC_XMIT_SIZE);}static void siccuart_flush_buffer(struct tty_struct *tty){    struct SICC_info *info = tty->driver_data;    unsigned long flags;    pr_debug("siccuart_flush_buffer(%d) called\n", tty->index);    /* lock info->xmit while zeroing buffer counts */    spin_lock_irqsave(&info->state->sicc_lock,flags);    info->xmit.head = info->xmit.tail = 0;    spin_unlock_irqrestore(&info->state->sicc_lock,flags);    wake_up_interruptible(&tty->write_wait);    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&        tty->ldisc.write_wakeup)        (tty->ldisc.write_wakeup)(tty);}/* * This function is used to send a high-priority XON/XOFF character to * the device */static void siccuart_send_xchar(struct tty_struct *tty, char ch){    struct SICC_info *info = tty->driver_data;    info->x_char = ch;    if (ch)       siccuart_enable_tx_interrupt(info);}static void siccuart_throttle(struct tty_struct *tty){    struct SICC_info *info = tty->driver_data;    unsigned long flags;    if (I_IXOFF(tty))        siccuart_send_xchar(tty, STOP_CHAR(tty));    if (tty->termios->c_cflag & CRTSCTS) {        /* disable interrupts while setting modem control lines */        spin_lock_irqsave(&info->state->sicc_lock,flags);        info->mctrl &= ~TIOCM_RTS;        info->port->set_mctrl(info->port, info->mctrl);        spin_unlock_irqrestore(&info->state->sicc_lock,flags);    }}static void siccuart_unthrottle(struct tty_struct *tty){    struct SICC_info *info = (struct SICC_info *) tty->driver_data;    unsigned long flags;    if (I_IXOFF(tty)) {        if (info->x_char)            info->x_char = 0;        else            siccuart_send_xchar(tty, START_CHAR(tty));    }    if (tty->termios->c_cflag & CRTSCTS) {        /* disable interrupts while setting modem control lines */        spin_lock_irqsave(&info->state->sicc_lock,flags);        info->mctrl |= TIOCM_RTS;        info->port->set_mctrl(info->port, info->mctrl);        spin_unlock_irqrestore(&info->state->sicc_lock,flags);    }}static int get_serial_info(struct SICC_info *info, struct serial_struct *retinfo){    struct SICC_state *state = info->state;    struct SICC_port *port = info->port;    struct serial_struct tmp;    memset(&tmp, 0, sizeof(tmp));    tmp.type       = 0;    tmp.line       = state->line;    tmp.port       = port->uart_base;    if (HIGH_BITS_OFFSET)        tmp.port_high = port->uart_base >> HIGH_BITS_OFFSET;    tmp.irq        = port->irqrx;    tmp.flags      = 0;    tmp.xmit_fifo_size = port->fifosize;    tmp.baud_base      = port->uartclk / 16;    tmp.close_delay    = state->close_delay;    tmp.closing_wait   = state->closing_wait;    tmp.custom_divisor = state->custom_divisor;    if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))        return -EFAULT;    return 0;}static int set_serial_info(struct SICC_info *info,               struct serial_struct *newinfo){    struct serial_struct new_serial;    struct SICC_state *state, old_state;    struct SICC_port *port;    unsigned long new_port;    unsigned int i, change_irq, change_port;    int retval = 0;    if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))        return -EFAULT;    state = info->state;    old_state = *state;    port = info->port;    new_port = new_serial.port;    if (HIGH_BITS_OFFSET)        new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;    change_irq  = new_serial.irq != port->irqrx;    change_port = new_port != port->uart_base;    if (!capable(CAP_SYS_ADMIN)) {        if (change_irq || change_port ||            (new_serial.baud_base != port->uartclk / 16) ||            (new_serial.close_delay != state->close_delay) ||            (new_serial.xmit_fifo_size != port->fifosize) ||            ((new_serial.flags & ~ASYNC_USR_MASK) !=             (state->flags & ~ASYNC_USR_MASK)))            return -EPERM;        state->flags = ((state->flags & ~ASYNC_USR_MASK) |                (new_serial.flags & ASYNC_USR_MASK));        info->flags = ((info->flags & ~ASYNC_USR_MASK) |                   (new_serial.flags & ASYNC_USR_MASK));        state->custom_divisor = new_serial.custom_divisor;        goto check_and_exit;    }    if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) ||        (new_serial.baud_base < 9600))        return -EINVAL;    if (new_serial.type && change_port) {        for (i = 0; i < SERIAL_SICC_NR; i++)            if ((port != sicc_ports + i) &&                sicc_ports[i].uart_base != new_port)                return -EADDRINUSE;    }    if ((change_port || change_irq) && (state->count > 1))        return -EBUSY;    /*     * OK, past this point, all the error checking has been done.     * At this point, we start making changes.....     */    port->uartclk = new_serial.baud_base * 16;    state->flags = ((state->flags & ~ASYNC_FLAGS) |            (new_serial.flags & ASYNC_FLAGS));    info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |               (info->flags & ASYNC_INTERNAL_FLAGS));    state->custom_divisor = new_serial.custom_divisor;    state->close_delay = new_serial.close_delay * HZ / 100;    state->closing_wait = new_serial.closing_wait * HZ / 100;    info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;    port->fifosize = new_serial.xmit_fifo_size;    if (change_port || change_irq) {        /*         * We need to shutdown the serial port at the old         * port/irq combination.         */        siccuart_shutdown(info);        port->irqrx = new_serial.irq;        port->uart_base = new_port;    }check_and_exit:    if (!port->uart_base)        return 0;    if (info->flags & ASYNC_INITIALIZED) {        if ((old_state.flags & ASYNC_SPD_MASK) !=            (state->flags & ASYNC_SPD_MASK) ||            (old_state.custom_divisor != state->custom_divisor)) {            if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)                info->tty->alt_speed = 57600;            if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)                info->tty->alt_speed = 115200;            if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)                info->tty->alt_speed = 230400;            if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)                info->tty->alt_speed = 460800;            siccuart_change_speed(info, NULL);        }    } else        retval = siccuart_startup(info);    return retval;}/* * get_lsr_info - get line status register info */static int get_lsr_info(struct SICC_info *info, unsigned int *value){    unsigned int result, status;    unsigned long flags;    /* disable interrupts while reading status from port */    spin_lock_irqsave(&info->state->sicc_lock,flags);    status = readb(info->port->uart_base +  BL_SICC_LSR);    spin_unlock_irqrestore(&info->state->sicc_lock,flags);    result = status & _LSR_TSR_EMPTY ? TIOCSER_TEMT : 0;    /*     * If we're about to load something into the transmit     * register, we'll pretend the transmitter isn't empty to     * avoid a race condition (depending on when the transmit     * interrupt happens).     */    if (info->x_char ||        ((CIRC_CNT(info->xmit.head, info->xmit.tail,               SICC_XMIT_SIZE) > 0) &&         !info->tty->stopped && !info->tty->hw_stopped))

⌨️ 快捷键说明

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