blog/posts/2012-12-22-device-node-creation-without-using-mknod.markdown
2017-06-10 17:43:43 +05:30

263 lines
8.3 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
author: Sanchayan Maity
title: Device node creation without using "mknod"
tags: beagleboard, gpio driver
---
<p style='text-align: justify;'>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!!.</p>
<p style='text-align: justify;'>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.</p>
<p style='text-align: justify;'>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.</p>
**The Driver Module:**
```c
#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");
```
**The User Space Application:**
```c
#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;
}
```
**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
```
<p style='text-align: justify;'>The path for your kernel source and path for the CodeSourcery toolchain can and mostly will be different. So change them, as per your environment.</p>
<p style='text-align: justify;'>After this, compile your kernel driver module by typing “sudo make” at the command line prompt. After this, cross compile your user space application by typing</p>
```bash
arm-none-linux-gnueabi-gcc gpio_app.c -o gpio_app
```
<p style='text-align: justify;'>I have assumed that the cross compiler path has been added to your path environment variable.</p>
<p style='text-align: justify;'>You will now have a gpio.ko file and a gpio_app executable. Transfer these files to your beagleboard. I use the “scp” command to transfer files to my board over the ssh connection.</p>
<p style='text-align: justify;'>On the command prompt of your beagleboard, do “insmod gpio.ko”.</p>
<p style='text-align: justify;'>**This time, you won't have to do the mknod for device node creation under /dev. You can cd to /sys/class and you will find the chardev entry there. Do ls /dev and you will find gpio_drv already present without having run mknod.**</p>
<p style='text-align: justify;'>By default, the user leds 0 and 1 which are connected on GPIO 149 and 150, are used for indicating mmc card access activity and heartbeat.</p>
<p style='text-align: justify;'>You can turn these dafault behaviour off by first entering the /sys/class/gpio/beagleboard::usr0 and /sys/class/gpio/beagleboard::usr1 directory. After this, do “cat trigger”. You should see the default behaviour marked.</p>
<p style='text-align: justify;'>Now, change the default behaviour for both by doing “echo none > trigger” in their respective directories.</p>
<p style='text-align: justify;'>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.</p>
<p style='text-align: justify;'>Refer the Linux Device Drivers book by Corbet, Rubini and Greg Kroah Hartman. The second, third and fourteenth chapters are important for this tutorial.</p>
<p style='text-align: justify;'>Refer this link</p>
[http://www.linuxforu.com/2011/04/character-device-files-creation-operations/](http://www.linuxforu.com/2011/04/character-device-files-creation-operations/http://).
<p style='text-align: justify;'>as well. Thanks to Anil Pugalia for his wonderful series on Linux Device Drivers available on</p>
[http://www.linuxforu.com/tag/linux-device-drivers-series/](http://www.linuxforu.com/tag/linux-device-drivers-series/).