Chinaunix首页 | 论坛 | 博客
  • 博客访问: 493759
  • 博文数量: 223
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2145
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-01 10:23
个人简介

该坚持的时候坚持,该妥协的时候妥协,该放弃的时候放弃

文章分类

全部博文(223)

文章存档

2017年(56)

2016年(118)

2015年(3)

2014年(46)

我的朋友

分类: 嵌入式

2016-11-18 23:23:59

1.TTY数据接收
tty_read.c:
  1. /**
  2.  *    tty_read    -    read method for tty device files
  3.  *    @file: pointer to tty file
  4.  *    @buf: user buffer
  5.  *    @count: size of user buffer
  6.  *    @ppos: unused
  7.  *
  8.  *    Perform the read system call function on this terminal device. Checks
  9.  *    for hung up devices before calling the line discipline method.
  10.  *
  11.  *    Locking:
  12.  *        Locks the line discipline internally while needed. Multiple
  13.  *    read calls may be outstanding in parallel.
  14.  */

  15. static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
  16.             loff_t *ppos)
  17. {
  18.     int i;
  19.     struct tty_struct *tty;
  20.     struct inode *inode;
  21.     struct tty_ldisc *ld;

  22.     tty = (struct tty_struct *)file->private_data;
  23.     inode = file->f_path.dentry->d_inode;
  24.     if (tty_paranoia_check(tty, inode, "tty_read"))
  25.         return -EIO;
  26.     if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
  27.         return -EIO;

  28.     /* We want to wait for the line discipline to sort out in this
  29.      situation */
  30.     ld = tty_ldisc_ref_wait(tty);
  31.     if (ld->ops->read)
  32.         i = (ld->ops->read)(tty, file, buf, count);                                   //这里调用了线路规程中的read
  33.     else
  34.         i = -EIO;
  35.     tty_ldisc_deref(ld);
  36.     if (i > 0)
  37.         inode->i_atime = current_fs_time(inode->i_sb);
  38.     return i;
  39. }
tty_ldisc_N_TTY:
  1. struct tty_ldisc_ops tty_ldisc_N_TTY = {
  2.     .magic = TTY_LDISC_MAGIC,
  3.     .name = "n_tty",
  4.     .open = n_tty_open,
  5.     .close = n_tty_close,
  6.     .flush_buffer = n_tty_flush_buffer,
  7.     .chars_in_buffer = n_tty_chars_in_buffer,
  8.     .read = n_tty_read,                                                 //调用的read函数
  9.     .write = n_tty_write,
  10.     .ioctl = n_tty_ioctl,
  11.     .set_termios = n_tty_set_termios,
  12.     .poll = n_tty_poll,
  13.     .receive_buf = n_tty_receive_buf,
  14.     .write_wakeup = n_tty_write_wakeup
  15. };
n_tty_read:
  1. /**
  2.  *    n_tty_read        -    read function for tty
  3.  *    @tty: tty device
  4.  *    @file: file object
  5.  *    @buf: userspace buffer pointer
  6.  *    @nr: size of I/O
  7.  *
  8.  *    Perform reads for the line discipline. We are guaranteed that the
  9.  *    line discipline will not be closed under us but we may get multiple
  10.  *    parallel readers and must handle this ourselves. We may also get
  11.  *    a hangup. Always called in user context, may sleep.
  12.  *
  13.  *    This code must be sure never to sleep through a hangup.
  14.  */

  15. static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
  16.              unsigned char __user *buf, size_t nr)
  17. {
  18.     unsigned char __user *b = buf;
  19.     DECLARE_WAITQUEUE(wait, current);
  20.     int c;
  21.     int minimum, time;
  22.     ssize_t retval = 0;
  23.     ssize_t size;
  24.     long timeout;
  25.     unsigned long flags;
  26.     int packet;

  27.     .......

  28.         /* This statement must be first before checking for input
  29.          so that any interrupt will set the state back to
  30.          TASK_RUNNING. */
  31.         set_current_state(TASK_INTERRUPTIBLE);                                          //设置当前进程的状态,后面调度后阻塞

  32.         if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
  33.          ((minimum - (b - buf)) >= 1))
  34.             tty->minimum_to_wake = (minimum - (b - buf));

  35.         if (!input_available_p(tty, 0)) {                                                //判断有没有数据可以读取
  36.             if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
  37.                 retval = -EIO;
  38.                 break;
  39.             }
  40.             if (tty_hung_up_p(file))
  41.                 break;
  42.             if (!timeout)
  43.                 break;
  44.             if (file->f_flags & O_NONBLOCK) {
  45.                 retval = -EAGAIN;
  46.                 break;
  47.             }
  48.             if (signal_pending(current)) {
  49.                 retval = -ERESTARTSYS;
  50.                 break;
  51.             }
  52.             /* FIXME: does n_tty_set_room need locking ? */
  53.             n_tty_set_room(tty);
  54.             timeout = schedule_timeout(timeout);                                         //调度,如果没有数据可读,让阻塞生效
  55.             continue;
  56.         }
  57.         __set_current_state(TASK_RUNNING);                                               //如果有数据,

  58.         /* Deal with packet mode. */
  59.         if (packet && b == buf) {
  60.             if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
  61.                 retval = -EFAULT;
  62.                 b--;
  63.                 break;
  64.             }
  65.             nr--;
  66.         }

  67.         if (tty->icanon) {
  68.             /* N.B. avoid overrun if nr == 0 */
  69.             while (nr && tty->read_cnt) {
  70.                 int eol;

  71.                 eol = test_and_clear_bit(tty->read_tail,
  72.                         tty->read_flags);
  73.                 c = tty->read_buf[tty->read_tail];
  74.                 spin_lock_irqsave(&tty->read_lock, flags);
  75.                 tty->read_tail = ((tty->read_tail+1) &
  76.                          (N_TTY_BUF_SIZE-1));
  77.                 tty->read_cnt--;
  78.                 if (eol) {
  79.                     /* this test should be redundant:
  80.                      * we shouldn't be reading data if
  81.                      * canon_data is 0
  82.                      */
  83.                     if (--tty->canon_data < 0)
  84.                         tty->canon_data = 0;
  85.                 }
  86.                 spin_unlock_irqrestore(&tty->read_lock, flags);

  87.                 if (!eol || (c != __DISABLED_CHAR)) {
  88.                     if (tty_put_user(tty, c, b++)) {
  89.                         retval = -EFAULT;
  90.                         b--;
  91.                         break;
  92.                     }
  93.                     nr--;
  94.                 }
  95.                 if (eol) {
  96.                     tty_audit_push(tty);
  97.                     break;
  98.                 }
  99.             }
  100.             if (retval)
  101.                 break;
  102.         } else {
  103.             int uncopied;
  104.             /* The copy function takes the read lock and handles
  105.              locking internally for this case */
  106.             uncopied = copy_from_read_buf(tty, &b, &nr);                                             //从readbuf中读取shu
  107.             uncopied += copy_from_read_buf(tty, &b, &nr);
  108.             if (uncopied) {
  109.                 retval = -EFAULT;
  110.                 break;
  111.             }
  112.         }

  113.         /* If there is enough space in the read buffer now, let the
  114.          * low-level driver know. We use n_tty_chars_in_buffer() to
  115.          * check the buffer, as it now knows about canonical mode.
  116.          * Otherwise, if the driver is throttled and the line is
  117.          * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
  118.          * we won't get any more characters.
  119.          */
  120.         if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
  121.             n_tty_set_room(tty);
  122.             check_unthrottle(tty);
  123.         }

  124.         if (b - buf >= minimum)
  125.             break;
  126.         if (time)
  127.             timeout = time;
  128.     }
  129.     mutex_unlock(&tty->atomic_read_lock);
  130.     remove_wait_queue(&tty->read_wait, &wait);

  131.     if (!waitqueue_active(&tty->read_wait))
  132.         tty->minimum_to_wake = minimum;

  133.     __set_current_state(TASK_RUNNING);
  134.     size = b - buf;
  135.     if (size) {
  136.         retval = size;
  137.         if (nr)
  138.             clear_bit(TTY_PUSH, &tty->flags);
  139.     } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
  140.          goto do_it_again;

  141.     n_tty_set_room(tty);
  142.     return retval;
  143. }
copy_from_read_buf:

  1. static int copy_from_read_buf(struct tty_struct *tty,
  2.                  unsigned char __user **b,
  3.                  size_t *nr)

  4. {
  5.     int retval;
  6.     size_t n;
  7.     unsigned long flags;

  8.     retval = 0;
  9.     spin_lock_irqsave(&tty->read_lock, flags);
  10.     n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);
  11.     n = min(*nr, n);
  12.     spin_unlock_irqrestore(&tty->read_lock, flags);
  13.     if (n) {
  14.         retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);                         //read_buf就是读缓冲
  15.         n -= retval;
  16.         tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
  17.         spin_lock_irqsave(&tty->read_lock, flags);
  18.         tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
  19.         tty->read_cnt -= n;
  20.         spin_unlock_irqrestore(&tty->read_lock, flags);
  21.         *b += n;
  22.         *nr -= n;
  23.     }
  24.     return retval;
  25. }
总结:应用APP-->TTY核心-->TTY线路规程(read_buf有就给APP,没有就阻塞);然后read_buf其实是串口驱动收到的,只是不是同时处理的。

二、串口驱动接收分析
s3c24xx_serial_rx_chars:
  1. static irqreturn_t
  2. s3c24xx_serial_rx_chars(int irq, void *dev_id)
  3. {
  4.     struct s3c24xx_uart_port *ourport = dev_id;
  5.     struct uart_port *port = &ourport->port;
  6.     struct tty_struct *tty = port->info->port.tty;
  7.     unsigned int ufcon, ch, flag, ufstat, uerstat;
  8.     int max_count = 64;                                                             //一次中断最多64字符

  9.     while (max_count-- > 0) {
  10.         ufcon = rd_regl(port, S3C2410_UFCON);                                       //读取了UFCON寄存器
  11.         ufstat = rd_regl(port, S3C2410_UFSTAT);                                     //读取UFSTAT

  12.         if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)                        //如果接收FIFO数据量为0,则退出
  13.             break;

  14.         uerstat = rd_regl(port, S3C2410_UERSTAT);                                   //读取uerstat
  15.         ch = rd_regb(port, S3C2410_URXH);                                           //取出接收到的数据

  16.         if (port->flags & UPF_CONS_FLOW) {                                          //流控处理
  17.             int txe = s3c24xx_serial_txempty_nofifo(port);                          //判断发送缓冲是否为空

  18.             if (rx_enabled(port)) {                                                 //如果port接收功能是使能的
  19.                 if (!txe) {                                                         //如果txe为0
  20.                     rx_enabled(port) = 0;                                           
  21.                     continue;
  22.                 }
  23.             } else {
  24.                 if (txe) {                                                          //如果txe为1
  25.                     ufcon |= S3C2410_UFCON_RESETRX;
  26.                     wr_regl(port, S3C2410_UFCON, ufcon);
  27.                     rx_enabled(port) = 1;
  28.                     goto out;
  29.                 }
  30.                 continue;
  31.             }
  32.         }

  33.         /* insert the character into the buffer */

  34.         flag = TTY_NORMAL;
  35.         port->icount.rx++;

  36.         if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {                             //根据USRSTAT寄存器的值,
  37.             dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
  38.              ch, uerstat);

  39.             /* check for break */
  40.             if (uerstat & S3C2410_UERSTAT_BREAK) {
  41.                 dbg("break!\n");
  42.                 port->icount.brk++;
  43.                 if (uart_handle_break(port))
  44.                  goto ignore_char;
  45.             }

  46.             if (uerstat & S3C2410_UERSTAT_FRAME)
  47.                 port->icount.frame++;
  48.             if (uerstat & S3C2410_UERSTAT_OVERRUN)
  49.                 port->icount.overrun++;

  50.             uerstat &= port->read_status_mask;

  51.             if (uerstat & S3C2410_UERSTAT_BREAK)
  52.                 flag = TTY_BREAK;
  53.             else if (uerstat & S3C2410_UERSTAT_PARITY)
  54.                 flag = TTY_PARITY;
  55.             else if (uerstat & (S3C2410_UERSTAT_FRAME |
  56.                      S3C2410_UERSTAT_OVERRUN))
  57.                 flag = TTY_FRAME;
  58.         }

  59.         if (uart_handle_sysrq_char(port, ch))                                        //如果收到的是sysrq字符,进行特殊处理
  60.             goto ignore_char;

  61.         uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,                     //把接收到的字符送进串口驱动的buf_uart_insert_char
  62.                  ch, flag);

  63.  ignore_char:
  64.         continue;
  65.     }
  66.     tty_flip_buffer_push(tty);                                                       //把串口驱动收到的数据送进线路规程的read_buf

  67.  out:
  68.     return IRQ_HANDLED;
  69. }

三、串口流控
当A向B发送数据时,B的缓冲如果满了。要向A发送一个FIFO满了的信号,这个就是流控:
分成软件(信号)、硬件(B的串口RTS设置成高电位,A的CTS就知道B已经满了)(又分成非自动、和自动)



阅读(565) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~