📄 serial_core.c
字号:
tty->hw_stopped = 1; state->port->ops->stop_tx(state->port); } spin_unlock_irqrestore(&state->port->lock, flags); }#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(&state->info->open_wait);#endif}/* * In 2.4.5, calls to this will be serialized via the BKL in * linux/drivers/char/tty_io.c:tty_release() * linux/drivers/char/tty_io.c:do_tty_handup() */static void uart_close(struct tty_struct *tty, struct file *filp){ struct uart_state *state = tty->driver_data; struct uart_port *port; BUG_ON(!kernel_locked()); if (!state || !state->port) return; port = state->port; DPRINTK("uart_close(%d) called\n", port->line); mutex_lock(&state->mutex); if (tty_hung_up_p(filp)) goto done; 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(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " "state->count is %d\n", state->count); state->count = 1; } if (--state->count < 0) { printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", tty->name, state->count); state->count = 0; } if (state->count) goto done; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters by * setting tty->closing. */ tty->closing = 1; if (state->closing_wait != USF_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, msecs_to_jiffies(state->closing_wait)); /* * At this point, we stop accepting input. To do this, we * disable the receive line status interrupts. */ if (state->info->flags & UIF_INITIALIZED) { unsigned long flags; spin_lock_irqsave(&port->lock, flags); port->ops->stop_rx(port); spin_unlock_irqrestore(&port->lock, flags); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ uart_wait_until_sent(tty, port->timeout); } uart_shutdown(state); uart_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; state->info->tty = NULL; if (state->info->blocked_open) { if (state->close_delay) msleep_interruptible(state->close_delay); } else if (!uart_console(port)) { uart_change_pm(state, 3); } /* * Wake up anyone trying to open this port. */ state->info->flags &= ~UIF_NORMAL_ACTIVE; wake_up_interruptible(&state->info->open_wait); done: mutex_unlock(&state->mutex);}static void uart_wait_until_sent(struct tty_struct *tty, int timeout){ struct uart_state *state = tty->driver_data; struct uart_port *port = state->port; unsigned long char_time, expire; BUG_ON(!kernel_locked()); if (port->type == PORT_UNKNOWN || 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 = (port->timeout - HZ/50) / port->fifosize; char_time = char_time / 5; if (char_time == 0) char_time = 1; if (timeout && 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 port->timeout, this is probably due to a * UART bug of some kind. So, we clamp the timeout parameter at * 2*port->timeout. */ if (timeout == 0 || timeout > 2 * port->timeout) timeout = 2 * port->timeout; expire = jiffies + timeout; DPRINTK("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n", port->line, jiffies, expire); /* * Check whether the transmitter is empty every 'char_time'. * 'timeout' / 'expire' give us the maximum amount of time * we wait. */ while (!port->ops->tx_empty(port)) { msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; if (time_after(jiffies, expire)) break; } set_current_state(TASK_RUNNING); /* might not be needed */}/* * This is called with the BKL held in * linux/drivers/char/tty_io.c:do_tty_hangup() * We're called from the eventd thread, so we can sleep for * a _short_ time only. */static void uart_hangup(struct tty_struct *tty){ struct uart_state *state = tty->driver_data; BUG_ON(!kernel_locked()); DPRINTK("uart_hangup(%d)\n", state->port->line); mutex_lock(&state->mutex); if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) { uart_flush_buffer(tty); uart_shutdown(state); state->count = 0; state->info->flags &= ~UIF_NORMAL_ACTIVE; state->info->tty = NULL; wake_up_interruptible(&state->info->open_wait); wake_up_interruptible(&state->info->delta_msr_wait); } mutex_unlock(&state->mutex);}/* * Copy across the serial console cflag setting into the termios settings * for the initial open of the port. This allows continuity between the * kernel settings, and the settings init adopts when it opens the port * for the first time. */static void uart_update_termios(struct uart_state *state){ struct tty_struct *tty = state->info->tty; struct uart_port *port = state->port; if (uart_console(port) && port->cons->cflag) { tty->termios->c_cflag = port->cons->cflag; port->cons->cflag = 0; } /* * If the device failed to grab its irq resources, * or some other error occurred, don't try to talk * to the port hardware. */ if (!(tty->flags & (1 << TTY_IO_ERROR))) { /* * Make termios settings take effect. */ uart_change_speed(state, NULL); /* * And finally enable the RTS and DTR signals. */ if (tty->termios->c_cflag & CBAUD) uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS); }}/* * Block the open until the port is ready. We must be called with * the per-port semaphore held. */static intuart_block_til_ready(struct file *filp, struct uart_state *state){ DECLARE_WAITQUEUE(wait, current); struct uart_info *info = state->info; struct uart_port *port = state->port; unsigned int mctrl; info->blocked_open++; state->count--; add_wait_queue(&info->open_wait, &wait); while (1) { set_current_state(TASK_INTERRUPTIBLE); /* * If we have been hung up, tell userspace/restart open. */ if (tty_hung_up_p(filp) || info->tty == NULL) break; /* * If the port has been closed, tell userspace/restart open. */ if (!(info->flags & UIF_INITIALIZED)) break; /* * If non-blocking mode is set, or CLOCAL mode is set, * we don't want to wait for the modem status lines to * indicate that the port is ready. * * Also, if the port is not enabled/configured, we want * to allow the open to succeed here. Note that we will * have set TTY_IO_ERROR for a non-existant port. */ if ((filp->f_flags & O_NONBLOCK) || (info->tty->termios->c_cflag & CLOCAL) || (info->tty->flags & (1 << TTY_IO_ERROR))) { break; } /* * Set DTR to allow modem to know we're waiting. Do * not set RTS here - we want to make sure we catch * the data from the modem. */ if (info->tty->termios->c_cflag & CBAUD) uart_set_mctrl(port, TIOCM_DTR); /* * and wait for the carrier to indicate that the * modem is ready for us. */ spin_lock_irq(&port->lock); port->ops->enable_ms(port); mctrl = port->ops->get_mctrl(port); spin_unlock_irq(&port->lock); if (mctrl & TIOCM_CAR) break; mutex_unlock(&state->mutex); schedule(); mutex_lock(&state->mutex); if (signal_pending(current)) break; } set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); state->count++; info->blocked_open--; if (signal_pending(current)) return -ERESTARTSYS; if (!info->tty || tty_hung_up_p(filp)) return -EAGAIN; return 0;}static struct uart_state *uart_get(struct uart_driver *drv, int line){ struct uart_state *state; mutex_lock(&port_mutex); state = drv->state + line; if (mutex_lock_interruptible(&state->mutex)) { state = ERR_PTR(-ERESTARTSYS); goto out; } state->count++; if (!state->port) { state->count--; mutex_unlock(&state->mutex); state = ERR_PTR(-ENXIO); goto out; } if (!state->info) { state->info = kmalloc(sizeof(struct uart_info), GFP_KERNEL); if (state->info) { memset(state->info, 0, sizeof(struct uart_info)); init_waitqueue_head(&state->info->open_wait); init_waitqueue_head(&state->info->delta_msr_wait); /* * Link the info into the other structures. */ state->port->info = state->info; tasklet_init(&state->info->tlet, uart_tasklet_action, (unsigned long)state); } else { state->count--; mutex_unlock(&state->mutex); state = ERR_PTR(-ENOMEM); } } out: mutex_unlock(&port_mutex); return state;}/* * In 2.4.5, calls to uart_open are serialised by the BKL in * linux/fs/devices.c:chrdev_open() * Note that if this fails, then uart_close() _will_ be called. * * In time, we want to scrap the "opening nonpresent ports" * behaviour and implement an alternative way for setserial * to set base addresses/ports/types. This will allow us to * get rid of a certain amount of extra tests. */static int uart_open(struct tty_struct *tty, struct file *filp){ struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state; struct uart_state *state; int retval, line = tty->index; BUG_ON(!kernel_locked()); DPRINTK("uart_open(%d) called\n", line); /* * tty->driver->num won't change, so we won't fail here with * tty->driver_data set to something non-NULL (and therefore * we won't get caught by uart_close()). */ retval = -ENODEV; if (line >= tty->driver->num) goto fail; /* * We take the semaphore inside uart_get to guarantee that we won't * be re-entered while allocating the info structure, or while we * request any IRQs that the driver may need. This also has the nice * side-effect that it delays the action of uart_hangup, so we can * guarantee that info->tty will always contain something reasonable. */ state = uart_get(drv, line); if (IS_ERR(state)) { retval = PTR_ERR(state); goto fail; } /* * Once we set tty->driver_data here, we are guaranteed that * uart_close() will decrement the driver module use count. * Any failures from here onwards should not touch the count. */ tty->driver_data = state; tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0; tty->alt_speed = 0; state->info->tty = tty; /* * If the port is in the middle of closing, bail out now. */ if (tty_hung_up_p(filp)) { retval = -EAGAIN; state->count--; mutex_unlock(&state->mutex); goto fail; } /* * Make sure the device is in D0 state. */ if (state->count == 1) uart_change_pm(state, 0); /* * Start up the serial port. */ retval = uart_startup(state, 0); /* * If we succeeded, wait until the port is ready. */ if (retval == 0) retval = uart_block_til_ready(filp, state); mutex_unlock(&state->mutex); /* * If this is the first open to succeed, adjust things to suit. */ if (retval == 0 && !(state->info->flags & UIF_NORMAL_ACTIVE)) { state->info->flags |= UIF_NORMAL_ACTIVE; uart_update_termios(state); } fail: return retval;}static const char *uart_type(struct uart_port *port){ const char *str = NULL; if (port->ops->type) str = port->ops->type(port); if (!str) str = "unknown"; return str;}#ifdef CONFIG_PROC_FSstatic int uart_line_info(char *buf, struct uart_driver *drv, int i){ struct uart_state *state = drv->state + i; struct uart_port *port = state->port; char stat_buf[32]; unsigned int status; int ret; if (!port) return 0; ret = sprintf(buf, "%d: uart:%s %s%08lX irq:%d", port->line, uart_type(port), port->iotype == UPIO_MEM ? "mmio:0x" : "port:", port->iotype == UPIO_MEM ? port->mapbase : (unsigned long) port->iobase, port->irq); if (port->type == PORT_UNKNOWN) { strcat(buf, "\n"); return ret + 1; } if(capable(CAP_SYS_ADMIN)) { spin_lock_irq(&port->lock); status = port->ops->get_mctrl(port); spin_unlock_irq(&port->lock); ret += sprintf(buf + ret, " tx:%d rx:%d", port->icount.tx, port->icount.rx); if (port->icount.frame) ret += sprintf(buf + ret, " fe:%d", port->icount.frame); if (port->icount.parity) ret += sprintf(buf + ret, " pe:%d", port->icount.parity); if (port->icount.brk) ret += sprintf(buf + ret, " brk:%d", port->icount.brk); if (port->icount.overrun) ret += sprintf(buf + ret, " oe:%d", port->icount.overrun); #define INFOBIT(bit,str) \ if (port->mctrl & (bit)) \ strncat(stat_buf, (str), sizeof(stat_buf) - \ strlen(stat_buf) - 2)#define STATBIT(bit,str) \ if (status & (bit)) \ strncat(stat_buf, (str), sizeof(stat_buf) - \ strlen(stat_buf) - 2) stat_buf[0] = '\0'; stat_buf[1] = '\0'; INFOBIT(TIOCM_RTS, "|RTS"); STATBIT(TIOCM_CTS, "|CTS"); INFOBIT(TIOCM_DTR, "|DTR"); STATBIT(TIOCM_DSR, "|DSR"); STATBIT(TIOCM_CAR, "|CD"); STATBIT(TIOCM_RNG, "|RI"); if (stat_buf[0]) stat_buf[0] = ' '; strcat(stat_buf, "\n"); ret += sprintf(buf + ret, stat_buf); } else { strcat(buf, "\n"); ret++; }#undef STATBIT#undef INFOBIT return ret;}static int uart_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct tty_driver *ttydrv = data; struct uart_driver *drv = ttydrv->driver_state; int i, len = 0, l; off_t begin = 0; len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n", "", "", ""); for (i = 0; i < drv->nr && len < PAGE_SIZE - 96; i++) { l = uart_line_info(page + len, drv, i); len += l; if (len + begin > off + count) goto done; if (len + begin < off) { begin += len; len = 0; } } *eof = 1; done: if (off >= len + begin) return 0; *start = page + (off - begin); return (count < begin + len - off) ? count : (begin + len - off);}#endif#ifdef CONFIG_SERIAL_CORE_CONSOLE/* * Check whether an invalid uart number has been specified, and * if so, search for the first available port that does have * console support. */struct uart_port * __inituart_get_console(struct uart_port *ports, int nr, struct console *co){ int idx = co->index; if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -