linux-sys目录下寄存器节点的创建

sys目录

ramdisk 文件系统基于磁盘模拟技术,实际文件系统是ex2 ex3等。sysfs是一种基于ram文件系统和proc一样。Sysfs文件系统是一个类似于proc文件系统的特殊文件系统,用于将系统中的设备组织成层次结构,并向用户模式程序提供详细的内核数据结构信息。其实,就是在用户态可以通过对sys文件系统的访问,来看内核态的一些驱动或者设备等。


补充-proc目录

proc目录是一种文件系统,即proc文件系统。与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。基于/proc文件系统如上所述的特殊性,其内的文件也常被称作虚拟文件,并具有一些独特的特点。例如,其中有些文件虽然使用查看命令查看时会返回大量信息,但文件本身的大小却会显示为0字节。此外,这些特殊文件中大多数文件的时间及日期属性通常为当前系统时间和日期,这跟它们随时会被刷新(存储于RAM中)有关。

sys节点创建

1.先定义好寄存器组(reg_labels[ ])

#define ADC_FS			20
#define ADC_EN			21
#define ADC_FS			22
#define ADC_EN			23

struct reg_label {
        char *name;
        unsigned int address;
}

#define REG_LABEL(REG) {#REG, REG}

static struct reg_label reg_labels[] = {
        REG_LABEL(ADC_FS),
	    REG_LABEL(ADC_EN),
	    REG_LABEL(ADC_FS),
	    REG_LABEL(ADC_EN),
};

2.定义回调函数,分别在cat和echo节点时触发

static ssize_t debug_show_reg(struct device *dev, struct device_attribute *attr,
					char *buf) {}  /* 在cat节点时触发 */
/* dev : 设备,用于拿到寄存器等设备信息 */
/* attr: 指向创建的device_attribute */
/* buf : 一段内存的指针,用于显示到输出设备。但是内存有限,*/
         /* 如果要输出大量信息需要自己打印,否则会报错 */


static ssize_t debug_store_reg(struct device *dev, struct device_attribute *attr,
					 const char *buf, size_t count) {} /* 在echo节点时触发 */
/* dev  : 设备,用于拿到寄存器等设备信息 */
/* attr : 指向创建的device_attribute */
/* buf  : 从用户层echo进来的字符串 */
/* count: 一般count大小就是一个PAGE_SIZE。 */ 
          /* 如果这个函数 return 0,这个store函数将被无限循环调用导致系统crash*/

一般在show函数可以打印寄存器信息或是打印使用的方法,在store函数里面就可以配合sscanf函数和buf变量来制定自己的规则

3.通过DEVICE_ATTR宏来定义一个struct device_attribute

static DEVICE_ATTR(sys_reg, 0644, debug_show_reg, debug_store_reg);

这里补充一下相关的宏以及结构体结构体

#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
/* name  : 节点的名字 */
/* _mode : 权限位,例如0664 */
/* _show : cat回调函数 */
/* _store: echo回调函数 */

#define __ATTR(_name,_mode,_show,_store) { \
        .attr = {.name = __stringify(_name), .mode = _mode },   \
        .show   = _show,                                        \
        .store  = _store,                                       \
}

/* 用于保存名字和权限 */
struct attribute {
        const char        *name;
        umode_t            mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
        bool            ignore_lockdep:1;
        struct lock_class_key    *key;
        struct lock_class_key    skey;
endif
}

struct device_attribute {
	    struct attribute attr;
	    ssize_t (*show)(struct device *dev, struct device_attribute *attr,
			char *buf);
    	ssize_t (*store)(struct device *dev, struct device_attribute *attr,
			const char *buf, size_t count);
};

4.定义struct attribute数组,以此收集数个struct attribute

static struct attribute *debug_attrs[] = {
	    &dev_attr_sys_reg.attr,
	    NULL,
};

注:这里的struct attribute的名字是上面那个宏DEVICE_ATTR定义好的

5.定义struct attribute_group,确定节点所在文件夹名字和传入定义好的struct attribute的指针函数的地址

static struct attribute_group debug_attr = {
	    .name	= "sys_debug",                    /* 节点文件夹的文字 */
	    .attrs	= debug_attrs,                    /* 定义好的debug_attrs */
};

注:这里传入的是struct attribute类型的指针数组,包含了数个struct attribute的指针,且每个attribute都能通过偏移找到对应的两个回调函数,因为struct attribute和两个回调函数同属一个结构体struct device_attribute

6.在相应的probe()和remove()函数里面调用下面两个函数即可

sysfs_create_group(&pdev->dev.kobj, debug_attr);

sysfs_remove_group(&pdev->dev.kobj, debug_attr);

猜你喜欢

转载自blog.csdn.net/hhx123456798/article/details/123439403
今日推荐