如何从 Linux 内核空间向用户空间发送信号以通知输入硬件事件

2024-01-03

我的内核模块代码需要向用户态程序发送信号,以将其执行转移到注册的信号处理程序。

事实上,我为我的嵌入式板开发了一个 C 程序,当我按下按钮(输入事件)时,它可以使 LED 打开和关闭。另一方面,我刚刚开发了一个简单的 Linux 模块及其基本功能(OPEN、CLOSE、READ、WRITE)。

我只是不知道如何修改我的主要程序和内核模块以达到我的目标。

我与您分享我的用户空间程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.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 green "green"

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 "/" green "/brightness", 0);
}

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

    /* Configure leds for hand control */

    r_fd = fopen(LED_PATH "/" green "/trigger", "w");




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


    fclose(r_fd);


    /* Switch off leds */
    reset_leds();

    return 0;
}

void eval_keycode(int code)
{

    static int green_state = 0;

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

        /* figure out green state */

        green_state = green_state ? 0 : 1;

        change_led_state(LED_PATH "/" green "/brightness", green_state);
        break;
    }
}


int main(void)
{
    int file;
    /* how many bytes were read */
    size_t  rb;
    int ret;
    int yalv;
    /* the events (up to 64 at once) */
    struct input_event  ev[64];
    char    *str = BTN_FILE_PATH;

    printf("Starting simplekey app\n");

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

    printf("File Path: %s\n", str);

    if((file = open(str, O_RDONLY)) < 0) {
        perror("simplekey: File can not open");
        exit(1);
    }

    for (;;) {
        /* Blocking read */
        rb= read(file, &ev, sizeof(ev));

        if (rb < (int) sizeof(struct input_event)) {
            perror("simplekey: short read");
            exit(1);
        }

        for (yalv = 0;
            yalv < (int) (rb / sizeof(struct input_event));
            yalv++) {
            if (ev[yalv].type == EV_KEY) {
                printf("%ld.%06ld ",
                    ev[yalv].time.tv_sec,
                    ev[yalv].time.tv_usec);
                printf("type %d code %d value %d\n",
                        ev[yalv].type,
                        ev[yalv].code, ev[yalv].value);

                /* Change state on button pressed */
                if (ev[yalv].value == 0)
                    eval_keycode(ev[yalv].code);
            }
        }
    }

    close(file);

这是基本的内核模块:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>  
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/input.h>

MODULE_LICENSE("GPL");      
MODULE_AUTHOR("Gaston");  
MODULE_DESCRIPTION("A simple Linux char driver"); 
MODULE_VERSION("0.1"); 


ssize_t exer_open(struct inode *pinode, struct file *pfile) {

    printk(KERN_INFO "Device has been opened\n");

    return 0;
}



ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {

    return 0;
}



ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {

    return 0;

}   




ssize_t exer_close(struct inode *pinode, struct file *pfile) {

    printk(KERN_INFO "Device successfully closed\n");
    return 0;
}


struct file_operations exer_file_operations = { 
    .owner = THIS_MODULE,
    .open = exer_open,
    .read = exer_read,
    .write = exer_write,
    .release = exer_close,
};


int exer_simple_module_init(void) {

    printk(KERN_INFO "Initializing the LKM\n");
    register_chrdev(240, "Simple Char Drv", &exer_file_operations);
    return 0;
}


void exer_simple_module_exit(void) {

    unregister_chrdev(240, "Simple Char Drv");
}


module_init(exer_simple_module_init);
module_exit(exer_simple_module_exit);

我希望你能帮助我。谢谢你!


我将集中精力发送信号,因为这就是您所要求的,尽管向进程发送信号是相当残酷的。最好实施一下poll and read文件操作,以便用户代码可以等待来自设备的事件并读取它们。

无论如何,为了向打开设备的进程发送信号,您需要的是:

  1. 你需要一个struct fasync_struct *在您设备的私人数据中:

    struct fasync_struct *pasync_queue;
    

    需要初始化为NULL在设备私有数据初始化期间通过某种方式。如何做到这一点取决于您。

  2. 您需要一个由 指向的 fasync 文件操作处理程序fasync你的成员struct file_operations。 fasync 处理程序的实现非常简单,只需调用fasync_helper()使用提供的参数和指向设备私有的指针struct fasync_struct *:

    static int exer_fasync(int fd, struct file *pfile, int mode)
    {
         // N.B. Change this code to use the pasync_queue member from your device private data.
         struct fasync_struct **fapp = &pasync_queue;
         return fasync_helper(fd, pfile, mode, fapp);
    }
    
    struct file_operations exer_file_operations = { 
         .owner = THIS_MODULE,
         .open = exer_open,
         .read = exer_read,
         .write = exer_write,
         .release = exer_close,
         .fasync = exer_fasync,
    };
    
  3. 您的设备驱动程序可以发送SIGIO通过呼叫发出信号kill_fasync()如下:

         // N.B. Change this code to use the pasync_queue member from your device private data.
         struct fasync_struct **fapp = &pasync_queue;
         kill_fasync(fapp, SIGIO, POLL_IN);
    

    注意:最后一个参数(值POLL_IN在这种情况下)影响的值si_band的成员siginfo_t您的应用程序在其信号处理程序中看到的。

  4. 您的应用程序需要设置一个信号处理程序SIGIO信号。我建议使用sigaction()来设置这个。

  5. 您的应用程序需要设置O_ASYNC打开设备文件时标记,或通过调用设置它fcntl(fd, F_SETFL, O_ASYNC);打开设备文件后。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从 Linux 内核空间向用户空间发送信号以通知输入硬件事件 的相关文章

  • Signalr 在生产服务器中总是陷入长轮询

    当我在服务器中托管应用程序时 它会检查服务器端事件并始终回退到长轮询 服务器托管环境为Windows Server 2012 R1和IIS 7 5 无论如何 我们是否可以解决这个问题 https cloud githubuserconten
  • 如何在 Unity 中从 RenderTexture 访问原始数据

    问题的简短版本 我正在尝试访问 Unity 中 RenderTexture 的内容 我一直在使用 Graphics Blit 使用自己的材质进行绘制 Graphics Blit null renderTexture material 我的材
  • 模板类的不明确多重继承

    我有一个真实的情况 可以总结为以下示例 template lt typename ListenerType gt struct Notifier void add listener ListenerType struct TimeListe
  • 在 Xamarin Android 中将图像从 URL 异步加载到 ImageView 中

    我有一个包含多个项目的 ListView 列表中的每个项目都应该有一个与之关联的图像 我创建了一个数组适配器来保存每个列表项并具有我希望加载的图像的 url 我正在尝试使用 Web 请求异步加载图像 并设置图像并在加载后在视图中更新它 但视
  • C++ 求二维数组每一行的最大值

    我已经设法用这个找到我的二维数组的每一行的最小值 void findLowest int A Cm int n int m int min A 0 0 for int i 0 i lt n i for int j 0 j lt m j if
  • fgets() 和 Ctrl+D,三次才能结束?

    I don t understand why I need press Ctrl D for three times to send the EOF In addition if I press Enter then it only too
  • 使用 Microsoft Graph API 订阅 Outlook 推送通知时出现 400 错误请求错误

    我正在尝试使用 Microsoft Graph API 创建订阅以通过推送通知获取 Outlook 电子邮件 mentions 我在用本文档 https learn microsoft com en us graph api subscri
  • 如何在我的应用程序中使用 Windows Key

    Like Windows Key E Opens a new Explorer Window And Windows Key R Displays the Run command 如何在应用程序的 KeyDown 事件中使用 Windows
  • C# 中值类型和引用类型有什么区别? [复制]

    这个问题在这里已经有答案了 我知道一些差异 值类型存储在堆栈上 而引用类型存储在托管堆上 值类型变量直接包含它们的值 而引用变量仅包含对托管堆上创建的对象位置的引用 我错过了任何其他区别吗 如果是的话 它们是什么 请阅读 堆栈是一个实现细节
  • 将字符串从非托管代码传递到托管

    我在将字符串从非托管代码传递到托管代码时遇到问题 在我的非托管类中 非托管类 cpp 我有一个来自托管代码的函数指针 TESTCALLBACK FUNCTION testCbFunc TESTCALLBACK FUNCTION 接受一个字符
  • 写入和读取文本文件 - C# Windows 通用平台应用程序 Windows 10

    有用 但在显示任何内容之前 您必须在文本框中输入内容 我想那是因为我使用了 TextChanged 事件处理程序 如果我希望它在没有用户交互的情况下显示文本文件的内容 我应该使用哪个事件处理程序 因此 我想在按下按钮时将一些数据写入 C W
  • 基于范围的 for 循环中的未命名循环变量?

    有没有什么方法可以不在基于范围的 for 循环中 使用 循环变量 同时也避免编译器发出有关未使用它的警告 对于上下文 我正在尝试执行以下操作 我启用了 将警告视为错误 并且我不想进行像通过在某处毫无意义地提及变量来强制 使用 变量这样的黑客
  • .Net Core / 控制台应用程序 / 配置 / XML

    我第一次尝试使用新的 ConfigurationBuilder 和选项模式进入 Net Core 库 这里有很多很好的例子 https docs asp net en latest fundamentals configuration ht
  • 在 ASP.Net Core 2.0 中导出到 Excel

    我曾经使用下面的代码在 ASP NET MVC 中将数据导出到 Excel Response AppendHeader content disposition attachment filename ExportedHtml xls Res
  • 使用安全函数在 C 中将字符串添加到字符串

    我想将文件名复制到字符串并附加 cpt 但我无法使用安全函数 strcat s 来做到这一点 错误 字符串不是空终止的 我确实设置了 0 如何使用安全函数修复此问题 size strlen locatie size nieuw char m
  • Windows 窗体不会在调试模式下显示

    我最近升级到 VS 2012 我有一组在 VS 2010 中编码的 UI 测试 我试图在 VS 2012 中启动它们 我有一个 Windows 窗体 在开始时显示使用 AssemblyInitialize 属性运行测试 我使用此表单允许用户
  • 如何在 Team Foundation 上强制发表有意义的签入评论?

    我有一个开发团队有一个坏习惯 他们写道poor签入评论 当我们必须在团队基础上查看文件的历史记录时 这使得它成为一场噩梦 我已经启用了变更集评论政策 这样他们甚至可以在签到时留下评论 否则他们不会 我们就团队的工作质量进行了一些讨论 他们很
  • Windows 10 中 Qt 桌面应用程序的缩放不当

    我正在为 Windows 10 编写一个简单的 Qt Widgets Gui 应用程序 我使用的是 Qt 5 6 0 beta 版本 我遇到的问题是它根本无法缩放到我的 Surfacebook 的屏幕上 这有点难以判断 因为 SO 缩放了图
  • ListDictionary 类是否有通用替代方案?

    我正在查看一些示例代码 其中他们使用了ListDictionary对象来存储少量数据 大约 5 10 个对象左右 但这个数字可能会随着时间的推移而改变 我使用此类的唯一问题是 与我所做的其他所有事情不同 它不是通用的 这意味着 如果我在这里
  • 如何使用 ReactiveList 以便在添加新项目时更新 UI

    我正在创建一个带有列表的 Xamarin Forms 应用程序 itemSource 是一个reactiveList 但是 向列表添加新项目不会更新 UI 这样做的正确方法是什么 列表定义 listView new ListView var

随机推荐