linux 下模擬/sys/class/gpio 編寫自己的動態創建節點 demo程序

在/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);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章