Chinaunix首页 | 论坛 | 博客
  • 博客访问: 119418
  • 博文数量: 15
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 530
  • 用 户 组: 普通用户
  • 注册时间: 2009-02-09 13:11
文章分类
文章存档

2010年(15)

我的朋友

分类: LINUX

2010-02-25 17:02:35

Eric Fang  2010-02-22

--------------------------------------------------------------

本站分析linux内核源码,版本号为2.6.32.3

转载请注明出处:http://ericfang.cublog.cn/

--------------------------------------------------------------

 

接上一篇文章。

接着分析tty_readtty_write函数。

0873       static ssize_t tty_read(struct file *file, char __user *buf, size_t count,

0874                            loff_t *ppos)

0875       {

0876              int i;

0877              struct tty_struct *tty;

0878              struct inode *inode;

0879              struct tty_ldisc *ld;

0880      

0881              tty = (struct tty_struct *)file->private_data;

0882              inode = file->f_path.dentry->d_inode;

0883              if (tty_paranoia_check(tty, inode, "tty_read"))

0884                     return -EIO;

0885              if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))

0886                     return -EIO;

0887      

0888              /* We want to wait for the line discipline to sort out in this

0889                 situation */

0890              ld = tty_ldisc_ref_wait(tty);

0891              if (ld->ops->read)

0892                     i = (ld->ops->read)(tty, file, buf, count);

0893              else

0894                     i = -EIO;

0895              tty_ldisc_deref(ld);

0896              if (i > 0)

0897                     inode->i_atime = current_fs_time(inode->i_sb);

0898              return i;

0899       }

如果tty_driver中没有readtty有错误都会有效性判断失败返回。

0881行从file->private_data取得tty,这个file->private_data的赋值是在打开设备是进行的。

0890tty_ldisc_ref_wait函数如下:

0328       struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)

0329       {

0330              struct tty_ldisc *ld;

0331      

0332              /* wait_event is a macro */

0333              wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);

0334              return ld;

0335       }

0299       static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)

0300       {

0301              unsigned long flags;

0302              struct tty_ldisc *ld;

0303      

0304              spin_lock_irqsave(&tty_ldisc_lock, flags);

0305              ld = NULL;

0306              if (test_bit(TTY_LDISC, &tty->flags))

0307                     ld = get_ldisc(tty->ldisc);

0308              spin_unlock_irqrestore(&tty_ldisc_lock, flags);

0309              return ld;

0310       }

当前进程在tty_ldisc_wait上睡眠,知道tty相应的线路规程存在才被唤醒,并递增ldsic的引用计数。

0891~0894行,如果线路规程的read操作存在则调用它。线路规程的read函数的实现后面在做分析。

tty_read函数分析完了,十几上比较简单,调用了相应线路规程的read函数。

接着看tty_write函数:

1048       static ssize_t tty_write(struct file *file, const char __user *buf,

1049                                                 size_t count, loff_t *ppos)

1050       {

1051              struct tty_struct *tty;

1052              struct inode *inode = file->f_path.dentry->d_inode;

1053              ssize_t ret;

1054              struct tty_ldisc *ld;

1055      

1056              tty = (struct tty_struct *)file->private_data;

1057              if (tty_paranoia_check(tty, inode, "tty_write"))

1058                     return -EIO;

1059              if (!tty || !tty->ops->write ||

1060                     (test_bit(TTY_IO_ERROR, &tty->flags)))

1061                            return -EIO;

1062              /* Short term debug to catch buggy drivers */

1063              if (tty->ops->write_room == NULL)

1064                     printk(KERN_ERR "tty driver %s lacks a write_room method.\n",

1065                            tty->driver->name);

1066              ld = tty_ldisc_ref_wait(tty);

1067              if (!ld->ops->write)

1068                     ret = -EIO;

1069              else

1070                     ret = do_tty_write(ld->ops->write, tty, file, buf, count);

1071              tty_ldisc_deref(ld);

1072              return ret;

1073       }

这个函数结构跟tty_read很相似,看到第1070do_tty_write函数:

0922       static inline ssize_t do_tty_write(

0923              ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),

0924              struct tty_struct *tty,

0925              struct file *file,

0926              const char __user *buf,

0927              size_t count)

0928       {

0929              ssize_t ret, written = 0;

0930              unsigned int chunk;

0931      

0932              ret = tty_write_lock(tty, file->f_flags & O_NDELAY);

0933              if (ret < 0)

0934                     return ret;

0935      

0936              /*

0937              * We chunk up writes into a temporary buffer. This

0938              * simplifies low-level drivers immensely, since they

0939              * don't have locking issues and user mode accesses.

0940              *

0941              * But if TTY_NO_WRITE_SPLIT is set, we should use a

0942              * big chunk-size..

0943              *

0944              * The default chunk-size is 2kB, because the NTTY

0945              * layer has problems with bigger chunks. It will

0946              * claim to be able to handle more characters than

0947              * it actually does.

0948              *

0949              * FIXME: This can probably go away now except that 64K chunks

0950              * are too likely to fail unless switched to vmalloc...

0951              */

0952              chunk = 2048;

0953              if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))

0954                     chunk = 65536;

0955              if (count < chunk)

0956                     chunk = count;

0957      

0958              /* write_buf/write_cnt is protected by the atomic_write_lock mutex */

0959              if (tty->write_cnt < chunk) {

0960                     unsigned char *buf_chunk;

0961      

0962                     if (chunk < 1024)

0963                            chunk = 1024;

0964      

0965                     buf_chunk = kmalloc(chunk, GFP_KERNEL);

0966                     if (!buf_chunk) {

0967                            ret = -ENOMEM;

0968                            goto out;

0969                     }

0970                     kfree(tty->write_buf);

0971                     tty->write_cnt = chunk;

0972                     tty->write_buf = buf_chunk;

0973              }

0974      

0975              /* Do the write .. */

0976              for (;;) {

0977                     size_t size = count;

0978                     if (size > chunk)

0979                            size = chunk;

0980                     ret = -EFAULT;

0981                     if (copy_from_user(tty->write_buf, buf, size))

0982                            break;

0983                     ret = write(tty, file, tty->write_buf, size);

0984                     if (ret <= 0)

0985                            break;

0986                     written += ret;

0987                     buf += ret;

0988                     count -= ret;

0989                     if (!count)

0990                            break;

0991                     ret = -ERESTARTSYS;

0992                     if (signal_pending(current))

0993                            break;

0994                     cond_resched();

0995              }

0996              if (written) {

0997                     struct inode *inode = file->f_path.dentry->d_inode;

0998                     inode->i_mtime = current_fs_time(inode->i_sb);

0999                     ret = written;

1000              }

1001       out:

1002              tty_write_unlock(tty);

1003              return ret;

1004       }

默认没次写2K数据。如果设置了TTY_NO_WRITE_SPLIT则一次写65536的数据。

tty->write_buf是写操作的临时缓存区。即将用户空的数据暂时存放到这里。

tty->write_cnt是临时缓存区的大小。

然后将用户空间的数据copy到临时缓存区,调用规程的write操作完成写操作。

最后再更新设备结点的时间戳。

tty_write函数就分析到这里。

 

tty_fops的其它操作有兴趣的读者请自行分析代码。

 

接下一篇文章。

 

阅读(3439) | 评论(0) | 转发(2) |
0

上一篇:LINUX设备驱动之tty及console驱动(一)

下一篇:没有了

给主人留下些什么吧!~~