现在的位置: 首页 > 综合 > 正文

linux tty core 源码分析(1)

2013年12月09日 ⁄ 综合 ⁄ 共 8228字 ⁄ 字号 评论关闭

本文以linux 2.6.27内核为基础,阅读tty core 源码并作注解,自己接触时间不长,希望与爱好者共同分享,错误之处还望指正。

  linux tty core 是建立在字符设备驱动的基础之上,并为tty类型设备(串口、控制台、虚拟终端)提供一个公用的平台。所以任何一个tty设备驱动的注册都是作为一个字符设备驱动而操作的。下面我们看看代码中是如何处理的:

 

/* 3/2004 jmc: why do these devices exist? */

 

//tty核心默认在内核中实现的字符型tty设备驱动

static struct cdev tty_cdev, console_cdev;
#ifdef CONFIG_UNIX98_PTYS
static struct cdev ptmx_cdev;
#endif
#ifdef CONFIG_VT
static struct cdev vc0_cdev;
#endif

 

/*
 * Ok, now we can initialize the rest of the tty devices and can count
 * on memory allocations, interrupts etc..
 */
static int __init tty_init(void)
{

//在字符设备模型中加入注册tty_cdev驱动并加入/dev/tty这样的设备

 cdev_init(&tty_cdev, &tty_fops);
 if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
     register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
  panic("Couldn't register /dev/tty driver/n");
 device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
         "tty");

 

//在字符设备模型中加入注册console_cdev驱动并加入/dev/console这样的设备

 cdev_init(&console_cdev, &console_fops);
 if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
     register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
  panic("Couldn't register /dev/console driver/n");
 device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
         "console");

 

//在字符设备模型中加入注册ptmx_cdev驱动并加入/dev/ptmx这样的设备

#ifdef CONFIG_UNIX98_PTYS
 cdev_init(&ptmx_cdev, &ptmx_fops);
 if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
     register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
  panic("Couldn't register /dev/ptmx driver/n");
 device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
#endif

 

//在字符设备模型中加入注册vc0_cdev驱动并加入/dev/tty0这样的设备

#ifdef CONFIG_VT
 cdev_init(&vc0_cdev, &console_fops);
 if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
     register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
  panic("Couldn't register /dev/tty0 driver/n");
 device_create_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");

 vty_init(); //这里暂时不做解释
#endif
 return 0;
}

 

//上面是本身加入的,也就是我们系统一般都有的设备,而且这几种设备都是指向其他的设备,在tty_open中我们将看到以后都会指向其

//他具体的设备。对这几种设备大多数人都存在一定的混淆,这里我就自己的理解解释下:

// /dev/console (5,1) 表示系统的控制台

// /dev/tty (5,0) 表示进程的控制终端

// /dev/tty0 (4,0) 表示当前使用的虚拟终端

// 这样的解释也不是很清楚,这得从历史说起,以前计算机还是比较昂贵的时候,一台电脑上一般接有很多键盘与显示器的组合设备用以

//操作计算机这样的组合设备就是所谓的终端,而还存在一种直接和电脑连接键盘和显示器这就是控制台。而现在的应用环境发生了变化,

//一般把能直接显示系统信息的终端称呼为系统控制台,而其他设备则称呼虚拟终端。也就是当前虚拟终端作控制台。

 

 

 

static const struct file_operations tty_fops = {
 .llseek  = no_llseek,
 .read  = tty_read,
 .write  = tty_write,
 .poll  = tty_poll,
 .unlocked_ioctl = tty_ioctl,
 .compat_ioctl = tty_compat_ioctl,
 .open  = tty_open,
 .release = tty_release,
 .fasync  = tty_fasync,
};

#ifdef CONFIG_UNIX98_PTYS
static const struct file_operations ptmx_fops = {
 .llseek  = no_llseek,
 .read  = tty_read,
 .write  = tty_write,
 .poll  = tty_poll,
 .unlocked_ioctl = tty_ioctl,
 .compat_ioctl = tty_compat_ioctl,
 .open  = ptmx_open,
 .release = tty_release,
 .fasync  = tty_fasync,
};
#endif

static const struct file_operations console_fops = {
 .llseek  = no_llseek,
 .read  = tty_read,
 .write  = redirected_tty_write,
 .poll  = tty_poll,
 .unlocked_ioctl = tty_ioctl,
 .compat_ioctl = tty_compat_ioctl,
 .open  = tty_open,
 .release = tty_release,
 .fasync  = tty_fasync,
};

//从上面看几个驱动的操作函数大致相同,只有ptmx_fops的open方法和console_fops的write方法不同其他操作都是相同的所以在其

//他操作上要兼顾各种设备

 

//下面我们介绍下tty_driver结构和tty_struct 结构。tty_driver表示一个具体的tty设备的驱动程序,而tty_struct 表示tty设备在

//具体的分析中介绍其成员。

 

struct tty_driver {
 int magic;  /* magic number for this structure */
 struct kref kref; /* Reference management */
 struct cdev cdev;//可见tty设备驱动是一个字符设备设备驱动
 struct module *owner;
 const char *driver_name;//这里是指驱动程序的名字
 const char *name;//tty设备的命名相关
 int name_base; /* offset of printed name */
 int major;  /* major device number */
 int minor_start; /* start of minor device number */
 int minor_num; /* number of *possible* devices */
 int num;  /* number of devices allocated */
 short type;  /* type of tty driver */
 short subtype; /* subtype of tty driver */
 struct ktermios init_termios; /* Initial termios */
 int flags;  /* tty driver flags */
 struct proc_dir_entry *proc_entry; /* /proc fs entry */
 struct tty_driver *other; /* only used for the PTY driver */

 /*
  * Pointer to the tty data structures
  */
 struct tty_struct **ttys;//驱动操作的具体tty设备
 struct ktermios **termios;
 struct ktermios **termios_locked;
 void *driver_state;

 /*
  * Driver methods
  */

 const struct tty_operations *ops;
 struct list_head tty_drivers; //用于链接tty驱动全局链表
};

本文以linux 2.6.27内核为基础,阅读tty core 源码并作注解,自己接触时间不长,希望与爱好者共同分享,错误之处还望指正。

  linux tty core 是建立在字符设备驱动的基础之上,并为tty类型设备(串口、控制台、虚拟终端)提供一个公用的平台。所以任何一个tty设备驱动的注册都是作为一个字符设备驱动而操作的。下面我们看看代码中是如何处理的:

 

/* 3/2004 jmc: why do these devices exist? */

 

//tty核心默认在内核中实现的字符型tty设备驱动

static struct cdev tty_cdev, console_cdev;
#ifdef CONFIG_UNIX98_PTYS
static struct cdev ptmx_cdev;
#endif
#ifdef CONFIG_VT
static struct cdev vc0_cdev;
#endif

 

/*
 * Ok, now we can initialize the rest of the tty devices and can count
 * on memory allocations, interrupts etc..
 */
static int __init tty_init(void)
{

//在字符设备模型中加入注册tty_cdev驱动并加入/dev/tty这样的设备

 cdev_init(&tty_cdev, &tty_fops);
 if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
     register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
  panic("Couldn't register /dev/tty driver/n");
 device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
         "tty");

 

//在字符设备模型中加入注册console_cdev驱动并加入/dev/console这样的设备

 cdev_init(&console_cdev, &console_fops);
 if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
     register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
  panic("Couldn't register /dev/console driver/n");
 device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
         "console");

 

//在字符设备模型中加入注册ptmx_cdev驱动并加入/dev/ptmx这样的设备

#ifdef CONFIG_UNIX98_PTYS
 cdev_init(&ptmx_cdev, &ptmx_fops);
 if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
     register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
  panic("Couldn't register /dev/ptmx driver/n");
 device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
#endif

 

//在字符设备模型中加入注册vc0_cdev驱动并加入/dev/tty0这样的设备

#ifdef CONFIG_VT
 cdev_init(&vc0_cdev, &console_fops);
 if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
     register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
  panic("Couldn't register /dev/tty0 driver/n");
 device_create_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");

 vty_init(); //这里暂时不做解释
#endif
 return 0;
}

 

//上面是本身加入的,也就是我们系统一般都有的设备,而且这几种设备都是指向其他的设备,在tty_open中我们将看到以后都会指向其

//他具体的设备。对这几种设备大多数人都存在一定的混淆,这里我就自己的理解解释下:

// /dev/console (5,1) 表示系统的控制台

// /dev/tty (5,0) 表示进程的控制终端

// /dev/tty0 (4,0) 表示当前使用的虚拟终端

// 这样的解释也不是很清楚,这得从历史说起,以前计算机还是比较昂贵的时候,一台电脑上一般接有很多键盘与显示器的组合设备用以

//操作计算机这样的组合设备就是所谓的终端,而还存在一种直接和电脑连接键盘和显示器这就是控制台。而现在的应用环境发生了变化,

//一般把能直接显示系统信息的终端称呼为系统控制台,而其他设备则称呼虚拟终端。也就是当前虚拟终端作控制台。

 

 

 

static const struct file_operations tty_fops = {
 .llseek  = no_llseek,
 .read  = tty_read,
 .write  = tty_write,
 .poll  = tty_poll,
 .unlocked_ioctl = tty_ioctl,
 .compat_ioctl = tty_compat_ioctl,
 .open  = tty_open,
 .release = tty_release,
 .fasync  = tty_fasync,
};

#ifdef CONFIG_UNIX98_PTYS
static const struct file_operations ptmx_fops = {
 .llseek  = no_llseek,
 .read  = tty_read,
 .write  = tty_write,
 .poll  = tty_poll,
 .unlocked_ioctl = tty_ioctl,
 .compat_ioctl = tty_compat_ioctl,
 .open  = ptmx_open,
 .release = tty_release,
 .fasync  = tty_fasync,
};
#endif

static const struct file_operations console_fops = {
 .llseek  = no_llseek,
 .read  = tty_read,
 .write  = redirected_tty_write,
 .poll  = tty_poll,
 .unlocked_ioctl = tty_ioctl,
 .compat_ioctl = tty_compat_ioctl,
 .open  = tty_open,
 .release = tty_release,
 .fasync  = tty_fasync,
};

//从上面看几个驱动的操作函数大致相同,只有ptmx_fops的open方法和console_fops的write方法不同其他操作都是相同的所以在其

//他操作上要兼顾各种设备

 

//下面我们介绍下tty_driver结构和tty_struct 结构。tty_driver表示一个具体的tty设备的驱动程序,而tty_struct 表示tty设备在

//具体的分析中介绍其成员。

 

struct tty_driver {
 int magic;  /* magic number for this structure */
 struct kref kref; /* Reference management */
 struct cdev cdev;//可见tty设备驱动是一个字符设备设备驱动
 struct module *owner;
 const char *driver_name;//这里是指驱动程序的名字
 const char *name;//tty设备的命名相关
 int name_base; /* offset of printed name */
 int major;  /* major device number */
 int minor_start; /* start of minor device number */
 int minor_num; /* number of *possible* devices */
 int num;  /* number of devices allocated */
 short type;  /* type of tty driver */
 short subtype; /* subtype of tty driver */
 struct ktermios init_termios; /* Initial termios */
 int flags;  /* tty driver flags */
 struct proc_dir_entry *proc_entry; /* /proc fs entry */
 struct tty_driver *other; /* only used for the PTY driver */

 /*
  * Pointer to the tty data structures
  */
 struct tty_struct **ttys;//驱动操作的具体tty设备
 struct ktermios **termios;
 struct ktermios **termios_locked;
 void *driver_state;

 /*
  * Driver methods
  */

 const struct tty_operations *ops;
 struct list_head tty_drivers; //用于链接tty驱动全局链表
};

抱歉!评论已关闭.