Linux Kernel 与应用交互的一些方式

Linux Kernel 与应用交互的一些方式

内核与应用的交互环节通常离不开内核的文件系统,通常使用proc、sysfs、debugfs三种

1.Debugfs

1.debugfs的介绍

通常debugfs用来在调试内核驱动时,dump或者写一些寄存器的工具

通过mount命令可以发现 debugfs别挂载在/sys/kernel/debug/ 下

debug on /sys/kernel/debug type debugfs (rw,relatime)

2.debugfs的使用

//debugfs的头文件及一些api介绍
#include 
//在debug的根目录下创建目录,返回目录的指针
struct dentry * debugfs_create_dir(const char *name, struct dentry *parent);
//创建文件节点
struct dentry *debugfs_create_file(const char *name, umode_t mode,
					struct dentry *parent, void *data,
					const struct file_operations *fops)
    
//example 
   mode:
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
struct dentry *debugfs_dir;

const struct file_operations debugfs_fops;
debugfs_dir = debugfs_create_dir("module_name", NULL);
debugfs_create_file("info", S_IRUSR, debugfs_dir, NULL, &debugfs_fops)

2.Proc

1.proc的使用

//头文件
#include 

//在proc下创建目录
struct proc_dir_entry *proc_mkdir(const char *name,
		struct proc_dir_entry *parent)
{
	return proc_mkdir_data(name, 0, parent, NULL);
}
//创建节点
struct proc_dir_entry *proc_create(const char *name, umode_t mode,
				   struct proc_dir_entry *parent,
				   const struct file_operations *proc_fops)
{
	return proc_create_data(name, mode, parent, proc_fops, NULL);
}
//用法
static proc_dir_entry demo_procdir;
static int demo_proc_show(struct seq_file *m, void *v)
{
	seq_printf(m, "%d\n", "demo_proc");
	return 0;
}
static int demo_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, demo_proc_show, NULL);
}
static const struct file_operation demo_fops = {
    .open = demo_proc_open,
    .read = seq_read,
    .llseek = seq_lseek,
    .release = single_release,
}
demo_procdir = proc_mkdir("demo_proc", NULL);
proc_create("demo_node1", 0666, demo_procdir, &demo_fops)

3.节点的创建

通常内核需要与用户空间进行交互,交互的方式有很多种,最常见的还是内核创建驱动属性节点,提供给应用空间

进行数据交互

1.device file属性节点

//device 节点的头文件
#include 

//属性的定义
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);
};

//设备属性的宏定义
#define __ATTR(_name, _mode, _show, _store) {				\
	.attr = {.name = __stringify(_name),				\
		 .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },		\
	.show	= _show,						\
	.store	= _store,						\
}
//进一步封装
#define DEVICE_ATTR(_name, _mode, _show, _store) \
	struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
//预定义设备属性读写的权限
#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)

#define DEVICE_ATTR_RW(_name) \
	struct device_attribute dev_attr_##_name = __ATTR_RW(_name)

//创建设备sys文件属性
/*	dev:device的指针
 	attr:设备属性
*/
int device_create_file(struct device *dev,
		       const struct device_attribute *attr)
{
	int error = 0;

	if (dev) {
		WARN(((attr->attr.mode & S_IWUGO) && !attr->store),
			"Attribute %s: write permission without 'store'\n",
			attr->attr.name);
		WARN(((attr->attr.mode & S_IRUGO) && !attr->show),
			"Attribute %s: read permission without 'show'\n",
			attr->attr.name);
		error = sysfs_create_file(&dev->kobj, &attr->attr);
	}

	return error;
}
//移除sys file attribute
void device_remove_file(struct device *dev,
			const struct device_attribute *attr)
{
	if (dev)
		sysfs_remove_file(&dev->kobj, &attr->attr);
}
//使用流程
1.定义设备的属性变量
2.通过device_create_file把属性添加到/sys/device下
example
//定义设备属性变量
static ssize_t led_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	char write_buf = "hello";
	return snprintf(buf, PAGE_SIZE, "%s", write_buf);
}
//缓冲区的大小应是一个页的大小PAGE_SIZE,show的方法应返回写入缓冲区的字节数,也就是snprintf的返回值,如果需要查看多个寄存器时,应该叠加snprintf的长度,store返回缓冲区已用的字节数,如果整个缓冲区已填满,字需要返回len的大小。show和store得到一个非法值时,必须返回一个错误值
static ssize_t led_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t len)
{
	return len;
}    
DEVICE_ATTR(led, 0666, led_show, led_store);
device_create_file(dev, &dev_attr_led);    

//当一个驱动需要多个设备属性时就不能用device_create_file一个个创建,内核还提供了sysfs_create_group
//通过这个api可以为驱动创建多个属性
//given a directory kobject, create an attribute group

int sysfs_create_group(struct kobject *kobj,
		       const struct attribute_group *grp)
{
	return internal_create_group(kobj, 0, grp);
}
/*
	常用属性
	name:group name
	attrs:attribute group
*/
struct attribute_group {
	const char		*name;
	umode_t			(*is_visible)(struct kobject *,
					      struct attribute *, int);
	umode_t			(*is_bin_visible)(struct kobject *,
						  struct bin_attribute *, int);
	struct attribute	**attrs;
	struct bin_attribute	**bin_attrs;
};

//万能交互内核读写寄存器
/* register read/write access 寄存器列表*/
#define REG_NONE_ACCESS					0
#define REG_RD_ACCESS					1 << 0
#define REG_WR_ACCESS					1 << 1
#define AW2023_REG_MAX					0x7F

const unsigned char aw2023_reg_access[AW2023_REG_MAX] = {
	[AW2023_REG_RESET]  = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_GCR1]   = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_STATUS] = REG_RD_ACCESS,
	[AW2023_REG_PATST]  = REG_RD_ACCESS,
	[AW2023_REG_GCR2]   = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_LEDEN]  = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_LCFG0]  = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_LCFG1]  = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_LCFG2]  = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_PWM0]   = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_PWM1]   = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_PWM2]   = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_LED0T0] = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_LED0T1] = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_LED0T2] = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_LED1T0] = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_LED1T1] = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_LED1T2] = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_LED2T0] = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_LED2T1] = REG_RD_ACCESS|REG_WR_ACCESS,
	[AW2023_REG_LED2T2] = REG_RD_ACCESS|REG_WR_ACCESS,
};
static ssize_t reg_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	struct led_classdev *led_cdev = dev_get_drvdata(dev);
	struct aw2023_led *led =
			container_of(led_cdev, struct aw2023_led, cdev);

	unsigned char i, reg_val;
	ssize_t len = 0;

    for(i=0; i<AW2023_REG_MAX; i++) {
        if(!(aw2023_reg_access[i]&REG_RD_ACCESS))
           continue;
        aw2023_read(led, i, &reg_val);
        len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%02x\n", i, reg_val);
    }
	return len;
}
static ssize_t reg_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t len)
{
	struct led_classdev *led_cdev = dev_get_drvdata(dev);
	struct aw2023_led *led =
			container_of(led_cdev, struct aw2023_led, cdev);

	unsigned int databuf[2];

	if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1]))
	{
		aw2023_write(led, (unsigned char)databuf[0], (unsigned char)databuf[1]);
	}

	return len;
}
static DEVICE_ATTR(demo1, 0644, reg_show, reg_store);

//使用前,需要先创建attribute group
static struct attribute *attrs_group[] = {
    &dev_attr_demo1.attr,
    &dev_attr_demo2.attr,
    &dev_attr_demo3.attr,
    NULL,
};
static struct attribute_group  demo_groups = {
    .name = "demo_group",
    .attrs = attrs_group,
}

sysfs_create_group(&dev->kobject, &demo_groups);

2.class节点

//驱动通常需要在/sys/class下创建自己的目录,就需要class_create 
#define class_create(owner, name)		\
({						\
	static struct lock_class_key __key;	\
	__class_create(owner, name, &__key);	\
})
//目录创建完也需要卸载class_destroy,成对存在
void class_destroy(struct class *cls)
{
	if ((cls == NULL) || (IS_ERR(cls)))
		return;

	class_unregister(cls);
}

static struct class demo_class;
demo_class = class_create(THIS_MODULE, "demo");

class_destroy(demo_class);

3.device create设备节点

//creates a device and registers it with sysfs 
struct device *device_create(struct class *class, struct device *parent,
			     dev_t devt, void *drvdata, const char *fmt, ...)
{
	va_list vargs;
	struct device *dev;

	va_start(vargs, fmt);
	dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
	va_end(vargs);
	return dev;
}
//目前看内核很少用device_create创建设备节点了
//register a device with the system device_add中创建uevent事件 用于udev管理
 int device_register(struct device *dev)
{
	device_initialize(dev);
	return device_add(dev);
}   

你可能感兴趣的:(linux,kernel,linux,物联网,驱动程序,kernel)