You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
3.6 KiB
C
145 lines
3.6 KiB
C
#include <linux/cdev.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/init.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/module.h>
|
|
#include <linux/printk.h>
|
|
#include <linux/random.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/types.h>
|
|
#include <linux/version.h>
|
|
|
|
MODULE_LICENSE("Dual BSD/GPL");
|
|
MODULE_AUTHOR("fef <owo@fef.moe>");
|
|
MODULE_DESCRIPTION("gay keymash character device driver");
|
|
MODULE_VERSION("0.1.1");
|
|
|
|
#define keymash_debug(msg, ...) printk(KERN_DEBUG "keymash: " msg, ##__VA_ARGS__)
|
|
#define keymash_info(msg, ...) printk(KERN_INFO "keymash: " msg, ##__VA_ARGS__)
|
|
#define keymash_warn(msg, ...) printk(KERN_WARN "keymash: " msg, ##__VA_ARGS__)
|
|
#define keymash_err(msg, ...) printk(KERN_ERR "keymash: " msg, ##__VA_ARGS__)
|
|
|
|
static dev_t keymash_dev = MKDEV(0, 0);
|
|
static struct cdev keymash_cdev;
|
|
static struct class *keymash_class;
|
|
static struct device *keymash_device;
|
|
|
|
#define KEYMASH_MINOR_COUNT 1
|
|
#define KEYMASH_DEVICE_NAME "keymash"
|
|
#define KEYMASH_CLASS_NAME "kmsh"
|
|
|
|
static const char keymash_chrs[] = "asdfghjkl;";
|
|
#define KEYMASH_CHRS_LEN (ARRAY_SIZE(keymash_chrs) - 1) /* minus NUL */
|
|
|
|
static void keymash_gay(void *buf, size_t len)
|
|
{
|
|
unsigned char *cbuf = buf;
|
|
|
|
get_random_bytes(buf, len);
|
|
|
|
while (len--) {
|
|
unsigned char rnd = *cbuf;
|
|
*cbuf++ = keymash_chrs[rnd % KEYMASH_CHRS_LEN];
|
|
}
|
|
}
|
|
|
|
static ssize_t keymash_read(struct file *file, char __user *user_buffer,
|
|
size_t size, loff_t *offset)
|
|
{
|
|
ssize_t ret;
|
|
void *gay = kmalloc(size, GFP_KERNEL);
|
|
|
|
if (gay) {
|
|
keymash_gay(gay, size);
|
|
if (copy_to_user(user_buffer, gay, size))
|
|
ret = -EFAULT;
|
|
else
|
|
ret = size;
|
|
kfree(gay);
|
|
} else {
|
|
ret = -ENOMEM;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const struct file_operations keymash_fops = {
|
|
.owner = THIS_MODULE,
|
|
.read = keymash_read,
|
|
};
|
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)
|
|
static char *keymash_devnode(struct device *dev, umode_t *mode)
|
|
#else
|
|
static char *keymash_devnode(const struct device *dev, umode_t *mode)
|
|
#endif
|
|
{
|
|
if (mode)
|
|
*mode = 0444;
|
|
return NULL;
|
|
}
|
|
|
|
__init
|
|
static int keymash_init(void)
|
|
{
|
|
int err = -1;
|
|
|
|
err = alloc_chrdev_region(&keymash_dev, 0, KEYMASH_MINOR_COUNT, KEYMASH_DEVICE_NAME);
|
|
if (err < 0) {
|
|
keymash_err("alloc_chrdev_region() returned %d\n", err);
|
|
goto err_alloc_chrdev_region;
|
|
}
|
|
keymash_debug("using device major number %d\n", MAJOR(keymash_dev));
|
|
|
|
cdev_init(&keymash_cdev, &keymash_fops);
|
|
err = cdev_add(&keymash_cdev, keymash_dev, 1);
|
|
if (err < 0) {
|
|
keymash_err("cdev_init() returned %d\n", err);
|
|
goto err_cdev_add;
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)
|
|
keymash_class = class_create(THIS_MODULE, KEYMASH_CLASS_NAME);
|
|
#else
|
|
keymash_class = class_create(KEYMASH_CLASS_NAME);
|
|
#endif
|
|
if (IS_ERR(keymash_class)) {
|
|
err = PTR_ERR(keymash_class);
|
|
keymash_err("class_create() returned %d\n", err);
|
|
goto err_class_create;
|
|
}
|
|
keymash_class->devnode = keymash_devnode;
|
|
|
|
keymash_device = device_create(keymash_class, NULL, keymash_dev, NULL, KEYMASH_DEVICE_NAME);
|
|
if (IS_ERR(keymash_device)) {
|
|
err = PTR_ERR(keymash_device);
|
|
keymash_err("device_create() returned %d\n", err);
|
|
goto err_device_create;
|
|
}
|
|
|
|
return 0;
|
|
|
|
err_device_create:
|
|
class_unregister(keymash_class);
|
|
class_destroy(keymash_class);
|
|
err_class_create:
|
|
cdev_del(&keymash_cdev);
|
|
err_cdev_add:
|
|
unregister_chrdev_region(keymash_dev, KEYMASH_MINOR_COUNT);
|
|
err_alloc_chrdev_region:
|
|
return err;
|
|
}
|
|
module_init(keymash_init);
|
|
|
|
__exit
|
|
static void keymash_exit(void)
|
|
{
|
|
device_destroy(keymash_class, keymash_dev);
|
|
class_unregister(keymash_class);
|
|
class_destroy(keymash_class);
|
|
cdev_del(&keymash_cdev);
|
|
unregister_chrdev_region(keymash_dev, KEYMASH_MINOR_COUNT);
|
|
}
|
|
module_exit(keymash_exit);
|