- 论坛徽章:
- 0
|
为什么下面的代码生成的字符驱动,在读的时候,内容一直在刷,是什么问题导致的呢?
测试方法:
date > /dev/对应的设备文件
cat /dev/对应的设备文件。
cat 后,屏幕上就一直打印出东西,内容还是乱码。
(代码就是linux设备驱动开发详解中的第6章的例子)
另外看到一个人的博客里这样写到:
2.加载和创建设备节点都是成功的.但就是用cat命令查看时,虽然读出了正确的字符,却总是在最后还要加上一句提示"找不到设备或地址".不知为何会多出这句来.
# echo 'hello world!' > /dev/globalmem
written 13 bytes(s) from 0
# cat /dev/
/dev/console /dev/globalmem /dev/null
# cat /dev/globalmem
read 4096 bytes(s) from 0
hello world!
cat: read error: No such device or address
#
ANSWER:其实没问题,
<1>你把globalmem_read函数中的if (p >= GLOBALMEM_SIZE)改为if (p > GLOBALMEM_SIZE)就好了。具体原因是一次调用cat会读两次,每次读取4096个字节,此时文件读指针ppos就是4096了,在第二次读的时候,到if (p >= GLOBALMEM_SIZE)这里条件为真,globalmem_read就返回ENXIO错误了,所以才会出现No such device or address"错误。不知道在宋老师的机子上为什么就是正确的?
<2> 宋宝华 :返回错误值才是正确的,因为读的位置已经越界,所以要返回错误。该返回错误的时候返回正确,那就是错误。改成if (p > GLOBALMEM_SIZE)是错误的。
<3> 根据上面两点可以小结书上是没有错误的。输出的错误信息是正常的debug信息,千不该万不该就是cat调用了read两次。
0
cat 会调用read两次?- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/types.h>
- #include <linux/errno.h>
- #include <linux/init.h>
- #include <linux/cdev.h>
- #include <asm/system.h>
- #include <asm/uaccess.h>
- #define GLOBALMEM_SIZE 0X1000 /* global memory size: 4kB */
- #define MEM_CLEAR 0X1 /* fill 0 to the global memory */
- #define GLOBALMEM_MAJOR 250 /* set globalmem device major number */
- MODULE_LICENSE("Dual BSD/GPL");
- static int globalmem_major = GLOBALMEM_MAJOR;
- static int globalmem_minor = 0;
- module_param(globalmem_major, int, S_IRUGO);
- /* define self dev struct */
- struct globalmem_dev
- {
- struct cdev cdev;
- unsigned char mem[GLOBALMEM_SIZE];
- };
- struct globalmem_dev *dev; /* the object of the device struct */
- int globalmem_open(struct inode *inode, struct file *filp)
- {
- struct globalmem_dev *dev;
- dev = container_of(inode, struct globalmem_dev, cdev);
- filp->private_data = dev;
- return 0;
- }
- int globalmem_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
- {
- unsigned long p = *f_pos;
- struct globalmem_dev *dev = filp->private_data;
-
- if (p >= GLOBALMEM_SIZE)
- {
- return count ? ENXIO:0;
- }
-
- if (count > GLOBALMEM_SIZE - p)
- {
- count = GLOBALMEM_SIZE - p;
- }
- if (copy_to_user(buf, (void *)(dev->mem + p), count))
- {
- return -EFAULT;
- }
- printk(KERN_WARNING "The buf content is %s\n", buf);
- *f_pos += count;
- printk(KERN_NOTICE "read %d bytes from globalmem, and the content is %s\n", count, buf);
- return count;
- }
- int globalmem_write(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
- {
- struct globalmem_dev *dev = filp->private_data;
- unsigned long p = *f_pos;
-
- if (p > GLOBALMEM_SIZE)
- {
- return count ? -ENXIO:0;
- }
-
- if (count > GLOBALMEM_SIZE - p)
- {
- count = GLOBALMEM_SIZE - p;
- }
- if (copy_from_user(dev->mem + p, buf, count))
- {
- printk(KERN_NOTICE "Writing data to device Fail\n");
- return -EFAULT;
- }
- printk(KERN_NOTICE "Writed %d bytes data to device\n", count);
- *f_pos += count;
- return count;
- }
- int globalmem_release(struct inode *inode, struct file *filp)
- {
- return 0;
- }
- loff_t globalmem_llseek(struct file *filp, loff_t off_set, int orig)
- {
- loff_t ret;
-
- switch(orig)
- {
- case 0: /* from the header of the file to move */
- if (off_set < 0)
- {
- ret = -EINVAL;
- }
- else if ((unsigned int)off_set > GLOBALMEM_SIZE)
- {
- ret = -EINVAL;
- }
- else
- {
- filp->f_pos = (unsigned int)off_set;
- ret = filp->f_pos;
- }
- break;
- case 1: /* from the current position of the file to move */
- if (off_set + filp->f_pos < 0 || off_set + filp->f_pos > GLOBALMEM_SIZE)
- {
- ret = -EINVAL;
- }
- else
- {
- filp->f_pos += off_set;
- ret = filp->f_pos;
- }
- break;
- case 2:
- if (off_set > 0 || off_set + filp->f_pos < 0)
- {
- ret = -EINVAL;
- }
- else
- {
- filp->f_pos += off_set;
- ret = filp->f_pos;
- }
- break;
- default:
- ret = -EINVAL;
- }
- return ret;
- }
- int globalmem_ioctrl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
- {
- int ret;
- struct globalmem_dev *dev = filp->private_data;
-
- switch(cmd)
- {
- case MEM_CLEAR:
- memset(dev->mem, 0, GLOBALMEM_SIZE);
- printk(KERN_NOTICE "globalmem memory content reset is zero\n");
- ret = 0;
- break;
- default:
- ret = -EINVAL;
- }
- return ret;
- }
- struct file_operations globalmem_fops =
- {
- .owner = THIS_MODULE,
- .open = globalmem_open,
- .release = globalmem_release,
- .read = globalmem_read,
- .write = globalmem_write,
- .ioctl = globalmem_ioctrl,
- .llseek = globalmem_llseek,
- };
- void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
- {
- int err;
- dev_t devno = MKDEV(globalmem_major, globalmem_minor + index);
- cdev_init(&(dev->cdev), &globalmem_fops);
- dev->cdev.owner = THIS_MODULE;
- err = cdev_add(&(dev->cdev), devno, 1);
- if (err)
- {
- printk(KERN_NOTICE "add cdev fail\n");
- }
- }
- static int globalmem_init(void)
- {
- int result;
- dev_t devno = MKDEV(globalmem_major, 0);
-
- if (globalmem_major)
- {
- result = register_chrdev_region(devno, 1, "globalmem");
- }
- else
- {
- result = alloc_chrdev_region(&devno, 0, 1, "globalmem");
- globalmem_major = MAJOR(devno);
- }
- if (result < 0)
- {
- printk(KERN_NOTICE "call globalmem_init fail!\n");
- return result;
- }
- dev = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
- if (dev == NULL)
- {
- printk(KERN_WARNING "Alloc gobalmem_dev Fail\n");
- unregister_chrdev_region(MKDEV(globalmem_major, 0), 1);
- return 0;
- }
- memset(dev, 0, sizeof(struct globalmem_dev));
- globalmem_setup_cdev(dev, 0);
-
-
- return 0;
- }
- void globalmem_exit(void)
- {
- cdev_del(&(dev->cdev));
- unregister_chrdev_region(MKDEV(globalmem_major, 0), 1);
- }
- module_init(globalmem_init);
- module_exit(globalmem_exit);
复制代码 |
|