Created
August 21, 2022 20:04
-
-
Save cetaSYN/fd7377f13784eac02e1617bd737bf8fa to your computer and use it in GitHub Desktop.
Kernel module character device driver that always returns full bit-level 1s (0xFF...)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/cdev.h> | |
#include <linux/device.h> | |
#include <linux/fs.h> | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#define DEVICE_NAME "one" | |
MODULE_LICENSE("GPL"); | |
MODULE_AUTHOR("cetaSYN"); | |
MODULE_DESCRIPTION("Device driver that always returns full bit-level 1s (0xFF...)"); | |
MODULE_VERSION("0.1"); | |
static int major_number; | |
static ssize_t dev_read(struct file *, char __user *, size_t, loff_t *); | |
static int dev_open(struct inode *, struct file *); | |
static int dev_release(struct inode *, struct file *); | |
static struct class *device_class; | |
static struct file_operations fops = { | |
.read = dev_read, | |
.open = dev_open, | |
.release = dev_release | |
}; | |
enum { | |
CDEV_NOT_USED = 0, | |
CDEV_EXCLUSIVE_OPEN = 1 | |
}; | |
static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED); | |
int init_module(void) { | |
major_number = register_chrdev(0, DEVICE_NAME, &fops); | |
if(major_number < 0) { | |
pr_err("Failed to acquire major number with %i\n", major_number); | |
return major_number; | |
} | |
pr_debug("Successfully acquired major number %i\n", major_number); | |
device_class = class_create(THIS_MODULE, DEVICE_NAME); | |
device_create(device_class, NULL, MKDEV(major_number, 0), NULL, DEVICE_NAME); | |
pr_info("Device created at /dev/%s\n", DEVICE_NAME); | |
return 0; | |
} | |
void cleanup_module(void) { | |
device_destroy(device_class, MKDEV(major_number, 0)); | |
class_destroy(device_class); | |
unregister_chrdev(major_number, DEVICE_NAME); | |
} | |
static int dev_open(struct inode *inode, struct file *file) { | |
if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN)) { | |
return -EBUSY; | |
} | |
try_module_get(THIS_MODULE); | |
return 0; | |
} | |
static int dev_release(struct inode *inode, struct file *file) { | |
atomic_set(&already_open, CDEV_NOT_USED); | |
module_put(THIS_MODULE); | |
return 0; | |
} | |
static ssize_t dev_read(struct file *filep, __user char *buffer, size_t length, loff_t *offset) { | |
int bytes_read = 0; | |
while (length) { | |
put_user(0xFF, buffer++); | |
length--; | |
bytes_read++; | |
} | |
return bytes_read; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is probably not efficient and could break in several ways.
Highly recommend not using this in production unless vetted by someone with more kernel module experience than myself.