Linux 内核驱动程序从用户空间读取正常,但回写总是0
所以我正在努力完成内核驱动程序编程,目前我正在尝试在应用程序和内核驱动程序之间建立一个简单的数据传输 我使用简单的字符设备作为这两者之间的链接,我已经成功地将数据传输到驱动程序,但我无法将有意义的数据返回到用户空间 内核驱动程序如下所示:Linux 内核驱动程序从用户空间读取正常,但回写总是0,linux,linux-device-driver,kernel-module,serial-communication,Linux,Linux Device Driver,Kernel Module,Serial Communication,所以我正在努力完成内核驱动程序编程,目前我正在尝试在应用程序和内核驱动程序之间建立一个简单的数据传输 我使用简单的字符设备作为这两者之间的链接,我已经成功地将数据传输到驱动程序,但我无法将有意义的数据返回到用户空间 内核驱动程序如下所示: #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> /* printk() */ #include <linux/er
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <asm/uaccess.h> /* copy_from/to_user */
MODULE_LICENSE("GPL");
//Declarations
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);
void memory_exit(void);
int memory_init(void);
/* Structure that declares the usual file access functions */
struct file_operations memory_fops = {
read: memory_read,
write: memory_write,
open: memory_open,
release: memory_release
};
//Default functions
module_init(memory_init);
module_exit(memory_exit);
/* Global variables of the driver */
/* Major number */
int memory_major = 60;
/* Buffer to store data */
char* tx_buffer;
char* rx_buffer;
int BUFFER_SIZE=64;
int actual_rx_size=0;
int memory_init(void) {
int result;
/* Registering device */
result = register_chrdev(memory_major, "move_data", &memory_fops);
if (result < 0) {
printk(
"<1>move_data: cannot obtain major number %d\n", memory_major);
return result;
}
/* Allocating memory for the buffers */
//Allocate buffers
tx_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
rx_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
//Check allocation was ok
if (!tx_buffer || !rx_buffer) {
result = -ENOMEM;
goto fail;
}
//Reset the buffers
memset(tx_buffer,0, BUFFER_SIZE);
memset(rx_buffer,0, BUFFER_SIZE);
printk("<1>Inserting memory module\n");
return 0;
fail:
memory_exit();
return result;
}
void memory_exit(void) {
/* Freeing the major number */
unregister_chrdev(memory_major, "memory");
/* Freeing buffers */
if (tx_buffer) {
kfree(tx_buffer); //Note kfree
}
if (rx_buffer) {
kfree(rx_buffer); //Note kfree
}
printk("<1>Removing memory module\n");
}
//Read function
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) {
printk("user requesting data, our buffer has (%d) \n", actual_rx_size);
/* Transfering data to user space */
int retval = copy_to_user(buf,rx_buffer,actual_rx_size);
printk("copy_to_user returned (%d)", retval);
return retval;
}
ssize_t memory_write( struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
//zero the input buffer
memset(tx_buffer,0,BUFFER_SIZE);
memset(rx_buffer,0,BUFFER_SIZE);
printk("New message from userspace - count:%d\n",count);
int retval = copy_from_user(tx_buffer,buf,count);
printk("copy_from_user returned (%d) we read [%s]\n",retval , tx_buffer);
printk("initialize rx buffer..\n");
memcpy(rx_buffer,tx_buffer, count);
printk("content of rx buffer [%s]\n", rx_buffer);
actual_rx_size = count;
return count; //inform that we read all (fixme?)
}
//Always successfull
int memory_open(struct inode *inode, struct file *filp) { return 0; }
int memory_release(struct inode *inode, struct file *filp) { return 0; }
所以看起来都是正确的。但当我试着阅读时:
./rw read 15
read op
Read 0 bytes from driver string[]
Kernel
[ 617.096521] user requesting data, our buffer has (15)
[ 575.797668] copy_to_user returned (0)
[ 617.096528] copy_to_user returned (0)
我想我做错的事情很简单,因为如果我不返回0,我可以返回一些数据,但例如,如果我用cat读取,它将继续无休止地循环
我想知道我在思想上犯了什么错误。
是否有一种方法,内核驱动程序只需吐出它的缓冲区,然后返回0,这样我就不必在中间构建一些协议来处理读取了多少数据等
谢谢你的建议
编辑:更正了内存写入函数中的printk语句,并添加了内存读取函数跟踪您的读取函数始终返回0,因为您返回的是
retval
,而不是读取的字节数。只要copy\u to_user()
调用始终成功,retval
将始终为0。相反,只要copy\u to\u user()
成功,就应该返回实际写入用户空间的字节数。声明copy\u to\u user()
返回无法复制的字节总数
另一方面,您忽略了count的值。很可能用户请求的数据少于缓冲区中的可用数据。你不应该忽视伯爵
现在出现了函数从不返回0的问题。返回0很重要,因为它告诉用户应用程序没有更多的数据可供读取,用户应用程序应关闭设备文件
您需要在驱动程序中跟踪读取的字节数与写入的字节数。这可以使用您的实际接收大小来实现
试试这个:
//Read function
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) {
ssize_t bytes;
if (actual_rx_size < count)
bytes = actual_rx_size;
else
bytes = count;
printk("user requesting data, our buffer has (%d) \n", actual_rx_size);
/* Check to see if there is data to transfer */
if (bytes == 0)
return 0;
/* Transfering data to user space */
int retval = copy_to_user(buf,rx_buffer,bytes);
if (retval) {
printk("copy_to_user() could not copy %d bytes.\n", retval);
return -EFAULT;
} else {
printk("copy_to_user() succeeded!\n");
actual_rx_size -= bytes;
return bytes;
}
}
//读取函数
ssize_t memory_read(结构文件*filp,字符*buf,大小计数,loff_t*f_pos){
ssize_t字节;
if(实际接收尺寸<计数)
字节=实际接收大小;
其他的
字节=计数;
printk(“请求数据的用户,我们的缓冲区有(%d)\n”,实际大小);
/*检查是否有数据要传输*/
如果(字节==0)
返回0;
/*将数据传输到用户空间*/
int retval=复制到用户(buf,接收缓冲区,字节);
如果(返回){
printk(“复制到用户()无法复制%d字节。\n”,retval);
返回-默认值;
}否则{
printk(“复制到用户()成功!\n”);
实际_rx_大小-=字节;
返回字节;
}
}
Benjamin,你的钱是对的。跟踪发送的内容是实现这一点的关键。很好的解决方案,完全符合我的期望!谢谢最后一个printk语句缺少“;”。哦,很抱歉。我在家里没有开发系统,所以我没有机会编译它。现在已修复。感谢@BenjaminLeinweber..我在写函数方面遇到问题。返回0会以某种方式将其发送到无限循环。现在我知道原因:)@SteveIrwin-为什么返回0会导致循环?我也在讨论这个问题。答案清楚地表明,每次你需要返回读取的字节数,否则它将进入无限循环。如果你发布代码,我们可能能够追踪罪犯。
./rw read 15
read op
Read 0 bytes from driver string[]
Kernel
[ 617.096521] user requesting data, our buffer has (15)
[ 575.797668] copy_to_user returned (0)
[ 617.096528] copy_to_user returned (0)
//Read function
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) {
ssize_t bytes;
if (actual_rx_size < count)
bytes = actual_rx_size;
else
bytes = count;
printk("user requesting data, our buffer has (%d) \n", actual_rx_size);
/* Check to see if there is data to transfer */
if (bytes == 0)
return 0;
/* Transfering data to user space */
int retval = copy_to_user(buf,rx_buffer,bytes);
if (retval) {
printk("copy_to_user() could not copy %d bytes.\n", retval);
return -EFAULT;
} else {
printk("copy_to_user() succeeded!\n");
actual_rx_size -= bytes;
return bytes;
}
}