#include #include #include #include #include #include #include #include //kmalloc() #include //copy_to/from_user() #include #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)");