reign_man
reign_man

Reputation: 569

ARM char device driver initialization isn't creating /dev/ file

I am writing a driver for the GPIO pins on an ARM platform. My driver works correctly and I've avoided the problem until now by manually mknod'ing a device file.

my initialization code:

static int __init gpio_init (void) {

    void *ptr_error;
    if (register_chrdev(249, "gpio_device", &fops) < 0){
            printk(KERN_INFO "Registering device failed\n");
            return -EINVAL;
    }

    if ((device_class = class_create(THIS_MODULE, "gpio_device"))
                                                    == NULL){
            unregister_chrdev_region(DEV_T, 1);
            printk(KERN_INFO "Class creation failed\n");
            return -EINVAL;
    }
    ptr_error = device_create(device_class, NULL, DEV_T, NULL, "gpio_device");
    if (IS_ERR(ptr_error)){
            class_destroy(device_class);
            unregister_chrdev_region(DEV_T, 1);
            printk(KERN_INFO "Device creation failed\n");
            return -EINVAL;
    }

    cdev_init(&c_dev, &fops);

    if (cdev_add(&c_dev, DEV_T, 1)){
            device_destroy(device_class, DEV_T);
            class_destroy(device_class);
            unregister_chrdev_region(DEV_T, 1);
            printk(KERN_INFO "Cdev add failed\n");
            return -EINVAL;
    }
    printk(KERN_INFO "Guten tag, GPIO driver initialized\n");
    return SUCCESS;

}

This runs with no errors, except no file "gpio_device" is created in /dev.

I'm cross compiling for ARM onto kernel 2.6.39.4. (using arm-linux-gcc)

As I understand it, device_create should be creating the /dev file.

Upvotes: 2

Views: 3794

Answers (2)

reign_man
reign_man

Reputation: 569

I just figured out what was going on here. We are using BuildRoot to create our custom linux, and the it turns out we had compiled out the udev device file management system.

So that's why this doesn't work.

Upvotes: 1

I&#39;m a frog dragon
I&#39;m a frog dragon

Reputation: 8815

I tried running your code and found a few mistakes:

  • When you register with register_chrdev(), you should unregister with unregister_chrdev(). unregister_chrdev_region() is used to unregister a registration done with alloc_chrdev_region() or register_chrdev_region().

  • A call to register_chrdev() registers minor numbers 0-255 for the given major, and sets up a default cdev structure for each, therefore, you do not need to deal with the cdev_init() & cdev_add().

  • You should check the error using IS_ERR & PTR_ERR for class_create() & device_create() as PTR_ERR will turn the return pointer to the error code with a cast.

You can read more here: Char Device Registration.

After applying the modification I mentioned, the /dev/gpio_device is created without mknod:

int init_module(void)
{   
    void *ptr_error;
    struct cdev* c_dev;
    int result=0;

    /* register_chrdev */
    result=register_chrdev(my_major, "gpio_device", &fops);
    if (result < 0)
    {
    printk(KERN_INFO "Registering device failed\n");
    return result;
    }

    DEV_T = MKDEV(my_major, my_minor);

    /* class_create */
    device_class = class_create(THIS_MODULE, "gpio_device");
    if (IS_ERR(device_class))
    {
    unregister_chrdev(my_major, "gpio_device");
    printk(KERN_INFO "Class creation failed\n");
    return PTR_ERR(device_class);
    }

    /* device_create */
    ptr_error = device_create(device_class, NULL, DEV_T, NULL, "gpio_device");
    if (IS_ERR(ptr_error))
    {
    class_destroy(device_class);
    unregister_chrdev(my_major, "gpio_device");
    printk(KERN_INFO "Device creation failed\n");
    return PTR_ERR(ptr_error);
    }

    /* //removed
    cdev_init(&c_dev, &fops);
    if (cdev_add(&c_dev, DEV_T, 1)){
    device_destroy(device_class, DEV_T);
    class_destroy(device_class);
    unregister_chrdev_region(DEV_T, 1);
    printk(KERN_INFO "Cdev add failed\n");
    return -EINVAL;
    }*/

    printk(KERN_INFO "Guten tag, GPIO driver initialized\n");
    return SUCCESS;
}

Upvotes: 3

Related Questions