据我所知,要从内核空间通知用户空间,一种方法是使用轮询。这意味着内核驱动程序应首先提供轮询方法。下面的代码是从互联网上找到的,它确实有效!
#include <linux/module.h> #include <linux/kernel.h> #include <linux/proc_fs.h> #include <linux/string.h> #include <linux/vmalloc.h> #include <asm/uaccess.h> MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Fortune Cookie Kernel Module"); MODULE_AUTHOR("M. Tim Jones"); #define MAX_COOKIE_LENGTH PAGE_SIZE static struct proc_dir_entry *proc_entry; static char *cookie_buf; // Space for fortune strings static int write_index; // Index to write next fortune static int read_index; // Index to read next fortune ssize_t fortune_write( struct file *filp, const char __user *buff, unsigned long len, void *data ) // Refer to: ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); { int space_available = (MAX_COOKIE_LENGTH-write_index); if (len > space_available) { printk(KERN_INFO "fortune: cookie buffer is full!\n"); return -ENOSPC; } if (copy_from_user( &cookie_buf[write_index], buff, len )) { return -EFAULT; } write_index += len; cookie_buf[write_index-1] = 0; return len; } ssize_t fortune_read(struct file *file, char *buf, size_t count, loff_t *f_pos){ // Refer to: ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); int len; //there's no fortune or a fortune has already been read //the *f_pos > 0 hack is needed because `cat /proc/fortune` would otherwise //display every thing in the cookie_buf if(write_index == 0 || *f_pos > 0){ return 0; } // cicle through fortunes if(read_index >= write_index){ read_index = 0; } len = sprintf(buf, "%s\n", &cookie_buf[read_index]); read_index += len; *f_pos += len; return len; } static const struct file_operations proc_test_fops = { .owner = THIS_MODULE, // .open = led_proc_open, .read = fortune_read, // .llseek = seq_lseek, // .release = single_release, .write = fortune_write, // unsigned int (*poll) (struct file *, struct poll_table_struct *); // int (*fasync) (int, struct file *, int); }; int __init init_fortune_module( void ) { int ret = 0; cookie_buf = (char *)vmalloc( MAX_COOKIE_LENGTH ); if (!cookie_buf) { ret = -ENOMEM; } else { memset( cookie_buf, 0, MAX_COOKIE_LENGTH ); // proc_entry = create_proc_entry( "fortune", 0644, NULL ); proc_entry = proc_create( "fortune", 0644, NULL, &proc_test_fops ); if (proc_entry == NULL) { ret = -ENOMEM; vfree(cookie_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 ) { // remove_proc_entry("fortune", &proc_entry); proc_remove(proc_entry); vfree(cookie_buf); printk(KERN_INFO "fortune: Module unloaded.\n"); } module_init( init_fortune_module ); module_exit( exit_fortune_module );
我可以这样使它起作用:
echo "hello" > /proc/fortune
然后
cat /proc/fortune
看结果。
但是如何添加轮询方法呢?我试了几次,但还是失败了。有人可以帮忙吗?谢谢!
您可以在内核本身中找到一些很好的示例。看下一个文件:
要将poll()功能添加到代码中,请遵循以下步骤。
poll()
#include <linux/wait.h> #include <linux/poll.h>
static DECLARE_WAIT_QUEUE_HEAD(fortune_wait);
fortune_poll()
.poll
static unsigned int fortune_poll(struct file *file, poll_table *wait) { poll_wait(file, &fortune_wait, wait); if (new-data-is-ready) return POLLIN | POLLRDNORM; return 0; } static const struct file_operations proc_test_fops = { .... .poll = fortune_poll, };
请注意,POLLIN | POLLRDNORM如果您有一些新数据要读取,并且0没有新数据要读取(poll()呼叫超时),则应返回。有关详细信息,请参见man2民意调查。
POLLIN | POLLRDNORM
0
wake_up_interruptible(&fortune_wait);
这是实现poll()操作的基本内容。根据您的任务,可能需要在函数中使用一些waitqueue API.read(例如wait_event_interruptible())。
.read
wait_event_interruptible()