문제

I want to create the number of minor character drivers for my module. I want to see it at the /dev/ . However, I see only one driver. What is the problem in my code? What should be the right code?

#include <linux/init.h>
#include <linux/module.h> /** needed by all modules **/
#include <linux/kernel.h>  /** This is for KERN_ALERT **/
#include <linux/fs.h> /** for file operations **/
#include <linux/cdev.h>  /** character device **/
#include <linux/device.h>  /** for sys device registration in /dev/ and /sys/class **/
/** for copy_to_user **/
#include <asm/uaccess.h>


/** For class registration to work, you need GPL license **/
MODULE_LICENSE("GPL");


static struct cdev basicCdev;
static struct class *basicDriverClass;

static int  basicMajorNumber = 0;

#define NUMBER_OF_MINOR_DEVICE (5)

/** Prototype for read, this will be invoked when the read function is done on to the driver **/
/** The declaration type is file operations based function pointer - read **/
static ssize_t basicRead(struct file *filp, char *buffer, size_t length,loff_t *offset);

static int basicOspen(struct inode *inode, struct file *file);   

/** File Operations function pointer table **/
/** There are plenty of file operations  **/

static struct file_operations fops = {
  .read = basicRead,
  .write = NULL,
  .open = basicOspen,
  .release = NULL
};

static ssize_t basicRead(struct file *filp, char *buffer, size_t length, loff_t *offset)
{
     char msg[1024] = "Hello SJ_read\0";
     printk(KERN_ALERT "The Read operation called\r\n");
     copy_to_user( buffer, msg, sizeof(msg) );
     return sizeof(msg);
}

static int basicOspen(struct inode *inode, struct file *file)
{

   printk("Kernel.Basic Driver Opened now!!\r\n");

   return 0;
}

static void setup_cdev(struct cdev *dev, int minor, struct file_operations *fops)
{
         int err = -1;
         /** MKDEV call creates a device number i.e. combination of major and minor number **/
         int devno = MKDEV(basicMajorNumber, minor);
         /** Initiliaze character dev with fops **/
         cdev_init(dev, fops);
         /**owner and operations initialized **/
         dev->owner = THIS_MODULE;
         dev->ops = fops;
         /** add the character device to the system**/
         /** Here 1 means only 1 minor number, you can give 2 for 2 minor device, the last param is the count of minor number enrolled **/
         err = cdev_add (dev, devno, 1);

         if (err)
         {
                 printk (KERN_NOTICE "Couldn't add cdev");
         }
 }

static int chrDriverInit(void)
{

    int result;
    dev_t dev; 

    printk("Welcome!! Device Init now..");

    /** int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,unsigned int count, char *name);  **/
    /** dev -> The dev_t variable type,which will get the major number that the kernel allocates.  **/
    /**The same name will appear in /proc/devices.  **/

    /** it is registering the character device **/   
    /** a major number will be dynamically allocated here **/
    /**  alloc_chrdev_region(&dev_num, FIRST_MINOR, COUNT, DEVICE_NAME); **/
    result = alloc_chrdev_region(&dev, 0, NUMBER_OF_MINOR_DEVICE, "pSeudoDrv");

    if( result < 0 )
    {
      printk("Error in allocating device");
      return -1;    
    }

    /** From these two if's we are avoiding the manual mknod command to create the /dev/<driver> **/
    /**  creating class, and then device created removes the dependency of calling mknod  **/
    /** A good method - the mknod way is depreciated **/
    /** mknod way is -  mknod /dev/<driver_name> c <majorNumber> <minorNumber>


    /** add the driver to /sys/class/chardrv **/
    if ((basicDriverClass = class_create(THIS_MODULE, "chardrv")) == NULL)    //$ls /sys/class
    {
        unregister_chrdev_region(dev, 1);
        return -1;
    }

     /** add the driver to /dev/pSeudoDrv -- here **/
    if (device_create(basicDriverClass, NULL, dev, NULL, "pSeudoDrv") == NULL) //$ls /dev/
    {
        class_destroy(basicDriverClass);
        unregister_chrdev_region(dev, 1);
        return -1;
    }

     /** let's see what major number was assigned by the Kernel **/
     basicMajorNumber = MAJOR(dev);
     printk("Kernel assigned major number is %d ..\r\n",basicMajorNumber );

    /** Now setup the cdev **/
    setup_cdev(&basicCdev,NUMBER_OF_MINOR_DEVICE, &fops);

    return 0;   

}


static void chrDriverExit(void)
{
    /** A reverse - destroy mechansim -- the way it was created **/
    printk("Releasing Simple Devs -- %s\r\n",  __FUNCTION__);
    /** delete the character driver added **/
    cdev_del(&basicCdev);
    /** destroy the device created **/
    device_destroy(basicDriverClass, MKDEV(basicMajorNumber, 0));
    /** destroy the class created **/
    class_destroy(basicDriverClass);
    /** unregister the chr dev **/
    unregister_chrdev(basicMajorNumber, NUMBER_OF_MINOR_DEVICE);

}


module_init(chrDriverInit);
module_exit(chrDriverExit);

I get errors, if I modify the init function to the following.

static int chrDriverInit(void)
    {

        int result;
        dev_t dev; 
        dev_t dev2; 

        printk("Welcome!! Device Init now..");

        /** int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,unsigned int count, char *name);  **/
        /** dev -> The dev_t variable type,which will get the major number that the kernel allocates.  **/
        /**The same name will appear in /proc/devices.  **/

        /** it is registering the character device **/   
        /** a major number will be dynamically allocated here **/
        /**  alloc_chrdev_region(&dev_num, FIRST_MINOR, COUNT, DEVICE_NAME); **/
        result = alloc_chrdev_region(&dev, 0, NUMBER_OF_MINOR_DEVICE, "pSeudoDrv");

        if( result < 0 )
        {
          printk("Error in allocating device");
          return -1;    
        }

        /** From these two if's we are avoiding the manual mknod command to create the /dev/<driver> **/
        /**  creating class, and then device created removes the dependency of calling mknod  **/
        /** A good method - the mknod way is depreciated **/
        /** mknod way is -  mknod /dev/<driver_name> c <majorNumber> <minorNumber>


        /** add the driver to /sys/class/chardrv **/
        if ((basicDriverClass = class_create(THIS_MODULE, "chardrv")) == NULL)    //$ls /sys/class
        {
            unregister_chrdev_region(dev, 1);
            return -1;
        }

         /** add the driver to /dev/pSeudoDrv -- here **/
        if (device_create(basicDriverClass, NULL, dev, NULL, "pSeudoDrv") == NULL) //$ls /dev/
        {
            class_destroy(basicDriverClass);
            unregister_chrdev_region(dev, 1);
            return -1;
        }

         /** let's see what major number was assigned by the Kernel **/
         basicMajorNumber = MAJOR(dev);
         printk("Kernel assigned major number is %d ..\r\n",basicMajorNumber );

         dev2 = MKDEV(basicMajorNumber,2);

        #if 1

         if (device_create(basicDriverClass, NULL, dev2, NULL, "pSeudoDrv2") == NULL) //$ls /dev/
        {
            class_destroy(basicDriverClass);
            unregister_chrdev_region(dev, 1);
            return -1;
        }

        #endif


        /** Now setup the cdev **/
        setup_cdev(&basicCdev,NUMBER_OF_MINOR_DEVICE, &fops);







        return 0;   

    }

Here is the crash -

[19554.180535] CPU: 1 PID: 16636 Comm: insmod Tainted: GF       W  O 3.13.5-101.fc19.x86_64 #1
[19554.180537] Hardware name: Dell Inc. Studio 1558/0G939P, BIOS A07 06/24/2010
[19554.180539]  0000000000000009 ffff8800667d7ad8 ffffffff81680664 ffff8800667d7b20
[19554.180543]  ffff8800667d7b10 ffffffff8106d35d ffff880130f9e810 00000000ffffffef
[19554.180547]  0000000000000000 ffff880133432378 0000000000000000 ffff8800667d7b70
[19554.180551] Call Trace:
[19554.180555]  [<ffffffff81680664>] dump_stack+0x45/0x56
[19554.180558]  [<ffffffff8106d35d>] warn_slowpath_common+0x7d/0xa0
[19554.180562]  [<ffffffff8106d3cc>] warn_slowpath_fmt+0x4c/0x50
[19554.180566]  [<ffffffff81315be4>] kobject_add_internal+0x214/0x320
[19554.180570]  [<ffffffff81316115>] kobject_add+0x65/0xb0
[19554.180574]  [<ffffffff81315550>] ? kobject_put+0x30/0x60
[19554.180578]  [<ffffffff814138b5>] device_add+0x125/0x640
[19554.180582]  [<ffffffff81413fe0>] device_create_groups_vargs+0xe0/0x110
[19554.180586]  [<ffffffffa078d0e0>] ? basicRead+0xc0/0xc0 [character_driver]
[19554.180590]  [<ffffffff81414071>] device_create+0x41/0x50
[19554.180595]  [<ffffffffa078d1d3>] chrDriverInit+0xf3/0x160 [character_driver]
[19554.180598]  [<ffffffff8100214a>] do_one_initcall+0xfa/0x1b0
[19554.180602]  [<ffffffff81054803>] ? set_memory_nx+0x43/0x50
[19554.180609]  [<ffffffff810e060d>] load_module+0x1e1d/0x25b0
[19554.180613]  [<ffffffff810dc320>] ? store_uevent+0x40/0x40
[19554.180617]  [<ffffffff810e0f16>] SyS_finit_module+0x86/0xb0
[19554.180622]  [<ffffffff8168f629>] system_call_fastpath+0x16/0x1b
[19554.180624] ---[ end trace dd8ae4ccda100ad8 ]---
도움이 되었습니까?

해결책

Your problem is that you only call device_create() for the first device. alloc_chrdev_region() only allocate major/minor numbers but it does not actually create the device structures in the kernel. The dev_t returned by alloc_chrdev_region() represents the first of your five major/minor numbers. You need to use a for loop, increment the minor number and then call device_create() on all of them.

Don't forget to destroy all of them in the exit function.

다른 팁

The kernel does not create device nodes automatically.

Something in userspace must do it, using mknod(2) or the mknod utility.

This can be done manually or when a file system image is created, by a script on boot, or by a daemon such as udev.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top