Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

05-Interfaces: Modules with sysfs/proc access #90

Open
wants to merge 1 commit into
base: Sergey.Perederiy
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions 05-Interfaces/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
obj-m += interface_module_sysfs.o
obj-m += interface_module_procfs.o

all:
make -C ${HEADERS_PATH} M=$(PWD) modules

clean:
make -C ${HEADERS_PATH} M=$(PWD) clean
3 changes: 3 additions & 0 deletions 05-Interfaces/envsetup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

export HEADERS_PATH="${HOME}/workspace/buildroot-2018.08.2/output/build/linux-4.13.16"
162 changes: 162 additions & 0 deletions 05-Interfaces/interface_module_procfs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

#define DIR_NAME "my_if_module"
#define ENT1_NAME "conv"
#define ENT2_NAME "stat"

#define STR_LENTH PAGE_SIZE/8

static char procfs_char[PAGE_SIZE];
static ssize_t procfs_size;

static struct statistic {
long char_processed;
long char_returned;
long char_received;
long total_write_calls;
long total_read_calls;
} procfs_stat;


ssize_t if_module_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
pr_info("procfs read func called\n");
procfs_stat.total_read_calls++;

ssize_t num, not_copied;

num = min_t(ssize_t, procfs_size, count);
if (num) {
not_copied = copy_to_user(buff, procfs_char, num);
num -= not_copied;
}

procfs_size = 0;
return num;
}

ssize_t if_module_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
{
pr_info("procfs write func called\n");
procfs_stat.total_write_calls++;

ssize_t not_copied;

char *msg = kmalloc(PAGE_SIZE, GFP_KERNEL);

not_copied = copy_from_user(msg, buff, count);

char *target = procfs_char;

while (*msg) {
procfs_stat.char_received++;
if (islower(*msg)) {
*target = toupper(*msg);
procfs_stat.char_processed++;
} else {
*target = *msg;
}
target++;
msg++;
}

procfs_size = count - not_copied;

return procfs_size;
}

ssize_t if_stat_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
pr_info("procfs stat read func called\n");

char line[STR_LENTH] = { 0 };
char out[STR_LENTH] = { 0 };

sprintf(line, "my_interface char processed: %ld,\n", procfs_stat.char_processed);
strcat(out, line);
sprintf(line, " char returned: %ld,\n", procfs_stat.char_returned);
strcat(out, line);
sprintf(line, " char received: %ld,\n", procfs_stat.char_received);
strcat(out, line);
sprintf(line, " total write calls: %ld,\n", procfs_stat.total_write_calls);
strcat(out, line);
sprintf(line, " total read calls: %ld\n", procfs_stat.total_read_calls);
strcat(out, line);

pr_info("%ld, %lld, %ld", count, *offp, strlen(out));

if (strlen(out) > *offp) {
copy_to_user(buff, out, strlen(out));
return strlen(out);
} else {
return 0;
}

}

static struct file_operations procfs_conv_fops = {
.owner = THIS_MODULE,
.read = if_module_read,
.write = if_module_write,
};

static struct file_operations procfs_stat_fops = {
.owner = THIS_MODULE,
.read = if_stat_read,
};

static struct proc_dir_entry *dir;
static struct proc_dir_entry *ent1, *ent2;

static int __init init_if_proc_module(void)
{
pr_info("Init interface module\n");

dir = proc_mkdir(DIR_NAME, NULL);
if (dir == NULL) {
pr_err("mymodule: error creating procfs directory\n");
return -ENOMEM;
}

ent1 = proc_create(ENT1_NAME, 0666, dir, &procfs_conv_fops);
if (ent1 == NULL) {
pr_err("mymodule: error creating procfs conv\n");
remove_proc_entry(DIR_NAME, NULL);
return -ENOMEM;
}

ent2 = proc_create(ENT2_NAME, 0444, dir, &procfs_stat_fops);
if (ent2 == NULL) {
pr_err("mymodule: error creating procfs stat\n");
remove_proc_entry(ENT1_NAME, dir);
remove_proc_entry(DIR_NAME, NULL);
return -ENOMEM;
}

pr_info("mymodule: module loaded\n");
return 0;
}

static void __exit exit_if_proc_module(void)
{

proc_remove(dir);

pr_info("mymodule: module exited\n");
pr_info("Goodbye, cruel world!\n");
}

module_init(init_if_proc_module);
module_exit(exit_if_proc_module);

MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Perederii Serhii");
MODULE_DESCRIPTION("A module for procfs string processing");
MODULE_VERSION("0.2");
125 changes: 125 additions & 0 deletions 05-Interfaces/interface_module_sysfs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/ctype.h>

static char sysfs_char[PAGE_SIZE];

static struct statisic
{
long char_processed;
long char_returned;
long char_received;
long total_write_calls;
long total_read_calls;
}
iface_sysfs_stat;

static ssize_t sysfs_conv_show(struct class *class, struct class_attribute *attr, char *buf)
{
pr_info("my_interface: sysfs_conv_show called\n");

iface_sysfs_stat.total_read_calls++;

sprintf(buf, "%s", sysfs_char);
return strlen(buf);
}

static ssize_t sysfs_conv_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count)
{
pr_info("my_interface: sysfs_conv_store called with %s", buf);

iface_sysfs_stat.total_write_calls++;

char *iter = buf;
char *target = sysfs_char;

while (*iter) {
iface_sysfs_stat.char_received++;
if (isupper(*iter)) {
*target = tolower(*iter);
iface_sysfs_stat.char_processed++;
} else {
*target = *iter;
}
target++;
iter++;
}

return count;
}

static ssize_t sysfs_stat_show(struct class *class, struct class_attribute *attr, char *buf)
{
pr_info("my_interface: sysfs_stat_show called\n");

char loc_buf[PAGE_SIZE];

sprintf(loc_buf, "my_interface char processed: %ld,\n", iface_sysfs_stat.char_processed);
strcat(buf,loc_buf);
sprintf(loc_buf, " char returned: %ld,\n", iface_sysfs_stat.char_returned);
strcat(buf,loc_buf);
sprintf(loc_buf, " char received: %ld,\n", iface_sysfs_stat.char_received);
strcat(buf,loc_buf);
sprintf(loc_buf, " total write calls: %ld,\n", iface_sysfs_stat.total_write_calls);
strcat(buf,loc_buf);
sprintf(loc_buf, " total read calls: %ld\n", iface_sysfs_stat.total_read_calls);
strcat(buf,loc_buf);

return strlen(buf);
}

CLASS_ATTR_RW(sysfs_conv);
CLASS_ATTR_RO(sysfs_stat);

static struct class *attr_class = NULL;

static int __init init_if_module(void)
{
pr_info("Init sysfs interface module\n");

int ret;

attr_class = class_create(THIS_MODULE, "my_interface");
if (attr_class == NULL) {
pr_err("my_interface: error creating sysfs class\n");
return -ENOMEM;
}

ret = class_create_file(attr_class, &class_attr_sysfs_conv);
if (ret) {
pr_err("my_interface: error creating sysfs class converter attribute\n");
class_destroy(attr_class);
return ret;
}

ret = class_create_file(attr_class, &class_attr_sysfs_stat);
if (ret) {
pr_err("my_interface: error creating sysfs class statistic attribute\n");
class_destroy(attr_class);
return ret;
}

pr_info("my_interface: module loaded\n");
return 0;
}

static void __exit exit_if_module(void)
{
class_remove_file(attr_class, &class_attr_sysfs_stat);
class_remove_file(attr_class, &class_attr_sysfs_conv);
class_destroy(attr_class);

pr_info("mymodule: module exited\n");
pr_info("Goodbye, cruel world!\n");
}

module_init(init_if_module);
module_exit(exit_if_module);

MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Perederii Serhii");
MODULE_DESCRIPTION("A module for sysfs string processing");
MODULE_VERSION("0.2");