From c00edd6c4c9d300bc721328de2f4aa299db24839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=B6pke?= <loepke@edfritsch.de> Date: Sun, 1 May 2016 10:54:30 +0200 Subject: [PATCH] Created modified version of chardev-1 which is able to hold a given name and make personalized outputs. --- 20160425/Makefile | 1 + 20160425/chardev-1write.c | 205 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 20160425/chardev-1write.c diff --git a/20160425/Makefile b/20160425/Makefile index 263a0a5..6075827 100644 --- a/20160425/Makefile +++ b/20160425/Makefile @@ -1,5 +1,6 @@ obj-m += hellomod-1.o obj-m += chardev-1.o +obj-m += chardev-1write.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules diff --git a/20160425/chardev-1write.c b/20160425/chardev-1write.c new file mode 100644 index 0000000..bb6c15e --- /dev/null +++ b/20160425/chardev-1write.c @@ -0,0 +1,205 @@ +/* Modified by: Christian Löpke <christian.loepke@hs-bochum.de> + * chardev-1write.c: Creates a char device that says Mr. Anderson or a + * written name how many times he read from the dev + * file. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <asm/uaccess.h> /* for put_user */ + +/* + * Prototypes - this would normally go in a .h file + */ +int init_module(void); +void cleanup_module(void); +static int device_open(struct inode *, struct file *); +static int device_release(struct inode *, struct file *); +static ssize_t device_read(struct file *, char *, size_t, loff_t *); +static ssize_t device_write(struct file *, const char *, size_t, loff_t *); + +#define SUCCESS 0 +#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */ +#define BUF_LEN 80 /* Max length of the message from the device */ +#define USERBUF_LEN 20 /* Max length for user definable name */ +/* + * Global variables are declared as static, so are global within the file. + */ + +static int Major; /* Major number assigned to our device driver */ +static int Device_Open = 0; /* Is device open? + * Used to prevent multiple access to device */ +static char msg[BUF_LEN]; /* The msg the device will give when asked */ +static char *msg_Ptr; /* The current char from msg we are writing */ + +static char msg_username[USERBUF_LEN]; /* User definable name */ +static int told_you_counter = 0; /* Counts the outputs I've made */ + +static struct file_operations fops = { + .read = device_read, + .write = device_write, + .open = device_open, + .release = device_release +}; + +/* + * This function is called when the module is loaded + */ +int init_module(void) +{ + Major = register_chrdev(0, DEVICE_NAME, &fops); + + if (Major < 0) { + printk( KERN_ALERT + "%s: Registering char device failed with %d\n", + DEVICE_NAME, + Major); + return Major; + } + + printk( KERN_INFO "%s: I was assigned major number %d. To talk to\n", + DEVICE_NAME, + Major); + printk( KERN_INFO + "%s: the driver, create a dev file with\n", DEVICE_NAME); + printk( KERN_INFO "%s: 'mknod /dev/%s c %d 0'.\n", + DEVICE_NAME, + DEVICE_NAME, + Major); + printk( KERN_INFO + "%s: Try various minor numbers. Try to cat and echo to\n", + DEVICE_NAME); + printk( KERN_INFO "%s: the device file.\n", DEVICE_NAME); + printk( KERN_INFO + "%s: Remove the device file and module when done.\n", + DEVICE_NAME); + + sprintf(msg_username, "Mr. Anderson"); //Setup initial username. + return SUCCESS; +} + +/* + * This function is called when the module is unloaded + */ +void cleanup_module(void) +{ + /* + * Unregister the device + */ + unregister_chrdev(Major, DEVICE_NAME); +} + +/* + * Methods + */ + +/* + * Called when a process tries to open the device file, like + * "cat /dev/mycharfile" + */ +static int device_open(struct inode *inode, struct file *file) +{ + if (Device_Open) + return -EBUSY; + + Device_Open++; + sprintf(msg, + "I already told you %d times Hello world!, %s.\n", + told_you_counter++, + msg_username); + msg_Ptr = msg; + try_module_get(THIS_MODULE); + + return SUCCESS; /* Device successfully opened */ +} + +/* + * Called when a process closes the device file. + */ +static int device_release(struct inode *inode, struct file *file) +{ + Device_Open--; /* We're now ready for our next caller */ + + /* + * Decrement the usage count, or else once you opened the file, you'll + * never get get rid of the module. + */ + module_put(THIS_MODULE); + + return 0; /* Device sucessfully closed */ +} + +/* + * Called when a process, which already opened the dev file, attempts to + * read from it. + */ +static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */ + char *buffer, /* buffer to fill with data */ + size_t length, /* length of the buffer */ + loff_t * offset) +{ + /* + * Number of bytes actually written to the buffer + */ + int bytes_read = 0; + + /* + * If we're at the end of the message, + * return 0 signifying end of file + */ + if (*msg_Ptr == 0) + return 0; + + /* + * Actually put the data into the buffer + */ + while (length && *msg_Ptr) { + + /* + * The buffer is in the user data segment, not the kernel + * segment so "*" assignment won't work. We have to use + * put_user which copies data from the kernel data segment to + * the user data segment. + */ + put_user(*(msg_Ptr++), buffer++); + + length--; + bytes_read++; + } + + /* + * Most read functions return the number of bytes put into the buffer + */ + return bytes_read; +} + +/* + * Called when a process writes to dev file: echo "hi" > /dev/hello + */ +static ssize_t +device_write(struct file *filp, const char *buff, size_t len, loff_t * off) +{ + /* Since nobody wants to read I have to correct the already told you + counter! */ + told_you_counter--; + if(len > USERBUF_LEN) { + printk( KERN_WARNING + "%s: Sorry, your input is too long. Max %d allowed!\n", + DEVICE_NAME, + USERBUF_LEN); + return -ENOMEM; //Return not enaugh memory + } + else { + int i; + for(i = 0; i < len; i++) //Save the given string + msg_username[i] = buff[i]; + for(i = len; i < USERBUF_LEN; i++) //Zeroing out the rest of mem + msg_username[i] = 0; + printk( KERN_INFO "%s: Successfully got %d bytes!\n", + DEVICE_NAME, (int)len); + if(msg_username[len-1] == '\n') //Got new line terminator ? + msg_username[len-1] = 0; //Then terminate it! + return len; //Emit successfully stored len bytes + } +} -- GitLab