Initial commit
This commit is contained in:
commit
7cd528626d
22
Makefile
Normal file
22
Makefile
Normal 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
3
README.md
Normal 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
143
main.c
Normal 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);
|
Loading…
Reference in New Issue
Block a user