对于家庭作业,我写了一个角色设备驱动程序。它似乎工作正常。我可以读写它。问题是,当我读取设备时,它会无休止地循环,一遍又一遍地打印出消息缓冲区的内容。
这似乎应该是相当直接的。只需使用copy_to_user(),但事实证明这是非常有问题的。
无论如何,这是代码。我认为问题出在gdev_read()函数中。 printk用作调试和谈话点,因为我必须在课堂上展示这个项目。
/*
* Implement a generic character pseudo-device driver
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
/* you need these, or the kernel will be tainted */
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple sample character device driver");
/*
* function prototypes
*/
int init_module(void);
void cleanup_module(void);
static ssize_t gdev_read(struct file *, char *, size_t, loff_t *);
static ssize_t gdev_write(struct file *, const char *, size_t, loff_t *);
static int gdev_open(struct inode *, struct file *);
static int gdev_release(struct inode *, struct file *);
/* macros */
#define TRUE 1
#define FALSE 0
#define MAX_MSG_LEN 64
/*
* global variables
*/
static dev_t dev_num; /* device number, for new device */
static char *mesg; /* buffer for message */
/* file operations structure, so my device knows how to act */
static struct file_operations fops = {
.owner = THIS_MODULE,
.read = gdev_read,
.write = gdev_write,
.open = gdev_open,
.release = gdev_release,
};
/* character device struct. Declaired here, but initialized elsewhere */
struct cdev *gdev;
int init_module(void)
{
int err;
printk(KERN_ALERT "in init_module\n");
if(alloc_chrdev_region(&dev_num, 0, 1, "/dev/gdev")){
printk(KERN_INFO "Could not allocate device numbers\n");
printk(KERN_INFO "Module gdev not loaded\n");
return -1;
}
/* now I need to make the device and register it */
gdev = cdev_alloc();
gdev->owner = THIS_MODULE;
gdev->ops = &fops;
err = cdev_add(gdev, dev_num, 1);
if(err){
printk(KERN_NOTICE "Error %d adding gdev", err);
return err;
}
mesg = (char *)vmalloc(MAX_MSG_LEN);
printk(KERN_INFO "Module gdev successfully loaded.\n");
printk(KERN_INFO "gdev Major Number: %d\n", MAJOR(dev_num));
return 0;
}
void cleanup_module(void)
{
printk(KERN_ALERT "in cleanup_module\n");
unregister_chrdev_region(dev_num, 3);
vfree(mesg);
cdev_del( gdev );
printk(KERN_INFO "Module gdev unregistered\n");
}
static ssize_t gdev_read(struct file *filp, char *page,
size_t len, loff_t *offset)
{
ssize_t bytes = len < MAX_MSG_LEN ? len : MAX_MSG_LEN;
printk(KERN_ALERT "in gdev_read\n");
if(copy_to_user(page, mesg, bytes)){
return -EFAULT;
}
return bytes;
}
static ssize_t gdev_write(struct file *filp, const char *page,
size_t len, loff_t *offset)
{
ssize_t bytes = len < MAX_MSG_LEN ? len : MAX_MSG_LEN;
printk(KERN_ALERT "in gdev_write\n");
if(copy_from_user(mesg, page, bytes)){
return -EFAULT;
}
return bytes;
}
static int gdev_open(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "in gdev_open\n");
return 0;
}
static int gdev_release(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "in gdev_release\n");
/* doesn't do anything because it doesn't need too */
return 0;
}
答案 0 :(得分:7)
如果未从read()
返回零(在您的情况下为gdev_read()
),则将再次调用读取函数。
要停止此操作,请使用loff_t *offset
参数。在(*offset) += bytes;
之后使用copy_to_user()
读取的字节数增加。下次调用read()
时,offset
将是您将其递增到的值。现在只需检查您之前发送的字节数,并仅发送剩余的内容。你的功能应如下所示:
static ssize_t gdev_read(struct file *filp, char *page,
size_t len, loff_t *offset)
{
ssize_t bytes = len < (MAX_MSG_LEN-(*offset)) ? len : (MAX_MSG_LEN-(*offset));
printk(KERN_ALERT "in gdev_read\n");
if(copy_to_user(page, mesg, bytes)){
return -EFAULT;
}
(*offset) += bytes;
return bytes;
}
答案 1 :(得分:0)
您可以使用'linux / fs.h'中的'simple_read_from_buffer'函数:
static ssize_t gdev_read(struct file *filep, char __user *buff, size_t count, loff_t *offp)
{
return simple_read_from_buffer(buff, count, offp, my_buffer, buffer_len);
}
您的模块中定义了' my_buffer '和' buffer_len '。