Character device driver
Today we will go thought character device driver. I am reading linux device driver(LDD) book and noting points in this blog.I will also present simple and miscellaneous codes on to this blog.If you find this theory portion boring you can skip it and move directly to practical side of blog. But I recommend to read the theory portion if you are new to this subject.
-Mainly there are three types of device drivers
1)char:to transfer stream of bytes
2)block:to transfer data in blocks of data.block size can be 512 or more in power of 2
3)network:they are used for network protocol
-Great thing of linux is every thing is file in linux. So character drivers are also files.So you can manipulate this file and control the device. This files are known as device file. They are present in /dev/char
$ls -l /dev/char
this would give you all device file
- Each device file are represented my major number and minor number
When a device file is opened, Linux examines its major number and forwards the call to the driver registered for that device.
The Internal Representation of Device Numbers
Within the kernel, the dev_t type (defined in <linux/types.h>) is used to hold device
numbers—both the major and minor parts.
MAJOR(dev_t dev);
MINOR(dev_t dev);
If, instead, you have the major and minor numbers and need to turn them into a dev_t, use:
MKDEV(int major, int minor);
A device file is a special file. It can’t just be created using cat or gedit or shell redirection for that matter.
mknod path type major minor
chmod flag path //used to give mode
Allocating and Freeing Device Numbers
Now we have to register device
int register_chrdev_region(dev_t first, unsigned int count, char *name);
-first is the device number to the first device,then comes count that is total number of continuous devices,then it gives name to our file.Name would be visible in
/proc/devices and sysfs.
-You should know your major number and minor number to use this API
-If this API returns 0 then it means device is succefully register
-If you dont know which major number to assign then there is know API which gives major number dynamically.
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,unsigned int count, char *name);
-To free memory use this API
void unregister_chrdev_region(dev_t first, unsigned int count);
-disadvantage for dynamic allocation is that it cant create device node in advance
-above API only gives number to your driver.It does not connect your driver.So we will learn now how to connect driver
Some Important Data Structures
1)struct file_operations,
2)struct file,
3)struct inode
1)File Operations
Conventionally, a file_operations structure or a pointer to one is called fops
struct module *owner
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*aio_read)(struct kiocb *, char __user *, size_t, loff_t);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_write)(struct kiocb *, const char __user *, size_t, loff_t *);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int);
.
.
.
there many such structures in file operation
this is example how file operation.More clearity will come when you check the code for char driver
struct file_operations scull_fops = {
.owner =THIS_MODULE,
.llseek =scull_llseek,
.read =scull_read,
.write =scull_write,
.ioctl =scull_ioctl,
.open =scull_open,
.release = scull_release,
};
2)file structure(struct file)
-struct file, defined in <linux/fs.h>
-The file structure represents an open file
field of file structure are
-mode_t f_mode;The file mode identifies the file as either readable or writable (or both), by means of the bits FMODE_READ and FMODE_WRITE
-loff_t f_pos:The current reading or writing position
-unsigned int f_flags-These are the file flags, such as O_RDONLY, O_NONBLOCK, and O_SYNC. O_NONBLOCK is mostly used
-struct file_operations *f_op-The operations associated with the file.
-void *private_data;
-struct dentry *f_dentry;
3)inode structure
The inode structure is used by the kernel internally to represent files.
dev_t i_rdev;
For inodes that represent device files, this field contains the actual device number.
struct cdev *i_cdev;
struct cdev is the kernel’s internal structure that represents char devices; this
field contains a pointer to that structure when the inode refers to a char device
file.
-this macro are used to get major number and minor number from inode of device file
unsigned int iminor(struct inode *inode);
unsigned int imajor(struct inode *inode);
this should be used instead of using i_rdev
We are done with data structure.Now we move forward for char device registration
-struct cdev is used to represent char device present in <linux/cdev.h>
-There are two ways of allocating and initializing one of these structures
1)This is at runtime
struct cdev *my_cdev = cdev_alloc( );
my_cdev->ops = &my_fops;
2)void cdev_init(struct cdev *cdev, struct file_operations *fops);
-finally when cdev structure is set up now its time to tell kernel with this API
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
-as soon as cdev_add returns, your device is “live” and its operations
can be called by the kernel.
-To remove a char device from the system, call:
void cdev_del(struct cdev *dev);
-For completeness, we describe the older char device registration interface.Classic way to register device
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
name is name of driver that reappears in /proc/devices
int unregister_chrdev(unsigned int major, const char *name);

Note:
some commands(let chardev be our device file)
ls -l /dev
mknod /dev/chardev 60 0
echo "jay kothari">/dev/chardev
cat /dev/chardev
modinfo (driver name)
lsmod | grep (driver name)
With this we compete the registration of char device
Practical:
Now lets try to load a character driver for number of devices:
step1:
-go to
$sudo cd /usr/src/linux-(version)/drivers/char
$mkdir (folder name)
$cd (folder name)
$vi (file name).c
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
/* fs/char_dev.c, drivers/base/class.c
* drivers/base/core.c
*/
#include <linux/slab.h>
#include <linux/kfifo.h>
#define MAX_SIZE 4096
int ndevices=5;
module_param(ndevices,int,S_IRUGO);
typedef struct private_object
{
struct cdev cdev;
unsigned char* pbuf;
struct kfifo kf1;
struct list_head lentry;
}C_DEV;
LIST_HEAD(phead);
dev_t pseudo_dev_id;
struct class *pseudo_cls;
//******************************************open()**************************************************************//
static int pseudo_open(struct inode *inode,struct file *file)
{
C_DEV* probj=container_of(inode->i_cdev,C_DEV,cdev);
printk("pseudo open method\n");
file->private_data=probj;
return 0;
}
//close(fd);
static int pseudo_release(struct inode *inode,struct file *file)
{
printk("pseudo close method\n");
return 0;
}
//****************************************read()******************************************************************//
static ssize_t pseudo_read(struct file *file, char __user *ubuf,size_t count, loff_t *ppos)
{
unsigned char* tbuf=kmalloc(count+1,GFP_KERNEL);
C_DEV* pdev=file->private_data;
int len=kfifo_len(&pdev->kf1);
int ret,nbytes;
printk("pseudo read method entered\n");
if(count>len)
count=len;//min(count,length)//
if(count==0) return -EAGAIN;
nbytes=kfifo_out(&pdev->kf1,tbuf,count);
printk("read:nbytes=%d\t,count=%d\t,off=%d\t,kfifo length=%d\n",nbytes,count,*ppos,kfifo_len(&pdev->kf1));
tbuf[nbytes]=0;
printk("read:tbuf=%s\n",tbuf);
ret=copy_to_user(ubuf,tbuf,nbytes);
// printf("tbub%s\n",*tbuf);
printk("read::ret=%d\n",ret);
if(ret) return -EFAULT;
// *ppos += nbytes;
kfree(tbuf);
return nbytes;
}
//*****************************************************************************************************************//
//**********************************write()***********************************************************************//
static ssize_t pseudo_write(struct file *file, const char __user *ubuf,size_t count, loff_t *ppos)
{
C_DEV* pdev=file->private_data;
int nbytes;
int remain=kfifo_avail(&pdev->kf1);
unsigned char* tbuf=kmalloc(count,GFP_KERNEL);
printk("write:pseudo write method entered,remain=%d\n",remain);
if(remain==0)
return -EAGAIN;
if(count > remain)
count=remain; //min(count,remain)
if(copy_from_user(tbuf,ubuf,count))
return -EFAULT;
nbytes=kfifo_in(&(pdev->kf1),tbuf,count);
printk("nbytes=%d\t,count=%d\t,off=%d\t,kfifo length=%d\t",nbytes,count,*ppos,kfifo_len(&pdev->kf1));
// *ppos += nbytes;
kfree(tbuf);
return nbytes;
}
//*****************************************************************************************************************//
//*************************************file operation**************************************************************//
static struct file_operations pseudo_fops=
{
.open=pseudo_open,
.release=pseudo_release,
.read=pseudo_read,
.write=pseudo_write,
.owner=THIS_MODULE,
//.ioctl.pseudo_ioctl
};
//******************************************************************************************************************//
//*********************************************init function()*****************************************************//
static int pseudo_init(void)
{
int ret,i=0;
C_DEV* pdev; //struct private_object* pdev;
ret=alloc_chrdev_region(&pseudo_dev_id,0,ndevices,"pseudo_char_driver");
if(ret<0) return -EFAULT;
printk("driver registered,major=%d\n",
MAJOR(pseudo_dev_id));
pseudo_cls=class_create(THIS_MODULE,"pseudo_class");
//per device initialization
for(i=0;i<ndevices;i++)
{
pdev=kmalloc(sizeof(C_DEV),GFP_KERNEL);
pdev->pbuf=kmalloc(MAX_SIZE,GFP_KERNEL);
kfifo_init(&(pdev->kf1),pdev->pbuf,MAX_SIZE);
// kfifo_alloc(&pdev->kf1,MAX_SIZE,GFP_KERNEL);//*
cdev_init(&pdev->cdev,&pseudo_fops);
kobject_set_name(&(pdev->cdev.kobj),"my_pseudo_dev%d",i);
ret=cdev_add(&pdev->cdev,pseudo_dev_id+i,1);
if(ret<0)
{
printk("cdev_add failed\n");
kfifo_free(&pdev->kf1);
//unregister the driver
return -EFAULT;
}
list_add_tail(&pdev->lentry,&phead);
device_create(pseudo_cls,NULL,pseudo_dev_id+i,NULL,"pchardev%d",i);
printk("device initialized:%d\n",i);
}
printk("Pseudo Char Driver registered successfully\n");
return 0;
}
//*****************************************************************************************************//
//*****************************************exit*******************************************************//
static void pseudo_exit(void)
{
struct list_head *ptemp,*qtemp;
C_DEV* pdev;
int i=0;
//per device cleanup/deallocation
list_for_each_safe(ptemp,qtemp,&phead)
{
pdev=container_of(ptemp,C_DEV,lentry);
kfifo_free(&pdev->kf1);
cdev_del(&pdev->cdev);
kfree(pdev);
device_destroy(pseudo_cls,pseudo_dev_id+i);
printk("cleaned device:%d\n",i);
i++;
}
class_destroy(pseudo_cls);
unregister_chrdev_region(pseudo_dev_id,5);
printk("Pseudo Char Driver:Bye\n");
}
//********************************************************************************************************//
module_init(pseudo_init);
module_exit(pseudo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jay Kothari");
MODULE_DESCRIPTION("driver for n number of device");
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//
-step 2:
make a Makefile in this same folder as follwing
$vi Makefile
obj-m += (file name).o
all:
make -C /lib/modules/$(shell uname -r)/build M=${PWD} modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=${PWD} clean
-step 3:
Now compile using make
$make
$ls
check .ko file is generated?
-step4
now load the module to the kernel using insmod command
$insmod (file name).ko
-step 5:
now go to user space /home director
then make a folder
$mkdir(folder name)
-step6:
write a c program that all the char device file
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//
#include<stdio.h>
#include<fcntl.h>
#include<assert.h>
#include<string.h>
int main(int argc,char *argv[])
{
assert(argc>1);
char buf[100];
char i=0;
memset(buf,0,100);
printf("Input:%s\n",argv[1]);
int fd=open("/dev/pchardev3",O_RDWR);
if(fd<0)
{perror("open error");
exit(3);
}
int k;
k= write(fd,argv[1],strlen(argv[1]));
if(k<0)
{perror("write");
exit(2);
}
printf("write is done\n");
k= read(fd,buf,100);
if(k<0) {
perror("read");
exit(1);
}
buf[k]='\0';
printf("%s\n",buf);
printf("%s\n",buf);
return 0;
}
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//
-step 7:
make compile this in user space and run it
gcc -(file_name).c -o (file_name)
./(file_name) "JAY KOTHARI"
//------------------------------------------------------------------------------------------------------------------//
-There a code for single character driver that i found from net you can check it out as I used it as my reference code to make this code.Haven’t change authors name to give him honor and I am thankful to him.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#define DEVICE_NAME "chardev"
#define BUFFER_SIZE 1024
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Zobayer Hasan");
MODULE_DESCRIPTION("A simple character device driver.");
MODULE_SUPPORTED_DEVICE(DEVICE_NAME);
int device_init(void);
void device_exit(void);
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
module_init(device_init);
module_exit(device_exit);
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
static int device_major = 60;
static int device_opend = 0;
static char device_buffer[BUFFER_SIZE];
static char *buff_rptr;
static char *buff_wptr;
module_param(device_major, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
MODULE_PARM_DESC(device_major, DEVICE_NAME " major number");
int device_init() {
int ret;
ret = register_chrdev(device_major, DEVICE_NAME, &fops);
if(ret < 0) {
printk(KERN_ALERT "chardev: cannot obtain major number %d.\n", device_major);
return ret;
}
memset(device_buffer, 0, BUFFER_SIZE);
printk(KERN_INFO "chardev: chrdev loaded.\n");
return 0;
}
void device_exit() {
unregister_chrdev(device_major, DEVICE_NAME);
printk(KERN_INFO "chardev: chrdev unloaded.\n");
}
static int device_open(struct inode *nd, struct file *fp) {
if(device_opend) return -EBUSY;
device_opend++;
buff_rptr = buff_wptr = device_buffer;
try_module_get(THIS_MODULE);
return 0;
}
static int device_release(struct inode *nd, struct file *fp) {
if(device_opend) device_opend--;
module_put(THIS_MODULE);
return 0;
}
static ssize_t device_read(struct file *fp, char *buff, size_t length, loff_t *offset) {
int bytes_read = strlen(buff_rptr);
if(bytes_read > length) bytes_read = length;
copy_to_user(buff, buff_rptr, bytes_read);
buff_rptr += bytes_read;
return bytes_read;
}
static ssize_t device_write(struct file *fp, const char *buff, size_t length, loff_t *offset) {
int bytes_written = BUFFER_SIZE - (buff_wptr - device_buffer);
if(bytes_written > length) bytes_written = length;
copy_from_user(buff_wptr, buff, bytes_written);
buff_wptr += bytes_written;
return bytes_written;
}
/*
End of Source Code
*/
And you are done......enjoy......its easy so smile
what you need to do if you dont understand the code is that you google out each API you find and you would be done
Still if there are any troubles then let me know
Thank you
Bibliography:
-read chapter 3 of linux device drivers
-http://zobayer.blogspot.in/2011/07/simple-character-device.html
-http://www.makelinux.net/ldd3/chp-3-sect-4
Today we will go thought character device driver. I am reading linux device driver(LDD) book and noting points in this blog.I will also present simple and miscellaneous codes on to this blog.If you find this theory portion boring you can skip it and move directly to practical side of blog. But I recommend to read the theory portion if you are new to this subject.
-Mainly there are three types of device drivers
1)char:to transfer stream of bytes
2)block:to transfer data in blocks of data.block size can be 512 or more in power of 2
3)network:they are used for network protocol
-Great thing of linux is every thing is file in linux. So character drivers are also files.So you can manipulate this file and control the device. This files are known as device file. They are present in /dev/char
$ls -l /dev/char
this would give you all device file
- Each device file are represented my major number and minor number
When a device file is opened, Linux examines its major number and forwards the call to the driver registered for that device.
The Internal Representation of Device Numbers
Within the kernel, the dev_t type (defined in <linux/types.h>) is used to hold device
numbers—both the major and minor parts.
MAJOR(dev_t dev);
MINOR(dev_t dev);
If, instead, you have the major and minor numbers and need to turn them into a dev_t, use:
MKDEV(int major, int minor);
A device file is a special file. It can’t just be created using cat or gedit or shell redirection for that matter.
mknod path type major minor
chmod flag path //used to give mode
Allocating and Freeing Device Numbers
Now we have to register device
int register_chrdev_region(dev_t first, unsigned int count, char *name);
-first is the device number to the first device,then comes count that is total number of continuous devices,then it gives name to our file.Name would be visible in
/proc/devices and sysfs.
-You should know your major number and minor number to use this API
-If this API returns 0 then it means device is succefully register
-If you dont know which major number to assign then there is know API which gives major number dynamically.
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,unsigned int count, char *name);
-To free memory use this API
void unregister_chrdev_region(dev_t first, unsigned int count);
-disadvantage for dynamic allocation is that it cant create device node in advance
-above API only gives number to your driver.It does not connect your driver.So we will learn now how to connect driver
Some Important Data Structures
1)struct file_operations,
2)struct file,
3)struct inode
1)File Operations
Conventionally, a file_operations structure or a pointer to one is called fops
struct module *owner
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*aio_read)(struct kiocb *, char __user *, size_t, loff_t);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_write)(struct kiocb *, const char __user *, size_t, loff_t *);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int);
.
.
.
there many such structures in file operation
this is example how file operation.More clearity will come when you check the code for char driver
struct file_operations scull_fops = {
.owner =THIS_MODULE,
.llseek =scull_llseek,
.read =scull_read,
.write =scull_write,
.ioctl =scull_ioctl,
.open =scull_open,
.release = scull_release,
};
2)file structure(struct file)
-struct file, defined in <linux/fs.h>
-The file structure represents an open file
field of file structure are
-mode_t f_mode;The file mode identifies the file as either readable or writable (or both), by means of the bits FMODE_READ and FMODE_WRITE
-loff_t f_pos:The current reading or writing position
-unsigned int f_flags-These are the file flags, such as O_RDONLY, O_NONBLOCK, and O_SYNC. O_NONBLOCK is mostly used
-struct file_operations *f_op-The operations associated with the file.
-void *private_data;
-struct dentry *f_dentry;
3)inode structure
The inode structure is used by the kernel internally to represent files.
dev_t i_rdev;
For inodes that represent device files, this field contains the actual device number.
struct cdev *i_cdev;
struct cdev is the kernel’s internal structure that represents char devices; this
field contains a pointer to that structure when the inode refers to a char device
file.
-this macro are used to get major number and minor number from inode of device file
unsigned int iminor(struct inode *inode);
unsigned int imajor(struct inode *inode);
this should be used instead of using i_rdev
We are done with data structure.Now we move forward for char device registration
-struct cdev is used to represent char device present in <linux/cdev.h>
-There are two ways of allocating and initializing one of these structures
1)This is at runtime
struct cdev *my_cdev = cdev_alloc( );
my_cdev->ops = &my_fops;
2)void cdev_init(struct cdev *cdev, struct file_operations *fops);
-finally when cdev structure is set up now its time to tell kernel with this API
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
-as soon as cdev_add returns, your device is “live” and its operations
can be called by the kernel.
-To remove a char device from the system, call:
void cdev_del(struct cdev *dev);
-For completeness, we describe the older char device registration interface.Classic way to register device
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
name is name of driver that reappears in /proc/devices
int unregister_chrdev(unsigned int major, const char *name);
cdev_init() - used to initialize struct cdev with the defined file_operations
cdev_add() - used to add a character device to the system.
cdev_del() - used to remove a character device from the system
After a call to cdev_add()
, your device is immediately alive. All functions you defined (through the file_operations structure) can be called.Note:
struct cdev
is one of the elements of the inode
structure. As you probably may know already, an inode
structure is used by the kernel internally to represent files. The struct cdev
is the kernel's internal structure that represents char devices. So this field is a pointer to that structure while the inode
refers to the char device file. Therefore if the kernel has to invoke the device it has to register a structure of this type.some commands(let chardev be our device file)
ls -l /dev
mknod /dev/chardev 60 0
echo "jay kothari">/dev/chardev
cat /dev/chardev
modinfo (driver name)
lsmod | grep (driver name)
With this we compete the registration of char device
Practical:
Now lets try to load a character driver for number of devices:
step1:
-go to
$sudo cd /usr/src/linux-(version)/drivers/char
$mkdir (folder name)
$cd (folder name)
$vi (file name).c
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
/* fs/char_dev.c, drivers/base/class.c
* drivers/base/core.c
*/
#include <linux/slab.h>
#include <linux/kfifo.h>
#define MAX_SIZE 4096
int ndevices=5;
module_param(ndevices,int,S_IRUGO);
typedef struct private_object
{
struct cdev cdev;
unsigned char* pbuf;
struct kfifo kf1;
struct list_head lentry;
}C_DEV;
LIST_HEAD(phead);
dev_t pseudo_dev_id;
struct class *pseudo_cls;
//******************************************open()**************************************************************//
static int pseudo_open(struct inode *inode,struct file *file)
{
C_DEV* probj=container_of(inode->i_cdev,C_DEV,cdev);
printk("pseudo open method\n");
file->private_data=probj;
return 0;
}
//close(fd);
static int pseudo_release(struct inode *inode,struct file *file)
{
printk("pseudo close method\n");
return 0;
}
//****************************************read()******************************************************************//
static ssize_t pseudo_read(struct file *file, char __user *ubuf,size_t count, loff_t *ppos)
{
unsigned char* tbuf=kmalloc(count+1,GFP_KERNEL);
C_DEV* pdev=file->private_data;
int len=kfifo_len(&pdev->kf1);
int ret,nbytes;
printk("pseudo read method entered\n");
if(count>len)
count=len;//min(count,length)//
if(count==0) return -EAGAIN;
nbytes=kfifo_out(&pdev->kf1,tbuf,count);
printk("read:nbytes=%d\t,count=%d\t,off=%d\t,kfifo length=%d\n",nbytes,count,*ppos,kfifo_len(&pdev->kf1));
tbuf[nbytes]=0;
printk("read:tbuf=%s\n",tbuf);
ret=copy_to_user(ubuf,tbuf,nbytes);
// printf("tbub%s\n",*tbuf);
printk("read::ret=%d\n",ret);
if(ret) return -EFAULT;
// *ppos += nbytes;
kfree(tbuf);
return nbytes;
}
//*****************************************************************************************************************//
//**********************************write()***********************************************************************//
static ssize_t pseudo_write(struct file *file, const char __user *ubuf,size_t count, loff_t *ppos)
{
C_DEV* pdev=file->private_data;
int nbytes;
int remain=kfifo_avail(&pdev->kf1);
unsigned char* tbuf=kmalloc(count,GFP_KERNEL);
printk("write:pseudo write method entered,remain=%d\n",remain);
if(remain==0)
return -EAGAIN;
if(count > remain)
count=remain; //min(count,remain)
if(copy_from_user(tbuf,ubuf,count))
return -EFAULT;
nbytes=kfifo_in(&(pdev->kf1),tbuf,count);
printk("nbytes=%d\t,count=%d\t,off=%d\t,kfifo length=%d\t",nbytes,count,*ppos,kfifo_len(&pdev->kf1));
// *ppos += nbytes;
kfree(tbuf);
return nbytes;
}
//*****************************************************************************************************************//
//*************************************file operation**************************************************************//
static struct file_operations pseudo_fops=
{
.open=pseudo_open,
.release=pseudo_release,
.read=pseudo_read,
.write=pseudo_write,
.owner=THIS_MODULE,
//.ioctl.pseudo_ioctl
};
//******************************************************************************************************************//
//*********************************************init function()*****************************************************//
static int pseudo_init(void)
{
int ret,i=0;
C_DEV* pdev; //struct private_object* pdev;
ret=alloc_chrdev_region(&pseudo_dev_id,0,ndevices,"pseudo_char_driver");
if(ret<0) return -EFAULT;
printk("driver registered,major=%d\n",
MAJOR(pseudo_dev_id));
pseudo_cls=class_create(THIS_MODULE,"pseudo_class");
//per device initialization
for(i=0;i<ndevices;i++)
{
pdev=kmalloc(sizeof(C_DEV),GFP_KERNEL);
pdev->pbuf=kmalloc(MAX_SIZE,GFP_KERNEL);
kfifo_init(&(pdev->kf1),pdev->pbuf,MAX_SIZE);
// kfifo_alloc(&pdev->kf1,MAX_SIZE,GFP_KERNEL);//*
cdev_init(&pdev->cdev,&pseudo_fops);
kobject_set_name(&(pdev->cdev.kobj),"my_pseudo_dev%d",i);
ret=cdev_add(&pdev->cdev,pseudo_dev_id+i,1);
if(ret<0)
{
printk("cdev_add failed\n");
kfifo_free(&pdev->kf1);
//unregister the driver
return -EFAULT;
}
list_add_tail(&pdev->lentry,&phead);
device_create(pseudo_cls,NULL,pseudo_dev_id+i,NULL,"pchardev%d",i);
printk("device initialized:%d\n",i);
}
printk("Pseudo Char Driver registered successfully\n");
return 0;
}
//*****************************************************************************************************//
//*****************************************exit*******************************************************//
static void pseudo_exit(void)
{
struct list_head *ptemp,*qtemp;
C_DEV* pdev;
int i=0;
//per device cleanup/deallocation
list_for_each_safe(ptemp,qtemp,&phead)
{
pdev=container_of(ptemp,C_DEV,lentry);
kfifo_free(&pdev->kf1);
cdev_del(&pdev->cdev);
kfree(pdev);
device_destroy(pseudo_cls,pseudo_dev_id+i);
printk("cleaned device:%d\n",i);
i++;
}
class_destroy(pseudo_cls);
unregister_chrdev_region(pseudo_dev_id,5);
printk("Pseudo Char Driver:Bye\n");
}
//********************************************************************************************************//
module_init(pseudo_init);
module_exit(pseudo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jay Kothari");
MODULE_DESCRIPTION("driver for n number of device");
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//
-step 2:
make a Makefile in this same folder as follwing
$vi Makefile
obj-m += (file name).o
all:
make -C /lib/modules/$(shell uname -r)/build M=${PWD} modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=${PWD} clean
-step 3:
Now compile using make
$make
$ls
check .ko file is generated?
-step4
now load the module to the kernel using insmod command
$insmod (file name).ko
-step 5:
now go to user space /home director
then make a folder
$mkdir(folder name)
-step6:
write a c program that all the char device file
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//
#include<stdio.h>
#include<fcntl.h>
#include<assert.h>
#include<string.h>
int main(int argc,char *argv[])
{
assert(argc>1);
char buf[100];
char i=0;
memset(buf,0,100);
printf("Input:%s\n",argv[1]);
int fd=open("/dev/pchardev3",O_RDWR);
if(fd<0)
{perror("open error");
exit(3);
}
int k;
k= write(fd,argv[1],strlen(argv[1]));
if(k<0)
{perror("write");
exit(2);
}
printf("write is done\n");
k= read(fd,buf,100);
if(k<0) {
perror("read");
exit(1);
}
buf[k]='\0';
printf("%s\n",buf);
printf("%s\n",buf);
return 0;
}
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//
-step 7:
make compile this in user space and run it
gcc -(file_name).c -o (file_name)
./(file_name) "JAY KOTHARI"
//------------------------------------------------------------------------------------------------------------------//
-There a code for single character driver that i found from net you can check it out as I used it as my reference code to make this code.Haven’t change authors name to give him honor and I am thankful to him.
And you are done......enjoy......its easy so smile
what you need to do if you dont understand the code is that you google out each API you find and you would be done
Still if there are any troubles then let me know
Thank you
Bibliography:
-read chapter 3 of linux device drivers
-http://zobayer.blogspot.in/2011/07/simple-character-device.html
-http://www.makelinux.net/ldd3/chp-3-sect-4
No comments:
Post a Comment