144 lines
2.9 KiB
C
144 lines
2.9 KiB
C
|
#include <linux/init.h>
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/debugfs.h>
|
||
|
#include <linux/uaccess.h>
|
||
|
#include <linux/rwlock_types.h>
|
||
|
|
||
|
#define STUDENT_LOGIN "cchauvet"
|
||
|
|
||
|
MODULE_LICENSE("GPL");
|
||
|
|
||
|
struct dentry *subdir;
|
||
|
|
||
|
struct dentry *id_file;
|
||
|
struct dentry *jiffies_file;
|
||
|
struct dentry *foo_file;
|
||
|
|
||
|
static ssize_t id_read(struct file *, char *, size_t, loff_t *);
|
||
|
static ssize_t id_write(struct file *, const char *, size_t, loff_t *);
|
||
|
|
||
|
const struct file_operations id_file_fops = {
|
||
|
.owner = THIS_MODULE,
|
||
|
.write = id_write,
|
||
|
.read = id_read,
|
||
|
};
|
||
|
|
||
|
static ssize_t foo_read(struct file *, char *, size_t, loff_t *);
|
||
|
static ssize_t foo_write(struct file *, const char *, size_t, loff_t *);
|
||
|
|
||
|
const struct file_operations foo_file_fops = {
|
||
|
.owner = THIS_MODULE,
|
||
|
.write = foo_write,
|
||
|
.read = foo_read,
|
||
|
};
|
||
|
|
||
|
char foo_data[PAGE_SIZE];
|
||
|
size_t foo_data_len = 0;
|
||
|
DEFINE_MUTEX(foo_data_mutex);
|
||
|
|
||
|
static int __init module_start(void)
|
||
|
{
|
||
|
subdir = debugfs_create_dir("fortytwo", NULL);
|
||
|
if (!subdir)
|
||
|
goto create_fail;
|
||
|
|
||
|
id_file = debugfs_create_file("id", 0666, subdir, NULL, &id_file_fops);
|
||
|
if (!id_file)
|
||
|
goto create_fail;
|
||
|
|
||
|
debugfs_create_size_t("jiffies", 0444, subdir, (size_t *) &jiffies);
|
||
|
|
||
|
foo_file = debugfs_create_file("foo",0644, subdir, NULL, &foo_file_fops);
|
||
|
if (!foo_file)
|
||
|
goto create_fail;
|
||
|
|
||
|
|
||
|
printk(KERN_INFO "Hello world !\n");
|
||
|
return 0;
|
||
|
|
||
|
create_fail:
|
||
|
debugfs_remove_recursive(subdir);
|
||
|
|
||
|
return -ENOENT;
|
||
|
}
|
||
|
|
||
|
static void __exit module_end(void)
|
||
|
{
|
||
|
debugfs_remove_recursive(subdir);
|
||
|
|
||
|
printk(KERN_INFO "Cleaning up module.\n");
|
||
|
}
|
||
|
|
||
|
static ssize_t id_read(struct file *f, char *buf, size_t len, loff_t *f_pos)
|
||
|
{
|
||
|
char data[] = STUDENT_LOGIN;
|
||
|
size_t data_len = strlen(data);
|
||
|
|
||
|
if(*f_pos > 0)
|
||
|
return 0;
|
||
|
|
||
|
if (copy_to_user(buf, data, data_len))
|
||
|
return -EFAULT;
|
||
|
|
||
|
*f_pos += data_len;
|
||
|
return data_len;
|
||
|
}
|
||
|
|
||
|
static ssize_t id_write(struct file *f, const char *buf, size_t len, loff_t *offset)
|
||
|
{
|
||
|
char data[10];
|
||
|
size_t len_red = 10 > len ? len : 10;
|
||
|
|
||
|
if (copy_from_user(data, buf, len_red))
|
||
|
return -EFAULT;
|
||
|
|
||
|
if (strcmp(data, STUDENT_LOGIN))
|
||
|
return -EINVAL;
|
||
|
|
||
|
return len_red;
|
||
|
}
|
||
|
|
||
|
static ssize_t foo_read(struct file *f, char __user *buf, size_t len, loff_t *offset)
|
||
|
{
|
||
|
size_t len_red;
|
||
|
|
||
|
mutex_lock(&foo_data_mutex);
|
||
|
|
||
|
if (!buf)
|
||
|
return -EINVAL;
|
||
|
|
||
|
if (*offset > foo_data_len)
|
||
|
return 0;
|
||
|
|
||
|
if (len + *offset >= foo_data_len)
|
||
|
len_red = foo_data_len - *offset;
|
||
|
else
|
||
|
len_red = len;
|
||
|
|
||
|
if (copy_to_user(buf, foo_data + *offset, len_red))
|
||
|
return -EFAULT;
|
||
|
|
||
|
mutex_unlock(&foo_data_mutex);
|
||
|
|
||
|
*offset += len_red;
|
||
|
return len_red;
|
||
|
}
|
||
|
|
||
|
static ssize_t foo_write(struct file *, const char __user *buf, size_t len, loff_t *offset)
|
||
|
{
|
||
|
if (len > PAGE_SIZE)
|
||
|
return -EINVAL;
|
||
|
|
||
|
mutex_lock(&foo_data_mutex);
|
||
|
if (copy_from_user(foo_data, buf, len))
|
||
|
return -EFAULT;
|
||
|
foo_data_len = len;
|
||
|
mutex_unlock(&foo_data_mutex);
|
||
|
*offset = len;
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
module_init(module_start);
|
||
|
module_exit(module_end);
|