LINUX设备驱动之tty及console驱动(二)

    技术2025-09-25  120

    Eric Fang 2010-02-22 -------------------------------------------------------------- 本站分析linux内核源码,版本号为2.6.32.3 转载请注明出处:http://ericfang.cublog.cn/ -------------------------------------------------------------- 接上一篇文章。 接着分析tty_read和tty_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中没有read或tty有错误都会有效性判断失败返回。 第0881行从file->private_data取得tty,这个file->private_data的赋值是在打开设备是进行的。 第0890行tty_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很相似,看到第1070行do_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的其它操作有兴趣的读者请自行分析代码。 接下一篇文章。
    最新回复(0)