I'm writing basic device driver module for character device driver.
I want following behavior in that: When I will be reading from device file using cat /dev/scull
, I should get, number of times the device is opened.
For that I am using variable count and increasing it when my open function is called. I'm storing this variable in private structure.
The problem I'm having is in read function
struct scull_dev{
int x; /*Private data members*/
struct cdev cdev; /*This is character device structure*/
};
ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
struct scull_dev *dev = filp->private_data;
pr_info("You have opened device %d times\n",dev->x);
return sizeof(dev->x);
}
The print statement "You have read device %d times" is printing infinite times. I have to press Ctr+D
to stop it.
I want output to go to cat as well as in log file.
Note: you were getting infinite output because you were always returning sizeof
. And, you had no code to copy data to cat
.
Okay, I've coded up what I think you'll need [please pardon some gratuitous style cleanup]. Note: I've not built it. I've annotated it a bit, so this should get you started:
struct scull_dev {
int x; /*Private data members*/
int rdpend; // 1=partial read in progress
int bufoff; // current offset within buffer
int buflen; // remaining length to transfer
char buf[100]; // buffer with text to output
struct cdev cdev; /*This is character device structure*/
};
ssize_t scull_read(struct file *filp, char __user *buf, size_t count,
loff_t *f_pos)
{
struct scull_dev *dev = filp->private_data;
ssize_t curlen;
long err;
// NOTES:
// (1) rdpend _must_ be cleared in the device close (and/or) device
// open -- we only want _one_ output line per invocation
// (2) _after_ you get this working, you might move _this_ code block
// to the open routine (i.e. the rdpend would not be necessary)
// (3) leaving it here makes the pr_info and cat output appear closer in
// time
do {
// only output a single line per open
if (dev->rdpend)
break;
dev->rdpend = 1;
dev->buflen = snprintf(dev->buf,sizeof(dev->buf),
"You have opened device %d times\n",dev->x);
pr_info("%s",dev->buf);
dev->bufoff = 0;
} while (0);
// get length and handle user short read
// [possibly less than we have--(e.g.) caller's count could be (say) 10
curlen = dev->buflen;
if (curlen > count)
curlen = count;
do {
// nothing left to output
if (curlen <= 0)
break;
err = copy_to_user(buf,dev->buf + dev->bufoff,curlen);
// probably an access violation or segmentation fault, etc.
if (err < 0) {
curlen = err;
break;
}
// creep through the buffer
dev->buflen -= curlen;
dev->bufoff += curlen;
} while (0);
return curlen;
}
Reminder: Don't forget to clear rdpend
in your open and/or close.