Linux Kernel Module Driver

From Kiwi
Jump to: navigation, search

Linux Kernel Module Driver

Makefile

obj-m += testkernel.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean


Kernal Source

#include <linux/init.h>		/* __init and __exit macroses */
#include <linux/kernel.h>	/* KERN_INFO macros */
#include <linux/module.h>	/* required for all kernel modules */
#include <linux/moduleparam.h>	/* module_param() and MODULE_PARM_DESC() */

#include <linux/fs.h>		/* struct file_operations, struct file */
#include <linux/miscdevice.h>	/* struct miscdevice and misc_[de]register() */
#include <linux/mutex.h>	/* mutexes */
#include <linux/string.h>	/* memchr() function */
#include <linux/slab.h>		/* kzalloc() function */
#include <linux/sched.h>	/* wait queues */
#include <linux/uaccess.h>	/* copy_{to,from}_user() */
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Xiaojing Ma <randymxj@gmail.com>");
MODULE_DESCRIPTION("Kernel Test Module");

//#define DEFAULT_MAJOR 99

static unsigned long buffer_size = 8192;
module_param(buffer_size, ulong, (S_IRUSR | S_IRGRP | S_IROTH));
MODULE_PARM_DESC(buffer_size, "Internal buffer size");

struct buffer 
{
	struct mutex lock;
	char *data;
	int size;
};

static int function_open(struct inode *inode, struct file *file)
{
	struct buffer *buf = NULL;
	
	printk(KERN_INFO "Kernel Module: open\n");

	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
	
	buf->data = kzalloc(buffer_size, GFP_KERNEL);

	mutex_init(&buf->lock);
	
	buf->size = 0;
	
	file->private_data = buf;

	return 0;
}

static int function_close(struct inode *inode, struct file *file)
{
	struct buffer *buf = file->private_data;
	
	printk(KERN_INFO "Kernel Module: close\n");
	
	kfree(buf->data);
	kfree(buf);

	return 0;
}

static ssize_t function_read(struct file *file, char __user * out, size_t size, loff_t * off)
{
	struct buffer *buf = file->private_data;
	
	printk(KERN_INFO "Kernel Module: read\n");
	
	if(copy_to_user(out, buf->data, buf->size))
		return 0;
		
	return buf->size;
}

static ssize_t function_write(struct file *file, const char __user * in, size_t size, loff_t * off)
{
	struct buffer *buf = file->private_data;
	int count = 0;
	
	if(size > buffer_size)
		return 0;
	
	if(copy_from_user(buf->data, in, size))
		return 0;
		
	for( ; size > 0; size-- )
	{
		printk(KERN_INFO "@: %c\n", buf->data[count]);
		count++;
	}
	
	buf->size = count;
	return count;
}

static struct file_operations module_fops = 
{
	.owner = THIS_MODULE,
	.open = function_open,
	.read = function_read,
	.write = function_write,
	.release = function_close,
	.llseek = noop_llseek
};

static struct miscdevice my_misc_device = 
{
    .minor = MISC_DYNAMIC_MINOR,
    .name = "testkernel",
    .fops = &module_fops
};

static int __init function_init(void)
{
	if (!buffer_size)
		return -1;
		
	printk(KERN_INFO "Kernel Module has been registered, buffer size is %lu bytes\n", buffer_size);
	
	misc_register(&my_misc_device);
	
	/*
	r = register_chrdev(DEFAULT_MAJOR, "testkernel", &module_fops);
	if( r < 0 )
	{
		printk(KERN_INFO "Kernel Module Register Failed\n");
		return r;
	}
	*/
	
	return 0;
}
 
static void __exit function_exit(void)
{
    printk(KERN_INFO "Kernel Module has been unregistered\n");
	
	misc_deregister(&my_misc_device);
	
	//unregister_chrdev(DEFAULT_MAJOR, "testkernel");
}
 
module_init(function_init);
module_exit(function_exit);