方式一: 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);