tty_alloc_driver

  /inclue/linux/tty_driver.h

/* Use TTY_DRIVER_* flags below */
#define tty_alloc_driver(lines, flags) \
                __tty_alloc_driver(lines, THIS_MODULE, flags)
/*
 * DEPRECATED Do not use this in new code, use tty_alloc_driver instead.
 * 不赞成使用这个新代码,通常使用tty_alloc_driver来代替。其实他们实际意义是一样的
 * (And change the return value checks.)
 */
static inline struct tty_driver *alloc_tty_driver(unsigned int lines)
{
    struct tty_driver *ret = tty_alloc_driver(lines, 0);
//当看到代码中调用alloc_tty_driver时,flag默认为0
    if (IS_ERR(ret))
        return NULL;
    return ret;
}
----------------------------------------------------------------------
/*
 * tty driver flags
 *   
 * TTY_DRIVER_RESET_TERMIOS --- requests the tty layer to reset the
 *      termios setting when the last process has closed the device.
 *      Used for PTY's, in particular.
 * 当设备关闭时,请求复位termios。通常使用PTY
 * 
 * TTY_DRIVER_REAL_RAW --- if set, indicates that the driver will
 *      guarantee never not to set any special character handling
 *      flags if ((IGNBRK || (!BRKINT && !PARMRK)) && (IGNPAR ||
 *      !INPCK)).  That is, if there is no reason for the driver to
 *      send notifications of parity and break characters up to the
 *      line driver, it won't do so.  This allows the line driver to
 *      optimize for this case if this flag is set.  (Note that there
 *      is also a promise, if the above case is true, not to signal
 *      overruns, either.)
 * 如果设置,驱动将不会设置任何特殊的字符处理标志 
 * 意味着,如果没有原因,驱动将不会将通知送给线驱动
 * 如果设置了,可以使线驱动优化这一处理程序
 *
 * TTY_DRIVER_DYNAMIC_DEV --- if set, the individual tty devices need
 *      to be registered with a call to tty_register_device() when the
 *      device is found in the system and unregistered with a call to
 *      tty_unregister_device() so the devices will be show up
 *      properly in sysfs.  If not set, driver->num entries will be
 *      created by the tty core in sysfs when tty_register_driver() is
 *      called.  This is to be used by drivers that have tty devices
 *      that can appear and disappear while the main tty driver is
 *      registered with the tty core.
 * 如果设置,特别的tty设备将在其被发现时注册 和 调用注销函数时注销
 * 如果不设置,当注册函数被调用时,sysfs的tty核心层会自动创建driver->num
 * 这个flag通常使用在主tty驱动被tty核心注册,且tty设备可能出现和消失
 * 
 * TTY_DRIVER_DEVPTS_MEM -- don't use the standard arrays, instead
 *      use dynamic memory keyed through the devpts filesystem.  This
 *      is only applicable to the pty driver.
 * 不使用标准数组, 而是使用devpts文件系统的动态记忆链
 * 这个是给pty驱动使用的
 *
 * TTY_DRIVER_HARDWARE_BREAK -- hardware handles break signals. Pass
 *      the requested timeout to the caller instead of using a simple
 *      on/off interface.
 * 硬件处理断点信号。发送暂时休息(timeout)请求而不是简单地打开/关闭接口
 *
 * TTY_DRIVER_DYNAMIC_ALLOC -- do not allocate structures which are
 *      needed per line for this driver as it would waste memory.
 *      The driver will take care.
 * 不每条线都分配结构,因其会浪费内存。使用这个flag,驱动将注意这一情况
 *
 * TTY_DRIVER_UNNUMBERED_NODE -- do not create numbered /dev nodes. In
 *      other words create /dev/ttyprintk and not /dev/ttyprintk0.
 *      Applicable only when a driver for a single tty device is
 *      being allocated.
 * 不创建已经分配的/dev节点。
 * 意思是创建/dev/ttyprintk 而非创建/dev/ttyprintk0
 * 只用在一个驱动为了一个单独的且已经被分配tty设备注册时
 */
#define TTY_DRIVER_INSTALLED            0x0001
#define TTY_DRIVER_RESET_TERMIOS        0x0002
#define TTY_DRIVER_REAL_RAW             0x0004
#define TTY_DRIVER_DYNAMIC_DEV          0x0008
#define TTY_DRIVER_DEVPTS_MEM           0x0010
#define TTY_DRIVER_HARDWARE_BREAK       0x0020
#define TTY_DRIVER_DYNAMIC_ALLOC        0x0040
#define TTY_DRIVER_UNNUMBERED_NODE      0x0080

  在看分配函数之前,先来看一下tty_driver这个结构体

  /include/linux/tty/tty_driver.h

struct tty_driver {
    int     magic;          /* magic number for this structure */
    struct kref kref;       /* Reference management */
    struct cdev *cdevs;
    struct module   *owner;
    const char      *driver_name;
    const char      *name;
    int     name_base;      /* offset of printed name */
    int     major;          /* major device number */
    int     minor_start;    /* start of minor device number */
    unsigned int    num;    /* number of devices allocated */
    short   type;           /* type of tty driver */
    short   subtype;        /* subtype of tty driver */
    struct ktermios init_termios; /* Initial termios */
    unsigned long   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;
    struct tty_port **ports;
    struct ktermios **termios;
    void *driver_state;

    /*
     * Driver methods
     */

    const struct tty_operations *ops;
    struct list_head tty_drivers;
};

   分配tty驱动函数

  /drivers/tty/tty_io.c

/**
 * __tty_alloc_driver -- allocate tty driver
 * @lines: count of lines this driver can handle at most
 * @owner: module which is repsonsible for this driver
 * @flags: some of TTY_DRIVER_* flags, will be set in driver->flags
 *
 * This should not be called directly, some of the provided macros should be
 * used instead. Use IS_ERR and friends on @retval.
 */
struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
        unsigned long flags)
{
    struct tty_driver *driver;
    unsigned int cdevs = 1;
    int err;

    if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1))
//The priority is '&' higher than '&&'
//当设置flag为TTY_DRIVER_UNNUMBERD_NODE或lines为0的时候,返回-EINVAL
//means -E(rror)IN(put)VAL(ue)
        return ERR_PTR(-EINVAL);

    driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
    if (!driver)  //若分配失败,返回-ENOMEM
        return ERR_PTR(-ENOMEM);

    kref_init(&driver->kref);
    driver->magic = TTY_DRIVER_MAGIC;
    driver->num = lines;
    driver->owner = owner;
    driver->flags = flags;

//看看声明的flags有什么特点就知道这个 & 的作用了
    if (!(flags & TTY_DRIVER_DEVPTS_MEM)) {
//若没设置TTY_DRIVER_DEVPTS_MEM
//使用标准数组
        driver->ttys = kcalloc(lines, sizeof(*driver->ttys),
                GFP_KERNEL);
//定义为struct tty_struct **tty, kcalloc分配成功返回0
        driver->termios = kcalloc(lines, sizeof(*driver->termios),
                GFP_KERNEL);
//定义为struct ktermios **termios
        if (!driver->ttys || !driver->termios) {
//ttys和termios任一成功才继续往下
            err = -ENOMEM;
            goto err_free_all;
        }
    }

    if (!(flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
//若没设置TTY_DRIVER_DYNAMIC_ALLOC, 则为每条线都分配结构
        driver->ports = kcalloc(lines, sizeof(*driver->ports),
                GFP_KERNEL);
        if (!driver->ports) {
            err = -ENOMEM;
            goto err_free_all;
        }
        cdevs = lines;
    }

    driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs), GFP_KERNEL);
    if (!driver->cdevs) {
        err = -ENOMEM;
        goto err_free_all;
    }

    return driver;
err_free_all:
    kfree(driver->ports);
    kfree(driver->ttys);
    kfree(driver->termios);
    kfree(driver);
    return ERR_PTR(err);
}
EXPORT_SYMBOL(__tty_alloc_driver);

原文地址:https://www.cnblogs.com/plinx/p/2910782.html