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

GSoC Warm Up Kernel Task #234

Open
wants to merge 17 commits into
base: 5.4-rt
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 8 additions & 1 deletion drivers/char/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,12 @@ config ADI
and SSM (Silicon Secured Memory). Intended consumers of this
driver include crash and makedumpfile.

config GSOC_DUMMY_CHAR_DEVICE
tristate "GSoC Warmup Driver"
help
This builds the GSoC Dummy Char Driver, which is required for the warmup task.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Help lines should be indented with 1 tab + 2 spaces

Say Y to build it into the kernel, M to build it as a module and N to not build it.

endmenu

config RANDOM_TRUST_CPU
Expand All @@ -559,4 +565,5 @@ config RANDOM_TRUST_BOOTLOADER
device randomness. Say Y here to assume the entropy provided by the
booloader is trustworthy so it will be added to the kernel's entropy
pool. Otherwise, say N here so it will be regarded as device input that
only mixes the entropy pool.
only mixes the entropy pool.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Watch out for unintentional changes like editors that automatically add a newline at the end of the file.


2 changes: 2 additions & 0 deletions drivers/char/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,5 @@ js-rtc-y = rtc.o
obj-$(CONFIG_XILLYBUS) += xillybus/
obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o
obj-$(CONFIG_ADI) += adi.o

obj-$(CONFIG_GSOC_DUMMY_CHAR_DEVICE) += gsoc-dummy-char-dev.o
140 changes: 140 additions & 0 deletions drivers/char/gsoc-dummy-char-dev.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* GSoC Dummy Driver for warm up exercise
*
* Author: Niklas Wantrupp <[email protected]>
* based on
* Dummy character driver by
* John Madieu <[email protected]>
*
* This program is free software; you can redistribute it and/or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using SPDX license identifier is used nowdays instead of license paragraphs.

https://www.kernel.org/doc/html/latest/process/license-rules.html

* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/version.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>

static int gsoc_char_dev_open(struct inode * inode, struct file * file);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably depends on the area of the kernel but most code I have seen tries to avoid forward declarations if possible by rearranging the code.

static int gsoc_char_dev_close(struct inode * inode, struct file * file);
static ssize_t gsoc_char_dev_read(struct file *file, char __user * buf, size_t count,
loff_t * offset);
static ssize_t gsoc_char_dev_write(struct file * file, const char __user * buf, size_t count,
loff_t * offset);
static int gsoc_char_dev_uevent(struct device *dev, struct kobj_uevent_env *env);

static unsigned int major;
static struct class *gsoc_dummy_class;
static struct cdev gsoc_dummy_device;

static const struct file_operations gsoc_dummy_dev_file_ops = {
.open = gsoc_char_dev_open,
.release = gsoc_char_dev_close,
.read = gsoc_char_dev_read,
.write = gsoc_char_dev_write,
};

static int __init gsoc_dummy_char_dev_init_module(void)
{
struct device *dummy_device;
int err;
dev_t gsoc_dev;

// register a range of char dev numbers 0 to 1 in this case
err = alloc_chrdev_region(&gsoc_dev, 0, 1, "gsoc_dummy_char_dev");
if (err < 0) {
pr_err("Can't get major number\n");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a good idea to include the module name in the error message so users know which module the error came from.

return err;
}
major = MAJOR(gsoc_dev);
pr_info("gsoc_dummy_char_dev major number = %d\n",major);

// Create sysfs class
gsoc_dummy_class = class_create(THIS_MODULE, "gsoc_dummy_char_dev_class");

if (IS_ERR(gsoc_dummy_class)) {
pr_err("GSoC char device class could not be created.\n");
unregister_chrdev_region(MKDEV(major, 0), 1);
return PTR_ERR(gsoc_dummy_class);
}

gsoc_dummy_class->dev_uevent = gsoc_char_dev_uevent;

// Create device and bind file ops
cdev_init(&gsoc_dummy_device, &gsoc_dummy_dev_file_ops);
gsoc_dummy_device.owner = THIS_MODULE;

// add device to system
cdev_add(&gsoc_dummy_device, gsoc_dev, 1);

// create device node
dummy_device = device_create(gsoc_dummy_class, NULL, gsoc_dev, NULL, "gsoc_dummy_char_dev");

if (IS_ERR(dummy_device)) {
pr_err("GSoC char device could not be created.\n");
class_destroy(gsoc_dummy_class);
unregister_chrdev_region(gsoc_dev, 1);
return -1;
}

pr_info("loaded GSoC dummy driver\n");
return 0;
}

static void __exit gsoc_dummy_char_dev_exit_module(void)
{
unregister_chrdev_region(MKDEV(major, 0), 1);
device_destroy(gsoc_dummy_class, MKDEV(major, 0));
cdev_del(&gsoc_dummy_device);
class_destroy(gsoc_dummy_class);

pr_info("unloaded GSoC dummy driver\n");
}

static int gsoc_char_dev_open(struct inode * inode, struct file * file)
{
pr_info("Open function of GSoC dummy driver called.\n");
return 0;
}

static int gsoc_char_dev_close(struct inode * inode, struct file * file)
{
pr_info("Close function of GSoC dummy driver called.\n");
return 0;
}

static ssize_t gsoc_char_dev_read(struct file *file, char __user * buf, size_t count,
loff_t * offset)
{
pr_info("Read function of GSoC dummy driver called.\n");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be fun to actually put something in the buffer so that you can actually read something from the character device.

return 0;
}

static ssize_t gsoc_char_dev_write(struct file * file, const char __user * buf, size_t count,
loff_t * offset)
{
pr_info("Write function of GSoC dummy driver called.\n");
return count;
}

static int gsoc_char_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
{
add_uevent_var(env, "DEVMODE=%#o", 0666);
return 0;
}

module_init(gsoc_dummy_char_dev_init_module);
module_exit(gsoc_dummy_char_dev_exit_module);

MODULE_AUTHOR("Niklas Wantrupp <[email protected]>");
MODULE_DESCRIPTION("GSoC warm up dummy char device driver");
MODULE_LICENSE("GPL");