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

📄 serial_sicc.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 5 页
字号:
    } 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){    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;#if DEBUG    printk("siccuart_flush_buffer(%d) called\n",           MINOR(tty->device) - tty->driver.minor_start);#endif    save_flags(flags); cli();    info->xmit.head = info->xmit.tail = 0;    restore_flags(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) {        save_flags(flags); cli();        info->mctrl &= ~TIOCM_RTS;        info->port->set_mctrl(info->port, info->mctrl);        restore_flags(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) {        save_flags(flags); cli();        info->mctrl |= TIOCM_RTS;        info->port->set_mctrl(info->port, info->mctrl);        restore_flags(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;    save_flags(flags); cli();    status = readb(info->port->uart_base +  BL_SICC_LSR);    restore_flags(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))        result &= TIOCSER_TEMT;        return put_user(result, value);}static int get_modem_info(struct SICC_info *info, unsigned int *value){    unsigned int result = info->mctrl;    return put_user(result, value);}static int set_modem_info(struct SICC_info *info, unsigned int cmd,              unsigned int *value){    unsigned int arg, old;

⌨️ 快捷键说明

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