Sunday, June 17, 2012

How to build a character driver

First we include the functions open, release, read, write and ioctl (input output control) to the driver.

<chardev.c>
1:  #include <linux/init.h>               //specify initialization and cleanup functions  
2:  #include <linux/module.h>          //definitions of symbols and functions  
3:  #include <linux/fs.h>               //allocating and freeing device numbers  
4:  #include <linux/errno.h>          //error codes  
5:  #include <asm/uaccess.h>          //user space access (to move data to and from user space)  
6:  #define DEV_MAJOR          223  
7:  #define     DEV_MINOR          0  
8:  char my_data[80]="first chardevice";   
9:  int dev_open(struct inode *inode,struct file *filep);  
10:  int dev_release(struct inode *inode,struct file *filep);  
11:  ssize_t dev_read(struct file *filep,char *buff,size_t count,loff_t *offp );  
12:  ssize_t dev_write(struct file *filep,const char *buff,size_t count,loff_t *offp );  
13:  int dev_ioctl(struct inode *inode, struct file *filep,unsigned int cmd, unsigned long arg);  
14:  struct file_operations my_fops={  
15:       .open = dev_open,  
16:       .release = dev_release,       
17:       .read = dev_read,  
18:       .ioctl = dev_ioctl,  
19:       .write = dev_write,            
20:  };  
21:  int dev_ioctl(struct inode *inode, struct file *filep,unsigned int cmd, unsigned long arg)  
22:  {  
23:       if (cmd==10)  
24:            printk("\nIOCTL function\n");            
25:            return 10;  
26:  }  
27:  int dev_open(struct inode *inode,struct file *filep)  
28:  {  
29:       printk("\ndev open\n");  
30:       return 0;  
31:  }  
32:  int dev_release(struct inode *inode,struct file *filep)  
33:  {       
34:       printk("\ndev release\n");  
35:       return 0;  
36:  }  
37:  ssize_t dev_read(struct file *filep,char *buff,size_t count,loff_t *offp )  
38:  {       
39:       if ( copy_to_user(buff,my_data,strlen(my_data)) != 0 )  
40:            printk( "Kernel -> userspace copy failed!\n" );  
41:       else  
42:            printk("reading is successful");  
43:       return strlen(my_data);  
44:  }  
45:  ssize_t dev_write(struct file *filep,const char *buff,size_t count,loff_t *offp )  
46:  {       
47:       if ( copy_from_user(my_data,buff,count) != 0 )  
48:            printk( "Userspace -> kernel copy failed!\n" );  
49:       else  
50:            printk("writing is successful");  
51:       return 0;  
52:  }  
53:  static int dev_init(void){  
54:       printk("\nmodule init\n");  
55:       if(register_chrdev(DEV_MAJOR,"chardev",&my_fops)){  
56:            printk("<1>failed to register");  
57:       }  
58:       return 0;  
59:  }  
60:  static void dev_exit(void){  
61:       printk("\nmodule exit\n");  
62:       unregister_chrdev(DEV_MAJOR,"chardev");  
63:       return 0;  
64:  }  
65:  module_init(dev_init);  
66:  module_exit(dev_exit);  
67:  MODULE_LICENSE("GPL");  
68:  MODULE_AUTHOR("SUNETH <sunethe@zone24.com>");  
69:  MODULE_DESCRIPTION("CHAR DRIVER");  
Major and minor numbers

  • Normally character drivers are listed with ‘c’ letter.
  • ls –l’ command will list devices. There you can find two numbers. One is called the major number and the other is the minor number.
  • Major number is used to identify the device that is associated with the device driver.
  • Minor number is used by the kernel to determine the driver that is exactly referring at the moment.
Char device registration, is done when the module is inserted to the kernel.
Unregistering the device the char driver happens when the module is removed from the kernel.
Unregistering the driver allows us reusing the device numbers that we used.
The functionality of the module_init(); and module_exit(); was describes in the previous article.

open method

Prototype for the open method.
int (*open)(struct inode *inode, struct file *filp);

release method

Prototype for the open method.
int scull_release(struct inode *inode, struct file *filp);

read method

Prototype for the read method.
ssize_t read(struct file *filp, char __user *buff, size_t count, loff_t *offp);


write method

Prototype for the write method.
ssize_t write(struct file *filp, const char __user *buff, size_t count, loff_t *offp);


How to test the driver
1:  #include <stdio.h>  
2:  #include <unistd.h>  
3:  #include <sys/types.h>  
4:  #include <sys/stat.h>  
5:  #include <fcntl.h>  
6:  #include <sys/ioctl.h>  
7:  #include <string.h>  
8:  int main()  
9:  {  
10:       int fd=0,ret=0,iot=0;  
11:       char buff[80],wrbuff[80],iob[80];       
12:       char wbuff[80]="writing data     ";   
13:       int chk=0;  
14:       fd=open("/dev/chardev",O_RDWR);          //open the device for read and write  
15:       printf("\nfd :%d\n",fd);  
16:       memset(buff, 0, sizeof(buff));  
17:       ret=read(fd,buff,10);                    //read the device  
18:       buff[ret]='\0';  
19:       chk=write(fd,wbuff,strlen(wbuff));     //write to the device  
20:       memset(wrbuff, 0, sizeof(wrbuff));  
21:       ret=read(fd,wrbuff,80);                    //read again  
22:       buff[ret]='\0';  
23:       memset(iob, 0, sizeof(iob));          //call ioctl  
24:       iot=ioctl(fd,10,iob);  
25:       printf("\n%d\n",iot);  
26:       printf("\nbuff: %s ;length: %d bytes\n",buff,ret);  
27:       printf("\nbuff: %s ;length: %d bytes\n",wrbuff,ret);  
28:       close(fd);                              //close the device  
29:  }  

Creating a device file

This is special file that is usually created in /dev
‘mknod path type major minor’
Eg: ‘mknode /dev/chardev c 235 0
   ‘chardev’ -  device file name
   ‘c’ indicated that this is a char driver
   ‘235’ and ‘0’ – major number and minor number respectively.

Compile the driver
  • Create the  Makefile
<Makefile>
1:  obj-m := chardev.o  
2:  KVERSION =$(shell uname -r)  
3:  all:  
4:     make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules  
5:  clean :  
6:     rm -rf *.o  

            In the terminal  $ make’
            This will create ‘chardev.ko’ file.
  • Load the module
           ‘# insmod chardev.ko’
  • Run the test application
            First compile the test application and run the executable file ‘# ./a.out
            This will give you the results as given by the test application.
  • Remove the module
           ‘# rmmod chardev

No comments:

Post a Comment