我的内核模块代码需要将信号发送到用户陆地程序,以将其执行转移到已注册的信号处理程序。
实际上,我为嵌入式板开发了一个C程序,当按BUTTON(输入事件)时,LED会亮起和熄灭。另一方面,我刚刚开发了一个具有其基本功能(OPEN,CLOSE,READ,WRITE)的简单Linux模块。
我只是不知道如何修改我的主体程序和内核模块,以达到我的目标。
我与您分享我的用户空间计划:
#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
和read
文件操作,以便用户代码可以等待设备中的事件并读取它们。
无论如何,要向打开设备的进程发送信号,您需要做的是:
您需要在设备的私人数据中输入struct fasync_struct *
:
struct fasync_struct *pasync_queue;
在设备专用数据初始化期间,需要通过某种方式将其初始化为
NULL
。您的操作方式取决于您。您需要一个由
fasync
的struct file_operations
成员指向的fasync文件操作处理程序。 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,
};
您的设备驱动程序可以通过调用
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);
N.B.最后一个参数(在这种情况下为值
POLL_IN
)影响应用程序在其信号处理程序中看到的si_band
的siginfo_t
成员的值。您的应用程序需要为
SIGIO
信号设置信号处理程序。我建议使用sigaction()
进行设置。您的应用程序在打开设备文件时需要设置
O_ASYNC
标志,或者在打开设备文件后通过调用fcntl(fd, F_SETFL, O_ASYNC);
进行设置。关于c - 如何从Linux内核空间向用户空间发送信号以通知输入硬件事件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58639288/