First we include the functions open, release, read, write and ioctl (input output control) to the driver.
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");
- 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.
Prototype for the open method.
int (*open)(struct inode *inode, struct file *filp);
Prototype for the open method.
int scull_release(struct inode *inode, struct file *filp);
Prototype for the read method.
ssize_t read(struct file *filp, char __user *buff, size_t
count, loff_t *offp);
Prototype for the write method.
ssize_t write(struct file *filp, const char __user *buff,
size_t count, loff_t *offp);
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: }
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
<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
This will create ‘chardev.ko’ file.
First compile the test application and run the executable
file ‘# ./a.out’
This will give you the results as given by the test application.