在/sys/class/下生成hwconfig节点
创建节点
echo xxx > configexport
然后会在sys/class/hwconfig节点下生成xxx节点
xxx节点下有value节点
cat value 可以查看数据
echo xxx > value 可以对value节点进行写数据
测试可用。
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/idr.h>
#include <linux/slab.h>
#define FALSE 0
#define TRUE 1
/* gpio_lock prevents conflicts during gpio_desc[] table updates.
* While any GPIO is requested, its gpio_chip is not removable;
* each GPIO's "requested" flag serves as a lock and refcount.
*/
static DEFINE_SPINLOCK(config_lock);
/* lock protects against unexport_gpio() being called while
* sysfs files are active.
*/
static DEFINE_MUTEX(sysfs_lock);
#define ARCH_NR_CONFIG 256
struct config_desc {
char* name;
char* value;
char flag;
};
static struct config_desc config_desc[ARCH_NR_CONFIG];
static ssize_t config_export_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t len);
static struct class_attribute hwconfig_class_attrs[] = {
__ATTR(configexport, 0200, NULL, config_export_store),
__ATTR_NULL,
};
static struct class hwconfig_class = {
.name = "hwconfig",
.owner = THIS_MODULE,
.class_attrs = hwconfig_class_attrs,
};
static ssize_t hwConfig_value_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct config_desc *desc = dev_get_drvdata(dev);
ssize_t status;
mutex_lock(&sysfs_lock);
if( desc->value != NULL ){
status = sprintf(buf, "%s\n", desc->value);
}else{
// printk("[%s] The value of %s have not set.\n",__FUNCTION__,desc->name);
status = -EIO;
}
mutex_unlock(&sysfs_lock);
return status;
}
static ssize_t hwConfig_value_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct config_desc *desc = dev_get_drvdata(dev);
ssize_t status;
if( desc->flag == FALSE ){
if( desc->value == NULL ){
desc->value = kmalloc( size, GFP_KERNEL );
memset(desc->value, 0 , size);
}
mutex_lock(&sysfs_lock);
memcpy( desc->value, buf, size -1);
desc->flag = TRUE;
status = size;
mutex_unlock(&sysfs_lock);
}else{
// printk("[%s] Can not set the value of %s.\n",__FUNCTION__,desc->name);
status = -EPERM;
}
return status;
}
static DEVICE_ATTR(value,0664, hwConfig_value_show, hwConfig_value_store);
static const struct attribute *value_attrs[] = {
&dev_attr_value.attr,
NULL,
};
static const struct attribute_group value_attr_group = {
.attrs = (struct attribute **) value_attrs,
};
/*
* /sys/class/gpio/export ... write-only
* integer N ... number of GPIO to export (full access)
* /sys/class/gpio/unexport ... write-only
* integer N ... number of GPIO to unexport
*/
static ssize_t config_export_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t len)
{
struct device *dev;
int status;
int index;
unsigned long flags;
char *tmp = (char*)kmalloc((len),GFP_KERNEL);
memset(tmp,0,len);
memcpy(tmp,buf,len-1);
for( index = 0; index < ARCH_NR_CONFIG; ++index ){
spin_lock_irqsave(&config_lock, flags);
if( config_desc[index].name != NULL ){
if( strcmp(config_desc[index].name,tmp) == 0 ){
// printk("[%s] request name is busy!\n",__FUNCTION__);
status = -EBUSY;
spin_lock_irqsave(&config_lock, flags);
goto fail;
}
}else{
config_desc[index].name = (char*)kmalloc( len, GFP_KERNEL );
memcpy(config_desc[index].name,tmp,len);
config_desc[index].flag = FALSE;
spin_lock_irqsave(&config_lock, flags);
break;
}
spin_unlock_irqrestore(&config_lock, flags);
}
if( index >= ARCH_NR_CONFIG ){
// printk("[%s] request number is large then max:%d!\n",__FUNCTION__,ARCH_NR_CONFIG);
status = -ENFILE;
goto fail;
}
dev = device_create(&hwconfig_class, NULL, MKDEV(0, 0), &config_desc[index], tmp);
if (IS_ERR(dev)) {
status = PTR_ERR(dev);
goto fail;
}
status = sysfs_create_group(&dev->kobj, &value_attr_group);
if (status)
goto fail;
kfree(tmp);
return len;
fail:
kfree(tmp);
return status;
}
static int __init rcar_hwConfiglib_sysfs_init(void)
{
int status;
status = class_register(&hwconfig_class);
if (status < 0)
return status;
return status;
}
subsys_initcall(rcar_hwConfiglib_sysfs_init);