Article On Character Driver
This Article is based on how I implemented character driver till now. First of all we have to know actually what a driver Is. Let take a example in real world we have a man who can drive a bike but can’t run car so we need a driver who can run a car .in the similar way there are some specific hardware devices which can’t be run on simple program for that we need a special program. This program load in the kernel as a part of our operating system ,run and remove when it need is ended. They are used to
1.To allow interaction with hardware devices
2.Black boxes to hide details of hardware devices
3.Use standardized calls
4.Map standard calls to device-specific operations
So device drivers are that loadable kernel modules which insert in kernel ,work as part of kernel and removes as the need is ended.
Now there are Basically three types of drivers:
1.Character Driver
2.Block Driver
3.Network Driver
Character Driver:- First of all in driver we have to know that we are legally hack the kernel so we cant user level commands here for example we can’t use printf ,we use printk instead of that.
In kernel level there are two main functions which are module_init (arg) and Module_exit (arg).Here arguments is our start and exit functions. This is the two main micros of a driver. That mean a driver perform Module_init at starting and Module_exit on exit.
module_init (fn name):In module _init we register our driver by using
alloc_chrdev_region(&dev, minorno, nod, DRIVER_NAME);
in this dev id dev_t type and minor no is device no and nod Is number of devices .
now we get a a combination of major and minor no in dev which is of 32 byte in which 20 byte is of minor no and 12 byte is for major no. we can get our major no. by using micros major(dev) and minor(dev) this will give major and minor no.
We make our user defined function sculldev which have all the information about the device and allocate memory for it using Kmalloc. Which return a pointer which points to it starting address.
Now initialize our C_dev which is points to struct cdev and fops.
cdev_init (&sculldev->c_dev, &fop);
we can inform the kernel about this c dev structure using the cdev_add call.
int cdev_add(struct sculldev ->c_dev, dev_t dev, unsigned int count);
this is our start function. Now we proceeed to exit one.
In exit function we do nothing but to unregister device and free the memory allocatd to sculldev.
Now we go to our header file and define our sculldev structure and assign its members that are our quantum_size ,qset size,device size.and struct cdev type c_dev and struct scullaset *scullqs.et which points to our structure ScullQset which contains two things which are first our next pointer which points to out next scullqset structure and second is data pointer which contains qset which actually an array of pointer.It contains starting address of quantums.Ultimately our data is going to store in the quantums.
The whole structure of ScullQset is known as Item.We can relate it as our linked list which has next pointer and an info part.
This is our scullqset structure.
struct ScullQset
{
struct ScullQset *next;
void **data;
};
.
Now as we know that every device has its own set of open,close etc fn. So we have to map it using a structure names file_operations.
const struct file_operations fop=
{
open:scull_open,
write:scull_write,
read:scull_read,
release:scull_release
};
Here we map open call by scull_open means whenever a open call is make the command goes to scull open and perform scull_open.Simiarly we can map any no. of user level command.
Now we are defining prototypes of mapped command which are given in fs.h libraray which can accessible in kernel file.
int scull_open(struct inode *, struct file * );
int scull_release(struct inode *, struct file * );
ssize_t scull_read (struct file *, char __user *, size_t, loff_t *);
ssize_t scull_write(struct file *, const char __user *, size_t, loff_t *);
Now after that I write our open function in which I use Container_of which is used to map scull memory on device.
I preserve starting point pointer i.e sculldev in filep->private data.
Now In read fn . I get data from application and perform some calculation which give me idea on how many no. of quantum’s I needed to write this data .After that I write the data in Quantums by using the micro copy_from_user(destination,source,len)
Now I mapped the read function also so I read this data and show it in application by micro copy_to_user (destination, source, len)
Now I make a simple application and test it .I pass the data by using file descriptors.
I make a node which connect device driver to application.
I connect the application with device driver code by writing a command in script as
./ appl node.
Loadable Moduler kernel can be inserted and removed from the running kernel(using kernel utilities insmod and rmmod respectively);
Successfully worked till this. Working on lseek now.