Skip to content

Instantly share code, notes, and snippets.

@strezh
Last active February 7, 2024 12:16
Show Gist options
  • Save strezh/b01fcd50875c214e510a81c6aa6d2a2a to your computer and use it in GitHub Desktop.
Save strezh/b01fcd50875c214e510a81c6aa6d2a2a to your computer and use it in GitHub Desktop.
Automatic create /dev file when driver module is loaded, automatic load driver on startup.

Automatic create /dev file

example driver module:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/device.h>
#include <linux/cdev.h>
 
#define GPIO_NUMBER    149     //User LED 0. GPIO number 149. Page 71 of BB-xM Sys Ref Manual.
 
static dev_t first;         // Global variable for the first device number
static struct cdev c_dev;     // Global variable for the character device structure
static struct class *cl;     // Global variable for the device class
 
static int init_result;
 
static ssize_t gpio_read( struct file* F, char *buf, size_t count, loff_t *f_pos )
{
    char buffer[10];
 
    int temp = gpio_get_value(GPIO_NUMBER);
 
    sprintf( buffer, "%1d" , temp );
 
    count = sizeof( buffer );
 
    if( copy_to_user( buf, buffer, count ) )
    {
        return -EFAULT;
    }
 
    if( *f_pos == 0 )
    {
        *f_pos += 1;
        return 1;
    }
    else
    {
        return 0;
    }
}
 
static ssize_t gpio_write( struct file* F, const char *buf, size_t count, loff_t *f_pos )
{
 
    printk(KERN_INFO "Executing WRITE.\n");
 
    switch( buf[0] )
    {
        case '0':
        gpio_set_value(GPIO_NUMBER, 0);
        break;
 
        case '1':
        gpio_set_value(GPIO_NUMBER, 1);
        break;
 
        default:
        printk("Wrong option.\n");
        break;
    }
    return count;
}
 
static int gpio_open( struct inode *inode, struct file *file )
{
    return 0;
}
 
static int gpio_close( struct inode *inode, struct file *file )
{
    return 0;
}
 
static struct file_operations FileOps =
{
    .owner        = THIS_MODULE,
    .open         = gpio_open,
    .read         = gpio_read,
    .write        = gpio_write,
    .release      = gpio_close,
};
 
static int init_gpio(void)
{
    //init_result = register_chrdev( 0, "gpio", &FileOps );
 
    init_result = alloc_chrdev_region( &first, 0, 1, "gpio_drv" );
 
    if( 0 > init_result )
    {
        printk( KERN_ALERT "Device Registration failed\n" );
        return -1;
    }
    //else
    //{
    //    printk( KERN_ALERT "Major number is: %d\n",init_result );
    //    return 0;
    //}
 
    if ( (cl = class_create( THIS_MODULE, "chardev" ) ) == NULL )
    {
        printk( KERN_ALERT "Class creation failed\n" );
        unregister_chrdev_region( first, 1 );
        return -1;
    }
 
    if( device_create( cl, NULL, first, NULL, "gpio_drv" ) == NULL )
    {
        printk( KERN_ALERT "Device creation failed\n" );
        class_destroy(cl);
        unregister_chrdev_region( first, 1 );
        return -1;
    }
 
    cdev_init( &c_dev, &FileOps );
 
    if( cdev_add( &c_dev, first, 1 ) == -1)
    {
        printk( KERN_ALERT "Device addition failed\n" );
        device_destroy( cl, first );
        class_destroy( cl );
        unregister_chrdev_region( first, 1 );
        return -1;
    }
 
    return 0;
}
 
void cleanup_gpio(void)
{
    //unregister_chrdev( init_result, "gpio" );
 
    cdev_del( &c_dev );
    device_destroy( cl, first );
    class_destroy( cl );
    unregister_chrdev_region( first, 1 );
 
    printk(KERN_ALERT "Device unregistered\n");
}
 
module_init(init_gpio);
module_exit(cleanup_gpio);
 
MODULE_AUTHOR("Sanchayan");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Beagleboard-xM GPIO Driver");

example user space app:

#include <stdio.h>
#include <fcntl.h>
 
int main(void)
{
    int fd;
    char gpio_buffer[10];
    char choice[10];
 
    fd = open( "/dev/gpio_drv", O_RDWR );
 
    printf( "Value of fd is: %d", fd );
 
    if( fd < 0 )
    {
        printf("Cannot open device \t");
        printf(" fd = %d \n",fd);
        return 0;
     }
 
     printf("\nPlease enter choice: \t");
     scanf( "%s", choice );
     printf("Your choice is: %s \n", choice );
     write( fd, choice, 1 );
     read( fd, gpio_buffer, 1);
     printf("GPIO value is: %s \n", gpio_buffer );
 
     if( 0 != close(fd) )
     {
         printf("Could not close device\n");
     }
 
     return 0;
}

example Makefile:

# Cross compilation Makefile for ARM
 
KERN_SRC=/home/vm/buildroot/output/build/linux-3.2.8
KERN_COMPILER=/opt/CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_GNU_Linux/bin
 
obj-m := gpio.o
 
all:
make -C $(KERN_SRC) ARCH=arm CROSS_COMPILE=$(KERN_COMPILER)/arm-none-linux-gnueabi- M=`pwd` modules
 
clean:
make -C $(KERN_SRC) ARCH=arm CROSS_COMPILE=$(KERN_COMPILER)/arm-none-linux-gnueabi- M=`pwd` clean

Link: https://coherentmusings.wordpress.com/2012/12/22/device-node-creation-without-using-mknod/

Autoload driver on startup:

  1. Put module.ko in /lib/modules/$(uname -r)/kernel/drivers/ - You may need to create the "module" directory for the first time

  2. Write Udev rules file for device (in directory /etc/udev/rules.d for Debian):

example /etc/udev/rules.d/50-xpdma.rules:

KERNEL=="xpdma", GROUP="users", MODE="0666"
  1. $> sudo depmod -a This will update the dependencies of the drivers

  2. Check /lib/modules/$(uname -r)/modules.dep file and search for modules.ko . It should list the dependencies on other modules if any

  3. add module to /etc/modules (for Debian)

  4. $> sudo /sbin/reboot OR sudo udevadm trigger

Link: http://stackoverflow.com/questions/8697300/how-to-create-a-device-in-dev-automatically-upon-loading-of-the-kernel-module-f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment