Initial commit

This commit is contained in:
KoroLion 2021-01-08 15:18:01 +03:00
commit 7cd528626d
3 changed files with 168 additions and 0 deletions

22
Makefile Normal file
View File

@ -0,0 +1,22 @@
BINARY := kl_char_driver
KERNEL := /lib/modules/$(shell uname -r)/build
KMOD_DIR := $(shell pwd)
ccflags-y += -Wall
obj-m += $(BINARY).o
$(BINARY)-y := main.o
$(BINARY).ko: main.c
make -C $(KERNEL) M=$(KMOD_DIR) modules
showlog:
tail -n10 /var/log/messages
enable: $(BINARY).ko
-insmod $(BINARY).ko
disable:
-rmmod $(BINARY)
check: disable enable
echo wolf228 > /dev/kl_char_dev-0 && head -1 /dev/kl_char_dev-0 && make showlog
clean:
make -C $(KERNEL) M=$(KMOD_DIR) clean

3
README.md Normal file
View File

@ -0,0 +1,3 @@
This driver creates devices in /dev. You could save anything to these devices and then read.
Compile and check driver using **sudo make check**

143
main.c Normal file
View File

@ -0,0 +1,143 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#define DEVICES_AMOUNT 3
#define MAX_DATA_LEN 64
const char DEVICE_NAME[] = "kl_char_dev";
static char user_data[DEVICES_AMOUNT][MAX_DATA_LEN];
static int char_dev_open(struct inode *inode, struct file *file);
static int char_dev_release(struct inode *inode, struct file *file);
static ssize_t char_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset);
static ssize_t char_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset);
static const struct file_operations char_dev_fops = {
.owner = THIS_MODULE,
.open = char_dev_open,
.release = char_dev_release,
.read = char_dev_read,
.write = char_dev_write
};
struct CHAR_DEV_DATA {
struct cdev cdev;
};
static int dev_major = 0;
static struct class *char_dev_class = NULL;
static struct CHAR_DEV_DATA char_dev_data[DEVICES_AMOUNT];
static int char_dev_uevent(struct device *dev, struct kobj_uevent_env *env) {
// permissions for device file
add_uevent_var(env, "DEVMODE=%#o", 0666);
return 0;
}
static int char_dev_init(void) {
int err, i;
dev_t dev;
size_t dev_num;
err = alloc_chrdev_region(&dev, 0, DEVICES_AMOUNT, DEVICE_NAME);
dev_major = MAJOR(dev);
char_dev_class = class_create(THIS_MODULE, DEVICE_NAME);
char_dev_class->dev_uevent = char_dev_uevent;
for (i = 0; i < DEVICES_AMOUNT; i++) {
cdev_init(&char_dev_data[i].cdev, &char_dev_fops);
char_dev_data[i].cdev.owner = THIS_MODULE;
dev_num = MKDEV(dev_major, i);
cdev_add(&char_dev_data[i].cdev, dev_num, 1);
device_create(char_dev_class, NULL, dev_num, NULL, "%s-%d", DEVICE_NAME, i);
if (i % 2 == 0) {
strncpy(user_data[i], "WOLF\n", MAX_DATA_LEN);
} else {
strncpy(user_data[i], "LION\n", MAX_DATA_LEN);
}
}
return 0;
}
static void char_dev_exit(void) {
int i;
for (i = 0; i < DEVICES_AMOUNT; i++) {
device_destroy(char_dev_class, MKDEV(dev_major, i));
}
class_unregister(char_dev_class);
class_destroy(char_dev_class);
unregister_chrdev_region(MKDEV(dev_major, 0), MINORMASK);
}
static int char_dev_open(struct inode *inode, struct file *file) {
int minor = MINOR(file->f_path.dentry->d_inode->i_rdev);
printk(KERN_INFO "#%s: minor %d opened\n", DEVICE_NAME, minor);
return 0;
}
static int char_dev_release(struct inode *inode, struct file *file) {
int minor = MINOR(file->f_path.dentry->d_inode->i_rdev);
printk(KERN_INFO "#%s: minor %d closed\n", DEVICE_NAME, minor);
return 0;
}
static ssize_t char_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) {
size_t datalen;
int minor = MINOR(file->f_path.dentry->d_inode->i_rdev);
printk(KERN_INFO "#%s: reading from minor %d\n", DEVICE_NAME, minor);
datalen = strlen(user_data[minor]);
if (count > datalen) {
count = datalen;
}
if (copy_to_user(buf, user_data[minor], count)) {
return -EFAULT;
}
return count;
}
static ssize_t char_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) {
size_t not_copied;
int minor = MINOR(file->f_path.dentry->d_inode->i_rdev);
printk(KERN_INFO "#%s: writing to minor %d\n", DEVICE_NAME, minor);
if (count > MAX_DATA_LEN) {
count = MAX_DATA_LEN;
}
not_copied = copy_from_user(user_data[minor], buf, count);
if (not_copied != 0) {
printk(KERN_WARNING "#%s: unable to copy %zd bytes from the user\n", DEVICE_NAME, not_copied);
}
user_data[minor][count] = 0;
printk(KERN_INFO "#%s: received from user: %s", DEVICE_NAME, user_data[minor]);
return count;
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("KoroLion <github.com/KoroLion>");
module_init(char_dev_init);
module_exit(char_dev_exit);