我的用于raspi的内核模块,用于获得双光栅,如果两个输入gpio的每个边缘都在上升并且中断发生,则会读取单调时间。时间值通过普通的sysfs文件传递给用户空间(不是dev文件)。这很好用。
我的用户空间实现应该读取这些值并计算通过光栅的对象的最终速度。目前通过定期读取sysfs文件解决了这个问题。如果值发生变化,则会拾取并使用新值。
为了保存资源,我想在相关的sysfs文件上使用poll()获取POLLPRI。在内核模块中,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
答案 0 :(得分:2)
放置sysfs_notify()函数时出错了。
在这种情况下,正确的地方是在ISR内。
当发生中断时,会调用ISR并通过sysfs_notify()通知用户空间新数据是可读的。 poll()取消阻止并获取数据。
在我之前的星座中,用户空间poll()被阻塞,直到调用了kobj_attribute show函数。但是,如果从文件中读取数据,则仅调用此函数。这意味着用户空间应用程序正在等待内核模块和签证验证。
现在工作正常。
这是我编辑过的代码:
// [...]
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