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