将旧设备文件用于char设备驱动程序

时间:2013-06-05 06:30:47

标签: linux-kernel linux-device-driver device-driver ioctl

我有两个问题,因为我正在尝试将设备驱动程序作为初学者。

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

  2. 当我在设备文件上执行cat时,读取会无限期地继续发生。为什么?停止需要使用偏移操作。这看起来是因为缓冲区长度默认为32768?

  3. 编辑:进一步在这里我添加了一个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);
    

2 个答案:

答案 0 :(得分:3)

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

2-看起来没问题......修改偏移量,返回正确的字节数,然后如果offset为1则返回0,表示EOF。但你应该检查* off&gt; = 1。

编辑 - 传入读处理函数的长度来自user-land 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。

答案 1 :(得分:0)

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

    mknod /dev/you_device c major_number minor_number