在字符设备驱动程序中,打印语句在读取方法中执行无限时间
In Character Device Driver print statement executing infinite time in read method
我正在为字符设备驱动程序编写基本设备驱动程序模块。
我想要以下行为:当我使用 cat /dev/scull
从设备文件中读取时,我应该得到设备打开的次数。
为此,我使用变量 count 并在调用我的 open 函数时增加它。我将这个变量存储在私有结构中。
我遇到的问题是读取函数
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);
}
打印语句 "You have read device %d times" 正在打印无限次。我必须按 Ctr+D
才能停止它。
我希望输出到 cat 以及日志文件中。
注意:您获得无限输出是因为您总是返回 sizeof
。而且,您没有将数据复制到 cat
.
的代码
好的,我已经编写了我认为您需要的代码[请原谅一些无偿的样式清理]。注意:我没有构建它。我已经对其进行了一些注释,所以这应该可以帮助您入门:
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;
}
提醒:不要忘记在打开 and/or 关闭时清除 rdpend
。
我正在为字符设备驱动程序编写基本设备驱动程序模块。
我想要以下行为:当我使用 cat /dev/scull
从设备文件中读取时,我应该得到设备打开的次数。
为此,我使用变量 count 并在调用我的 open 函数时增加它。我将这个变量存储在私有结构中。
我遇到的问题是读取函数
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);
}
打印语句 "You have read device %d times" 正在打印无限次。我必须按 Ctr+D
才能停止它。
我希望输出到 cat 以及日志文件中。
注意:您获得无限输出是因为您总是返回 sizeof
。而且,您没有将数据复制到 cat
.
好的,我已经编写了我认为您需要的代码[请原谅一些无偿的样式清理]。注意:我没有构建它。我已经对其进行了一些注释,所以这应该可以帮助您入门:
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;
}
提醒:不要忘记在打开 and/or 关闭时清除 rdpend
。