From 391f8bee7ef5a2e92d24d73f0072915b7cb12b6b Mon Sep 17 00:00:00 2001 From: Marcin Chrzanowski Date: Thu, 3 May 2018 12:52:32 +0200 Subject: Create basic char device --- Kbuild | 2 +- char.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ char.h | 9 ++++++ harddoom_main.c | 16 +++++----- pci.c | 19 ++++++------ util.h | 22 ++++++++++++++ 6 files changed, 142 insertions(+), 18 deletions(-) create mode 100644 char.c create mode 100644 char.h create mode 100644 util.h diff --git a/Kbuild b/Kbuild index d4a3e64..0214343 100644 --- a/Kbuild +++ b/Kbuild @@ -1,2 +1,2 @@ obj-m := harddoom.o -harddoom-objs := harddoom_main.o pci.o +harddoom-objs := harddoom_main.o pci.o char.o diff --git a/char.c b/char.c new file mode 100644 index 0000000..7fe7652 --- /dev/null +++ b/char.c @@ -0,0 +1,92 @@ +#include "char.h" + +#include "linux/cdev.h" +#include "linux/device.h" +#include "linux/fs.h" + +#include "util.h" + +#define DOOMDEV_COUNT 256 +#define DOOMDEV_NAME "doom" + +dev_t first; +int major; +int next_minor = 0; + +long doom_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + return -1; +} + +int doom_open(struct inode *inode, struct file *filp) +{ + return -1; +} + +struct file_operations doomdev_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = doom_ioctl, + .compat_ioctl = doom_ioctl, + .open = doom_open +}; + +struct class *doom_class; + +int new_doomdev(void) +{ + int err = 0; + int minor; + dev_t devt; + struct cdev *doom_cdev; + struct device *doomdev; + if (next_minor >= DOOMDEV_COUNT) { + return -ENOMEM; + } + + doom_cdev = cdev_alloc(); + if (doom_cdev == NULL) { + return -ENOMEM; + } + + doom_cdev->ops = &doomdev_fops; + ORFAIL(cdev_add(doom_cdev, first, 1), error_add); + minor = next_minor++; + devt = MKDEV(major, minor); + ORFAIL_PTR(device_create(doom_class, NULL, devt, NULL, + "doom%d", minor), + doomdev, error_create); + +error_create: + cdev_del(doom_cdev); +error_add: + return err; +} + +void destroy_doomdev(void) +{ + device_destroy(doom_class, first); +} + +int char_init(void) +{ + int err = 0; + ORFAIL(alloc_chrdev_region(&first, 0, DOOMDEV_COUNT, DOOMDEV_NAME), + error_region); + major = MAJOR(first); + doom_class = class_create(THIS_MODULE, "doom"); + if (IS_ERR(doom_class)) { + err = PTR_ERR(doom_class); + goto error_create; + } + +error_create: + unregister_chrdev_region(first, DOOMDEV_COUNT); +error_region: + return err; +} + +void char_cleanup(void) +{ + unregister_chrdev_region(first, DOOMDEV_COUNT); + class_unregister(doom_class); +} diff --git a/char.h b/char.h new file mode 100644 index 0000000..503ba04 --- /dev/null +++ b/char.h @@ -0,0 +1,9 @@ +#ifndef CHAR_H +#define CHAR_H + +int new_doomdev(void); +void destroy_doomdev(void); +int char_init(void); +void char_cleanup(void); + +#endif diff --git a/harddoom_main.c b/harddoom_main.c index 9ffe62f..300c910 100644 --- a/harddoom_main.c +++ b/harddoom_main.c @@ -1,29 +1,31 @@ #include #include +#include "char.h" #include "pci.h" +#include "util.h" MODULE_LICENSE("GPL"); int harddoom_init(void) { int err = 0; - printk(KERN_INFO "Initializing harddoom\n"); - err = pci_init(); - if (err < 0) { - goto error; - } + + ORFAIL(char_init(), error_char) ; + ORFAIL(pci_init(), error_pci); return 0; -error: +error_pci: + char_cleanup(); +error_char: return err; } void harddoom_cleanup(void) { - printk(KERN_INFO "Removing harddoom\n"); pci_cleanup(); + char_cleanup(); } module_init(harddoom_init); diff --git a/pci.c b/pci.c index 36f1ad8..3850633 100644 --- a/pci.c +++ b/pci.c @@ -3,46 +3,47 @@ #include #include +#include "char.h" #include "harddoom.h" +#include "pci.h" +#include "util.h" int doom_probe(struct pci_dev *dev, const struct pci_device_id *id) { - printk(KERN_INFO "In probe\n"); - return 0; + int err = 0; + ORFAIL(new_doomdev(), error_doomdev); + +error_doomdev: + return err; } void doom_remove (struct pci_dev *dev) { - printk(KERN_INFO "In remove\n"); + destroy_doomdev(); } int doom_suspend (struct pci_dev *dev, pm_message_t state) { - printk(KERN_INFO "In suspend\n"); return 0; } int doom_suspend_late (struct pci_dev *dev, pm_message_t state) { - printk(KERN_INFO "In suspend_late\n"); return 0; } int doom_resume_early (struct pci_dev *dev) { - printk(KERN_INFO "In resume_early\n"); return 0; } int doom_resume (struct pci_dev *dev) { - printk(KERN_INFO "In resume\n"); return 0; } void doom_shutdown (struct pci_dev *dev) { - printk(KERN_INFO "In shutdown\n"); } struct pci_device_id device_ids[1] = { @@ -63,12 +64,10 @@ struct pci_driver driver = { int pci_init(void) { - printk(KERN_INFO "In pci init\n"); return pci_register_driver(&driver); } void pci_cleanup(void) { - printk(KERN_INFO "In pci cleanup\n"); pci_unregister_driver(&driver); } diff --git a/util.h b/util.h new file mode 100644 index 0000000..bd9bcc3 --- /dev/null +++ b/util.h @@ -0,0 +1,22 @@ +#ifndef UTIL_H +#define UTIL_H + +#define ORFAIL(cond, label) \ +({ \ + err = (cond); \ + if (err < 0) { \ + goto label; \ + } \ +}) + +#define ORFAIL_PTR(cond, lvalue, label) \ +({ \ + lvalue = (cond); \ + if (IS_ERR(lvalue)) { \ + err = PTR_ERR(lvalue); \ + goto label; \ + } \ +}) + + +#endif -- cgit v1.2.3