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);