我正在摆弄一个 scull 驱动程序代码,然后试图让它打印输入的整个字符,而不是一个。那就是:
# insmod memory.ko
# chmod 666 /dev/memory
$ echo -n abcdef >/dev/memory
$ cat /dev/memory
应该打印 abcdef,但只打印 f
为此,我对 scull 代码进行了如下修改:
ssize_t memory_read(struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
/* Transfering data to user space */
copy_to_user(buf,memory_buffer,5);
/* Changing reading position as best suits */
if (*f_pos == 0) {
*f_pos+=1;
return 1;
} else {
return 0;
}
}
ssize_t memory_write( struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
char *tmp;
tmp=buf+count-1;
copy_from_user(memory_buffer,tmp,5);
return 1;
}
int memory_init(void) {
int result;
/* Registering device */
result = register_chrdev(memory_major, "memory", &memory_fops);
if (result < 0) {
printk(
"<1>memory: cannot obtain major number %d\n", memory_major);
return result;
}
/* Allocating memory for the buffer */
memory_buffer = kmalloc(5, GFP_KERNEL);
if (!memory_buffer) {
result = -ENOMEM;
goto fail;
}
memset(memory_buffer, 0, 5);
printk("<1>Inserting memory module\n");
return 0;
fail:
memory_exit();
return result;
}
最佳答案
read
未正确实现。它不应该向用户写入超过 count
个字节(他可以有更小的缓冲区)。更相关的是,它应该返回写入用户的字节数,并且仅在文件结束时才返回 0
。如果出现错误,它还可以将错误代码作为负数返回,如 -EIO
。
你写了5个字符,但是返回了1,所以cat
认为是读不全,读了1个字节。我尝试再次读取并得到 0,因此它将其解释为文件结尾。
write
有类似的问题,它还应该检查用户缓冲区的大小并返回字节数。
这或多或少是我为固定大小的缓冲区实现 read
的方式:
ssize_t memory_read(struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
ssize_t retval;
if(down_interruptible(&sem)) // some mutex is probably necessary
return -ERESTARTSYS;
count = MIN(count, MEMORY_SIZE - *f_pos);
if(count == 0) { // this if is probably not necessary
retval = 0;
goto out;
}
/* Transfering data to user space */
if(copy_to_user(buf, memory_buffer + *f_pos, count)) {
retval = -EFAULT;
goto out;
}
*f_pos += count;
retval = count;
out:
up(&sem);
return retval;
}
关于c - 为什么这个 char 驱动程序总是只复制一个字节?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17047581/