Linux Device Driver - what's wrong with my device_read()?
I've been writing a device dev/my_inc that's meant to take a positive integer N represented as an ASCII string, and store it internally. Any read from the device should produce the ASCII string representation of the integer (N+1).
However, when I cat /dev/my_inc
, I only seem to be getting the first half of the myinc_value
message buffer back in user space.
If
myinc_value
is 48,cat /dev/my_inc
yields 4.If
myinc_value
is 489324,cat /dev/my_inc yields
489.
However, bytes_read
indicates the entire message was copied into user space. Here is the output from dmesg:
[54471.381170] my_inc opened with initial value 489324 = 489324.
[54471.381177] my_inc device_read() called with value 489325 and msg 489324.
[54471.381179] my_inc device_read() read 4.
[54471.381182] my_inc device_read() read 8.
[54471.381183] my_inc device_read() read 9.
[54471.381184] my_inc device_read() read 3.
[54471.381185] my_inc device_read() read 2.
[54471.381186] my_inc device_read() read 5. my_inc device_read() returning 7.
[54471.381192] my_inc device_read() called with value 489325 and msg 489325.
And when called from the shell:
root@rbst:/home/rob/myinc_mod# cat /dev/my_inc
489
And the source:
// Read from the device
//
static ssize_t device_read(struct file * filp, char * buffer,
size_t length, loff_t * offset)
{
char c;
int bytes_read = 0;
int value = myinc_value + 1;
printk(KERN_INFO "my_inc device_read() called with value %d and msg %s.\n",
value, msg);
// Check for zero pointer
if (*msg_ptr == 0)
{
return 0;
}
// Put the incremented value in msg
snprintf(msg, MAX_LENGTH, "%d", value);
// Copy msg into user space
while (length && *msg_ptr)
{
c = *(msg_ptr++);
printk(KERN_INFO "%s device_read() read %c. ", DEV_NAME, c);
if(put_user(c, buffer++))
{
return -EFAULT;
}
length--;
bytes_read++;
}
// Nul-terminate the buffer
if(put_user('\0', buffer++))
{
return -EFAULT;
}
bytes_read++;
printk("my_inc device_read() returning %d.\n", byte开发者_JAVA百科s_read);
return bytes_read;
}
It may be that put_user() is defined as a macro so that the post increment operator in
if(put_user(c, buffer++))
is screwing up - though I don't see how it explains what you are seeing.
Anyway it would be more convenient and more efficient to use copy_to_user() to copy the whole msg.
The reason it only shows 1 byte is because you are incrementing the msg_ptr before setting it equal to c. It needs to be c = *msg_ptr++; or c = *msg_ptr; msg_ptr++; so that the increment happens after the assignment
精彩评论