From 8a8b8cf56aa52b93d738d73bfd4c03020ec7d7b9 Mon Sep 17 00:00:00 2001 From: Hizenberg469 Date: Mon, 24 Feb 2025 17:45:02 +0000 Subject: [PATCH] ioctl done --- ioctl/Makefile | 7 ++ ioctl/demo_ioctl_driver.c | 160 ++++++++++++++++++++++++++++++++++++++ ioctl/ioctl_app | Bin 0 -> 16232 bytes ioctl/ioctl_app.c | 35 +++++++++ ioctl/ioctl_const.h | 48 ++++++++++++ 5 files changed, 250 insertions(+) create mode 100644 ioctl/Makefile create mode 100644 ioctl/demo_ioctl_driver.c create mode 100755 ioctl/ioctl_app create mode 100644 ioctl/ioctl_app.c create mode 100644 ioctl/ioctl_const.h diff --git a/ioctl/Makefile b/ioctl/Makefile new file mode 100644 index 0000000..1e87598 --- /dev/null +++ b/ioctl/Makefile @@ -0,0 +1,7 @@ +obj-m += demo_ioctl_driver.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 \ No newline at end of file diff --git a/ioctl/demo_ioctl_driver.c b/ioctl/demo_ioctl_driver.c new file mode 100644 index 0000000..e42d611 --- /dev/null +++ b/ioctl/demo_ioctl_driver.c @@ -0,0 +1,160 @@ +#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)"); \ No newline at end of file diff --git a/ioctl/ioctl_app b/ioctl/ioctl_app new file mode 100755 index 0000000000000000000000000000000000000000..27b48860a4dbc79be8256bbf0a11ba49ea33f9f8 GIT binary patch literal 16232 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 Cq9@h> literal 0 HcmV?d00001 diff --git a/ioctl/ioctl_app.c b/ioctl/ioctl_app.c new file mode 100644 index 0000000..1a80844 --- /dev/null +++ b/ioctl/ioctl_app.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "ioctl_const.h" + +int main(){ + + int fd; + int32_t value , number; + + printf("\nOpening Driver\n"); + fd = open("/dev/demo_ioctl_device", O_RDWR); + if( fd < 0 ){ + printf("Cannot open device file...\n"); + return 0; + } + + printf("Enter the Value to send\n"); + scanf("%d", &number); + printf("Writing Value to Driver\n"); + ioctl(fd, WR_VALUE, (int32_t*) &number); + + printf("Reading Value from Driver\n"); + ioctl(fd, RD_VALUE, (int32_t*) &value); + printf("Value is %d\n", value); + + printf("Closing Driver\n"); + close(fd); + return 0; +} \ No newline at end of file diff --git a/ioctl/ioctl_const.h b/ioctl/ioctl_const.h new file mode 100644 index 0000000..8569434 --- /dev/null +++ b/ioctl/ioctl_const.h @@ -0,0 +1,48 @@ +#ifndef _IOCTL_CHAR_DEVICE_H_ +#define _IOCTL_CHAR_DEVICE_H_ + +#include + +/** + * ioctl constants are defined in this header file for our + * char_driver_ioctl driver. + * + * This file explains how the constants are defined with + * the use of inline comments + */ + +/** + * Constants have to be globally unique. Though this is not + * compulsory, it is necessary. This is because of the simple + * reason: we do not want our commands to clash with the commands + * in other drivers. we don't want the right command doing to + * the wrong driver or vice-versa + */ + +/** + * We have to base our constants based on a magic number. + */ + +#define DEMO_IOCTL_MAGIC 'a' + +/** + * Defining constants requires us to decide following values + * + * 1. type or magic number (type) + * 2. sequence number which is eight bits wide. This means + * we can have up to 256 ioctl commands (nr) + * 3. direction if the arg is involed, whether we are reading + * or writing + * 4. size(composition) of the argument. + * + * To arrive at unique numbers easily we use the following macros + * _IO(type, nr); -> no data is passed from kernel to user space, just like void function + * _IOW(type, nr, dataitem) the fourth item calculated using sizeof -> to read from user to kernel + * _IOR(type, nr, dataitem) -> to write to user from kernel + * _IOWR(type, nr, dataitem) -> to do both read and write + */ + +#define WR_VALUE _IOW(DEMO_IOCTL_MAGIC, 1, int32_t *) +#define RD_VALUE _IOR(DEMO_IOCTL_MAGIC, 2, int32_t *) + +#endif \ No newline at end of file