1.TTY数据接收
tty_read.c:
tty_ldisc_N_TTY:
n_tty_read:
copy_from_read_buf:
总结:应用APP-->TTY核心-->TTY线路规程(read_buf有就给APP,没有就阻塞);然后read_buf其实是串口驱动收到的,只是不是同时处理的。
二、串口驱动接收分析
s3c24xx_serial_rx_chars:
三、串口流控
当A向B发送数据时,B的缓冲如果满了。要向A发送一个FIFO满了的信号,这个就是流控:
分成软件(信号)、硬件(B的串口RTS设置成高电位,A的CTS就知道B已经满了)(又分成非自动、和自动)
阅读(73) | 评论(0) | 转发(0) |
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
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;
- }
- 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 - 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;
- }
-
- 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;
- }
二、串口驱动接收分析
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已经满了)(又分成非自动、和自动)
给主人留下些什么吧!~~
评论热议