一. tty结构体

1.tty_driver

  1. struct tty_driver {  
  2.     int magic;  
  3.     struct kref kref;   //参考计数  
  4.     struct cdev cdev;   //字符设备  
  5.     struct module   *owner; //模块所有者  
  6.     const char  *driver_name;   //驱动名  
  7.     const char  *name;  //设备名  
  8.     int name_base;  
  9.     int major;  //主设备号  
  10.     int minor_start;    //起始次设备号  
  11.     int minor_num;  //设备个数  
  12.     int num;    //分配了的tty设备个数  
  13.     short   type;   //tty设备的类型  
  14.     short   subtype;    //tty设备子类型  
  15.     struct ktermios init_termios;   //初始化的ktermios  
  16.     int flags;  //tty驱动标志  
  17.     struct proc_dir_entry *proc_entry;  //procfs入口  
  18.     struct tty_driver *other;  
  19.     struct tty_struct **ttys;  
  20.     struct ktermios **termios;  
  21.     struct ktermios **termios_locked;  
  22.     void *driver_state;  
  23.     const struct tty_operations *ops;   //操作函数集  
  24.     struct list_head tty_drivers;   //驱动链表  
  25. };  

1.1 tty->flag

  1. #define TTY_DRIVER_INSTALLED    0x0001  
  2. #define TTY_DRIVER_RESET_TERMIOS    0x0002  
  3. #define TTY_DRIVER_REAL_RAW     0x0004  
  4. #define TTY_DRIVER_DYNAMIC_DEV  0x0008  
  5. #define TTY_DRIVER_DEVPTS_MEM   0x0010  
  6. #define TTY_DRIVER_HARDWARE_BREAK   0x0020  

1.2 tty->type tty设备类型

  1. #define TTY_DRIVER_TYPE_SYSTEM  0x0001  
  2. #define TTY_DRIVER_TYPE_CONSOLE 0x0002  
  3. #define TTY_DRIVER_TYPE_SERIAL  0x0003  
  4. #define TTY_DRIVER_TYPE_PTY     0x0004  
  5. #define TTY_DRIVER_TYPE_SCC     0x0005  /* scc driver */  
  6. #define TTY_DRIVER_TYPE_SYSCONS 0x0006  

2.ktermios结构体

  1. struct ktermios {  
  2.     tcflag_t c_iflag;   /* input mode flags */  //输入模式标志  
  3.     tcflag_t c_oflag;   /* output mode flags */ //输出模式标志  
  4.     tcflag_t c_cflag;   /* control mode flags */    //控制模式标志  
  5.     tcflag_t c_lflag;   /* local mode flags */  //本地模式标志  
  6.     cc_t c_line;    /* line discipline */   //线路规程类型  
  7.     cc_t c_cc[NCCS];    /* control characters */    //控制字符  
  8.     speed_t c_ispeed;   /* input speed */       //输入速度  
  9.     speed_t c_ospeed;   /* output speed */      //输出速度  
  10. };  

3.tty_struct

  1. struct tty_struct {  
  2.     int magic;  //魔数  
  3.     struct kref kref;   //参考计数  
  4.     struct device *dev; //设备文件  
  5.     struct tty_driver *driver;  //tty驱动  
  6.     const struct tty_operations *ops;   //tty操作函数集  
  7.     int index;    
  8.     struct mutex ldisc_mutex;  
  9.     struct tty_ldisc *ldisc;    //线路规程  
  10.     struct mutex termios_mutex;  
  11.     spinlock_t ctrl_lock;  
  12.     struct ktermios *termios, *termios_locked;  
  13.     struct termiox *termiox;  
  14.     char name[64];  //名字  
  15.     struct pid *pgrp;  
  16.     struct pid *session;  
  17.     unsigned long flags;  
  18.     int count;  
  19.     struct winsize winsize;  
  20.     unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;  
  21.     unsigned char low_latency:1, warned:1;  
  22.     unsigned char ctrl_status;  
  23.     unsigned int receive_room;  
  24.     struct tty_struct *link;  
  25.     struct fasync_struct *fasync;  
  26.     struct tty_bufhead buf;  
  27.     int alt_speed;  
  28.     wait_queue_head_t write_wait;  
  29.     wait_queue_head_t read_wait;  
  30.     struct work_struct hangup_work;  
  31.     void *disc_data;  
  32.     void *driver_data;  
  33.     struct list_head tty_files;  
  34. #define N_TTY_BUF_SIZE 4096  
  35.     unsigned int column;  
  36.     unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;  
  37.     unsigned char closing:1;  
  38.     unsigned char echo_overrun:1;  
  39.     unsigned short minimum_to_wake;  
  40.     unsigned long overrun_time;  
  41.     int num_overrun;  
  42.     unsigned long process_char_map[256/(8*sizeof(unsigned long))];  
  43.     char *read_buf;  
  44.     int read_head;  
  45.     int read_tail;  
  46.     int read_cnt;  
  47.     unsigned long read_flags[N_TTY_BUF_SIZE/(8*sizeof(unsigned long))];  
  48.     unsigned char *echo_buf;  
  49.     unsigned int echo_pos;  
  50.     unsigned int echo_cnt;  
  51.     int canon_data;  
  52.     unsigned long canon_head;  
  53.     unsigned int canon_column;  
  54.     struct mutex atomic_read_lock;  
  55.     struct mutex atomic_write_lock;  
  56.     struct mutex output_lock;  
  57.     struct mutex echo_lock;  
  58.     unsigned char *write_buf;  
  59.     int write_cnt;  
  60.     spinlock_t read_lock;  
  61.     struct work_struct SAK_work;  
  62.     struct tty_port *port;  
  63. };  

4.tty_ldisc线路规程

  1. struct tty_ldisc {  
  2.     struct tty_ldisc_ops *ops;  
  3.     atomic_t users;  
  4. };  

4.1 线路规程操作函数集

  1. struct tty_ldisc_ops {  
  2.     int magic;  
  3.     char    *name;  
  4.     int num;  
  5.     int flags;  
  6.     int (*open)(struct tty_struct *);  
  7.     void    (*close)(struct tty_struct *);  
  8.     void    (*flush_buffer)(struct tty_struct *tty);  
  9.     ssize_t (*chars_in_buffer)(struct tty_struct *tty);  
  10.     ssize_t (*read)(struct tty_struct * tty, struct file * file,unsigned char __user * buf, size_t nr);  
  11.     ssize_t (*write)(struct tty_struct * tty, struct file * file,const unsigned char * buf, size_t nr);   
  12.     int (*ioctl)(struct tty_struct * tty, struct file * file,unsigned int cmd, unsigned long arg);  
  13.     long    (*compat_ioctl)(struct tty_struct * tty, struct file * file,unsigned int cmd, unsigned long arg);  
  14.     void    (*set_termios)(struct tty_struct *tty, struct ktermios * old);  
  15.     unsigned int (*poll)(struct tty_struct *, struct file *,struct poll_table_struct *);  
  16.     int (*hangup)(struct tty_struct *tty);  
  17.     void    (*receive_buf)(struct tty_struct *, const unsigned char *cp,char *fp, int count);  
  18.     void    (*write_wakeup)(struct tty_struct *);  
  19.     void    (*dcd_change)(struct tty_struct *, unsigned int,struct timespec *);  
  20.     struct  module *owner;  
  21.     int refcount;  
  22. };  


二.系统初始化

设备类初始化

  1. static int __init tty_class_init(void)  
  2. {  
  3.     tty_class = class_create(THIS_MODULE, "tty");   //创建tty类  
  4.     if (IS_ERR(tty_class))  
  5.         return PTR_ERR(tty_class);  
  6.     tty_class->devnode = tty_devnode;    //指定tty设备节点  
  7.     return 0;  
  8. }  

字符设备初始化

  1. int __init tty_init(void)  
  2. {  
  3.     cdev_init(&tty_cdev, &tty_fops);    //初始化tty字符设备  
  4.     if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||   //添加tty字符设备  
  5.         register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)   //注册/dev/tty字符设备  
  6.         panic("Couldn't register /dev/tty driver\n");  
  7.     device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,"tty"); //注册tty设备  
  8.     cdev_init(&console_cdev, &console_fops);    //初始化console字符设备  
  9.     if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||   //添加console字符设备  
  10.         register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)   //注册/dev/console设备  
  11.         panic("Couldn't register /dev/console driver\n");  
  12.     device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,"console"); //创建console设备  
  13. #ifdef CONFIG_VT  
  14.     vty_init(&console_fops);  
  15. #endif  
  16.     return 0;  
  17. }  

虚拟终端/dev/tty0初始化vty_init

  1. int __init vty_init(const struct file_operations *console_fops)  
  2. {  
  3.     cdev_init(&vc0_cdev, console_fops);  
  4.     if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)  
  5.         panic("Couldn't register /dev/tty0 driver\n");  
  6.     device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");  //创建/dev/tty0 (4,0)  
  7.     vcs_init();  
  8.     console_driver = alloc_tty_driver(MAX_NR_CONSOLES);  
  9.     if (!console_driver)  
  10.         panic("Couldn't allocate console driver\n");  
  11.     console_driver->owner = THIS_MODULE;  
  12.     console_driver->name = "tty";  
  13.     console_driver->name_base = 1;  
  14.     console_driver->major = TTY_MAJOR;  
  15.     console_driver->minor_start = 1;  
  16.     console_driver->type = TTY_DRIVER_TYPE_CONSOLE;  
  17.     console_driver->init_termios = tty_std_termios;  
  18.     if (default_utf8)  
  19.         console_driver->init_termios.c_iflag |= IUTF8;  
  20.     console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;  
  21.     tty_set_operations(console_driver, &con_ops);  
  22.     if (tty_register_driver(console_driver))  
  23.         panic("Couldn't register console driver\n");  
  24.     kbd_init();  
  25.     console_map_init();  
  26. #ifdef CONFIG_MDA_CONSOLE  
  27.     mda_console_init();  
  28. #endif  
  29.     return 0;  
  30. }  


 

三.tty初始化步骤

1.分配tty结构体

  1. struct tty_driver *alloc_tty_driver(int lines)  
  2. {  
  3.     struct tty_driver *driver;  
  4.     driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);    //分配内存  
  5.     if (driver) {  
  6.         kref_init(&driver->kref);    //引用计数+1  
  7.         driver->magic = TTY_DRIVER_MAGIC;    //设置魔数0x5402  
  8.         driver->num = lines; //设置tty line个数  
  9.     }  
  10.     return driver;  
  11. }  


2.填充tty结构体成员

3.注册tty设备驱动

  1. int tty_register_driver(struct tty_driver *driver)  
  2. {  
  3.     int error;  
  4.     int i;  
  5.     dev_t dev;  
  6.     void **p = NULL;  
  7.     struct device *d;  
  8.   
  9.     if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {  
  10.         p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);  
  11.         if (!p)  
  12.             return -ENOMEM;  
  13.     }  
  14.     if (!driver->major) {    //指定了主设备号  
  15.         error = alloc_chrdev_region(&dev, driver->minor_start,driver->num, driver->name);  //分配多个设备号  
  16.         if (!error) {  
  17.             driver->major = MAJOR(dev);  //主设备号  
  18.             driver->minor_start = MINOR(dev);    //次设备号  
  19.         }  
  20.     } else {  
  21.         dev = MKDEV(driver->major, driver->minor_start);  //获取第一个设备号  
  22.         error = register_chrdev_region(dev, driver->num, driver->name);   //分配多个设备号     
  23.     }  
  24.     if (error < 0) {  
  25.         kfree(p);  
  26.         return error;  
  27.     }  
  28.     if (p) {  
  29.         driver->ttys = (struct tty_struct **)p;  //tty_struct  
  30.         driver->termios = (struct ktermios **)(p + driver->num);  //ktermios  
  31. k   } else {  
  32.         driver->ttys = NULL;  
  33.         driver->termios = NULL;  
  34.     }  
  35.   
  36.     cdev_init(&driver->cdev, &tty_fops); //初始化字符设备  
  37.     driver->cdev.owner = driver->owner;   //设置模块所有者  
  38.     error = cdev_add(&driver->cdev, dev, driver->num);    //添加字符设备  
  39.     if (error) {  
  40.         unregister_chrdev_region(dev, driver->num);  
  41.         driver->ttys = NULL;  
  42.         driver->termios = NULL;  
  43.         kfree(p);  
  44.         return error;  
  45.     }  
  46.   
  47.     mutex_lock(&tty_mutex);  
  48.     list_add(&driver->tty_drivers, &tty_drivers);        //添加到全局tty_drivers链表  
  49.     mutex_unlock(&tty_mutex);  
  50.   
  51.     if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) { //标志动态创建设备标志  
  52.         for (i = 0; i < driver->num; i++) {  
  53.             d = tty_register_device(driver, i, NULL);   //添加tty设备文件/dev/ttyXX  
  54.             if (IS_ERR(d)) {  
  55.                 error = PTR_ERR(d);  
  56.                 goto err;  
  57.             }  
  58.         }  
  59.     }  
  60.     proc_tty_register_driver(driver);   //设置tty在/proc下的接口  
  61.     driver->flags |= TTY_DRIVER_INSTALLED;  
  62.     return 0;  
  63.   
  64. err:  
  65.     for (i--; i >= 0; i--)  
  66.         tty_unregister_device(driver, i);  
  67.   
  68.     mutex_lock(&tty_mutex);  
  69.     list_del(&driver->tty_drivers);  
  70.     mutex_unlock(&tty_mutex);  
  71.   
  72.     unregister_chrdev_region(dev, driver->num);  
  73.     driver->ttys = NULL;  
  74.     driver->termios = NULL;  
  75.     kfree(p);  
  76.     return error;  
  77. }  

4.创建tty设备文件/dev/ttyXXX

  1. struct device *tty_register_device(struct tty_driver *driver, unsigned index,struct device *device)  
  2. {  
  3.     char name[64];  
  4.     dev_t dev = MKDEV(driver->major, driver->minor_start) + index;    //获取设备号  
  5.     if (index >= driver->num) {  
  6.         printk(KERN_ERR "Attempt to register invalid tty line number (%d).\n", index);  
  7.         return ERR_PTR(-EINVAL);  
  8.     }  
  9.     if (driver->type == TTY_DRIVER_TYPE_PTY) //伪终端  
  10.         pty_line_name(driver, index, name);  
  11.     else                    //"/dev/ttyXXX"  
  12.         tty_line_name(driver, index, name);  
  13.     return device_create(tty_class, device, dev, NULL, name);   //创建设备文件  
  14. }  

5.tty设备文件捆绑的操作函数集tty_fops

  1. static const struct file_operations tty_fops = {  
  2.     .llseek     = no_llseek,  
  3.     .read       = tty_read,  
  4.     .write      = tty_write,  
  5.     .poll       = tty_poll,  
  6.     .unlocked_ioctl = tty_ioctl,  
  7.     .compat_ioctl   = tty_compat_ioctl,  
  8.     .open       = tty_open,  
  9.     .release        = tty_release,  
  10.     .fasync     = tty_fasync,  
  11. };  


四. tty的操作

当打开/dev/ttyXX的时候会调用tty_open函数

tty_open操作

  1. static int tty_open(struct inode *inode, struct file *filp)  
  2. {  
  3.     struct tty_struct *tty = NULL;  
  4.     int noctty, retval;  
  5.     struct tty_driver *driver;  
  6.     int index;  
  7.     dev_t device = inode->i_rdev;    //通过i节点获取设备号  
  8.     unsigned saved_flags = filp->f_flags;  
  9.     nonseekable_open(inode, filp);  //设置打开关联文件的模式  
  10. retry_open:  
  11.     noctty = filp->f_flags & O_NOCTTY;   //设置O_NOCTTY标志  
  12.     index  = -1;  
  13.     retval = 0;  
  14.     mutex_lock(&tty_mutex);  
  15.     tty_lock();  
  16.     if (device == MKDEV(TTYAUX_MAJOR, 0)) { //打开的设备是/dev/tty (5,0)  
  17.         tty = get_current_tty();    //取当前进程tty_struct  
  18.         if (!tty) {  
  19.             tty_unlock();  
  20.             mutex_unlock(&tty_mutex);  
  21.             return -ENXIO;  
  22.         }  
  23.         driver = tty_driver_kref_get(tty->driver);   //获取tty_driver  
  24.         index = tty->index;  
  25.         filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */  
  26.         tty_kref_put(tty);      //引用计数  
  27.         goto got_driver;  
  28.     }  
  29. #ifdef CONFIG_VT    //虚拟终端设备 /dev/tty0  
  30.     if (device == MKDEV(TTY_MAJOR, 0)) {    //(4,0)  
  31.         extern struct tty_driver *console_driver;  
  32.         driver = tty_driver_kref_get(console_driver);   //获取tty_struct  
  33.         index = fg_console;  
  34.         noctty = 1;  
  35.         goto got_driver;  
  36.     }  
  37. #endif  
  38.     if (device == MKDEV(TTYAUX_MAJOR, 1)) { //打开的是/dev/console (5,1)  
  39.         struct tty_driver *console_driver = console_device(&index); //获取console对应的tty_driver  
  40.         if (console_driver) {  
  41.             driver = tty_driver_kref_get(console_driver);   //获取tty_struct  
  42.             if (driver) {  
  43.                 filp->f_flags |= O_NONBLOCK;  
  44.                 noctty = 1;  
  45.                 goto got_driver;  
  46.             }  
  47.         }  
  48.         tty_unlock();  
  49.         mutex_unlock(&tty_mutex);  
  50.         return -ENODEV;  
  51.     }  
  52.     driver = get_tty_driver(device, &index);    //获取tty_driver,设置次设备号(索引值) 非特殊的tty  
  53.     if (!driver) {  
  54.         tty_unlock();  
  55.         mutex_unlock(&tty_mutex);  
  56.         return -ENODEV;  
  57.     }  
  58. got_driver:  
  59.     if (!tty) {  
  60.         tty = tty_driver_lookup_tty(driver, inode, index);  //获取tty_drivver的tty_struct  
  61.         if (IS_ERR(tty)) {  
  62.             tty_unlock();  
  63.             mutex_unlock(&tty_mutex);  
  64.             return PTR_ERR(tty);  
  65.         }  
  66.     }  
  67.     if (tty) {  //若tty_struct不为空  
  68.         retval = tty_reopen(tty);  
  69.         if (retval)  
  70.             tty = ERR_PTR(retval);  
  71.     } else  //若tty_struct为空  
  72.         tty = tty_init_dev(driver, index, 0);   //调用tty_init_dev函数(下面分析)  
  73.     mutex_unlock(&tty_mutex);  
  74.     tty_driver_kref_put(driver);    //增加引用计数  
  75.     if (IS_ERR(tty)) {  
  76.         tty_unlock();  
  77.         return PTR_ERR(tty);  
  78.     }  
  79.     retval = tty_add_file(tty, filp);  
  80.     if (retval) {  
  81.         tty_unlock();  
  82.         return retval;  
  83.     }  
  84.     check_tty_count(tty, "tty_open");  
  85.     if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER)  
  86.         noctty = 1;  
  87. #ifdef TTY_DEBUG_HANGUP  
  88.     printk(KERN_DEBUG "opening %s...", tty->name);  
  89. #endif  
  90.     if (!retval) {  
  91.         if (tty->ops->open)   //若tty_struct存在open方法  
  92.             retval = tty->ops->open(tty, filp);   //则调用其open方法  
  93.         else  
  94.             retval = -ENODEV;  
  95.     }  
  96.     filp->f_flags = saved_flags;  
  97.     if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&!capable(CAP_SYS_ADMIN))  
  98.         retval = -EBUSY;  
  99.     if (retval) {  
  100. #ifdef TTY_DEBUG_HANGUP  
  101.         printk(KERN_DEBUG "error %d in opening %s...", retval,tty->name);  
  102. #endif  
  103.         tty_unlock(); /* need to call tty_release without BTM */  
  104.         tty_release(inode, filp);  
  105.         if (retval != -ERESTARTSYS)  
  106.             return retval  
  107.         if (signal_pending(current))  
  108.             return retval;  
  109.         schedule();  
  110.         tty_lock();  
  111.         if (filp->f_op == &hung_up_tty_fops)  
  112.             filp->f_op = &tty_fops;  
  113.         tty_unlock();  
  114.         goto retry_open;  
  115.     }  
  116.     tty_unlock();  
  117.     mutex_lock(&tty_mutex);  
  118.     tty_lock();  
  119.     spin_lock_irq(¤t->sighand->siglock);  
  120.     if (!noctty && current->signal->leader &&!current->signal->tty && tty->session == NULL)  
  121.         __proc_set_tty(current, tty);  
  122.     spin_unlock_irq(¤t->sighand->siglock);  
  123.     tty_unlock();  
  124.     mutex_unlock(&tty_mutex);  
  125.     return 0;  
  126. }  

tty_init_dev函数

  1. struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,int first_ok)  
  2. {  
  3.     struct tty_struct *tty;  
  4.     int retval;  
  5.   
  6.     if (driver->subtype == PTY_TYPE_MASTER &&(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {  
  7.         return ERR_PTR(-EIO);  
  8.     }  
  9.     if (!try_module_get(driver->owner))  
  10.         return ERR_PTR(-ENODEV);  
  11.   
  12.     tty = alloc_tty_struct();   //分配tty_struct  
  13.     if (!tty)  
  14.         goto fail_no_mem;  
  15.     initialize_tty_struct(tty, driver, idx);    //初始化tty_struct  
  16.   
  17.     retval = tty_driver_install_tty(driver, tty);   //调用tty_driver的install方法,并初始化termios  
  18.     if (retval < 0) {  
  19.         free_tty_struct(tty);  
  20.         module_put(driver->owner);  
  21.         return ERR_PTR(retval);  
  22.     }  
  23.   
  24.     retval = tty_ldisc_setup(tty, tty->link);    //调用线路规程的open方法,及线路规程link的open方法  
  25.     if (retval)  
  26.         goto release_mem_out;  
  27.     return tty;  
  28.   
  29. fail_no_mem:  
  30.     module_put(driver->owner);  
  31.     return ERR_PTR(-ENOMEM);  
  32.   
  33. release_mem_out:  
  34.     if (printk_ratelimit())  
  35.         printk(KERN_INFO "tty_init_dev: ldisc open failed,clearing slot %d\n", idx);  
  36.     release_tty(tty, idx);  
  37.     return ERR_PTR(retval);  
  38. }  

tty_init_dev>>>initialize_tty_struct

  1. void initialize_tty_struct(struct tty_struct *tty,struct tty_driver *driver, int idx)  
  2. {  
  3.     memset(tty, 0, sizeof(struct tty_struct));  //初始化tty_struct  
  4.     kref_init(&tty->kref);  
  5.     tty->magic = TTY_MAGIC;  //魔数  
  6.     tty_ldisc_init(tty);    //初始化线路规程  
  7.     tty->session = NULL;  
  8.     tty->pgrp = NULL;  
  9.     tty->overrun_time = jiffies;  
  10.     tty->buf.head = tty->buf.tail = NULL;  
  11.     tty_buffer_init(tty);  
  12.     mutex_init(&tty->termios_mutex);  
  13.     mutex_init(&tty->ldisc_mutex);  
  14.     init_waitqueue_head(&tty->write_wait);   //初始化写等待队列头  
  15.     init_waitqueue_head(&tty->read_wait);    //初始化读等待队列头  
  16.     INIT_WORK(&tty->hangup_work, do_tty_hangup);  
  17.     mutex_init(&tty->atomic_read_lock);  
  18.     mutex_init(&tty->atomic_write_lock);  
  19.     mutex_init(&tty->output_lock);  
  20.     mutex_init(&tty->echo_lock);  
  21.     spin_lock_init(&tty->read_lock);  
  22.     spin_lock_init(&tty->ctrl_lock);  
  23.     INIT_LIST_HEAD(&tty->tty_files);  
  24.     INIT_WORK(&tty->SAK_work, do_SAK_work);  
  25.   
  26.     tty->driver = driver;    //tty_struct->driver=tty_driver 捆绑tty_struct和tty_driver  
  27.     tty->ops = driver->ops;   //tty_strcut的操作函数集=tty_driver的操作函数集  
  28.     tty->index = idx;    //设置索引值  
  29.     tty_line_name(driver, idx, tty->name);  
  30.     tty->dev = tty_get_device(tty);  //设置tty_struct的设备文件  
  31. }  

tty_init_dev>>>initialize_tty_struct>>>tty_ldisc_init

  1. void tty_ldisc_init(struct tty_struct *tty)  
  2. {  
  3.     struct tty_ldisc *ld = tty_ldisc_get(N_TTY);    //获取线路规程数组tty_ldiscs[N_TTY]项  
  4.     if (IS_ERR(ld))  
  5.         panic("n_tty: init_tty");  
  6.     tty_ldisc_assign(tty, ld);  //设置线路规程  
  7. }  

在start_kernel-->console_init-->tty_ldisc_begin-->tty_register_ldisc将tty_ldiscs[N_TTY]=tty_ldisc_N_TTY

tty_driver_install_tty

  1. static int tty_driver_install_tty(struct tty_driver *driver,struct tty_struct *tty)  
  2. {  
  3.     int idx = tty->index;  
  4.     int ret;  
  5.   
  6.     if (driver->ops->install) {   //tty驱动操作函数集存在install方法  
  7.         ret = driver->ops->install(driver, tty);  //则调用install方法  
  8.         return ret;  
  9.     }  
  10.   
  11.     if (tty_init_termios(tty) == 0) {   //初始化termios  
  12.         tty_driver_kref_get(driver);  
  13.         tty->count++;  
  14.         driver->ttys[idx] = tty;  
  15.         return 0;  
  16.     }  
  17.     return -ENOMEM;  
  18. }  

tty_driver_install_tty>>>tty_init_termios

  1. int tty_init_termios(struct tty_struct *tty)  
  2. {  
  3.     struct ktermios *tp;  
  4.     int idx = tty->index;  
  5.   
  6.     tp = tty->driver->termios[idx];   //获取termios  
  7.     if (tp == NULL) {  
  8.         tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);  
  9.         if (tp == NULL)  
  10.             return -ENOMEM;  
  11.         memcpy(tp, &tty->driver->init_termios,sizeof(struct ktermios));  
  12.         tty->driver->termios[idx] = tp;  
  13.     }  
  14.     tty->termios = tp;  
  15.     tty->termios_locked = tp + 1;  
  16.   
  17.     /* Compatibility until drivers always set this */  
  18.     tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);    //设置接收波特率  
  19.     tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);  //设置波特率  
  20.     return 0;  
  21. }  
  22. EXPORT_SYMBOL_GPL(tty_init_termios);  

tty_ldisc_setup

  1. int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)  
  2. {  
  3.     struct tty_ldisc *ld = tty->ldisc;  
  4.     int retval;  
  5.     retval = tty_ldisc_open(tty, ld);   //调用tty_struct的open方法  
  6.     if (retval)  
  7.         return retval;  
  8.     if (o_tty) {  
  9.         retval = tty_ldisc_open(o_tty, o_tty->ldisc);    //调用tty_struct->link的open方法  
  10.         if (retval) {  
  11.             tty_ldisc_close(tty, ld);  
  12.             return retval;  
  13.         }  
  14.         tty_ldisc_enable(o_tty);    //使能tty_struct->kink  
  15.     }  
  16.     tty_ldisc_enable(tty);  //使能tty_struct  
  17.     return 0;  
  18. }  

 

tty_read操作

  1. static ssize_t tty_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)  
  2. {  
  3.     int i;  
  4.     struct inode *inode = file->f_path.dentry->d_inode;  
  5.     struct tty_struct *tty = file_tty(file);    //获取tty_strcut  
  6.     struct tty_ldisc *ld;  
  7.   
  8.     if (tty_paranoia_check(tty, inode, "tty_read"))  
  9.         return -EIO;  
  10.     if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))  
  11.         return -EIO;  
  12.   
  13.     ld = tty_ldisc_ref_wait(tty);   //获取线路规程  
  14.     if (ld->ops->read)        //线路规程存在读方法  
  15.         i = (ld->ops->read)(tty, file, buf, count);   //调用其读方法  
  16.     else  
  17.         i = -EIO;  
  18.     tty_ldisc_deref(ld);    //引用计数  
  19.     if (i > 0)  
  20.         inode->i_atime = current_fs_time(inode->i_sb);  
  21.     return i;  
  22. }  

 

tty_write操作

  1. static ssize_t tty_write(struct file *file, const char __user *buf,size_t count, loff_t *ppos)  
  2. {  
  3.     struct inode *inode = file->f_path.dentry->d_inode;  
  4.     struct tty_struct *tty = file_tty(file);    //获取tty_struct  
  5.     struct tty_ldisc *ld;  
  6.     ssize_t ret;  
  7.   
  8.     if (tty_paranoia_check(tty, inode, "tty_write"))  
  9.         return -EIO;  
  10.     if (!tty || !tty->ops->write ||(test_bit(TTY_IO_ERROR, &tty->flags)))  
  11.             return -EIO;  
  12.     /* Short term debug to catch buggy drivers */  
  13.     if (tty->ops->write_room == NULL)  
  14.         printk(KERN_ERR "tty driver %s lacks a write_room method.\n",tty->driver->name);  
  15.     ld = tty_ldisc_ref_wait(tty);  
  16.     if (!ld->ops->write)  //线路规程存在写方法  
  17.         ret = -EIO;  
  18.     else  
  19.         ret = do_tty_write(ld->ops->write, tty, file, buf, count);    //调用线路规程写方法  
  20.     tty_ldisc_deref(ld);  
  21.     return ret;  
  22. }  

do_tty_write函数

do_tty_write(ld->ops->write,

                       tty, file, buf, count);

这个函数第一个参数是调用线路规程的写方法,写方法函数的参数是后面四个参数

该写方法将数据写入tty_struct相关的file里

  1. static inline ssize_t do_tty_write(ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),  
  2.             struct tty_struct *tty,struct file *file,const char __user *buf,size_t count)  
  3. {  
  4.     ssize_t ret, written = 0;  
  5.     unsigned int chunk;  
  6.   
  7.     ret = tty_write_lock(tty, file->f_flags & O_NDELAY);  
  8.     if (ret < 0)  
  9.         return ret;  
  10.     chunk = 2048;  
  11.     if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))  
  12.         chunk = 65536;  
  13.     if (count < chunk)  
  14.         chunk = count;  
  15.   
  16.     /* write_buf/write_cnt is protected by the atomic_write_lock mutex */  
  17.     if (tty->write_cnt < chunk) {  
  18.         unsigned char *buf_chunk;  
  19.   
  20.         if (chunk < 1024)  
  21.             chunk = 1024;  
  22.   
  23.         buf_chunk = kmalloc(chunk, GFP_KERNEL);  
  24.         if (!buf_chunk) {  
  25.             ret = -ENOMEM;  
  26.             goto out;  
  27.         }  
  28.         kfree(tty->write_buf);  
  29.         tty->write_cnt = chunk;  
  30.         tty->write_buf = buf_chunk;  
  31.     }  
  32.   
  33.     /* Do the write .. */  
  34.     for (;;) {  
  35.         size_t size = count;  
  36.         if (size > chunk)  
  37.             size = chunk;  
  38.         ret = -EFAULT;  
  39.         if (copy_from_user(tty->write_buf, buf, size))  
  40.             break;  
  41.         ret = write(tty, file, tty->write_buf, size);  
  42.         if (ret <= 0)  
  43.             break;  
  44.         written += ret;  
  45.         buf += ret;  
  46.         count -= ret;  
  47.         if (!count)  
  48.             break;  
  49.         ret = -ERESTARTSYS;  
  50.         if (signal_pending(current))  
  51.             break;  
  52.         cond_resched();  
  53.     }  
  54.     if (written) {  
  55.         struct inode *inode = file->f_path.dentry->d_inode;  
  56.         inode->i_mtime = current_fs_time(inode->i_sb);  
  57.         ret = written;  
  58.     }  
  59. out:  
  60.     tty_write_unlock(tty);  
  61.     return ret;  
  62. }  

五.线路规程操作

tty_driver的open,read,write最终都会调用线路规程的对应操作方法

线路规程默认函数集

  1. struct tty_ldisc_ops tty_ldisc_N_TTY = {  
  2.     .magic           = TTY_LDISC_MAGIC,  
  3.     .name            = "n_tty",  
  4.     .open            = n_tty_open,  
  5.     .close           = n_tty_close,  
  6.     .flush_buffer    = n_tty_flush_buffer,  
  7.     .chars_in_buffer = n_tty_chars_in_buffer,  
  8.     .read            = n_tty_read,  
  9.     .write           = n_tty_write,  
  10.     .ioctl           = n_tty_ioctl,  
  11.     .set_termios     = n_tty_set_termios,  
  12.     .poll            = n_tty_poll,  
  13.     .receive_buf     = n_tty_receive_buf,  
  14.     .write_wakeup    = n_tty_write_wakeup  
  15. };  

1.open方法

  1. static int n_tty_open(struct tty_struct *tty)  
  2. {  
  3.     if (!tty)  
  4.         return -EINVAL;  
  5.   
  6.     if (!tty->read_buf) {  
  7.         tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);  
  8.         if (!tty->read_buf)  
  9.             return -ENOMEM;  
  10.     }  
  11.     if (!tty->echo_buf) {  
  12.         tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);  
  13.   
  14.         if (!tty->echo_buf)  
  15.             return -ENOMEM;  
  16.     }  
  17.     reset_buffer_flags(tty);  
  18.     tty->column = 0;  
  19.     n_tty_set_termios(tty, NULL);  
  20.     tty->minimum_to_wake = 1;  
  21.     tty->closing = 0;  
  22.     return 0;  
  23. }  

2.写方法

  1. static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,const unsigned char *buf, size_t nr)  
  2. {  
  3.     const unsigned char *b = buf;  
  4.     DECLARE_WAITQUEUE(wait, current);  
  5.     int c;  
  6.     ssize_t retval = 0;  
  7.   
  8.     /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */  
  9.     if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {  
  10.         retval = tty_check_change(tty);  
  11.         if (retval)  
  12.             return retval;  
  13.     }  
  14.   
  15.     /* Write out any echoed characters that are still pending */  
  16.     process_echoes(tty);  
  17.   
  18.     add_wait_queue(&tty->write_wait, &wait);  
  19.     while (1) {  
  20.         set_current_state(TASK_INTERRUPTIBLE);  
  21.         if (signal_pending(current)) {  
  22.             retval = -ERESTARTSYS;  
  23.             break;  
  24.         }  
  25.         if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {  
  26.             retval = -EIO;  
  27.             break;  
  28.         }  
  29.         if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {  
  30.             while (nr > 0) {  
  31.                 ssize_t num = process_output_block(tty, b, nr);  
  32.                 if (num < 0) {  
  33.                     if (num == -EAGAIN)  
  34.                         break;  
  35.                     retval = num;  
  36.                     goto break_out;  
  37.                 }  
  38.                 b += num;  
  39.                 nr -= num;  
  40.                 if (nr == 0)  
  41.                     break;  
  42.                 c = *b;  
  43.                 if (process_output(c, tty) < 0)  
  44.                     break;  
  45.                 b++; nr--;  
  46.             }  
  47.             if (tty->ops->flush_chars)  
  48.                 tty->ops->flush_chars(tty);   //调用tty_struct操作函数集合的flush_chars方法  
  49.         } else {  
  50.             while (nr > 0) {  
  51.                 c = tty->ops->write(tty, b, nr);  //调用tty_struct操作函数集合的write方法  
  52.                 if (c < 0) {  
  53.                     retval = c;  
  54.                     goto break_out;  
  55.                 }  
  56.                 if (!c)  
  57.                     break;  
  58.                 b += c;  
  59.                 nr -= c;  
  60.             }  
  61.         }  
  62.         if (!nr)  
  63.             break;  
  64.         if (file->f_flags & O_NONBLOCK) {  
  65.             retval = -EAGAIN;  
  66.             break;  
  67.         }  
  68.         schedule();  
  69.     }  
  70. break_out:  
  71.     __set_current_state(TASK_RUNNING);  
  72.     remove_wait_queue(&tty->write_wait, &wait);  
  73.     if (b - buf != nr && tty->fasync)  
  74.         set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);  
  75.     return (b - buf) ? b - buf : retval;  
  76. }  

3.读方法

  1. static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,unsigned char __user *buf, size_t nr)  
  2. {  
  3.     unsigned char __user *b = buf;  
  4.     DECLARE_WAITQUEUE(wait, current);  
  5.     int c;  
  6.     int minimum, time;  
  7.     ssize_t retval = 0;  
  8.     ssize_t size;  
  9.     long timeout;  
  10.     unsigned long flags;  
  11.     int packet;  
  12.   
  13. do_it_again:  
  14.   
  15.     BUG_ON(!tty->read_buf);  
  16.   
  17.     c = job_control(tty, file);  
  18.     if (c < 0)  
  19.         return c;  
  20.   
  21.     minimum = time = 0;  
  22.     timeout = MAX_SCHEDULE_TIMEOUT;  
  23.     if (!tty->icanon) {  
  24.         time = (HZ / 10) * TIME_CHAR(tty);  
  25.         minimum = MIN_CHAR(tty);  
  26.         if (minimum) {  
  27.             if (time)  
  28.                 tty->minimum_to_wake = 1;  
  29.             else if (!waitqueue_active(&tty->read_wait) ||  
  30.                  (tty->minimum_to_wake > minimum))  
  31.                 tty->minimum_to_wake = minimum;  
  32.         } else {  
  33.             timeout = 0;  
  34.             if (time) {  
  35.                 timeout = time;  
  36.                 time = 0;  
  37.             }  
  38.             tty->minimum_to_wake = minimum = 1;  
  39.         }  
  40.     }  
  41.   
  42.     if (file->f_flags & O_NONBLOCK) {  
  43.         if (!mutex_trylock(&tty->atomic_read_lock))  
  44.             return -EAGAIN;  
  45.     } else {  
  46.         if (mutex_lock_interruptible(&tty->atomic_read_lock))  
  47.             return -ERESTARTSYS;  
  48.     }  
  49.     packet = tty->packet;  
  50.   
  51.     add_wait_queue(&tty->read_wait, &wait);  
  52.     while (nr) {  
  53.         /* First test for status change. */  
  54.         if (packet && tty->link->ctrl_status) {  
  55.             unsigned char cs;  
  56.             if (b != buf)  
  57.                 break;  
  58.             spin_lock_irqsave(&tty->link->ctrl_lock, flags);  
  59.             cs = tty->link->ctrl_status;  
  60.             tty->link->ctrl_status = 0;  
  61.             spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);  
  62.             if (tty_put_user(tty, cs, b++)) {  
  63.                 retval = -EFAULT;  
  64.                 b--;  
  65.                 break;  
  66.             }  
  67.             nr--;  
  68.             break;  
  69.         }  
  70.         set_current_state(TASK_INTERRUPTIBLE);  
  71.   
  72.         if (((minimum - (b - buf)) < tty->minimum_to_wake) &&  
  73.             ((minimum - (b - buf)) >= 1))  
  74.             tty->minimum_to_wake = (minimum - (b - buf));  
  75.   
  76.         if (!input_available_p(tty, 0)) {  
  77.             if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {  
  78.                 retval = -EIO;  
  79.                 break;  
  80.             }  
  81.             if (tty_hung_up_p(file))  
  82.                 break;  
  83.             if (!timeout)  
  84.                 break;  
  85.             if (file->f_flags & O_NONBLOCK) {  
  86.                 retval = -EAGAIN;  
  87.                 break;  
  88.             }  
  89.             if (signal_pending(current)) {  
  90.                 retval = -ERESTARTSYS;  
  91.                 break;  
  92.             }  
  93.             /* FIXME: does n_tty_set_room need locking ? */  
  94.             n_tty_set_room(tty);  
  95.             timeout = schedule_timeout(timeout);  
  96.             continue;  
  97.         }  
  98.         __set_current_state(TASK_RUNNING);  
  99.   
  100.         /* Deal with packet mode. */  
  101.         if (packet && b == buf) {  
  102.             if (tty_put_user(tty, TIOCPKT_DATA, b++)) {  
  103.                 retval = -EFAULT;  
  104.                 b--;  
  105.                 break;  
  106.             }  
  107.             nr--;  
  108.         }  
  109.   
  110.         if (tty->icanon && !L_EXTPROC(tty)) {  
  111.             /* N.B. avoid overrun if nr == 0 */  
  112.             while (nr && tty->read_cnt) {  
  113.                 int eol;  
  114.   
  115.                 eol = test_and_clear_bit(tty->read_tail,tty->read_flags);  
  116.                 c = tty->read_buf[tty->read_tail];  
  117.                 spin_lock_irqsave(&tty->read_lock, flags);  
  118.                 tty->read_tail = ((tty->read_tail+1) &(N_TTY_BUF_SIZE-1));  
  119.                 tty->read_cnt--;  
  120.                 if (eol) {  
  121.                     if (--tty->canon_data < 0)  
  122.                         tty->canon_data = 0;  
  123.                 }  
  124.                 spin_unlock_irqrestore(&tty->read_lock, flags);  
  125.   
  126.                 if (!eol || (c != __DISABLED_CHAR)) {  
  127.                     if (tty_put_user(tty, c, b++)) {  
  128.                         retval = -EFAULT;  
  129.                         b--;  
  130.                         break;  
  131.                     }  
  132.                     nr--;  
  133.                 }  
  134.                 if (eol) {  
  135.                     tty_audit_push(tty);  
  136.                     break;  
  137.                 }  
  138.             }  
  139.             if (retval)  
  140.                 break;  
  141.         } else {  
  142.             int uncopied;  
  143.             uncopied = copy_from_read_buf(tty, &b, &nr);  
  144.             uncopied += copy_from_read_buf(tty, &b, &nr);  
  145.             if (uncopied) {  
  146.                 retval = -EFAULT;  
  147.                 break;  
  148.             }  
  149.         }  
  150.   
  151.         if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {  
  152.             n_tty_set_room(tty);  
  153.             check_unthrottle(tty);  
  154.         }  
  155.   
  156.         if (b - buf >= minimum)  
  157.             break;  
  158.         if (time)  
  159.             timeout = time;  
  160.     }  
  161.     mutex_unlock(&tty->atomic_read_lock);  
  162.     remove_wait_queue(&tty->read_wait, &wait);  
  163.   
  164.     if (!waitqueue_active(&tty->read_wait))  
  165.         tty->minimum_to_wake = minimum;  
  166.   
  167.     __set_current_state(TASK_RUNNING);  
  168.     size = b - buf;  
  169.     if (size) {  
  170.         retval = size;  
  171.         if (nr)  
  172.             clear_bit(TTY_PUSH, &tty->flags);  
  173.     } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))  
  174.          goto do_it_again;  
  175.   
  176.     n_tty_set_room(tty);  
  177.     return retval;  
  178. }  

六.线路规程的操作函数集会调用对应的tty_struct的操作函数集
在initialize_tty_struct中tty->ops = driver->ops也就是说tty_struct的操作函数集就是tty_driver的操作函数集合

tty_driver的操作函数集设置在其register之前,例如串口的注册函数uart_register_driver中调用tty_set_operations(normal, &uart_ops)

将tty_driver->ops设置为uart_ops。

这样我们对/dev/ttyXXX的操作的调用顺序:字符设备的操作函数集tty_fops-->线路规程的操作函数集tty_ldisc_N_TTY-->串口核心或其他类型设备的操作函数集uart_ops
五 linux 串口驱动

Logo

更多推荐