linux可以通过udev接收内核消息创建设备节点。例如虚拟节点/dev/pts/0就是动态创建的。
static int __init tty_class_init(void)
=>tty_class = class_create(THIS_MODULE, "tty");
static void __init unix98_pty_init(void)
=>ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
=>pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
=>ptm_driver->owner = THIS_MODULE;
ptm_driver->driver_name = "pty_master";
ptm_driver->name = "ptm";
ptm_driver->major = UNIX98_PTY_MASTER_MAJOR;
ptm_driver->minor_start = 0;
ptm_driver->type = TTY_DRIVER_TYPE_PTY;
ptm_driver->subtype = PTY_TYPE_MASTER;
ptm_driver->init_termios = tty_std_termios;
ptm_driver->init_termios.c_iflag = 0;
ptm_driver->init_termios.c_oflag = 0;
ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
ptm_driver->init_termios.c_lflag = 0;
ptm_driver->init_termios.c_ispeed = 38400;
ptm_driver->init_termios.c_ospeed = 38400;
ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
=>tty_set_operations(ptm_driver, &ptm_unix98_ops);
=>pts_driver->owner = THIS_MODULE;
pts_driver->driver_name = "pty_slave";
pts_driver->name = "pts";
pts_driver->major = UNIX98_PTY_SLAVE_MAJOR;
pts_driver->minor_start = 0;
pts_driver->type = TTY_DRIVER_TYPE_PTY;
pts_driver->subtype = PTY_TYPE_SLAVE;
pts_driver->init_termios = tty_std_termios;
pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pts_driver->init_termios.c_ispeed = 38400;
pts_driver->init_termios.c_ospeed = 38400;
pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
=>tty_set_operations(pts_driver, &pty_unix98_ops);
/\
||
V
static const struct tty_operations pty_unix98_ops = {
.lookup = pts_unix98_lookup,
.install = pty_unix98_install,
.remove = pty_unix98_remove,
.open = pty_open,
.close = pty_close,
.write = pty_write,
.write_room = pty_write_room,
.flush_buffer = pty_flush_buffer,
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.shutdown = pty_unix98_shutdown
};
=>tty_register_driver(ptm_driver)
=>tty_register_driver(pts_driver)
=>register_sysctl_table(pty_root_table);
=>tty_default_fops(&ptmx_fops);
ptmx_fops.open = ptmx_open;
=>cdev_init(&ptmx_cdev, &ptmx_fops);
=>cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1)
=>register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx")
=>device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
static int ptmx_open(struct inode *inode, struct file *filp)
=>ret = __ptmx_open(inode, filp);
=>/* find a device that is not in use. */
index = devpts_new_index(inode);
=>tty = tty_init_dev(ptm_driver, index, 1);
=>filp->private_data = tty;
=>retval = devpts_pty_new(inode, tty->link);
=>dentry = d_alloc_name(root, s);
=>d_add(dentry, inode);
=>fsnotify_create(root->d_inode, dentry);
=>retval = ptm_driver->ops->open(tty, filp);
int device_register(struct device *dev)
=>device_initialize(dev);
=>return device_add(dev);
=>error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
=>retval = kobject_add_varg(kobj, parent, fmt, args);
=>retval = kobject_add_varg(kobj, parent, fmt, args);
=>if (MAJOR(dev->devt)) {
error = device_create_file(dev, &devt_attr);
if (error)
goto ueventattrError;
error = device_create_sys_dev_entry(dev);
if (error)
goto devtattrError;
devtmpfs_create_node(dev);//里面为空,不会执行
}
=>error = device_create_file(dev, &uevent_attr);
=>if (MAJOR(dev->devt)) {
error = device_create_file(dev, &devt_attr);
if (error)
goto ueventattrError;
error = device_create_sys_dev_entry(dev);
if (error)
goto devtattrError;
devtmpfs_create_node(dev);//不执行
}
=>error = device_add_class_symlinks(dev);//dev/ttyS0 1 2 3节点创建的关键在于这句话,很是疑惑
if (error)
goto SymlinkError;
error = device_add_attrs(dev);
if (error)
goto AttrsError;
error = bus_add_device(dev);
if (error)
goto BusError;
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
device_pm_add(dev);
=>if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
=>kobject_uevent(&dev->kobj, KOBJ_ADD);///通过内核kobject_uevent向用户态发消息,udev或者mdev监听之后再用户态增加/dev/xxx节点
=>bus_probe_device(dev);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
if (dev->class) {
mutex_lock(&dev->class->p->class_mutex);
/* tie the class to the device */
klist_add_tail(&dev->knode_class,
&dev->class->p->class_devices);
/* notify any interfaces that the device is here */
list_for_each_entry(class_intf,
&dev->class->p->class_interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
mutex_unlock(&dev->class->p->class_mutex);
}
done:
put_device(dev);
return error;
以串口节点为例,查看内容:
#cat /sys/class/tty/ttyS0/dev
4:64
#cat /sys/class/tty/ttyS0/uevent
MAJOR=4
MINOR=64
DEVNAME=ttyS0
Linux驱动开发二:自动获得设备节点在/dev/目录下
https://blog.csdn.net/long123bin/article/details/40055763
在/dev下自动创建设备节点
https://blog.csdn.net/huyubin/article/details/46726949
/dev下设备节点的创建
https://bbs.csdn.net/topics/392371795
Linux中tty、pty、pts的概念区别
https://www.cnblogs.com/zengkefu/p/5558851.html
/dev/tty 与 /dev/pts
https://www.cnblogs.com/zengkefu/p/5558840.html
三种创建节点的方法
https://blog.csdn.net/qq_33160790/article/details/67165019
Linux设备节点文件的创建—从mknod到devfs再到udev
https://blog.csdn.net/tankai19880619/article/details/17792167
devtmpfs文件系统创建设备节点 老旧方法,仅做参考
http://blog.chinaunix.net/uid-27717694-id-3574368.html
Linux Kernel 学习笔记4:自动创建设备节点
https://blog.csdn.net/stone8761/article/details/70232768
ttyUSB串口设备节点生成过程
https://blog.csdn.net/mingtianwoyueni/article/details/63709861
device_create device_destroy 使用==mknod及通过class_create自动创建设备节点
http://blog.chinaunix.net/uid-22666248-id-3052861.html
一步一步学习 Linux 驱动之自动创建设备节点
https://blog.csdn.net/xy010902100449/article/details/45394981
Linux下的device_create创建字符设备节点流程 作者分析得很不错
https://blog.csdn.net/chen_chuang_/article/details/48462591
class_create(),device_create解析.device_create和device_add区别
https://blog.csdn.net/wanmj2/article/details/42709707
Linux设备模型浅析之uevent篇
https://wenku.baidu.com/view/3f08de275901020207409cd4.html
device_create和device_add区别
https://blog.csdn.net/qq_16777851/article/details/81259307
device_create和device_add和udev
http://bbs.chinaunix.net/thread-4151639-1-1.html