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

📄 serial_sicc.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    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);    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;    unsigned long flags;    if (get_user(arg, value))        return -EFAULT;    old = info->mctrl;    switch (cmd) {    case TIOCMBIS:        info->mctrl |= arg;        break;    case TIOCMBIC:        info->mctrl &= ~arg;        break;    case TIOCMSET:        info->mctrl = arg;        break;    default:        return -EINVAL;    }    save_flags(flags); cli();    if (old != info->mctrl)        info->port->set_mctrl(info->port, info->mctrl);    restore_flags(flags);    return 0;}static void siccuart_break_ctl(struct tty_struct *tty, int break_state){    struct SICC_info *info = tty->driver_data;    unsigned long flags;    unsigned int lcr_h;    save_flags(flags); cli();    lcr_h = readb(info->port + BL_SICC_LSR);    if (break_state == -1)        lcr_h |=  _LSR_LB_MASK;    else        lcr_h &= ~_LSR_LB_MASK;    writeb(lcr_h, info->port + BL_SICC_LSRS);    restore_flags(flags);}static int siccuart_ioctl(struct tty_struct *tty, struct file *file,               unsigned int cmd, unsigned long arg){    struct SICC_info *info = tty->driver_data;    struct SICC_icount cnow;    struct serial_icounter_struct icount;    unsigned long flags;    if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&        (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&        (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {        if (tty->flags & (1 << TTY_IO_ERROR))            return -EIO;    }    switch (cmd) {        case TIOCMGET:            return get_modem_info(info, (unsigned int *)arg);        case TIOCMBIS:        case TIOCMBIC:        case TIOCMSET:            return set_modem_info(info, cmd, (unsigned int *)arg);        case TIOCGSERIAL:            return get_serial_info(info,                           (struct serial_struct *)arg);        case TIOCSSERIAL:            return set_serial_info(info,                           (struct serial_struct *)arg);        case TIOCSERGETLSR: /* Get line status register */            return get_lsr_info(info, (unsigned int *)arg);        /*         * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change         * - mask passed in arg for lines of interest         *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)         * Caller should use TIOCGICOUNT to see which one it was         */        case TIOCMIWAIT:            return 0;        /*         * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)         * Return: write counters to the user passed counter struct         * NB: both 1->0 and 0->1 transitions are counted except for         *     RI where only 0->1 is counted.         */        case TIOCGICOUNT:            save_flags(flags); cli();            cnow = info->state->icount;            restore_flags(flags);            icount.cts = cnow.cts;            icount.dsr = cnow.dsr;            icount.rng = cnow.rng;            icount.dcd = cnow.dcd;            icount.rx  = cnow.rx;            icount.tx  = cnow.tx;            icount.frame = cnow.frame;            icount.overrun = cnow.overrun;            icount.parity = cnow.parity;            icount.brk = cnow.brk;            icount.buf_overrun = cnow.buf_overrun;            return copy_to_user((void *)arg, &icount, sizeof(icount))                    ? -EFAULT : 0;        default:            return -ENOIOCTLCMD;    }    return 0;}static void siccuart_set_termios(struct tty_struct *tty, struct termios *old_termios){    struct SICC_info *info = tty->driver_data;    unsigned long flags;    unsigned int cflag = tty->termios->c_cflag;    if ((cflag ^ old_termios->c_cflag) == 0 &&        RELEVENT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)        return;    siccuart_change_speed(info, old_termios);    /* Handle transition to B0 status */    if ((old_termios->c_cflag & CBAUD) &&        !(cflag & CBAUD)) {        save_flags(flags); cli();        info->mctrl &= ~(TIOCM_RTS | TIOCM_DTR);        info->port->set_mctrl(info->port, info->mctrl);        restore_flags(flags);    }    /* Handle transition away from B0 status */    if (!(old_termios->c_cflag & CBAUD) &&        (cflag & CBAUD)) {        save_flags(flags); cli();        info->mctrl |= TIOCM_DTR;        if (!(cflag & CRTSCTS) ||            !test_bit(TTY_THROTTLED, &tty->flags))            info->mctrl |= TIOCM_RTS;        info->port->set_mctrl(info->port, info->mctrl);        restore_flags(flags);    }    /* Handle turning off CRTSCTS */    if ((old_termios->c_cflag & CRTSCTS) &&        !(cflag & CRTSCTS)) {        tty->hw_stopped = 0;        siccuart_start(tty);    }#if 0    /*     * No need to wake up processes in open wait, since they     * sample the CLOCAL flag once, and don't recheck it.     * XXX  It's not clear whether the current behavior is correct     * or not.  Hence, this may change.....     */    if (!(old_termios->c_cflag & CLOCAL) &&        (tty->termios->c_cflag & CLOCAL))        wake_up_interruptible(&info->open_wait);#endif}static void siccuart_close(struct tty_struct *tty, struct file *filp){    struct SICC_info *info = tty->driver_data;    struct SICC_state *state;    unsigned long flags;    if (!info)        return;    state = info->state;    //pr_debug("siccuart_close() called\n");    save_flags(flags); cli();    if (tty_hung_up_p(filp)) {        restore_flags(flags);        return;    }    if ((tty->count == 1) && (state->count != 1)) {        /*         * Uh, oh.  tty->count is 1, which means that the tty         * structure will be freed.  state->count should always         * be one in these conditions.  If it's greater than         * one, we've got real problems, since it means the         * serial port won't be shutdown.         */        printk("siccuart_close: bad serial port count; tty->count is 1, state->count is %d\n", state->count);        state->count = 1;    }    if (--state->count < 0) {        printk("rs_close: bad serial port count for %s: %d\n", tty->name, state->count);        state->count = 0;    }    if (state->count) {        restore_flags(flags);        return;    }    info->flags |= ASYNC_CLOSING;    restore_flags(flags);    /*     * Now we wait for the transmit buffer to clear; and we notify     * the line discipline to only process XON/XOFF characters.     */    tty->closing = 1;    if (info->state->closing_wait != ASYNC_CLOSING_WAIT_NONE)        tty_wait_until_sent(tty, info->state->closing_wait);    /*     * At this point, we stop accepting input.  To do this, we     * disable the receive line status interrupts.     */    if (info->flags & ASYNC_INITIALIZED) {        siccuart_disable_rx_interrupt(info);        /*         * Before we drop DTR, make sure the UART transmitter         * has completely drained; this is especially         * important if there is a transmit FIFO!         */        siccuart_wait_until_sent(tty, info->timeout);    }    siccuart_shutdown(info);    if (tty->driver->flush_buffer)        tty->driver->flush_buffer(tty);    if (tty->ldisc.flush_buffer)        tty->ldisc.flush_buffer(tty);    tty->closing = 0;    info->event = 0;    info->tty = NULL;    if (info->blocked_open) {        if (info->state->close_delay) {            set_current_state(TASK_INTERRUPTIBLE);            schedule_timeout(info->state->close_delay);        }        wake_up_interruptible(&info->open_wait);    }    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);    wake_up_interruptible(&info->close_wait);}static void siccuart_wait_until_sent(struct tty_struct *tty, int timeout){    struct SICC_info *info = (struct SICC_info *) tty->driver_data;    unsigned long char_time, expire;    if (info->port->fifosize == 0)        return;    /*     * Set the check interval to be 1/5 of the estimated time to     * send a single character, and make it at least 1.  The check     * interval should also be less than the timeout.     *     * Note: we have to use pretty tight timings here to satisfy     * the NIST-PCTS.     */    char_time = (info->timeout - HZ/50) / info->port->fifosize;    char_time = char_time / 5;    if (char_time == 0)        char_time = 1;    // Crazy!!   sometimes the input arg 'timeout' can be negtive numbers  :-(    if (timeout >= 0 && timeout < char_time)        char_time = timeout;

⌨️ 快捷键说明

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