--------------------
char_dev.c
--------------------
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h> // required for various structures related to files liked fops.
#include <asm/uaccess.h> // required for copy_from and copy_to user functions
#include <linux/semaphore.h>
#include <linux/cdev.h>
static int Major;
dev_t dev_no,dev;
struct device
{
char array[100];
struct semaphore sem;
}char_dev;
int open(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "Inside open \n");
if(down_interruptible(&char_dev.sem)) {
printk(KERN_INFO " could not hold semaphore");
return -1;
}
return 0;
}
int release(struct inode *inode, struct file *filp)
{
printk (KERN_INFO "Inside close \n");
printk(KERN_INFO "Releasing semaphore");
up(&char_dev.sem);
return 0;
}
ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp)
{
unsigned long ret;
printk("Inside read \n");
ret = copy_to_user(buff, char_dev.array, count);
return ret;
}
ssize_t write(struct file *filp, const char *buff, size_t count, loff_t *offp)
{
unsigned long ret;
printk(KERN_INFO "Inside write \n");
ret = copy_from_user(char_dev.array, buff, count);
return count;
}
struct file_operations fops = {
read: read,
write: write,
open: open,
release: release
};
struct cdev *kernel_cdev;
int char_dev_init (void)
{
int ret;
kernel_cdev = cdev_alloc();
kernel_cdev->ops = &fops;
kernel_cdev->owner = THIS_MODULE;
printk (" Inside init module\n");
ret = alloc_chrdev_region( &dev_no , 0, 1,"chr_arr_dev");
if (ret < 0) {
printk("Major number allocation is failed\n");
return ret;
}
Major = MAJOR(dev_no);
dev = MKDEV(Major,0);
sema_init(&char_dev.sem,1);
printk (" The major number for your device is %d\n", Major);
ret = cdev_add( kernel_cdev,dev,1);
if(ret < 0 )
{
printk(KERN_INFO "Unable to allocate cdev");
return ret;
}
return 0;
}
void char_dev_cleanup(void)
{
printk(KERN_INFO " Inside cleanup_module\n");
cdev_del(kernel_cdev);
unregister_chrdev_region(Major, 1);
}
MODULE_LICENSE("GPL");
module_init(char_dev_init);
module_exit(char_dev_cleanup);
-------------
Makefile :
-------------
ifneq ($(KERNELRELEASE),)
obj-m := char_dev.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
----------------
creating a node:
----------------
mknod /dev/char_dev c 250 0
User Application :-
-------------------
main.c
------------------
#include <stdio.h>
#include <fcntl.h>
main ( )
{
int i,fd;
char ch, write_buf[100], read_buf[100];
fd = open("/dev/char_dev", O_RDWR);
if (fd == -1)
{
printf("Error in opening file \n");
exit(-1);
}
printf ("Press r to read from device or w to write the device ");
scanf ("%c", &ch);
switch (ch) {
case 'w':
printf (" Enter the data to be written into device");
scanf (" %[^\n]", write_buf);
write(fd, write_buf, sizeof(write_buf));
break;
case 'r':
read(fd, read_buf, sizeof(read_buf));
printf ("The data in the device is %s\n", read_buf);
break;
default:
printf("Wrong choice \n");
break;
}
close(fd);
}
------------------------------
Compiling User Application :
------------------------------
$gcc -o main main.c
#./main
Press r to read from device or w to write the device : w
Enter the data to be written into device : American Megatrends Inc.
#./main
Press r to read from device or w to write the device : r
The data in the device is : American Megatrends Inc.
char_dev.c
--------------------
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h> // required for various structures related to files liked fops.
#include <asm/uaccess.h> // required for copy_from and copy_to user functions
#include <linux/semaphore.h>
#include <linux/cdev.h>
static int Major;
dev_t dev_no,dev;
struct device
{
char array[100];
struct semaphore sem;
}char_dev;
int open(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "Inside open \n");
if(down_interruptible(&char_dev.sem)) {
printk(KERN_INFO " could not hold semaphore");
return -1;
}
return 0;
}
int release(struct inode *inode, struct file *filp)
{
printk (KERN_INFO "Inside close \n");
printk(KERN_INFO "Releasing semaphore");
up(&char_dev.sem);
return 0;
}
ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp)
{
unsigned long ret;
printk("Inside read \n");
ret = copy_to_user(buff, char_dev.array, count);
return ret;
}
ssize_t write(struct file *filp, const char *buff, size_t count, loff_t *offp)
{
unsigned long ret;
printk(KERN_INFO "Inside write \n");
ret = copy_from_user(char_dev.array, buff, count);
return count;
}
struct file_operations fops = {
read: read,
write: write,
open: open,
release: release
};
struct cdev *kernel_cdev;
int char_dev_init (void)
{
int ret;
kernel_cdev = cdev_alloc();
kernel_cdev->ops = &fops;
kernel_cdev->owner = THIS_MODULE;
printk (" Inside init module\n");
ret = alloc_chrdev_region( &dev_no , 0, 1,"chr_arr_dev");
if (ret < 0) {
printk("Major number allocation is failed\n");
return ret;
}
Major = MAJOR(dev_no);
dev = MKDEV(Major,0);
sema_init(&char_dev.sem,1);
printk (" The major number for your device is %d\n", Major);
ret = cdev_add( kernel_cdev,dev,1);
if(ret < 0 )
{
printk(KERN_INFO "Unable to allocate cdev");
return ret;
}
return 0;
}
void char_dev_cleanup(void)
{
printk(KERN_INFO " Inside cleanup_module\n");
cdev_del(kernel_cdev);
unregister_chrdev_region(Major, 1);
}
MODULE_LICENSE("GPL");
module_init(char_dev_init);
module_exit(char_dev_cleanup);
-------------
Makefile :
-------------
ifneq ($(KERNELRELEASE),)
obj-m := char_dev.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
----------------
creating a node:
----------------
mknod /dev/char_dev c 250 0
User Application :-
-------------------
main.c
------------------
#include <stdio.h>
#include <fcntl.h>
main ( )
{
int i,fd;
char ch, write_buf[100], read_buf[100];
fd = open("/dev/char_dev", O_RDWR);
if (fd == -1)
{
printf("Error in opening file \n");
exit(-1);
}
printf ("Press r to read from device or w to write the device ");
scanf ("%c", &ch);
switch (ch) {
case 'w':
printf (" Enter the data to be written into device");
scanf (" %[^\n]", write_buf);
write(fd, write_buf, sizeof(write_buf));
break;
case 'r':
read(fd, read_buf, sizeof(read_buf));
printf ("The data in the device is %s\n", read_buf);
break;
default:
printf("Wrong choice \n");
break;
}
close(fd);
}
------------------------------
Compiling User Application :
------------------------------
$gcc -o main main.c
#./main
Press r to read from device or w to write the device : w
Enter the data to be written into device : American Megatrends Inc.
#./main
Press r to read from device or w to write the device : r
The data in the device is : American Megatrends Inc.
Thanks for providing nice program. However, it may necessary to give procedure for successfully run the example.
ReplyDelete1. Compile char_drv.c driver with given MakeFile.
2. Load char_drv in to kernel using # insmod char_drv.ko.
3. Verify the driver is loaded using # dmesg
[root@linux ldd1]# dmesg | tail -5
[12904.294818] Inside close
[12873.302846] Releasing semaphore
[12904.294823] Releasing semaphore<6>[13023.776464] Inside cleanup_module
[13710.280654] Inside init module
[13710.280659] The major number for your device is 246
[root@linux ldd1]#
4. See the Major number of device (here is 246)
5. Now create nod in /dev using # mknod /dev/char_dev c 246 0
6. Verify the above node created in /dev using [root@linux ldd1]# ls -l /dev/char_dev
crw-r--r--. 1 root root 247, 0 Mar 17 09:03 /dev/char_dev
[root@linux ldd1]#
7. compile user application program main.c using #gcc -o main main.c
I have modified the main.c is below
int main ( )
{
int lock, i,fd;
char ch, write_buf[100], read_buf[100];
fd = open("/dev/char_dev", O_RDWR);
if (fd == -1)
{
printf("Error in opening file \n");
exit(-1);
}
lock = 1;
while(lock != 'q')
{
printf ("Press (w,r,q) w: write to mem; r-read from mem; q: Exit: ");
scanf ("%c", &ch);
switch (ch)
{
case 'w':
printf ("Enter the data to be written into device: ");
scanf (" %[^\n]", write_buf);
write(fd, write_buf, sizeof(write_buf));
break;
case 'r':
read(fd, read_buf, sizeof(read_buf));
printf ("The data in the device is: %s\n", read_buf);
break;
case 'q':
lock = 'q';
printf ("\n Good bye...\n");
break;
default:
printf("Wrong choice \n");
break;
} // switch
} // while
close(fd);
return 0;
} // main
Finally run # ./main
Enjoy....
Compiler warning during char_dev.c compilation:
ReplyDeleteIn function ‘copy_from_user.constprop.0’,
inlined from ‘write’ at /home/linux/Project/ldd1/char_dev.c:53:7:
/usr/src/kernels/3.7.9-104.fc17.i686.PAE/arch/x86/include/asm/uaccess_32.h:211:26: warning: call to ‘copy_from_user_overflow’ declared with attribute warning: copy_from_user() buffer size is not provably correct [enabled by default]
To overcome the above warning I have modified the driver source code as follows.
#include
#include
#include // required for various structures related to files liked fops.
#include // required for copy_from and copy_to user functions
#include
#include
// array size is fixed modified on 16.03.13
#define MAX 100
static int Major;
dev_t dev_no,dev;
struct device
{
char array[MAX];
struct semaphore sem;
}char_dev;
int open(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "Inside open \n");
if(down_interruptible(&char_dev.sem))
{
printk(KERN_INFO " could not hold semaphore");
return -1;
}
return 0;
}
int release(struct inode *inode, struct file *filp)
{
printk (KERN_INFO "Inside close \n");
printk(KERN_INFO "Releasing semaphore");
up(&char_dev.sem);
return 0;
}
ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp)
{
unsigned long ret;
printk("Inside read \n");
ret = copy_to_user(buff, char_dev.array, count);
return ret;
}
ssize_t write(struct file *filp, const char *buff, size_t count, loff_t *offp)
{
unsigned long ret;
printk(KERN_INFO "Inside write \n");
if(count > MAX) // added this statement to avoid overflow warning (16.03.13)
count = MAX;
ret = copy_from_user(char_dev.array, buff, count);
return count;
}
struct file_operations fops =
{
read: read,
write: write,
open: open,
release: release
};
struct cdev *kernel_cdev;
int char_dev_init (void)
{
int ret;
kernel_cdev = cdev_alloc();
kernel_cdev->ops = &fops;
kernel_cdev->owner = THIS_MODULE;
printk (" Inside init module\n");
ret = alloc_chrdev_region( &dev_no , 0, 1,"chr_arr_dev");
if (ret < 0)
{
printk("Major number allocation is failed\n");
return ret;
}
Major = MAJOR(dev_no);
dev = MKDEV(Major,0);
sema_init(&char_dev.sem,1);
printk (" The major number for your device is %d\n", Major);
ret = cdev_add( kernel_cdev,dev,1);
if(ret < 0 )
{
printk(KERN_INFO "Unable to allocate cdev");
return ret;
}
return 0;
}
void char_dev_cleanup(void)
{
printk(KERN_INFO " Inside cleanup_module\n");
cdev_del(kernel_cdev);
unregister_chrdev_region(Major, 1);
}
MODULE_LICENSE("GPL");
module_init(char_dev_init);
module_exit(char_dev_cleanup);
This source code gives clean compilation:
Hi.,
ReplyDeleteI have tested the code which is given/last updated.,But I could find the some issue ie., continious printing, whicle reading the written text. And the captures a sgiven below, can u pls check this why this continious printing during the read operation.,,
The logs are.,
root@lcl:$> ls -l /dev/chr_dev
ls: cannot access /dev/chr_dev: No such file or directory
root@lcl:$> mknod /dev/chr_dev c 246 0
root@lcl:$> ls -l /dev/chr_dev
crw-r--r-- 1 root root 246, 0 Jan 29 04:22 /dev/chr_dev
root@lcl:$> echo "HELLO.............UUUUUUUUUUUUUUU" > /dev/chr_dev; dmesg | tail -10
Inside open
Inside write
Inside close
Releasing semaphore
root@lcl:$> cat > /dev/chr_dev; dmesg | tail -10
root@lcl:$> cat /dev/chr_dev; dmesg | tail -10
HELLO.............UUUUUUUUUUUUUUU
O÷O÷``AEEUOdDtOdDtOdDt*OnXEt0OoaHt8Oo At=OdDtNOo(Xtcleanup_modulechar_dev_initinit_modulewritereleasereadchar_dev_cleanupopenHELLO.............UUUUUUUUUUUUUUU
O÷O÷``AEEUOdDtOdDtOdDt*OnXEt0OoaHt8Oo At=OdDtNOo(Xtcleanup_modulechar_dev_initinit_modulewritereleasereadchar_dev_cleanupopenHELLO.............UUUUUUUUUUUUUUU
O÷O÷``AEEUOdDtOdDtOdDt*OnXEt0OoaHt8Oo At=OdDtNOo(Xtcleanup_modulechar_dev_initinit_modulewritereleasereadchar_dev_cleanupopenHELLO.............UUUUUUUUUUUUUUU
O÷O÷``AEEUOdDtOdDtOdDt*OnXEt0OoaHt8Oo At=OdDtNOo(Xtcleanup_modulechar_dev_initinit_modulewritereleasereadchar_dev_cleanupopenHELLO.............UUUUUUUUUUUUUUU
O÷O÷``AEEUOdDtOdDtOdDt*OnXEt0OoaHt8Oo At=OdDtNOo(Xtcleanup_modulechar_dev_initinit_modulewritereleasereadchar_dev_cleanupopenHELLO.............UUUUUUUUUUUUUUU
O÷O÷``AEEUOdDtOdDtOdDt*OnXEt0OoaHt8Oo At=OdDtNOo(Xtcleanup_modulechar_dev_initinit_modulewritereleasereadchar_dev_cleanupopenHELLO.............UUUUUUUUUUUUUUU
O÷O÷``AEEUOdDtOdDtOdDt*OnXEt0OoaHt8Oo At=OdDtNOo(Xtcleanup_modulechar_dev_initinit_modulewritereleasereadchar_dev_cleanupopenHELLO.............UUUUUUUUUUUUUUU
O÷O÷``AEEUOdDtOdDtOdDt*OnXEt0OoaHt8Oo At=OdDtNOo(Xtcleanup_modulechar_dev_initinit_modulewritereleasereadchar_dev_cleanupopenHELLO.............UUUUUUUUUUUUUUU
O÷O÷``AEEUOdDtOdDtOdDt*OnXEt0OoaHt8Oo At=OdDtNOo(Xtcleanup_modulechar_dev_initinit_modulewritereleasereadchar_dev_cleanupopenHELLO.............UUUUUUUUUUUUUUU
O÷O÷``AEEUOdDtOdDtOdDt*OnXEt0OoaHt8Oo At=OdDtNOo(Xtcleanup_modulechar_dev_initinit_modulewritereleasereadchar_dev_cleanupopenHELLO.............UUUUUUUUUUUUUUU
O÷O÷``AEEUOdDtOdDtOdDt*OnXEt0OoaHt8Oo At=OdDtNOo(Xtcleanup_modulechar_dev_init init_module write releasereadchar_dev_cleanupopen HELLO.............UUUUUUUUUUUUUUU
O÷O÷``AEEUOdDtOdDtOdDt*OnXEt0OoaHt8Oo At=OdDtNOo(Xtcleanup_modulechar_dev_initinit_modulewritereleasereadchar_dev_cleanupopen^C
....................this is continues printing which is non stop till then we use ctrl+C znd ^z............
Inside close
Releasing semaphore
root@lcl:$>
Hi, i have followed the complete steps but am getting error prints that is unable to open the file... Please advise
ReplyDeleteMight be you need to run it as root.
Delete