c - 来自用户空间的 sysfs 文件中的 poll() 和来自内核空间的 sysfs_notify() 不会一起工作

标签 c linux-kernel sysfs

我的 raspi 内核模块是为了获得双光屏障而编写的,如果两个输入 gpio 的边缘中的每一个都在上升并且发生中断,则读取单调时间。时间值通过普通的 sysfs 文件传递​​给用户空间(不是开发文件)。这工作正常。

我的用户空间实现应该读取这些值并计算对象通过光栅的最终速度。这目前通过定期读取 sysfs 文件来解决。如果值发生变化,则选择并使用新值。

为了节省资源,我想在相关的 sysfs 文件上为 POLLPRI 进行 poll()。在内核模块内部应该有一个 sysfs_notify() 向用户空间提供相关 sysfs 文件的更改状态和值。

但是我在用户空间中的 poll() 会永久阻塞。我也尝试将 POLLIN 作为事件。结果是 poll() 函数立即返回。

这是我的代码...

// [...]

static struct kobject *gpio; // dir /sys/kernel/gpio

static ssize_t gpio17s_show(struct kobject *kobj,struct kobj_attribute
            *attr,char *buf)
{
    return sprintf(buf,"%li",sec1);
}

static ssize_t gpio17s_store(struct kobject *kobj,struct kobj_attribute
            *attr,const char *buf,size_t count)
{
    sscanf(buf,"%li",&sec1);
    return count;
}

}

// [...] (two more files)

static ssize_t gpio26n_show(struct kobject *kobj,struct kobj_attribute
            *attr,char *buf)
{
    sysfs_notify(gpio,NULL,"gpio26n"); // Is this the right place, the right invocation????
    // I saw this already in isr, but i believe this is not a good idea....
    // Has it perhaps to be in module_init function???
    // First arg('gpio') is kobject of the dir containing files(attributes)..
    // This can not be right in my mind, but how do I find the right kobj??
    // The third param 'gpio26n' if the file, on which I'm polling.

    return sprintf(buf,"%li",nsec2);
}

static ssize_t gpio26n_store(struct kobject *kobj,struct kobj_attribute
            *attr,const char *buf,size_t count)
{
    sscanf(buf,"%li",&nsec2);
    return count;
}

static int cleanup(int value,int ret) {

    switch(value) {
        case 5:
            free_irq(speed_irq2,NULL);
        case 4:
            free_irq(speed_irq1,NULL);
        case 3:
            gpio_free(PIN2);
        case 2:
            gpio_free(PIN1);
        case 1:
            kobject_put(gpio);
    }

    return ret;
}

static irqreturn_t speed_isr(int irq, void *data) {

    if(irq==speed_irq1) {
        getrawmonotonic(&ts1);
        sec1=ts1.tv_sec;
        nsec1=ts1.tv_nsec;
    }

    if(irq==speed_irq2) {
        getrawmonotonic(&ts2);
        sec2=ts2.tv_sec;
        nsec2=ts2.tv_nsec;
    }

    return IRQ_HANDLED;
}

static struct kobj_attribute gpio17s_attr = __ATTR(gpio17s,0644,
        gpio17s_show,gpio17s_store);
static struct kobj_attribute gpio26n_attr = __ATTR(gpio26n,0644,
        gpio26n_show,gpio26n_store);

static int  __init d_init(void) {

    int ret=0;

    printk(KERN_INFO "Module successfully loaded...");

    gpio=kobject_create_and_add("gpio",kernel_kobj);
    if(!gpio) {
        printk(KERN_ERR "Failed to create 'gpio'");
        return -ENOMEM;
    }

    ret=sysfs_create_file(gpio,&gpio17s_attr.attr);
    if(ret) {
        printk(KERN_ERR "Failed to create file 'gpio17s'");
        return cleanup(1,2);
    }

    // [...] (two more files)

    ret=sysfs_create_file(gpio,&gpio26n_attr.attr);
    if(ret) {
        printk(KERN_ERR "Failed to create file 'gpio26n'");
        return cleanup(1,5);
    }

    ret=gpio_request(PIN1,"gpio 17");
    if(ret) {
        printk(KERN_ERR "Failed to request 'gpio17'");
        return cleanup(1,6);
    }

    ret=gpio_request(PIN2,"gpio 26");
    if(ret) {
        printk(KERN_ERR "Failed to request 'gpio26'");
        return cleanup(2,7);
    }

    ret=gpio_to_irq(PIN1);
    if(ret<0) {
        printk(KERN_ERR "Unable to get irq for pin 17");
        return cleanup(3,8);
    }

    speed_irq1=ret;

    ret=gpio_to_irq(PIN2);
    if(ret<0) {
        printk(KERN_ERR "Unable to get irq for pin 26");
        return cleanup(3,9);
    }

    speed_irq2=ret;

    ret=request_irq(speed_irq1,speed_isr,IRQF_TRIGGER_RISING,
            "Speed trigger 17",NULL);
    if(ret) {
        printk(KERN_ERR "Unable to request irq for pin 17");
        return cleanup(3,10);
    }

    ret=request_irq(speed_irq2,speed_isr,IRQF_TRIGGER_RISING,
            "Speed trigger 26",NULL);
    if(ret) {
        printk(KERN_ERR "Unable to request irq for pin 26");
        return cleanup(4,10);
    }

    return 0;
}

static void __exit d_exit(void) {
// [...]

还有我的用户空间应用
// [...]

int main() {

    int           f      ;
    char          buf[16];
    struct pollfd pfd    ;

    while(1) {
        memset(buf,0,sizeof(buf));

        if((f=open("/sys/kernel/gpio/gpio26n",O_RDONLY)) <0) {
            fprintf(stderr,"Failed to open sysfs file\n");
            exit(1);
        }

        if((lseek(f,0L,SEEK_SET)) <0) {
            fprintf(stderr,"Failed to set pointer\n");
            exit(2);
        }


        if((read(f,buf,1)) <0) {
            fprintf(stderr,"Failed to read from file\n");
            exit(3);
        }

        pfd.fd     = f      ;
        pfd.events = POLLPRI;

        poll(&pfd,1,-1); // This should block until value has changed....
        close(f);


        // fopen, read new value etc.
        // [...]

        // Do some stuff, calculate speed, etc
    }
}

问候 pfau

最佳答案

放置 sysfs_notify() 函数时我错了。

在这种情况下,正确的位置是在 ISR 中。

当中断发生时,ISR 被调用并通过 sysfs_notify() 通知用户空间,新数据是可读的。 poll() 解除阻塞并获取数据。

在我之前的星座中,用户空间 poll() 被阻塞,直到调用 kobj_attribute show 函数。但是这个函数只有在从文件中读取数据时才会被调用。这意味着用户空间应用程序正在等待内核模块和签证verce。

现在它工作正常。

这是我编辑的代码:

// [...]

static struct kobject *gpio; // dir /sys/kernel/gpio

static ssize_t gpio17s_show(struct kobject *kobj,struct kobj_attribute
            *attr,char *buf)
{
    return sprintf(buf,"%li",sec1);
}

static ssize_t gpio17s_store(struct kobject *kobj,struct kobj_attribute
            *attr,const char *buf,size_t count)
{
    sscanf(buf,"%li",&sec1);
    return count;
}

}

// [...] (two more files)

static ssize_t gpio26n_show(struct kobject *kobj,struct kobj_attribute
            *attr,char *buf)
{
    return sprintf(buf,"%li",nsec2);
}

static ssize_t gpio26n_store(struct kobject *kobj,struct kobj_attribute
            *attr,const char *buf,size_t count)
{
    sscanf(buf,"%li",&nsec2);
    return count;
}

static int cleanup(int value,int ret) {

    switch(value) {
        case 5:
            free_irq(speed_irq2,NULL);
        case 4:
            free_irq(speed_irq1,NULL);
        case 3:
            gpio_free(PIN2);
        case 2:
            gpio_free(PIN1);
        case 1:
            kobject_put(gpio);
    }

    return ret;
}

static irqreturn_t speed_isr(int irq, void *data) {

    if(irq==speed_irq1) {
        getrawmonotonic(&ts1);
        sec1=ts1.tv_sec;
        nsec1=ts1.tv_nsec;
    }

    if(irq==speed_irq2) {
        getrawmonotonic(&ts2);
        sec2=ts2.tv_sec;
        nsec2=ts2.tv_nsec;

        sysfs_notify(gpio,NULL,"gpio26n"); // !! HERE IS THE RIGHT PLACE !!
    }

    return IRQ_HANDLED;
}

static struct kobj_attribute gpio17s_attr = __ATTR(gpio17s,0644,
        gpio17s_show,gpio17s_store);
static struct kobj_attribute gpio26n_attr = __ATTR(gpio26n,0644,
        gpio26n_show,gpio26n_store);

static int  __init d_init(void) {

    int ret=0;

    printk(KERN_INFO "Module successfully loaded...");

    gpio=kobject_create_and_add("gpio",kernel_kobj);
    if(!gpio) {
        printk(KERN_ERR "Failed to create 'gpio'");
        return -ENOMEM;
    }

    ret=sysfs_create_file(gpio,&gpio17s_attr.attr);
    if(ret) {
        printk(KERN_ERR "Failed to create file 'gpio17s'");
        return cleanup(1,2);
    }

    // [...] (two more files)

    ret=sysfs_create_file(gpio,&gpio26n_attr.attr);
    if(ret) {
        printk(KERN_ERR "Failed to create file 'gpio26n'");
        return cleanup(1,5);
    }

    ret=gpio_request(PIN1,"gpio 17");
    if(ret) {
        printk(KERN_ERR "Failed to request 'gpio17'");
        return cleanup(1,6);
    }

    ret=gpio_request(PIN2,"gpio 26");
    if(ret) {
        printk(KERN_ERR "Failed to request 'gpio26'");
        return cleanup(2,7);
    }

    ret=gpio_to_irq(PIN1);
    if(ret<0) {
        printk(KERN_ERR "Unable to get irq for pin 17");
        return cleanup(3,8);
    }

    speed_irq1=ret;

    ret=gpio_to_irq(PIN2);
    if(ret<0) {
        printk(KERN_ERR "Unable to get irq for pin 26");
        return cleanup(3,9);
    }

    speed_irq2=ret;

    ret=request_irq(speed_irq1,speed_isr,IRQF_TRIGGER_RISING,
            "Speed trigger 17",NULL);
    if(ret) {
        printk(KERN_ERR "Unable to request irq for pin 17");
        return cleanup(3,10);
    }

    ret=request_irq(speed_irq2,speed_isr,IRQF_TRIGGER_RISING,
            "Speed trigger 26",NULL);
    if(ret) {
        printk(KERN_ERR "Unable to request irq for pin 26");
        return cleanup(4,10);
    }

    return 0;
}

static void __exit d_exit(void) {
// [...]

问候 pfau

关于c - 来自用户空间的 sysfs 文件中的 poll() 和来自内核空间的 sysfs_notify() 不会一起工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47857927/

相关文章:

c - 在与定义相同的文件中使用外部声明的好处?

c - 通过 SPI 读取 22 位

linux-kernel - kmalloc 中的缓冲区也是 DMA 安全缓冲区吗?

c - 正确使用 sysfs_notify_dirent()

c - 在条件语句中分配一个可变长度的字符串

c - 初始化结构的结构

c - 如何重置驱动程序读取函数:myread(struct file *file, char __user *buf,size_t len, loff_t *fops)中的缓冲区(初始化为零)?

c - SK_BUFF 结构成员

linux - 为什么 Linux 内核的 sysfs API 中的存储函数需要返回使用的字节?

c - 如何在Linux中以编程方式获取USB大容量存储大小?