poll 監聽/sys/class/xxx下節點的兩種實現方式

方式一: lseek到09

方式二:reopen節點操作.(這個一定要注意在第一次open需要對它做一次dummy讀操作)

 

app 代碼如下

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <termios.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h>  
#include <fcntl.h>  
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <linux/videodev2.h>
#include <linux/fb.h>
#include <time.h>
#include <poll.h>


int main(int argv,char *argc[])
{
	char *opt_path="/sys/class/hwconfig/aa/value";
	int fd,len,fd2;
	struct pollfd pfd;
	int i;
	char read_buf[512];
	char dummy_buf;
	int r;
	memset(read_buf,0,sizeof(read_buf));

	if((fd = open(opt_path,O_RDONLY/*|O_NONBLOCK*/))<0)
	{

		printf("open uart %s err \n",opt_path);
		exit(1);
	}
	printf("open uart [%s] success.\n",opt_path);
	pfd.fd = fd;

	while(1)
    	{
		len = 0;
		
		pfd.events = POLLERR|POLLPRI;

		r = poll(&pfd,1,-1);

		if (-1 == r) {
			printf ("poll error\n");
		}
		else if(0 == r){
			printf ("poll timeout\n");
		}
		#if 0	/* lseek operation */
//		printf("poll return r = %d;pfd.revents=%d.\n",r,pfd.revents);
		lseek(fd,0,SEEK_SET);
		len = read(fd, read_buf, 512);
		printf("len =%d;fd=%d\n[sysfs_test] read data:",len,fd);
		for( i = 0; i< len; i++ ){
			printf("0x%02x,",read_buf[i]);
		}
		printf("\n");
	
		memset(read_buf, 0, sizeof(read_buf));
		pfd.revents = 0;
#else/* reopen operation */
		len = read(fd,& dummy_buf, 1);

		if((fd2 = open(opt_path,O_RDONLY/*|O_NONBLOCK*/))<0)
		{

			printf("open uart %s err \n",opt_path);
			exit(1);
		}

		len=0;
		len = read(fd2, read_buf, 512);
//		printf("len =%d;fd=%d,fd2=%d\n",len,fd,fd2);
//		while((len /*= read(fd, read_buf, 512)*/)>0)
        		{
			
			printf("len =%d;fd=%d\n[sysfs_test] read data:",len,fd);
			for( i = 0; i< len; i++ ){
				printf("0x%02x,",read_buf[i]);
			}
			printf("\n");
		
			memset(read_buf, 0, sizeof(read_buf));
			len = 0;
//			sleep(1);
        		}
		close(fd2);
		//system("cat /sys/class/hwconfig/aa/value");

		pfd.revents = 0;
#endif
		
		
	}
}

驅動代碼實現

#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>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/delay.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;
	struct device *dev;
	wait_queue_head_t wait;
};
static struct config_desc  config_desc[ARCH_NR_CONFIG];

static ssize_t hwConfig_value_show(struct device *dev,
                                     struct device_attribute *attr, char *buf);


static ssize_t config_export_store(struct class *class,
				struct class_attribute *attr,
				const char *buf, size_t len);

static ssize_t hwConfig_value_store(struct device *dev,
                                      struct device_attribute *attr, const char *buf, size_t size);



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 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,
};


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;
	printk("111111111\n");

//	wait_event_interruptible(config_desc[0].wait,0);
	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);
	printk("buf=%s,status=%d\n",buf,status);
	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 ){
				kfree(desc->value);
			}
		//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;
	}
	sysfs_notify(&desc->dev->kobj,NULL,dev_attr_value.attr.name);
	return status;
}





/*
 * /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_unlock_irqrestore(&config_lock, flags);
				goto fail;
			}
		}else{
//			printk("=============\n");
			config_desc[index].name  = (char*)kmalloc(  len, GFP_KERNEL );
			memcpy(config_desc[index].name,tmp,len);

			config_desc[index].flag = FALSE;
//			init_waitqueue_head(&config_desc[0].wait);
			spin_unlock_irqrestore(&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;
	}
	config_desc[index].dev = dev;
	status = sysfs_create_group(&config_desc[index].dev->kobj, &value_attr_group);
	if (status)
		goto fail;

	kfree(tmp);
	return  len;

fail:
	kfree(tmp);
	return  status;
}

int my_kernel_thread(void *arg)
{
	int n = 0;

	while(1)
	{
		
		ssleep(3);
//		if( config_desc[0].dev != NULL )
			{
//			sysfs_notify(&config_desc[0].dev->kobj,NULL,dev_attr_value.attr.name);
			
//			wake_up_interruptible_all(&config_desc[0].wait);
//			printk("=========%s : %d===========\n",__func__,n++);
			//if( config_desc[0].value != NULL ){
		//		mutex_lock(&sysfs_lock);
				//memcpy( desc->value, buf,  size -1);
		//		desc->flag = TRUE;
				//status = size;
		//		config_desc[0].value[0] += 1;
		//		mutex_unlock(&sysfs_lock);
		//	}

			
			}
	}
	return 0;
}

static int __init rcar_hwConfiglib_sysfs_init(void)
{
	int		status;


	status = class_register(&hwconfig_class);
	if (status < 0)
		return status;
	kernel_thread(my_kernel_thread,NULL,CLONE_KERNEL);

	return status;
}
subsys_initcall(rcar_hwConfiglib_sysfs_init);

 

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