转自:http://blog.youkuaiyun.com/longwang155069/article/details/42776059
- /*串口read函数分析
- * 当应用程序调用read系统调用时,会调用tty_fops中的tty_read
- * 接下来分析tty_read函数
- *
- * 其中最重要的就是ld->ops->read(tty,file,buf,count);
- * 也就是调用线路规程中read函数
- */
- static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
- {
- int i;
- struct inode *inode = file->f_path.dentry->d_inode;
- struct tty_struct *tty = file_tty(file);
- struct tty_ldisc *ld;
- 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);
- else
- i = -EIO;
- tty_ldisc_deref(ld);
- if (i > 0)
- inode->i_atime = current_fs_time(inode->i_sb);
- return i;
- }
- /* 线路规程的ops是: tty_ldisc_N_TTY
- * read = = n_tty_read,
- * buf代表的是用户空间传下来的buf, 将来需要我们把数据写到buf中去
- */
- 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;
- /*其实n_tty_read就是调用copy_from_read_buf将tty->read_buf中的数据送到用户传下来的buf中。 前面都是一些合法的判断
- */
- uncopied = copy_from_read_buf(tty, &b, &nr);
- uncopied += copy_from_read_buf(tty, &b, &nr);
- }
- /*** 其实从copy_from_read_buf中可以很明显的看见*/
- static int copy_from_read_buf(struct tty_struct *tty,unsigned char __user **b,size_t *nr)
- {
- /*很明显的可以看见copy_to_user函数。数据是从tty->read_buf中拷贝到b中去的。
- * 那么tty->read中的数据那又是从那里来的?
- */
- if (n) {
- retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
- 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;
- /* Turn single EOF into zero-length read */
- if (L_EXTPROC(tty) && tty->icanon && n == 1) {
- if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
- n--;
- }
- spin_unlock_irqrestore(&tty->read_lock, flags);
- *b += n;
- *nr -= n;
- }
- return retval;
- }
- /*接下来分析tty->read_buf中的数据是从那里来的?
- * 首先: 数据当然是从硬件里read出来的。
- * 那么当我们的串口有数据的话,当然就调用我们以前注册的rx中断函数了。
- */
- 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->state->port.tty;
- unsigned int ufcon, ch, flag, ufstat, uerstat;
- int max_count = 64;
- while (max_count-- > 0) {
- /*读取UFCON串口配置寄存器*/
- ufcon = rd_regl(port, S3C2410_UFCON);
- /*读取 UFSTAT串口状态寄存器。*/
- ufstat = rd_regl(port, S3C2410_UFSTAT);
- /*根据读出的ufstat判断UFSTAT中rx的fifo是否为0*/
- if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
- break;
- /*读取UERSTAT错误状态寄存器*/
- uerstat = rd_regl(port, S3C2410_UERSTAT);
- /*读取URXH寄存器*/
- ch = rd_regb(port, S3C2410_URXH);
- /*进行流量控制*/
- if (port->flags & UPF_CONS_FLOW) {
- int txe = s3c24xx_serial_txempty_nofifo(port);
- if (rx_enabled(port)) {
- if (!txe) {
- rx_enabled(port) = 0;
- continue;
- }
- } else {
- if (txe) {
- 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)) {
- 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))
- goto ignore_char;
- /*插入ch也就是数据到tty->tty_bufhead中去。 当whiel大循环完后, 整个64字节数据都存放到tty->tty_bufhead中去*/
- uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
- ch, flag);
- }
- /*这是才将整个数据送tty->read_buf中去*/
- tty_flip_buffer_push(tty);
- }
- /* 将串口产生的数据送进tty->buf.tail中去。 */
- static inline int tty_insert_flip_char(struct tty_struct *tty,unsigned char ch, char flag)
- {
- struct tty_buffer *tb = tty->buf.tail;
- if (tb && tb->used < tb->size) {
- tb->flag_buf_ptr[tb->used] = flag; /*用于存放flag,也就是状态位*/
- tb->char_buf_ptr[tb->used++] = ch; /*用于存放真正的数据*/
- return 1;
- }
- return tty_insert_flip_string_flags(tty, &ch, &flag, 1);
- }
- static void flush_to_ldisc(struct work_struct *work)
- {
- char_buf = head->char_buf_ptr + head->read; /*char_buf用于存放真实数据*/
- flag_buf = head->flag_buf_ptr + head->read; /*flag_buf用于存放flag标志*/
- head->read += count;
- spin_unlock_irqrestore(&tty->buf.lock, flags);
- disc->ops->receive_buf(tty, char_buf, /*调用tty_ldisc_N_TTY中的recive_buf函数*/
- flag_buf, count);
- }
- static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,char *fp, int count)
- {
- if (tty->real_raw) {
- spin_lock_irqsave(&tty->read_lock, cpuflags);
- i = min(N_TTY_BUF_SIZE - tty->read_cnt, /*判断大小*/
- N_TTY_BUF_SIZE - tty->read_head);
- i = min(count, i);
- memcpy(tty->read_buf + tty->read_head, cp, i); /*这才是真正的拷贝数据到tty->read_buf中去*/
- tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1); /*其实read_buf是一个环形缓冲区。 每次写进数据都会调正read_head的位置。 同时改变read_cnt*/
- tty->read_cnt += i;
- cp += i;
- count -= i;
- i = min(N_TTY_BUF_SIZE - tty->read_cnt,
- N_TTY_BUF_SIZE - tty->read_head);
- i = min(count, i);
- memcpy(tty->read_buf + tty->read_head, cp, i);
- tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
- tty->read_cnt += i;
- spin_unlock_irqrestore(&tty->read_lock, cpuflags);
- }
- }