内核与应用的交互环节通常离不开内核的文件系统,通常使用proc、sysfs、debugfs三种
通常debugfs用来在调试内核驱动时,dump或者写一些寄存器的工具
通过mount命令可以发现 debugfs别挂载在/sys/kernel/debug/ 下
debug on /sys/kernel/debug type debugfs (rw,relatime)
//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)
//头文件
#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)
通常内核需要与用户空间进行交互,交互的方式有很多种,最常见的还是内核创建驱动属性节点,提供给应用空间
进行数据交互
//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]®_RD_ACCESS))
continue;
aw2023_read(led, i, ®_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);
//驱动通常需要在/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);
//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);
}