EmbLogic's Blog

GPIO Device driver

GPIO Device driver

Device node creation without using “mknod”
In my last post, where i showed how to write a character gpio driver, i had used mknod for device node creation. Without mknod the device files would not have been created under /dev. So, we had to manually create the device node under /dev using mknod. Now, cannot this manual work be done away with? Of course, it can be done!!.
The automatic creation of device files can be handled with udev. One has to ensure that the major and minor numbers assigned to a device controlled by the driver are exported to user space through the sysfs interface. To know more about this, read “The Linux Device Module” chapter from the Linux Device Drivers book.
Below i am posting the source code for the driver module, the user space application and the Makefile. The user space application and Makefile remain the same. I have only changed the name of the device node under /dev from gpio to gpio_drv. So, the user space application code accordingly reflects this.
The Driver Module:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
 
#define GPIO_NUMBER    149     //any valid gpio number
 
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”);
The User Space Application:
#include
#include
 
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 trigger” in their respective directories.
Now, run the user space application by typing ./gpio_app on the command line prompt. You will be prompted to enter the value “0? or “1? to turn off or turn on the led. You can observe the state of the led pin on your board after this.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>