A minimal char device driver for arm linux

/*
 * SimpleCharDevice.c
 *
 */

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>

#define DEVICE_NAME "SimpleCharDevice"
#define CLASS_NAME "SimpleCharDeviceClass"

MODULE_AUTHOR("PraveenMax");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple char device driver for BBB");
MODULE_VERSION("0.1");

static int majorNumber;//For device driver
static int devOpenCount=0;
static struct class* simpleCharClass = NULL;
static struct device* simpleCharDevice = NULL;
static short size_of_message;//used to store the length of previously written string
static char message[256]={0};

//File operations prototypes
static int dev_open(struct inode *, struct file *);
static int dev_release(struct inode *, struct file *);
static ssize_t dev_read(struct file *, char *, size_t, loff_t *);
static ssize_t dev_write(struct file *,const char *, size_t, loff_t *);

//our custom file-operation struct.
static struct file_operations fops={
		.open=dev_open,
		.release=dev_release,
		.read=dev_read,
		.write=dev_write,
		.owner= THIS_MODULE,
};

static int __init loadModule(void){

	printk(KERN_ALERT "Initializing the SimpleChar LKM\n");

	//try to dynamically allocate the Major number
	majorNumber = register_chrdev(0, DEVICE_NAME, &fops);
	if(majorNumber < 0)
	{
		printk(KERN_ALERT "Failed to register a major number\n");
		return majorNumber;
	}

	printk(KERN_ALERT "Registered Successfully with major number : %d\n",majorNumber);

	//Register the device class
	simpleCharClass = class_create(THIS_MODULE, CLASS_NAME);
	if(IS_ERR(simpleCharClass)){
		//if error found, unregister it
		unregister_chrdev(majorNumber, DEVICE_NAME);
		printk(KERN_ALERT "Failed to register the device class\n");
		return PTR_ERR(simpleCharClass);
	}

	printk(KERN_ALERT "Device class registered successfully\n");

	//Register the device driver
	simpleCharDevice = device_create(simpleCharClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
	if( IS_ERR(simpleCharDevice)){
		class_destroy(simpleCharClass);
		unregister_chrdev(majorNumber, DEVICE_NAME);
		printk(KERN_ALERT "Failed to create the device\n");
		return PTR_ERR(simpleCharDevice);
	}

	printk(KERN_INFO "Device class created correctly\n");
	return 0;
}

static void __exit unloadModule(void){
	//device_destory(simpleCharClass, MKDEV(majorNumber,0));
	class_unregister(simpleCharClass);
	class_destroy(simpleCharClass);
	unregister_chrdev(majorNumber, DEVICE_NAME);
	printk(KERN_ALERT "Goodbye from SimpleCharDevice\n");
}

static int dev_open(struct inode *inodep, struct file *filep){
	devOpenCount++;
	printk(KERN_ALERT "SimpleCharDevice has been opened for %d times\n", devOpenCount);
	return 0;
}

static int dev_release(struct inode *inodep, struct file *filep){
	printk(KERN_ALERT "SimpleCharDevice successfully closed\n");
	return 0;
}

//Send char from KERNEL to USER
static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset){
	int error_count = 0;

	error_count = copy_to_user(buffer, message, size_of_message);

	if(error_count==0){
		printk(KERN_ALERT "SimpleCharDevice :: Sent %d characters to the user\n", size_of_message);
		printk(KERN_ALERT "OUTPUT : %s", message);
		size_of_message = 0;//reset the size_of_message
		return 0;
	}
	else{
		printk(KERN_ALERT "SimpleCharDevice :: Failed to send %d characters to the user\n", error_count);
		return -EFAULT;
	}
}

//Send char from USER to KERNEL
static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){
	/*
	sprintf(message, "%s(%zu letters)", buffer, len);
	size_of_message = strlen(message);
	printk(KERN_ALERT "SimpleCharDevice :: Received %d chars from USER \n", len);
	return len;
	*/

	if(copy_from_user(message, buffer, len )!=0)
	{
		printk(KERN_ALERT "SimpleCharDevice :: Write failed!!\n");
	}
	else
	{
		printk(KERN_ALERT "SimpleCharDevice :: Write succeeded\n");
		size_of_message = strlen(message);
	}

	return len;

}

module_init(loadModule);
module_exit(unloadModule);