mirror of
https://github.com/Hizenberg469/Driver-tutorial.git
synced 2026-04-20 00:42:25 +03:00
ioctl done
This commit is contained in:
7
ioctl/Makefile
Normal file
7
ioctl/Makefile
Normal file
@@ -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
|
||||||
160
ioctl/demo_ioctl_driver.c
Normal file
160
ioctl/demo_ioctl_driver.c
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
#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)");
|
||||||
BIN
ioctl/ioctl_app
Executable file
BIN
ioctl/ioctl_app
Executable file
Binary file not shown.
35
ioctl/ioctl_app.c
Normal file
35
ioctl/ioctl_app.c
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
48
ioctl/ioctl_const.h
Normal file
48
ioctl/ioctl_const.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef _IOCTL_CHAR_DEVICE_H_
|
||||||
|
#define _IOCTL_CHAR_DEVICE_H_
|
||||||
|
|
||||||
|
#include <linux/ioctl.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
Reference in New Issue
Block a user