1.TTY数据接收
tty_read.c:
-
/**
-
* tty_read - read method for tty device files
-
* @file: pointer to tty file
-
* @buf: user buffer
-
* @count: size of user buffer
-
* @ppos: unused
-
*
-
* Perform the read system call function on this terminal device. Checks
-
* for hung up devices before calling the line discipline method.
-
*
-
* Locking:
-
* Locks the line discipline internally while needed. Multiple
-
* read calls may be outstanding in parallel.
-
*/
-
-
static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
-
loff_t *ppos)
-
{
-
int i;
-
struct tty_struct *tty;
-
struct inode *inode;
-
struct tty_ldisc *ld;
-
-
tty = (struct tty_struct *)file->private_data;
-
inode = file->f_path.dentry->d_inode;
-
if (tty_paranoia_check(tty, inode, "tty_read"))
-
return -EIO;
-
if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
-
return -EIO;
-
-
/* We want to wait for the line discipline to sort out in this
-
situation */
-
ld = tty_ldisc_ref_wait(tty);
-
if (ld->ops->read)
-
i = (ld->ops->read)(tty, file, buf, count); //这里调用了线路规程中的read
-
else
-
i = -EIO;
-
tty_ldisc_deref(ld);
-
if (i > 0)
-
inode->i_atime = current_fs_time(inode->i_sb);
-
return i;
-
}
tty_ldisc_N_TTY:
-
struct tty_ldisc_ops tty_ldisc_N_TTY = {
-
.magic = TTY_LDISC_MAGIC,
-
.name = "n_tty",
-
.open = n_tty_open,
-
.close = n_tty_close,
-
.flush_buffer = n_tty_flush_buffer,
-
.chars_in_buffer = n_tty_chars_in_buffer,
-
.read = n_tty_read, //调用的read函数
-
.write = n_tty_write,
-
.ioctl = n_tty_ioctl,
-
.set_termios = n_tty_set_termios,
-
.poll = n_tty_poll,
-
.receive_buf = n_tty_receive_buf,
-
.write_wakeup = n_tty_write_wakeup
-
};
n_tty_read:
-
/**
-
* n_tty_read - read function for tty
-
* @tty: tty device
-
* @file: file object
-
* @buf: userspace buffer pointer
-
* @nr: size of I/O
-
*
-
* Perform reads for the line discipline. We are guaranteed that the
-
* line discipline will not be closed under us but we may get multiple
-
* parallel readers and must handle this ourselves. We may also get
-
* a hangup. Always called in user context, may sleep.
-
*
-
* This code must be sure never to sleep through a hangup.
-
*/
-
-
static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
-
unsigned char __user *buf, size_t nr)
-
{
-
unsigned char __user *b = buf;
-
DECLARE_WAITQUEUE(wait, current);
-
int c;
-
int minimum, time;
-
ssize_t retval = 0;
-
ssize_t size;
-
long timeout;
-
unsigned long flags;
-
int packet;
-
-
.......
-
-
/* This statement must be first before checking for input
-
so that any interrupt will set the state back to
-
TASK_RUNNING. */
-
set_current_state(TASK_INTERRUPTIBLE); //设置当前进程的状态,后面调度后阻塞
-
-
if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
-
((minimum - (b - buf)) >= 1))
-
tty->minimum_to_wake = (minimum - (b - buf));
-
-
if (!input_available_p(tty, 0)) { //判断有没有数据可以读取
-
if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
-
retval = -EIO;
-
break;
-
}
-
if (tty_hung_up_p(file))
-
break;
-
if (!timeout)
-
break;
-
if (file->f_flags & O_NONBLOCK) {
-
retval = -EAGAIN;
-
break;
-
}
-
if (signal_pending(current)) {
-
retval = -ERESTARTSYS;
-
break;
-
}
-
/* FIXME: does n_tty_set_room need locking ? */
-
n_tty_set_room(tty);
-
timeout = schedule_timeout(timeout); //调度,如果没有数据可读,让阻塞生效
-
continue;
-
}
-
__set_current_state(TASK_RUNNING); //如果有数据,
-
-
/* Deal with packet mode. */
-
if (packet && b == buf) {
-
if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
-
retval = -EFAULT;
-
b--;
-
break;
-
}
-
nr--;
-
}
-
-
if (tty->icanon) {
-
/* N.B. avoid overrun if nr == 0 */
-
while (nr && tty->read_cnt) {
-
int eol;
-
-
eol = test_and_clear_bit(tty->read_tail,
-
tty->read_flags);
-
c = tty->read_buf[tty->read_tail];
-
spin_lock_irqsave(&tty->read_lock, flags);
-
tty->read_tail = ((tty->read_tail+1) &
-
(N_TTY_BUF_SIZE-1));
-
tty->read_cnt--;
-
if (eol) {
-
/* this test should be redundant:
-
* we shouldn't be reading data if
-
* canon_data is 0
-
*/
-
if (--tty->canon_data < 0)
-
tty->canon_data = 0;
-
}
-
spin_unlock_irqrestore(&tty->read_lock, flags);
-
-
if (!eol || (c != __DISABLED_CHAR)) {
-
if (tty_put_user(tty, c, b++)) {
-
retval = -EFAULT;
-
b--;
-
break;
-
}
-
nr--;
-
}
-
if (eol) {
-
tty_audit_push(tty);
-
break;
-
}
-
}
-
if (retval)
-
break;
-
} else {
-
int uncopied;
-
/* The copy function takes the read lock and handles
-
locking internally for this case */
-
uncopied = copy_from_read_buf(tty, &b, &nr); //从readbuf中读取shu
-
uncopied += copy_from_read_buf(tty, &b, &nr);
-
if (uncopied) {
-
retval = -EFAULT;
-
break;
-
}
-
}
-
-
/* If there is enough space in the read buffer now, let the
-
* low-level driver know. We use n_tty_chars_in_buffer() to
-
* check the buffer, as it now knows about canonical mode.
-
* Otherwise, if the driver is throttled and the line is
-
* longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
-
* we won't get any more characters.
-
*/
-
if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
-
n_tty_set_room(tty);
-
check_unthrottle(tty);
-
}
-
-
if (b - buf >= minimum)
-
break;
-
if (time)
-
timeout = time;
-
}
-
mutex_unlock(&tty->atomic_read_lock);
-
remove_wait_queue(&tty->read_wait, &wait);
-
-
if (!waitqueue_active(&tty->read_wait))
-
tty->minimum_to_wake = minimum;
-
-
__set_current_state(TASK_RUNNING);
-
size = b - buf;
-
if (size) {
-
retval = size;
-
if (nr)
-
clear_bit(TTY_PUSH, &tty->flags);
-
} else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
-
goto do_it_again;
-
-
n_tty_set_room(tty);
-
return retval;
-
}
copy_from_read_buf:
-
-
static int copy_from_read_buf(struct tty_struct *tty,
-
unsigned char __user **b,
-
size_t *nr)
-
-
{
-
int retval;
-
size_t n;
-
unsigned long flags;
-
-
retval = 0;
-
spin_lock_irqsave(&tty->read_lock, flags);
-
n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);
-
n = min(*nr, n);
-
spin_unlock_irqrestore(&tty->read_lock, flags);
-
if (n) {
-
retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n); //read_buf就是读缓冲
-
n -= retval;
-
tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
-
spin_lock_irqsave(&tty->read_lock, flags);
-
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
-
tty->read_cnt -= n;
-
spin_unlock_irqrestore(&tty->read_lock, flags);
-
*b += n;
-
*nr -= n;
-
}
-
return retval;
-
}
总结:应用APP-->TTY核心-->TTY线路规程(read_buf有就给APP,没有就阻塞);然后read_buf其实是串口驱动收到的,只是不是同时处理的。
二、串口驱动接收分析
s3c24xx_serial_rx_chars:
-
static irqreturn_t
-
s3c24xx_serial_rx_chars(int irq, void *dev_id)
-
{
-
struct s3c24xx_uart_port *ourport = dev_id;
-
struct uart_port *port = &ourport->port;
-
struct tty_struct *tty = port->info->port.tty;
-
unsigned int ufcon, ch, flag, ufstat, uerstat;
-
int max_count = 64; //一次中断最多64字符
-
-
while (max_count-- > 0) {
-
ufcon = rd_regl(port, S3C2410_UFCON); //读取了UFCON寄存器
-
ufstat = rd_regl(port, S3C2410_UFSTAT); //读取UFSTAT
-
-
if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) //如果接收FIFO数据量为0,则退出
-
break;
-
-
uerstat = rd_regl(port, S3C2410_UERSTAT); //读取uerstat
-
ch = rd_regb(port, S3C2410_URXH); //取出接收到的数据
-
-
if (port->flags & UPF_CONS_FLOW) { //流控处理
-
int txe = s3c24xx_serial_txempty_nofifo(port); //判断发送缓冲是否为空
-
-
if (rx_enabled(port)) { //如果port接收功能是使能的
-
if (!txe) { //如果txe为0
-
rx_enabled(port) = 0;
-
continue;
-
}
-
} else {
-
if (txe) { //如果txe为1
-
ufcon |= S3C2410_UFCON_RESETRX;
-
wr_regl(port, S3C2410_UFCON, ufcon);
-
rx_enabled(port) = 1;
-
goto out;
-
}
-
continue;
-
}
-
}
-
-
/* insert the character into the buffer */
-
-
flag = TTY_NORMAL;
-
port->icount.rx++;
-
-
if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) { //根据USRSTAT寄存器的值,
-
dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
-
ch, uerstat);
-
-
/* check for break */
-
if (uerstat & S3C2410_UERSTAT_BREAK) {
-
dbg("break!\n");
-
port->icount.brk++;
-
if (uart_handle_break(port))
-
goto ignore_char;
-
}
-
-
if (uerstat & S3C2410_UERSTAT_FRAME)
-
port->icount.frame++;
-
if (uerstat & S3C2410_UERSTAT_OVERRUN)
-
port->icount.overrun++;
-
-
uerstat &= port->read_status_mask;
-
-
if (uerstat & S3C2410_UERSTAT_BREAK)
-
flag = TTY_BREAK;
-
else if (uerstat & S3C2410_UERSTAT_PARITY)
-
flag = TTY_PARITY;
-
else if (uerstat & (S3C2410_UERSTAT_FRAME |
-
S3C2410_UERSTAT_OVERRUN))
-
flag = TTY_FRAME;
-
}
-
-
if (uart_handle_sysrq_char(port, ch)) //如果收到的是sysrq字符,进行特殊处理
-
goto ignore_char;
-
-
uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, //把接收到的字符送进串口驱动的buf_uart_insert_char
-
ch, flag);
-
-
ignore_char:
-
continue;
-
}
-
tty_flip_buffer_push(tty); //把串口驱动收到的数据送进线路规程的read_buf
-
-
out:
-
return IRQ_HANDLED;
-
}
三、串口流控
当A向B发送数据时,B的缓冲如果满了。要向A发送一个FIFO满了的信号,这个就是流控:
分成软件(信号)、硬件(B的串口RTS设置成高电位,A的CTS就知道B已经满了)(又分成非自动、和自动)
阅读(565) | 评论(0) | 转发(0) |