Files
Driver-tutorial/ioctl/demo_ioctl_driver.c
2025-02-24 17:45:02 +00:00

160 lines
4.8 KiB
C

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h> //kmalloc()
#include <linux/uaccess.h> //copy_to/from_user()
#include <linux/ioctl.h>
#include "ioctl_const.h"
int32_t value = 0;
dev_t dev = 0;
static struct cdev demo_ioctl_driver_cdev;
/**
* Function Prototypes
*/
static int __init demo_ioctl_driver_driver_init(void);
static void __exit demo_ioctl_driver_driver_exit(void);
static int demo_ioctl_driver_open(struct inode *inode, struct file *file);
static int demo_ioctl_driver_release(struct inode *inode, struct file *file);
static ssize_t demo_ioctl_driver_read(struct file *filp, char __user *buf, size_t len, loff_t *off);
static ssize_t demo_ioctl_driver_write(struct file *filp, const char __user *buf, size_t len, loff_t *off);
static long demo_ioctl_driver_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
/**
* __user is a macro in Linux kernel that indicates that
* the pointer is pointing to user-space memory. It is
* used for safety and correctness when writing kernel code
* that interacts with user-space.
*
* -> This annotation helps identify user-space pointer
* in kernel code.
* -> It is mainly used for static analysis and runtime
* safety checks.
*
*/
/**
* File operation structure
*/
static struct file_operations fops = {
.owner = THIS_MODULE,
.read = demo_ioctl_driver_read,
.write = demo_ioctl_driver_write,
.open = demo_ioctl_driver_open,
.unlocked_ioctl = demo_ioctl_driver_ioctl,
.release = demo_ioctl_driver_release
};
/**
* This function will be called when we open the Device file
*/
static int demo_ioctl_driver_open(struct inode *inode, struct file *file){
pr_info("Device File Opened...!!!\n"); // Same functionality as printk
return 0;
}
/**
* This Function will be called when we close the Device file
*/
static int demo_ioctl_driver_release(struct inode *inode, struct file *file){
pr_info("Device File Closed...!!!\n");
return 0;
}
/**
* This function will be called when read the Device file
*/
static ssize_t demo_ioctl_driver_read(struct file *filp, char __user *buf, size_t len,
loff_t *off){
pr_info("Read Function\n");
return 0;
}
/**
* This function will be called when we write the Device file
*/
static ssize_t demo_ioctl_driver_write(struct file *filp, const char __user *buf, size_t len, loff_t *off){
pr_info("Write fucntion\n");
return 0;
}
/**
* This function will be called when we write IOCTL on the Device file
*/
static long demo_ioctl_driver_ioctl(struct file *file, unsigned int cmd, unsigned long arg){
switch(cmd){
case WR_VALUE:
/*utility function by kernel to copy from/to between user and kernel space*/
if( copy_from_user(&value, (int32_t*) arg, sizeof(value)) ){
pr_err("Data Write . Err!\n");
}
pr_info("demo_ioctl_driver_ioctl :: WR_VALUE called\n" );
pr_info("Value = %d\n", value);
break;
case RD_VALUE:
if( copy_to_user((int32_t *)arg, &value, sizeof(value)) ){
pr_err("Data Read : Err\n");
}
pr_info("demo ioctl driver ioctl :: RD_VALUE called\n");
break;
default:
pr_info("Default\n");
break;
}
return 0L;
}
/**
* Module Init function
*/
static int __init demo_ioctl_driver_driver_init(void){
//this alloc_chrdev_region will acquire
//major number dynamically.
if(alloc_chrdev_region(&dev, 0, 1, "demo_ioctl_driver_Dev") < 0){
pr_err("Cannot allocate major number\n");
return -1;
}
pr_info("Major = %d Minor = %d \n", MAJOR(dev), MINOR(dev));
/*Creating cdev structure*/
cdev_init(&demo_ioctl_driver_cdev, &fops);
//cdev_add is used to add character device
//to character device list.
int ret = cdev_add(&demo_ioctl_driver_cdev, dev, 1);
if( ret < 0 ){
pr_info("Error registering device driver\n");
cdev_del( &demo_ioctl_driver_cdev );
unregister_chrdev_region(dev, 1);
return -1;
}
pr_info("\nDevice Registered: demo_ioctl_driver_Dev\n" );
return 0;
}
/**
* Module exit function
*/
static void __exit demo_ioctl_driver_driver_exit(void){
cdev_del( &demo_ioctl_driver_cdev);
unregister_chrdev_region(dev, 1);
pr_info("Device Driver Remove....Done!!!\n");
}
module_init(demo_ioctl_driver_driver_init);
module_exit(demo_ioctl_driver_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Junet Hossain");
MODULE_DESCRIPTION("Simple Linux device driver (IOCTL)");