mirror of
https://github.com/Hizenberg469/Driver-tutorial.git
synced 2026-04-19 16:32:23 +03:00
Character driver finished
This commit is contained in:
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"fcntl.h": "c"
|
||||||
|
}
|
||||||
|
}
|
||||||
10
LKM/Makefile
Normal file
10
LKM/Makefile
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
obj-m += hello.o
|
||||||
|
obj-m += hello_func.o
|
||||||
|
obj-m += depmod.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
|
||||||
|
|
||||||
23
LKM/depmod.c
Normal file
23
LKM/depmod.c
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include <linux/module.h> // included for all kernel module
|
||||||
|
#include <linux/kernel.h> // included for KERN_INFO
|
||||||
|
#include <linux/init.h> // included for __init and __exit macros
|
||||||
|
|
||||||
|
|
||||||
|
extern void func(void);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Junet Hossain");
|
||||||
|
MODULE_DESCRIPTION("A Simple Hello World module");
|
||||||
|
|
||||||
|
static int __init depmod_init(void){
|
||||||
|
printk(KERN_INFO "In depmod_init calling exported symbol func\n");
|
||||||
|
func();
|
||||||
|
return 0; // Non-zero return means that the module couldn't be loaded.
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit depmod_cleanup(void){
|
||||||
|
printk(KERN_INFO "Cleaning up dep module.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(depmod_init);
|
||||||
|
module_exit(depmod_cleanup);
|
||||||
43
LKM/hello.c
Normal file
43
LKM/hello.c
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#include <linux/module.h> // included for all kernel module
|
||||||
|
#include <linux/kernel.h> // included for KERN_INFO
|
||||||
|
#include <linux/init.h> // included for __init and __exit macros
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Junet Hossain");
|
||||||
|
MODULE_DESCRIPTION("A Simple Hello World module");
|
||||||
|
|
||||||
|
static int __init hello_init(void){
|
||||||
|
printk(KERN_INFO "Hello world!\n");
|
||||||
|
return 0; // Non-zero return means that the module couldn't be loaded.
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit hello_cleanup(void){
|
||||||
|
printk(KERN_INFO "Cleaning up hello module.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(hello_init);
|
||||||
|
module_exit(hello_cleanup);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use these macros for efficient and optimized kernel modules.
|
||||||
|
*
|
||||||
|
* __init: It's a macro which is used for marking
|
||||||
|
* the function which is executed when the
|
||||||
|
* kernel is loaded. After execution, its memory
|
||||||
|
* is freed (for built-in modules). For module
|
||||||
|
* compiled as a loadable kernel module (LKM),
|
||||||
|
* __init has no effect (because the memory
|
||||||
|
* is allocated dynamically). If not used for built
|
||||||
|
* -in kernel, the memory for the init function
|
||||||
|
* remains allocated even after module initializaiton
|
||||||
|
* (wasted memory)
|
||||||
|
*
|
||||||
|
* __exit: It's a macro which is used to mark the function
|
||||||
|
* which is executed when the module is unloaded
|
||||||
|
* from the kernel. It is ignored for built-in kernel modules
|
||||||
|
* (since they can't be removed at runtime). For
|
||||||
|
* dynamically loaded modules, it ensures proper
|
||||||
|
* cleanup. If __exit is not used, the function will
|
||||||
|
* still run when removing the module, but marking
|
||||||
|
* it properly makes the code cleaner and optimized.
|
||||||
|
*/
|
||||||
41
LKM/hello_func.c
Normal file
41
LKM/hello_func.c
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#include <linux/module.h> // included for all kernel module
|
||||||
|
#include <linux/kernel.h> // included for KERN_INFO
|
||||||
|
#include <linux/init.h> // included for __init and __exit macros
|
||||||
|
|
||||||
|
|
||||||
|
void func(void);
|
||||||
|
EXPORT_SYMBOL_GPL(func);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EXPORT_SYMBOL_GPL:
|
||||||
|
* Since, in user space to use variable/function of one
|
||||||
|
* file to another file we use extern or header file. But
|
||||||
|
* for kernel space such thing is not allowed. But to use
|
||||||
|
* variable or function in another module/file we use
|
||||||
|
* EXPORT_SYMBOL_GPL(<fun or var name>) to export the
|
||||||
|
* function or variable to global scope for all the modules.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int val = 300;
|
||||||
|
|
||||||
|
void func(){
|
||||||
|
|
||||||
|
printk(KERN_INFO"func invoked\n ");
|
||||||
|
printk(KERN_INFO" val = %d \n", val);
|
||||||
|
}
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Junet Hossain");
|
||||||
|
MODULE_DESCRIPTION("A Simple Hello World module");
|
||||||
|
|
||||||
|
static int __init hello_init(void){
|
||||||
|
printk(KERN_INFO "Init Hello func module\n");
|
||||||
|
return 0; // Non-zero return means that the module couldn't be loaded.
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit hello_cleanup(void){
|
||||||
|
printk(KERN_INFO "Cleaning up hello func module.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(hello_init);
|
||||||
|
module_exit(hello_cleanup);
|
||||||
8
character_driver/Makefile
Normal file
8
character_driver/Makefile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
obj-m += character_drivers.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
|
||||||
|
|
||||||
27
character_driver/app_test.c
Normal file
27
character_driver/app_test.c
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
|
||||||
|
int fd, i;
|
||||||
|
ssize_t ret;
|
||||||
|
char my_buf[12] = "Hello world";
|
||||||
|
|
||||||
|
fd = open( "/dev/demo_cdrv", O_RDWR);
|
||||||
|
if(fd < 0){
|
||||||
|
printf("failed acquiring file descriptor return status %d\n", fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the contents of my buffer into the device */
|
||||||
|
ret = write(fd, my_buf, 8);
|
||||||
|
ret = read(fd, my_buf, 12);
|
||||||
|
if( ret < 0 )
|
||||||
|
printf("read operation failed with return status %d\n", ret);
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
130
character_driver/character_drivers.c
Normal file
130
character_driver/character_drivers.c
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
List of printk Log Levels:
|
||||||
|
Log Level | Macro | Priority Code | Purpose
|
||||||
|
0 | KERN_EMERG | <0> | System is unstable (panic-level message).
|
||||||
|
1 | KERN_ALERT | <1> | Immediate action required.
|
||||||
|
2 | KERN_CRIT | <2> | Critical errors (serious issues).
|
||||||
|
3 | KERN_ERR | <3> | General errors (non-critical).
|
||||||
|
4 | KERN_WARNING| <4> | Warnings (might cause issues).
|
||||||
|
5 | KERN_NOTICE | <5> | Normal but notable conditions.
|
||||||
|
6 | KERN_INFO | <6> | Informational messages (default for general logs).
|
||||||
|
7 | KERN_DEBUG | <7> | Debugging messages (used for development).
|
||||||
|
*/
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <asm/current.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#define CHAR_DEV_NAME "demo_cdev"
|
||||||
|
#define MAX_LENGTH 4000
|
||||||
|
#define SUCCESS 0
|
||||||
|
|
||||||
|
static char *char_device_buf;
|
||||||
|
struct cdev *demo_cdev;
|
||||||
|
dev_t mydev; //device tree as an instance
|
||||||
|
//We are using this because all character
|
||||||
|
//drivers belongs to device tree.
|
||||||
|
|
||||||
|
static int char_dev_open(struct inode *inode,
|
||||||
|
struct file *file){
|
||||||
|
|
||||||
|
printk(KERN_INFO "chr_drv_dynamic :: open operation invoked \n");
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int char_dev_release(struct inode *inode,
|
||||||
|
struct file *file){
|
||||||
|
|
||||||
|
printk(KERN_INFO "chr_drv_dynamic :: release opration invoked\n");
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t char_dev_read(struct file *file,
|
||||||
|
char *buf,
|
||||||
|
size_t lbuf,
|
||||||
|
loff_t *ppos){
|
||||||
|
|
||||||
|
printk(KERN_INFO "chr_dev_dynamic :: read operation invoked\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t char_dev_write(struct file *file,
|
||||||
|
const char *buf,
|
||||||
|
size_t lbuf,
|
||||||
|
loff_t *ppos){
|
||||||
|
|
||||||
|
printk(KERN_INFO "chr_drv_dynamic :: write operation invoked \n");
|
||||||
|
return lbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This syntax is called "Designated initialization"*/
|
||||||
|
/* This is allowed in C after C99*/
|
||||||
|
static struct file_operations char_dev_fops = {
|
||||||
|
.owner = THIS_MODULE, //To define the ownership of this struct
|
||||||
|
.read = char_dev_read, //When file is read
|
||||||
|
.write = char_dev_write, //When file is written on
|
||||||
|
.open = char_dev_open, //When file is open
|
||||||
|
.release = char_dev_release //When file is closed
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init char_dev_init(void){
|
||||||
|
int ret, count = 1;
|
||||||
|
|
||||||
|
//this alloc_chrdev_region will acquire
|
||||||
|
//major number dynamically.
|
||||||
|
if(alloc_chrdev_region(&mydev, 0, count, CHAR_DEV_NAME) < 0){
|
||||||
|
printk(KERN_ERR "failed to reserve major/minor range\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cdev_alloc function is used to allocate
|
||||||
|
//a character device.
|
||||||
|
if( !(demo_cdev = cdev_alloc())){
|
||||||
|
printk(KERN_ERR "cdev_alloc() failed\n");
|
||||||
|
unregister_chrdev_region(mydev, count);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
//It is used to initialize one
|
||||||
|
//character device allocated.
|
||||||
|
//Also to mention the capabilities
|
||||||
|
//of this character device, we also
|
||||||
|
//mention char_dev_fops.
|
||||||
|
cdev_init(demo_cdev, &char_dev_fops);
|
||||||
|
|
||||||
|
//cdev_add is used to add character device
|
||||||
|
//to character device list.
|
||||||
|
ret = cdev_add(demo_cdev, mydev, count);
|
||||||
|
if( ret < 0 ){
|
||||||
|
printk(KERN_INFO "Error registering device driver\n");
|
||||||
|
cdev_del( demo_cdev );
|
||||||
|
unregister_chrdev_region(mydev, count);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printk(KERN_INFO"\nDevice Registered: %s\n", CHAR_DEV_NAME);
|
||||||
|
printk(KERN_INFO"Major number = %d, Minor number = %d\n", MAJOR (mydev), MINOR (mydev));
|
||||||
|
|
||||||
|
char_device_buf = (char *)kmalloc(MAX_LENGTH, GFP_KERNEL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void __exit char_dev_exit(void){
|
||||||
|
cdev_del(demo_cdev);
|
||||||
|
unregister_chrdev_region(mydev,1);
|
||||||
|
kfree(char_device_buf);
|
||||||
|
printk(KERN_INFO "\n Driver unregistered \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(char_dev_init);
|
||||||
|
module_exit(char_dev_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Junet Hossain");
|
||||||
|
MODULE_DESCRIPTION("Character Device Driver - Test");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
@@ -18,5 +18,8 @@ int main(){
|
|||||||
n = read( fd2, buf, 10);
|
n = read( fd2, buf, 10);
|
||||||
|
|
||||||
printf(" read data = %s from ptwo \n", buf);
|
printf(" read data = %s from ptwo \n", buf);
|
||||||
|
|
||||||
|
close(fd1);
|
||||||
|
close(fd2);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Binary file not shown.
@@ -20,7 +20,7 @@ int main(){
|
|||||||
FD_ZERO(&read_set);
|
FD_ZERO(&read_set);
|
||||||
FD_SET(fd1, &read_set);
|
FD_SET(fd1, &read_set);
|
||||||
FD_SET(fd2, &read_set);
|
FD_SET(fd2, &read_set);
|
||||||
|
|
||||||
n = select(FD_SETSIZE, &read_set, NULL, NULL, &timeout);
|
n = select(FD_SETSIZE, &read_set, NULL, NULL, &timeout);
|
||||||
if( n < 0 ){
|
if( n < 0 ){
|
||||||
perror("select ");
|
perror("select ");
|
||||||
@@ -40,6 +40,9 @@ int main(){
|
|||||||
n = read(fd2, buf, 10);
|
n = read(fd2, buf, 10);
|
||||||
printf(" read data = %s from ptwo \n", buf);
|
printf(" read data = %s from ptwo \n", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// close(fd1);
|
||||||
|
// close(fd2);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
46
select_poll/poll1.c
Normal file
46
select_poll/poll1.c
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
int fd1, fd2;
|
||||||
|
struct pollfd pollarray[10];
|
||||||
|
char buf[10];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
fd1 = open("./pone", O_RDWR);
|
||||||
|
fd2 = open("./ptwo", O_RDWR);
|
||||||
|
pollarray[0].fd = fd1;
|
||||||
|
pollarray[1].fd = fd2;
|
||||||
|
pollarray[0].events = POLLIN;
|
||||||
|
pollarray[1].events = POLLIN;
|
||||||
|
|
||||||
|
n = poll(pollarray, 2, 10000);
|
||||||
|
if(n < 0){
|
||||||
|
perror("poll:");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//test whether fd1 is ready or not
|
||||||
|
if( (pollarray[0].revents & POLLIN)){
|
||||||
|
printf(" reading from fd1 (pone)\n");
|
||||||
|
n = read(fd1, buf, 10);
|
||||||
|
printf(" read data = %s from pone\n", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//test whether fd2 is ready or not
|
||||||
|
if( (pollarray[1].revents & POLLIN)){
|
||||||
|
printf(" reading from fd2 (ptwo)\n");
|
||||||
|
n = read(fd2, buf, 10);
|
||||||
|
printf(" read data = %s from ptwo\n", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// close(fd1);
|
||||||
|
// close(fd2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user