#include <linux/miscdevice.h>
#include <linux/kfifo.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/mutex.h>
#include <linux/module.h>
#define DEV_NAME "ko_dev"
#define BUFFER_SIZE 32
DEFINE_KFIFO(FIFOBuffer, char, BUFFER_SIZE);
struct mutex BufferMutex;
static struct device *misc_device;
wait_queue_head_t read_queue;
wait_queue_head_t write_queue;
void show_fifo_content(void)
{
char buf[BUFFER_SIZE];
unsigned int copied;
mutex_lock(&BufferMutex);
copied = kfifo_out_peek(&FIFOBuffer, buf, BUFFER_SIZE);
mutex_unlock(&BufferMutex);
buf[copied] = '\0'; // Null-terminate the string
printk(KERN_INFO "ko_dev: KFIFO content: %s\n", buf);
}
static int device_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "ko_dev: Device opened\n");
show_fifo_content();
return 0;
}
static int device_release(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "ko_dev: Device released\n");
return 0;
}
static ssize_t device_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
int read = 0, ret = 0;
if (kfifo_is_empty(&FIFOBuffer))
{
if (file->f_flags & O_NONBLOCK)
return 0;
printk(KERN_INFO "ko_dev: Read process is blocked, needs space: %zu, available space: %u\n",
count, kfifo_len(&FIFOBuffer));
wait_event_interruptible(read_queue, !kfifo_is_empty(&FIFOBuffer));
}
// Lock the FIFO, read from it and then unlock
mutex_lock(&BufferMutex);
ret = kfifo_to_user(&FIFOBuffer, buf, count, &read);
mutex_unlock(&BufferMutex);
// If FIFO is not full, wake up any blocked write process
if (!kfifo_is_full(&FIFOBuffer))
{
printk(KERN_INFO "ko_dev: Wake up write process\n");
wake_up_interruptible(&write_queue);
}
show_fifo_content();
return read;
}
// Device write function
static ssize_t device_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
int write = 0, ret = 0;
// If FIFO is full, block the write process until there's space
if (kfifo_is_full(&FIFOBuffer))
{
if (file->f_flags & O_NONBLOCK)
return 0;
printk(KERN_INFO "ko_dev: Write process is blocked, needs space: %zu, available space: %u\n",
count, BUFFER_SIZE - kfifo_len(&FIFOBuffer));
wait_event_interruptible(write_queue, !kfifo_is_full(&FIFOBuffer));
}
// Lock the FIFO, write to it and then unlock
mutex_lock(&BufferMutex);
ret = kfifo_from_user(&FIFOBuffer, buf, count, &write);
mutex_unlock(&BufferMutex);
// If FIFO is not empty, wake up any blocked read process
if (!kfifo_is_empty(&FIFOBuffer))
{
printk(KERN_INFO "ko_dev: Wake up read process\n");
wake_up_interruptible(&read_queue);
}
show_fifo_content();
return write;
}
// File operations structure
static const struct file_operations DevFops = {
.owner = THIS_MODULE,
.open = device_open,
.release = device_release,
.read = device_read,
.write = device_write,
};
// Misc device structure
static struct miscdevice miscDeviceFIFOBlock = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEV_NAME,
.fops = &DevFops,
};
// Module initialization function
static int __init device_init(void)
{
// Register the misc device
int ret = misc_register(&miscDeviceFIFOBlock);
if (ret < 0)
{
printk(KERN_ERR "ko_dev: Failed to init\n");
return ret;
}
// Initialize the mutex
mutex_init(&BufferMutex);
// Set the device
misc_device = miscDeviceFIFOBlock.this_device;
// Initialize the wait queues for read and write
init_waitqueue_head(&read_queue);
init_waitqueue_head(&write_queue);
printk(KERN_INFO "ko_dev: Init successfully\n");
return ret;
}
// Module exit function
static void __exit device_exit(void)
{
// Unregister the misc device
misc_deregister(&miscDeviceFIFOBlock);
printk(KERN_INFO "ko_dev: Exited\n");
}
// Specify the init and exit functions
module_init(device_init);
module_exit(device_exit);
// Module metadata
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Liangruiying");
MODULE_DESCRIPTION("A simple device");
【无标题】ko_dev驱动程序
最新推荐文章于 2024-08-04 11:11:47 发布