这些设备文件定义在 linux/drivers/char/mem.c 的devlist 中。就像文件名和结构体名描述的,它们是基于内存的字符设备。
1 | static const struct memdev { |
文件系统初始化时,会调用chr_dev_init 函数,通过一个for 循环对devlist 中的这些设备进行初始化,并创建设备文件。
1 | static int __init chr_dev_init(void) |
device_create 函数在linux/drivers/base/core.c 中,它是一个包裹函数,负责将参数传入并调用device_create_vargs 再调用实际干活的device_create_groups_vargs.
device_create_groups_vargs先通过device_initialize 负责初始化一个空的设备的结构体dev,之后根据从device_create 传进来的参数填充数据,最后调用device_add 函数,传入刚刚填好数据的dev,在/sys/devices 目录下创建目录结构(例如/sys/devices/virtual/mem/null) ,并在/sys/class 下创建软链接(例如/sys/class/mem/null/),该目录下有设备的major:minor号,设备名称和权限等。
device_add 的最后,通过调用devtmpfs_create_node 函数,在devtmpfs,也就是/dev 目录下创建设备对应的文件(例如/dev/null)。
在/dev 下的设备文件创建完成后,就可以从用户态通过该文件对设备进行操作,不同的设备实现的fops 数量和方法也不同,其中null 和zero 的定义和实现都在 linux/drivers/char/mem.c 中:
1 | static const struct file_operations null_fops = { |
其中部分方法还是zero 和null 共用的,例如zero_lseek 和null_lseek(设置到文件起始位置),write_null 和write_zero 等就是同一个函数实现(只返回个数字,但不发生实际写入):
1 |
|
read_null 简单的返回一个0, 而read_iter_zero 则是通过memset 的方式向读buffer 写满0.
random 的实现在linux/drivers/char/random.c 中:
1 | const struct file_operations random_fops = { |
它的方法实现也比较复杂,有兴趣可以去研究一下。