Linux串口驱动分析read

转自:http://blog.csdn.net/longwang155069/article/details/42776059


  1. /*串口read函数分析 
  2. * 当应用程序调用read系统调用时,会调用tty_fops中的tty_read 
  3. * 接下来分析tty_read函数 
  4. * 
  5. * 其中最重要的就是ld->ops->read(tty,file,buf,count); 
  6. * 也就是调用线路规程中read函数 
  7. */  
  8.   
  9. static ssize_t tty_read(struct file *file, char __user *buf, size_t count,  
  10.             loff_t *ppos)  
  11. {  
  12.     int i;  
  13.     struct inode *inode = file->f_path.dentry->d_inode;  
  14.     struct tty_struct *tty = file_tty(file);  
  15.     struct tty_ldisc *ld;  
  16.   
  17.     if (tty_paranoia_check(tty, inode, "tty_read"))  
  18.         return -EIO;  
  19.     if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))  
  20.         return -EIO;  
  21.   
  22.     /* We want to wait for the line discipline to sort out in this 
  23.        situation */  
  24.     ld = tty_ldisc_ref_wait(tty);  
  25.     if (ld->ops->read)  
  26.         i = (ld->ops->read)(tty, file, buf, count);  
  27.     else  
  28.         i = -EIO;  
  29.     tty_ldisc_deref(ld);  
  30.     if (i > 0)  
  31.         inode->i_atime = current_fs_time(inode->i_sb);  
  32.     return i;  
  33. }  
  34.   
  35.   
  36. /* 线路规程的ops是: tty_ldisc_N_TTY 
  37. * read =   = n_tty_read, 
  38. * buf代表的是用户空间传下来的buf, 将来需要我们把数据写到buf中去 
  39. */  
  40. static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,unsigned char __user *buf, size_t nr)  
  41. {  
  42.     unsigned char __user *b = buf;  
  43.       
  44.     /*其实n_tty_read就是调用copy_from_read_buf将tty->read_buf中的数据送到用户传下来的buf中。 前面都是一些合法的判断 
  45.     */  
  46.     uncopied = copy_from_read_buf(tty, &b, &nr);  
  47.     uncopied += copy_from_read_buf(tty, &b, &nr);  
  48. }  
  49.   
  50. /*** 其实从copy_from_read_buf中可以很明显的看见*/  
  51. static int copy_from_read_buf(struct tty_struct *tty,unsigned char __user **b,size_t *nr)  
  52. {  
  53.     /*很明显的可以看见copy_to_user函数。数据是从tty->read_buf中拷贝到b中去的。 
  54.     * 那么tty->read中的数据那又是从那里来的? 
  55.     */  
  56.     if (n) {  
  57.         retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);  
  58.         n -= retval;  
  59.         tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);  
  60.         spin_lock_irqsave(&tty->read_lock, flags);  
  61.         tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);  
  62.         tty->read_cnt -= n;  
  63.         /* Turn single EOF into zero-length read */  
  64.         if (L_EXTPROC(tty) && tty->icanon && n == 1) {  
  65.             if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))  
  66.                 n--;  
  67.         }  
  68.         spin_unlock_irqrestore(&tty->read_lock, flags);  
  69.         *b += n;  
  70.         *nr -= n;  
  71.     }  
  72.     return retval;  
  73. }  
  74.   
  75. /*接下来分析tty->read_buf中的数据是从那里来的? 
  76. * 首先: 数据当然是从硬件里read出来的。 
  77. * 那么当我们的串口有数据的话,当然就调用我们以前注册的rx中断函数了。 
  78. */  
  79.   
  80. static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id)  
  81. {  
  82.     struct s3c24xx_uart_port *ourport = dev_id;  
  83.     struct uart_port *port = &ourport->port;  
  84.     struct tty_struct *tty = port->state->port.tty;  
  85.     unsigned int ufcon, ch, flag, ufstat, uerstat;  
  86.     int max_count = 64;  
  87.   
  88.     while (max_count-- > 0) {  
  89.         /*读取UFCON串口配置寄存器*/  
  90.         ufcon = rd_regl(port, S3C2410_UFCON);  
  91.         /*读取 UFSTAT串口状态寄存器。*/  
  92.         ufstat = rd_regl(port, S3C2410_UFSTAT);  
  93.   
  94.         /*根据读出的ufstat判断UFSTAT中rx的fifo是否为0*/  
  95.         if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)  
  96.             break;  
  97.   
  98.         /*读取UERSTAT错误状态寄存器*/  
  99.         uerstat = rd_regl(port, S3C2410_UERSTAT);  
  100.         /*读取URXH寄存器*/  
  101.         ch = rd_regb(port, S3C2410_URXH);  
  102.   
  103.         /*进行流量控制*/  
  104.         if (port->flags & UPF_CONS_FLOW) {  
  105.             int txe = s3c24xx_serial_txempty_nofifo(port);  
  106.   
  107.             if (rx_enabled(port)) {  
  108.                 if (!txe) {  
  109.                     rx_enabled(port) = 0;  
  110.                     continue;  
  111.                 }  
  112.             } else {  
  113.                 if (txe) {  
  114.                     ufcon |= S3C2410_UFCON_RESETRX;  
  115.                     wr_regl(port, S3C2410_UFCON, ufcon);  
  116.                     rx_enabled(port) = 1;  
  117.                     goto out;  
  118.                 }  
  119.                 continue;  
  120.             }  
  121.         }  
  122.   
  123.         /* insert the character into the buffer */  
  124.   
  125.         flag = TTY_NORMAL;  
  126.         port->icount.rx++;  
  127.   
  128.         if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {  
  129.             dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",  
  130.                 ch, uerstat);  
  131.   
  132.             /* check for break */  
  133.             if (uerstat & S3C2410_UERSTAT_BREAK) {  
  134.                 dbg("break!\n");  
  135.                 port->icount.brk++;  
  136.                 if (uart_handle_break(port))  
  137.                     goto ignore_char;  
  138.             }  
  139.   
  140.             if (uerstat & S3C2410_UERSTAT_FRAME)  
  141.                 port->icount.frame++;  
  142.             if (uerstat & S3C2410_UERSTAT_OVERRUN)  
  143.                 port->icount.overrun++;  
  144.   
  145.             uerstat &= port->read_status_mask;  
  146.   
  147.             if (uerstat & S3C2410_UERSTAT_BREAK)  
  148.                 flag = TTY_BREAK;  
  149.             else if (uerstat & S3C2410_UERSTAT_PARITY)  
  150.                 flag = TTY_PARITY;  
  151.             else if (uerstat & (S3C2410_UERSTAT_FRAME |  
  152.                         S3C2410_UERSTAT_OVERRUN))  
  153.                 flag = TTY_FRAME;  
  154.         }  
  155.           
  156.         if (uart_handle_sysrq_char(port, ch))  
  157.             goto ignore_char;  
  158.   
  159.         /*插入ch也就是数据到tty->tty_bufhead中去。 当whiel大循环完后, 整个64字节数据都存放到tty->tty_bufhead中去*/  
  160.         uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,  
  161.                  ch, flag);  
  162.             }  
  163.               
  164.         /*这是才将整个数据送tty->read_buf中去*/  
  165.         tty_flip_buffer_push(tty);  
  166. }  
  167. /* 将串口产生的数据送进tty->buf.tail中去。 */  
  168. static inline int tty_insert_flip_char(struct tty_struct *tty,unsigned char ch, char flag)  
  169. {  
  170.     struct tty_buffer *tb = tty->buf.tail;  
  171.     if (tb && tb->used < tb->size) {  
  172.         tb->flag_buf_ptr[tb->used] = flag;        /*用于存放flag,也就是状态位*/  
  173.         tb->char_buf_ptr[tb->used++] = ch;        /*用于存放真正的数据*/  
  174.         return 1;  
  175.     }  
  176.     return tty_insert_flip_string_flags(tty, &ch, &flag, 1);  
  177. }  
  178.   
  179. static void flush_to_ldisc(struct work_struct *work)  
  180. {  
  181.             char_buf = head->char_buf_ptr + head->read;       /*char_buf用于存放真实数据*/  
  182.             flag_buf = head->flag_buf_ptr + head->read;   /*flag_buf用于存放flag标志*/  
  183.             head->read += count;                                                       
  184.             spin_unlock_irqrestore(&tty->buf.lock, flags);  
  185.             disc->ops->receive_buf(tty, char_buf,         /*调用tty_ldisc_N_TTY中的recive_buf函数*/  
  186.                             flag_buf, count);  
  187. }  
  188.   
  189. static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,char *fp, int count)  
  190. {  
  191.       
  192.     if (tty->real_raw) {  
  193.         spin_lock_irqsave(&tty->read_lock, cpuflags);  
  194.         i = min(N_TTY_BUF_SIZE - tty->read_cnt,          /*判断大小*/  
  195.             N_TTY_BUF_SIZE - tty->read_head);  
  196.         i = min(count, i);  
  197.         memcpy(tty->read_buf + tty->read_head, cp, i);        /*这才是真正的拷贝数据到tty->read_buf中去*/  
  198.         tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1); /*其实read_buf是一个环形缓冲区。 每次写进数据都会调正read_head的位置。 同时改变read_cnt*/  
  199.         tty->read_cnt += i;  
  200.         cp += i;  
  201.         count -= i;  
  202.   
  203.         i = min(N_TTY_BUF_SIZE - tty->read_cnt,  
  204.             N_TTY_BUF_SIZE - tty->read_head);  
  205.         i = min(count, i);  
  206.         memcpy(tty->read_buf + tty->read_head, cp, i);  
  207.         tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);  
  208.         tty->read_cnt += i;  
  209.         spin_unlock_irqrestore(&tty->read_lock, cpuflags);  
  210.     }  
  211. }  

猜你喜欢

转载自blog.csdn.net/lzpdz/article/details/68064160