如何在内核模块代码中添加 fasync 函数?
How to add fasync function to the kernel module code?
套件:Beagle Bone Black,OS:Angstrom,内核:
root@beaglebone:~# uname -a
Linux beaglebone 3.12.9-00018-g9bdb229-dirty #67 SMP Sat Apr 18 11:45:30 CST 2015 armv7l GNU/Linux
我想在我的内核模块中添加 fasync 功能,但效果不佳。下面的代码来自互联网,我对其进行了修改(尝试添加 fasync)。它可以 运行 在 Beagle Bone Black 上。我简化了 write()、read() 和 poll() 函数。并将 kill_fasync() 放入 irq 处理程序中。
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Fortune Cookie Kernel Module");
MODULE_AUTHOR("M. Tim Jones");
#define MAX_BUF_LENGTH PAGE_SIZE
static struct proc_dir_entry *proc_entry;
static char *fortune_buf; // Space for fortune strings
static int write_index; // Index to write next fortune
static int read_index; // Index to read next fortune
static DEFINE_SPINLOCK(fortune_lock);
static DECLARE_WAIT_QUEUE_HEAD(fortune_wait);
static volatile unsigned long fortune_data_flag; /* our output to the world */
static struct fasync_struct *fortune_async_queue = NULL;
#define GPIO2_START_ADDR 0x481ac000
#define GPIO2_SIZE (0x481adfff - GPIO2_START_ADDR)
#define CM_PER_START_ADDR 0x44e00000
#define CM_PER_SIZE 0x400
#define CM_PER_GPIO2_CLKCTRL 0xb0 // page 948
#define GPIO_IRQSTATUS_0 0x2c
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_DATAIN 0x138 // page 4657
#define GPIO_OE 0x134 // page 4656
#define GPIO_FALLINGDETECT 0x14c
#define GPIO_DEBOUNCENABLE 0x150 // page 4663
#define GPIO_DEBOUNCINGTIME 0x154 // page 4664
#define PIN_A_GPIO 68 // is on BBB connector P8 pin10/TIMER6/GPIO2_4
#define PIN_A_FLAGS GPIOF_IN
#define PIN_A_LABEL "HI_PIN_A" // when floating, its level is high, 3.19~3.20V
#define PIN_B_GPIO 69 // is on BBB connector P8 pin9/TIMER5/GPIO2_5
#define PIN_B_FLAGS GPIOF_IN
#define PIN_B_LABEL "HI_PIN_B"
void __iomem *mem;
static irqreturn_t irq_handler_pin_a (int irq, void *dev_id)
{
int regval;
int regval_a, regval_b;
regval = ioread32 (mem + GPIO_DATAIN);
printk (KERN_DEBUG "interrupt: Hello from irq_handler_pin_a. The GPIO b read value is %x - %d \n", regval, (regval & 0x20) >> 5);
regval_a = (regval & 0x10) >> 4;
regval_b = (regval & 0x20) >> 5;
printk(KERN_DEBUG "irq 0: fortune_async_queue is 0x%p", fortune_async_queue);
if(regval_a == regval_b) {
printk (KERN_DEBUG "interrupt: 1 \n");
} else {
printk (KERN_DEBUG "interrupt: 2 \n");
}
kill_fasync(&fortune_async_queue, SIGIO, POLL_IN);
printk(KERN_DEBUG "irq 1: fortune_async_queue is 0x%p", fortune_async_queue);
return IRQ_HANDLED;
}
static int gpio_interrupt_init (void)
{
...
}
static void gpio_interrupt_exit(void)
{
printk ("HI: Releasing IRQ resources...\n");
iounmap (mem);
free_irq (gpio_to_irq (PIN_A_GPIO), NULL);
gpio_free (PIN_A_GPIO);
gpio_free (PIN_B_GPIO);
printk (KERN_DEBUG "Goodbye gpio_interrupt!\n");
}
ssize_t fortune_write( struct file *filp, const char __user *buff,
unsigned long len, void *data )
{
printk(KERN_INFO "fortune_write() executes\n");
return len;
}
ssize_t fortune_read(struct file *file, char *buf, size_t count, loff_t *f_pos)
{
int len;
printk(KERN_INFO "fortune_read() executes\n");
return len;
}
static unsigned int fortune_poll(struct file *file, poll_table *wait)
{
printk(KERN_INFO "fortune_poll() executes\n");
return 0;
}
static int fortune_fasync(int fd, struct file *file, int on)
{
printk("fortune_fasync() executes\n");
if(!fortune_async_queue)
{
if (fasync_helper(fd, file, 1, &fortune_async_queue) >= 0)
{
printk(KERN_DEBUG "fasync 0: fasync_helper works. fortune_async_queue is 0x%p", fortune_async_queue);
return 0;
}
else
{
printk(KERN_DEBUG "fasync 1: fasync_helper doesn't work. fortune_async_queue is 0x%p", fortune_async_queue);
return -EIO;
}
}
else
{
printk(KERN_DEBUG "fasync 2: fasync_helper doesn't work. fortune_async_queue is 0x%p", fortune_async_queue);
}
}
static int fortune_release(struct inode *inode, struct file *file)
{
struct fortune_dev *devp;
devp = file->private_data;
fortune_fasync(-1, file, 0);
file->private_data = NULL;
return 0;
}
static int fortune_open(struct inode *inode, struct file *file)
{
return 0;
}
static const struct file_operations proc_test_fops = {
.owner = THIS_MODULE,
.open = fortune_open,
.read = fortune_read,
.write = fortune_write,
.poll = fortune_poll,
.release = fortune_release,
.fasync = fortune_fasync,
};
int __init init_fortune_module( void )
{
int ret = 0;
gpio_interrupt_init();
fortune_buf = (char *)vmalloc( MAX_BUF_LENGTH );
if (!fortune_buf) {
ret = -ENOMEM;
} else {
memset( fortune_buf, 0, MAX_BUF_LENGTH );
proc_entry = proc_create( "fortune", 0644, NULL, &proc_test_fops );
if (proc_entry == NULL) {
ret = -ENOMEM;
vfree(fortune_buf);
printk(KERN_INFO "fortune: Couldn't create proc entry\n");
} else
write_index = 0;
read_index = 0;
printk(KERN_INFO "fortune: Module loaded.\n");
}
return ret;
}
void __exit exit_fortune_module( void )
{
gpio_interrupt_exit();
proc_remove(proc_entry);
vfree(fortune_buf);
printk(KERN_INFO "fortune: Module unloaded.\n");
}
module_init( init_fortune_module );
module_exit( exit_fortune_module );
我也找到这个用户space的代码,它被编译成a.out
:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fd;
void my_signal_io_fun(int signum)
{
printf("SIGIO occurs!\n");
}
void my_signal_int_fun(int signum)
{
printf("signum: 0x%x\n", signum);
close(fd);
exit(signum);
}
int main(int argc, char **argv)
{
unsigned char key_val;
int ret;
int Oflags;
signal(SIGIO, my_signal_io_fun);
signal(SIGINT, my_signal_int_fun);
fd = open("/proc/fortune", O_RDWR);
if (fd < 0)
{
printf("can't open!\n");
}
printf("open OK, fd = 0x%x\n", fd);
fcntl(fd, F_SETOWN, getpid());
Oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, Oflags | FASYNC);
while (1)
{
sleep(1000);
}
return 0;
}
然后我将模块上传到我的 Beagle Bone Black,如下所示:
root@beaglebone:~# insmod fasync_kernel.ko
root@beaglebone:~# cat /proc/fortune
root@beaglebone:~# ./a.out
open OK, fd = 0x3
SIGIO occurs!
SIGIO occurs!
SIGIO occurs!
SIGIO occurs!
^Csignum: 0x2
我在相应的GPIO上做了一些中断,然后显示SIGIO occurs!
。但问题是我必须在 运行 用户 space 代码 (a.out
) 之前先执行 cat /proc/fortune
。而且它并不总是像上面那样工作。通常我需要 rmmod - insmod - cat - a.out
两次,然后 fasync 代码才能工作。 dmesg 如下:
[ 5512.325893] fortune: Module loaded.
[ 5514.950859] fortune_read() executes
[ 5514.950932] fortune_fasync() executes
[ 5518.915844] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f2d - 1
[ 5514.950961] fasync 0: fasync_helper works. fortune_async_queue is 0xdf63eb18
[ 5518.915881] irq 0: fortune_async_queue is 0xdf63eb18
[ 5518.915895] interrupt: 2
[ 5518.915950] irq 1: fortune_async_queue is 0xdf63eb18
[ 5519.610571] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f2d - 1
[ 5519.610601] irq 0: fortune_async_queue is 0xdf63eb18
[ 5519.610612] interrupt: 2
[ 5519.610666] irq 1: fortune_async_queue is 0xdf63eb18
[ 5520.260265] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f0d - 0
[ 5520.260295] irq 0: fortune_async_queue is 0xdf63eb18
[ 5520.260306] interrupt: 1
[ 5520.260357] irq 1: fortune_async_queue is 0xdf63eb18
[ 5521.185887] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f0d - 0
[ 5521.185916] irq 0: fortune_async_queue is 0xdf63eb18
[ 5521.185926] interrupt: 1
[ 5522.777769] fortune_fasync() executes
[ 5521.185976] irq 1: fortune_async_queue is 0xdf63eb18
[ 5522.777812] fasync 2: fasync_helper doesn't work. fortune_async_queue is 0xdf63eb18
我的问题是为什么我必须在用户 space 代码执行之前执行 cat /proc/fortune
?有什么更好的办法吗?如何稳定运行?如何避免 运行 循环 (rmmod - insmod - cat - a.out
) 两次?
我在 fortune_async_queue
周围添加了一些 if-else,因为如果我简单地使用 fasync_helper()
和 kill_fasync()
,fortune_async_queue
将始终是 null
。而对于这个func:static int fortune_fasync(int fd, struct file *file, int on)
,我发现它的最后一个参数on
总是0,为什么呢?我必须手动将它设置为 1,如上面的代码:fasync_helper(fd, file, 1, &fortune_async_queue)
您正在使用 "insmod",它接受文件路径,但不会自动加载依赖项。因此,您必须在用户 space 代码执行加载依赖项之前执行 cat /proc/fortune。
您可以尝试 "modprobe" 代替 "insmod"。它会默认加载依赖项。
默认情况下,文件描述符的异步通知处于关闭状态。因此,on = 0 总是。
套件:Beagle Bone Black,OS:Angstrom,内核:
root@beaglebone:~# uname -a
Linux beaglebone 3.12.9-00018-g9bdb229-dirty #67 SMP Sat Apr 18 11:45:30 CST 2015 armv7l GNU/Linux
我想在我的内核模块中添加 fasync 功能,但效果不佳。下面的代码来自互联网,我对其进行了修改(尝试添加 fasync)。它可以 运行 在 Beagle Bone Black 上。我简化了 write()、read() 和 poll() 函数。并将 kill_fasync() 放入 irq 处理程序中。
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Fortune Cookie Kernel Module");
MODULE_AUTHOR("M. Tim Jones");
#define MAX_BUF_LENGTH PAGE_SIZE
static struct proc_dir_entry *proc_entry;
static char *fortune_buf; // Space for fortune strings
static int write_index; // Index to write next fortune
static int read_index; // Index to read next fortune
static DEFINE_SPINLOCK(fortune_lock);
static DECLARE_WAIT_QUEUE_HEAD(fortune_wait);
static volatile unsigned long fortune_data_flag; /* our output to the world */
static struct fasync_struct *fortune_async_queue = NULL;
#define GPIO2_START_ADDR 0x481ac000
#define GPIO2_SIZE (0x481adfff - GPIO2_START_ADDR)
#define CM_PER_START_ADDR 0x44e00000
#define CM_PER_SIZE 0x400
#define CM_PER_GPIO2_CLKCTRL 0xb0 // page 948
#define GPIO_IRQSTATUS_0 0x2c
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_DATAIN 0x138 // page 4657
#define GPIO_OE 0x134 // page 4656
#define GPIO_FALLINGDETECT 0x14c
#define GPIO_DEBOUNCENABLE 0x150 // page 4663
#define GPIO_DEBOUNCINGTIME 0x154 // page 4664
#define PIN_A_GPIO 68 // is on BBB connector P8 pin10/TIMER6/GPIO2_4
#define PIN_A_FLAGS GPIOF_IN
#define PIN_A_LABEL "HI_PIN_A" // when floating, its level is high, 3.19~3.20V
#define PIN_B_GPIO 69 // is on BBB connector P8 pin9/TIMER5/GPIO2_5
#define PIN_B_FLAGS GPIOF_IN
#define PIN_B_LABEL "HI_PIN_B"
void __iomem *mem;
static irqreturn_t irq_handler_pin_a (int irq, void *dev_id)
{
int regval;
int regval_a, regval_b;
regval = ioread32 (mem + GPIO_DATAIN);
printk (KERN_DEBUG "interrupt: Hello from irq_handler_pin_a. The GPIO b read value is %x - %d \n", regval, (regval & 0x20) >> 5);
regval_a = (regval & 0x10) >> 4;
regval_b = (regval & 0x20) >> 5;
printk(KERN_DEBUG "irq 0: fortune_async_queue is 0x%p", fortune_async_queue);
if(regval_a == regval_b) {
printk (KERN_DEBUG "interrupt: 1 \n");
} else {
printk (KERN_DEBUG "interrupt: 2 \n");
}
kill_fasync(&fortune_async_queue, SIGIO, POLL_IN);
printk(KERN_DEBUG "irq 1: fortune_async_queue is 0x%p", fortune_async_queue);
return IRQ_HANDLED;
}
static int gpio_interrupt_init (void)
{
...
}
static void gpio_interrupt_exit(void)
{
printk ("HI: Releasing IRQ resources...\n");
iounmap (mem);
free_irq (gpio_to_irq (PIN_A_GPIO), NULL);
gpio_free (PIN_A_GPIO);
gpio_free (PIN_B_GPIO);
printk (KERN_DEBUG "Goodbye gpio_interrupt!\n");
}
ssize_t fortune_write( struct file *filp, const char __user *buff,
unsigned long len, void *data )
{
printk(KERN_INFO "fortune_write() executes\n");
return len;
}
ssize_t fortune_read(struct file *file, char *buf, size_t count, loff_t *f_pos)
{
int len;
printk(KERN_INFO "fortune_read() executes\n");
return len;
}
static unsigned int fortune_poll(struct file *file, poll_table *wait)
{
printk(KERN_INFO "fortune_poll() executes\n");
return 0;
}
static int fortune_fasync(int fd, struct file *file, int on)
{
printk("fortune_fasync() executes\n");
if(!fortune_async_queue)
{
if (fasync_helper(fd, file, 1, &fortune_async_queue) >= 0)
{
printk(KERN_DEBUG "fasync 0: fasync_helper works. fortune_async_queue is 0x%p", fortune_async_queue);
return 0;
}
else
{
printk(KERN_DEBUG "fasync 1: fasync_helper doesn't work. fortune_async_queue is 0x%p", fortune_async_queue);
return -EIO;
}
}
else
{
printk(KERN_DEBUG "fasync 2: fasync_helper doesn't work. fortune_async_queue is 0x%p", fortune_async_queue);
}
}
static int fortune_release(struct inode *inode, struct file *file)
{
struct fortune_dev *devp;
devp = file->private_data;
fortune_fasync(-1, file, 0);
file->private_data = NULL;
return 0;
}
static int fortune_open(struct inode *inode, struct file *file)
{
return 0;
}
static const struct file_operations proc_test_fops = {
.owner = THIS_MODULE,
.open = fortune_open,
.read = fortune_read,
.write = fortune_write,
.poll = fortune_poll,
.release = fortune_release,
.fasync = fortune_fasync,
};
int __init init_fortune_module( void )
{
int ret = 0;
gpio_interrupt_init();
fortune_buf = (char *)vmalloc( MAX_BUF_LENGTH );
if (!fortune_buf) {
ret = -ENOMEM;
} else {
memset( fortune_buf, 0, MAX_BUF_LENGTH );
proc_entry = proc_create( "fortune", 0644, NULL, &proc_test_fops );
if (proc_entry == NULL) {
ret = -ENOMEM;
vfree(fortune_buf);
printk(KERN_INFO "fortune: Couldn't create proc entry\n");
} else
write_index = 0;
read_index = 0;
printk(KERN_INFO "fortune: Module loaded.\n");
}
return ret;
}
void __exit exit_fortune_module( void )
{
gpio_interrupt_exit();
proc_remove(proc_entry);
vfree(fortune_buf);
printk(KERN_INFO "fortune: Module unloaded.\n");
}
module_init( init_fortune_module );
module_exit( exit_fortune_module );
我也找到这个用户space的代码,它被编译成a.out
:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fd;
void my_signal_io_fun(int signum)
{
printf("SIGIO occurs!\n");
}
void my_signal_int_fun(int signum)
{
printf("signum: 0x%x\n", signum);
close(fd);
exit(signum);
}
int main(int argc, char **argv)
{
unsigned char key_val;
int ret;
int Oflags;
signal(SIGIO, my_signal_io_fun);
signal(SIGINT, my_signal_int_fun);
fd = open("/proc/fortune", O_RDWR);
if (fd < 0)
{
printf("can't open!\n");
}
printf("open OK, fd = 0x%x\n", fd);
fcntl(fd, F_SETOWN, getpid());
Oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, Oflags | FASYNC);
while (1)
{
sleep(1000);
}
return 0;
}
然后我将模块上传到我的 Beagle Bone Black,如下所示:
root@beaglebone:~# insmod fasync_kernel.ko
root@beaglebone:~# cat /proc/fortune
root@beaglebone:~# ./a.out
open OK, fd = 0x3
SIGIO occurs!
SIGIO occurs!
SIGIO occurs!
SIGIO occurs!
^Csignum: 0x2
我在相应的GPIO上做了一些中断,然后显示SIGIO occurs!
。但问题是我必须在 运行 用户 space 代码 (a.out
) 之前先执行 cat /proc/fortune
。而且它并不总是像上面那样工作。通常我需要 rmmod - insmod - cat - a.out
两次,然后 fasync 代码才能工作。 dmesg 如下:
[ 5512.325893] fortune: Module loaded.
[ 5514.950859] fortune_read() executes
[ 5514.950932] fortune_fasync() executes
[ 5518.915844] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f2d - 1
[ 5514.950961] fasync 0: fasync_helper works. fortune_async_queue is 0xdf63eb18
[ 5518.915881] irq 0: fortune_async_queue is 0xdf63eb18
[ 5518.915895] interrupt: 2
[ 5518.915950] irq 1: fortune_async_queue is 0xdf63eb18
[ 5519.610571] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f2d - 1
[ 5519.610601] irq 0: fortune_async_queue is 0xdf63eb18
[ 5519.610612] interrupt: 2
[ 5519.610666] irq 1: fortune_async_queue is 0xdf63eb18
[ 5520.260265] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f0d - 0
[ 5520.260295] irq 0: fortune_async_queue is 0xdf63eb18
[ 5520.260306] interrupt: 1
[ 5520.260357] irq 1: fortune_async_queue is 0xdf63eb18
[ 5521.185887] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f0d - 0
[ 5521.185916] irq 0: fortune_async_queue is 0xdf63eb18
[ 5521.185926] interrupt: 1
[ 5522.777769] fortune_fasync() executes
[ 5521.185976] irq 1: fortune_async_queue is 0xdf63eb18
[ 5522.777812] fasync 2: fasync_helper doesn't work. fortune_async_queue is 0xdf63eb18
我的问题是为什么我必须在用户 space 代码执行之前执行 cat /proc/fortune
?有什么更好的办法吗?如何稳定运行?如何避免 运行 循环 (rmmod - insmod - cat - a.out
) 两次?
我在 fortune_async_queue
周围添加了一些 if-else,因为如果我简单地使用 fasync_helper()
和 kill_fasync()
,fortune_async_queue
将始终是 null
。而对于这个func:static int fortune_fasync(int fd, struct file *file, int on)
,我发现它的最后一个参数on
总是0,为什么呢?我必须手动将它设置为 1,如上面的代码:fasync_helper(fd, file, 1, &fortune_async_queue)
您正在使用 "insmod",它接受文件路径,但不会自动加载依赖项。因此,您必须在用户 space 代码执行加载依赖项之前执行 cat /proc/fortune。
您可以尝试 "modprobe" 代替 "insmod"。它会默认加载依赖项。
默认情况下,文件描述符的异步通知处于关闭状态。因此,on = 0 总是。