使用旧设备文件的字符设备驱动程序

问题描述:

我有两个问题,因为我试图将设备驱动程序作为初学者。使用旧设备文件的字符设备驱动程序

  1. 我创建了一个模块,加载它,它动态地把主数251说了一遍。次要设备的数量只保留1,即只有次要数量0.为了测试,我尝试使用设备文件(使用mknod创建)上的echo和cat,并按预期工作。现在,如果卸载模块但不删除/ dev条目并再次加载具有相同主号码的模块,并尝试对之前使用过的相同设备文件进行写入/读取,则内核崩溃。我知道我们不应该这样做,但只是想了解在这种情况下会发生什么事情导致这次崩溃。我认为VFS所做的一切。

  2. 当我在设备文件上做猫时,读取会一直发生。为什么?停止需要使用偏移操作。这看起来是因为缓冲区的长度是32768作为默认读取?

编辑:进一步在此我添加如下一个ioctl函数,然后我收到有关存储类init和清理功能,如果没有ioctl定义其正常工作的错误。没有获得ioctl和init/cleanup函数的存储类之间的链接。更新的代码已发布。错误是下面:

/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:95:12: error: invalid storage class for function ‘flow_init’ 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_init’: 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:98:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement] 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_ioctl’: 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:112:13: error: invalid storage class for function ‘flow_terminate’ 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: error: invalid storage class for function ‘__inittest’ 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: warning: ‘alias’ attribute ignored [-Wattributes] 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: invalid storage class for function ‘__exittest’ 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement] 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ‘alias’ attribute ignored [-Wattributes] 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: expected declaration or statement at end of input 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: At top level: 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:73:13: warning: ‘flow_ioctl’ defined but not used [-Wunused-function] 

下面是代码:

#include <linux/init.h> 
#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/fs.h> 
#include <asm/uaccess.h> 
#include <linux/cdev.h> 
#include <linux/kdev_t.h> 
#include <linux/errno.h> 
#include <linux/ioctl.h> 

#define SUCCESS 0 
#define BUF_LEN 80 

#define FLOWTEST_MAGIC 'f' 
#define FLOW_QUERY _IOR(FLOWTEST_MAGIC,1,int) 

MODULE_LICENSE("GPL"); 
int minor_num=0,i; 
int num_devices=1; 
int fopen=0,counter=0,ioctl_test; 

static struct cdev ms_flow_cd; 
static char c; 

///// Open , close and rest of the things 

static int flow_open(struct inode *f_inode, struct file *f_file) 
{ 
printk(KERN_ALERT "flowtest device: OPEN\n"); 
return SUCCESS; 
} 

static ssize_t flow_read(struct file *f_file, char __user *buf, size_t 
    len, loff_t *off) 
{ 
    printk(KERN_INFO "flowtest Driver: READ()\nlength len=%d, Offset = %d\n",len,*off); 

/* Check to avoid the infinitely printing on screen. Return 1 on first read, and 0 on subsequent read */ 
if(*off==1) 
return 0; 

printk(KERN_INFO "Copying...\n"); 
copy_to_user(buf,&c,1); 
printk(KERN_INFO "Copied : %s\n",buf); 

*off = *off+1; 
return 1;  // Return 1 on first read 


} 

static ssize_t flow_write(struct file *f_file, const char __user *buf, 
    size_t len, loff_t *off) 
{ 
    printk(KERN_INFO "flowtest Driver: WRITE()\n"); 
if (copy_from_user(&c,buf+len-2,1) != 0) 
    return -EFAULT; 
else 
{ 
printk(KERN_INFO "Length len = %d\n\nLast character written is - %c\n",len,*(buf+len-2)); 
return len; 
} 
} 

static int flow_close(struct inode *i, struct file *f) 
{ 
    printk(KERN_INFO "ms_tty Device: CLOSE()\n"); 
    return 0; 
} 

///* ioctl commands */// 

static long flow_ioctl (struct file *filp,unsigned int cmd, unsigned long arg) 
{ 
    switch(cmd) { 
     case FLOW_QUERY: 
      ioctl_test=51; 
      return ioctl_test; 
     default: 
      return -ENOTTY; 
} 
///////////////////File operations structure below///////////////////////// 

struct file_operations flow_fops = { 
     .owner = THIS_MODULE, 
     .llseek = NULL, 
     .read =  flow_read, 
     .write = flow_write, 
     .unlocked_ioctl = flow_ioctl, 
     .open =  flow_open, 
     .release = flow_close 
}; 


static int flow_init(void) 
    { 
    printk(KERN_ALERT "Here with flowTest module ... loading...\n"); 
int result=0; 
dev_t dev=0; 
result = alloc_chrdev_region(&dev, minor_num, 
num_devices,"mod_flowtest");        // allocate major number dynamically. 

i=MAJOR(dev); 
printk(KERN_ALERT "Major allocated = %d",i); 

cdev_init(&ms_flow_cd,&flow_fops); 
cdev_add(&ms_flow_cd,dev,1); 

return 0; 
    } 

static void flow_terminate(void) 
    { 
    dev_t devno=MKDEV(i,0);   // wrap major/minor numbers in a dev_t structure , to pass for deassigning. 
    printk(KERN_ALERT "Going out... exiting...\n"); 
    unregister_chrdev_region(devno,num_devices);  //remove entry from the /proc/devices 
    } 

module_init(flow_init); 
module_exit(flow_terminate); 

1 - 你是在为你的清理功能缺失cdev_del()。这意味着设备保持注册,但处理它的功能被卸载,从而导致崩溃。此外,cdev_add可能会在下次加载时失败,但您不知道,因为您没有检查返回值。

2-它看起来不错...你修改偏移量,返回正确的字节数,然后返回0,如果偏移量为1,这表明EOF。但你应该确实检查* off> = 1.

EDIT- 传递到你的读处理函数的长度一直来自用户地read()。如果用户打开设备文件并调用read(fd, buf, 32768);,那只意味着用户想要读取直到 32768字节的数据。该长度一直传递到您的读取处理程序。如果您没有提供32768个字节的数据,则提供您所拥有的数据并返回该长度。现在,用户代码不确定文件是否结束,因此它会尝试再次读取32768。你真的现在没有数据,所以你返回0,它告诉用户代码它已经命中EOF,所以它停止。

总之,作为读取处理程序的某种默认值,您看到的只是实用程序cat用于读取任何内容的块大小。如果您想要在读取功能中看到不同的数字,请尝试使用dd,因为它允许您指定块大小。

dd if=/dev/flowtest of=/dev/null bs=512 count=1 

此外,这应该读取一个块并停止,因为您指定count = 1。如果您省略count = 1,它将看起来更像cat,并尝试读取直到EOF。

+0

对于2,我仍然怀疑。我的意思是为什么我们需要检查偏移返回值?我们正在检查它是否会无限期停止阅读。但为什么阅读调用认为默认的len值为32768? –

+0

我已经编辑了答案以扩展32768的来源。 – Peter

+0

现在这真的很有帮助,非常感谢.. !! –

对于2,确保在使用mknod时将模块作为char设备启动。

mknod /dev/you_device c major_number minor_number