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

📄 serial_sicc.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 5 页
字号:
    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;#if DEBUG    //printk("siccuart_close() called\n");#endif    save_flags(flags); cli();    if (tty_hung_up_p(filp)) {        MOD_DEC_USE_COUNT;        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: %d\n", tty->driver.name, info->state->line, state->count);        state->count = 0;    }    if (state->count) {        MOD_DEC_USE_COUNT;        restore_flags(flags);        return;    }    info->flags |= ASYNC_CLOSING;    restore_flags(flags);    /*     * Save the termios structure, since this port may have     * separate termios for callout and dialin.     */    if (info->flags & ASYNC_NORMAL_ACTIVE)        info->state->normal_termios = *tty->termios;    if (info->flags & ASYNC_CALLOUT_ACTIVE)        info->state->callout_termios = *tty->termios;    /*     * 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_CALLOUT_ACTIVE|             ASYNC_CLOSING);    wake_up_interruptible(&info->close_wait);    MOD_DEC_USE_COUNT;}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;    /*     * If the transmitter hasn't cleared in twice the approximate     * amount of time to send the entire FIFO, it probably won't     * ever clear.  This assumes the UART isn't doing flow     * control, which is currently the case.  Hence, if it ever     * takes longer than info->timeout, this is probably due to a     * UART bug of some kind.  So, we clamp the timeout parameter at     * 2*info->timeout.     */    if (!timeout || timeout > 2 * info->timeout)        timeout = 2 * info->timeout;    expire = jiffies + timeout;#if DEBUG    printk("siccuart_wait_until_sent(%d), jiff=%lu, expire=%lu  char_time=%lu...\n",           MINOR(tty->device) - tty->driver.minor_start, jiffies,           expire, char_time);#endif    while ((readb(info->port->uart_base + BL_SICC_LSR) & _LSR_TX_ALL) != _LSR_TX_ALL) {        set_current_state(TASK_INTERRUPTIBLE);        schedule_timeout(char_time);        if (signal_pending(current))            break;        if (timeout && time_after(jiffies, expire))            break;    }    set_current_state(TASK_RUNNING);}static void siccuart_hangup(struct tty_struct *tty){    struct SICC_info *info = tty->driver_data;    struct SICC_state *state = info->state;    siccuart_flush_buffer(tty);    if (info->flags & ASYNC_CLOSING)        return;    siccuart_shutdown(info);    info->event = 0;    state->count = 0;    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);    info->tty = NULL;    wake_up_interruptible(&info->open_wait);}static int block_til_ready(struct tty_struct *tty, struct file *filp,               struct SICC_info *info){    DECLARE_WAITQUEUE(wait, current);    struct SICC_state *state = info->state;    unsigned long flags;    int do_clocal = 0, extra_count = 0, retval;    /*     * If the device is in the middle of being closed, then block     * until it's done, and then try again.     */    if (tty_hung_up_p(filp) ||        (info->flags & ASYNC_CLOSING)) {        if (info->flags & ASYNC_CLOSING)            interruptible_sleep_on(&info->close_wait);        return (info->flags & ASYNC_HUP_NOTIFY) ?            -EAGAIN : -ERESTARTSYS;    }    /*     * If this is a callout device, then just make sure the normal     * device isn't being used.     */    if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {        if (info->flags & ASYNC_NORMAL_ACTIVE)            return -EBUSY;        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&            (info->flags & ASYNC_SESSION_LOCKOUT) &&            (info->session != current->session))            return -EBUSY;        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&            (info->flags & ASYNC_PGRP_LOCKOUT) &&            (info->pgrp != current->pgrp))            return -EBUSY;        info->flags |= ASYNC_CALLOUT_ACTIVE;        return 0;    }    /*     * If non-blocking mode is set, or the port is not enabled,     * then make the check up front and then exit.     */    if ((filp->f_flags & O_NONBLOCK) ||        (tty->flags & (1 << TTY_IO_ERROR))) {        if (info->flags & ASYNC_CALLOUT_ACTIVE)            return -EBUSY;        info->flags |= ASYNC_NORMAL_ACTIVE;        return 0;    }    if (info->flags & ASYNC_CALLOUT_ACTIVE) {        if (state->normal_termios.c_cflag & CLOCAL)            do_clocal = 1;    } else {        if (tty->termios->c_cflag & CLOCAL)            do_clocal = 1;    }    /*     * Block waiting for the carrier detect and the line to become     * free (i.e., not in use by the callout).  While we are in     * this loop, state->count is dropped by one, so that     * rs_close() knows when to free things.  We restore it upon     * exit, either normal or abnormal.     */    retval = 0;    add_wait_queue(&info->open_wait, &wait);    save_flags(flags); cli();    if (!tty_hung_up_p(filp)) {        extra_count = 1;        state->count--;    }    restore_flags(flags);    info->blocked_open++;    while (1) {        save_flags(flags); cli();        if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&            (tty->termios->c_cflag & CBAUD)) {            info->mctrl = TIOCM_DTR | TIOCM_RTS;            info->port->set_mctrl(info->port, info->mctrl);        }        restore_flags(flags);        set_current_state(TASK_INTERRUPTIBLE);        if (tty_hung_up_p(filp) ||            !(info->flags & ASYNC_INITIALIZED)) {            if (info->flags & ASYNC_HUP_NOTIFY)                retval = -EAGAIN;            else                retval = -ERESTARTSYS;            break;        }        if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&            !(info->flags & ASYNC_CLOSING) &&            (do_clocal /*|| (UART_GET_FR(info->port) & SICC_UARTFR_DCD)*/))            break;

⌨️ 快捷键说明

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