问题从我的Linux内核模块向用户空间应用程序发送信号时

我正在使用具有Linux操作系统的嵌入式板。

此板有一个按钮和Led。

  • 按钮文件路径为 / dev / input / event0 ,并且代码为 260

  • Led文件路径为: / sys / class / leds

我想通过按钮控制Led,打开和关闭。此外,我想使用信号来通知发生按钮事件。事件发生后,信号将被发送到用户空间。

为此,我开发了Linux内核可加载模块和主要用户空间应用程序。

这是模块:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/siginfo.h>    //siginfo
#include <linux/rcupdate.h>    //rcu_read_lock
#include <linux/sched/signal.h>    //find_task_by_pid_type
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include<linux/slab.h>
#include <linux/input.h>
#include <linux/device.h>
#include <linux/fs.h> 


#define SIG_TEST 44    // we choose 44 as our signal number (real-time signals are in the range of 33 to 64)
#define BTN_FILE_PATH "/dev/input/event0"


char *str = BTN_FILE_PATH;
int file;

struct file *f;


static ssize_t write_pid(struct file *pfile,const char __user *buffer,size_t length,loff_t *offset)
{
    return 0;
}



static ssize_t read_pid(struct file *pfile,char __user *buffer,loff_t *offset)
{


     char mybuf[10];
    enum { MAX_BUF_SIZE = 4096 };
    size_t buf_size = 0;
    char *buf = NULL;
    ssize_t total = 0;
    ssize_t rc = 0;
    struct task_struct *t;
    struct input_event  *ev;
    int yalv;

    int ret;
    struct siginfo info;
    int pid =0; 

    /* Allocate temporary buffer. */
    if (length) {
        buf_size = min_t(size_t,MAX_BUF_SIZE,length);
        ev = kmalloc(buf_size,GFP_KERNEL);
        if (ev == NULL) {
            return -ENOMEM;
        }
    }

    /* read the value from user space */
    if(length > 10)
        return -EINVAL;
    copy_from_user(mybuf,buffer,length);
    sscanf(mybuf,"%d",&pid);
    printk("pid = %d\n",pid);

    rcu_read_lock();
    t = pid_task(find_vpid(pid),PIDTYPE_PID);  //find the task_struct associated with this pid
    if(t == NULL){
        printk("no such pid\n");
        rcu_read_unlock();
        return -ENODEV;
    }
    rcu_read_unlock();

 /* Read file to buffer in chunks. */

        size_t amount = min_t(size_t,length,buf_size);

        rc = kernel_read(f,ev,amount,offset);
        if (rc > 0) {
            /* Have read some data from file. */
            if (copy_to_user(buffer,rc) != 0) {
                /* Bad user memory! */
                rc = -EFAULT;
            } else {
                /* Update totals. */
                total += rc;
                buffer += rc;
                *offset += rc;
                length -= rc;

        for (yalv = 0; yalv < (int) (rc / sizeof(struct input_event)); yalv++) {
            if (ev[yalv].type == EV_KEY) {
                printk("signal was send\n");
                if (ev[yalv].value == 0)
                     ret = send_sig_info(SIG_TEST,&info,t);    //send the signal
                         if (ret < 0) {
                            printk("error sending signal\n");
                        kfree(buf);
                            return ret;
                         }

            }
        }
                if (rc < amount) {
                    /* Didn't read the full amount,so terminate early. */
                    rc = 0;
                }
            }

    } 


    /* Free temporary buffer. */

    kfree(buf);

}


static const struct file_operations my_fops = {
    .owner = THIS_MODULE,.write = write_pid,.read = read_pid,};

static int __init signalexample_module_init(void)
{

    /* we need to know the PID of the user space process
      * -> we use debugfs for this. As soon as a pid is written to 
      * this file,a signal is sent to that pid
      */
    /* only root can write to this file (no read) */
    register_chrdev(240,"Simple Char Drv",&my_fops);
    file = debugfs_create_file("signalconfpid",0200,NULL,&my_fops);
    f = filp_open(str,O_RDONLY);

    return 0;
}
static void __exit signalexample_module_exit(void)
{
    unregister_chrdev(240,"Simple Char Drv");
    debugfs_remove(file);

}

这是主要的用户空间应用程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>

#include <linux/input.h>

#define BTN_FILE_PATH "/dev/input/event0"
#define LED_PATH "/sys/class/leds"
#define red "red"
#define SIG_TEST 44
#define BUFFER_LENGTH 256

void change_led_state(char *led_path,int led_value)
{
    char    lpath[64];
    FILE    *led_fd;

    strncpy(lpath,led_path,sizeof(lpath) - 1);
    lpath[sizeof(lpath) - 1] = '\0';

    led_fd = fopen(lpath,"w");

    if (led_fd == NULL) {
        fprintf(stderr,"simplekey: unable to access led\n");
        return;
    }

    fprintf(led_fd,"%d\n",led_value);

    fclose(led_fd);
}

void reset_leds(void)
{
    change_led_state(LED_PATH "/" red "/brightness",0);
}

int configure_leds(void)
{
    FILE    *r_fd;
    char    *none_str = "none";

    /* Configure leds for hand control */
    l_fd = fopen(LED_PATH "/" red "/trigger","w");

    if ( r_fd == NULL) {
        perror("simplekey: unable to configure led");
        return -EaccES;
    }

    fprintf(r_fd,"%s\n",none_str);

    fclose(r_fd);

    /* Switch off leds */
    reset_leds();

    return 0;
}

void eval_keycode(int code)
{
    static int red_state = 0;

    switch (code) {
    case 260:
        printf("BTN left pressed\n");

        /* figure out red state */
        red_state = red_state ? 0 : 1;

        change_led_state(LED_PATH "/" red "/brightness",red_state);
        break;

    }
}


void receiveData(int n,siginfo_t *info,void *unused) 
{
    printf("received value %i\n",info->si_int);   
}

int main ( int argc,char **argv )
{
    int ret;
    int nc;
    int fd;
    int configfd;
    char buf[10];
    char buffer[BUFFER_LENGTH];
    /* setup the signal handler for SIG_TEST 
      * SA_SIGINFO -> we want the signal handler function with 3 arguments
      */
    struct sigaction sig;
    sig.sa_sigaction = receiveData;
    sig.sa_flags = SA_SIGINFO;
    sigaction(SIG_TEST,&sig,NULL);

    fd = open("/dev/char_device",O_RDONLY);             // Open the device with read access   
    if (fd < 0)
    {
            perror("Failed to open the device...");
            return errno;
    }
     sprintf(buffer,"%i",getpid());   
    nc = read(fd,strlen(buffer));
    if (nc < 0)
    {
            perror("Failed to read the message from the device.");
            return errno;
    }

    ret = configure_leds();
    if (ret < 0)
    exit(1);

    reset_leds();
    getchar();

    return 0;
}

在插入模块并运行应用程序之后,这仅向我返回用户代码的 PID ,但是当我按下按钮时,什么也没有发生。信号未发送,我猜。

如果有人能帮助我,我将不胜感激。谢谢!

wakal 回答:问题从我的Linux内核模块向用户空间应用程序发送信号时

暂时没有好的解决方案,如果你有好的解决方案,请发邮件至:iooj@foxmail.com
本文链接:https://www.f2er.com/3153574.html

大家都在问