Simple Linux char driver Since the resources I found to learn are generally out-of-date, I'm having to read a lot of documentation, which makes the learning process somewhat haphazard. The module makes a simple character stack which can be read and written to by multiple processes.

#include&lt;linux/init.h&gt;
#include&lt;linux/module.h&gt;

#include&lt;linux/fs.h&gt;
#include&lt;linux/types.h&gt;
#include&lt;linux/kdev_t.h&gt;
#include&lt;linux/cdev.h&gt;

#include&lt;linux/mutex.h&gt;

#include&lt;asm/uaccess.h&gt;


#define MHELLO_STACK_SIZE 20

static int major;
static dev_t dev;
static struct cdev my_cdev;
static int count;
static DEFINE_MUTEX(lock);
static char stack[MHELLO_STACK_SIZE];
static int head;


static ssize_t hello_read(struct file* f,char* buf,size_t count,loff_t * offset)
{
    unsigned int res;
    printk(KERN_ALERT"R\n");

    mutex_lock(&amp;lock);

    if(head&lt;0)
    {
        mutex_unlock(&amp;lock);
        return 0;
    }
    res=copy_to_user(buf,stack+head,1);
    head--;

    mutex_unlock(&amp;lock);
    return 1;
}
static ssize_t hello_write(struct file* f,const char* buf,size_t count,loff_t * offset)
{
    unsigned int res;
    printk(KERN_ALERT"W\n");

    mutex_lock(&amp;lock);

    if(head &gt;= MHELLO_STACK_SIZE-1)
    {
        mutex_unlock(&amp;lock);
        return -ENOSPC;
    }
    head++;
    res=copy_from_user(stack+head,buf,1);

    mutex_unlock(&amp;lock);
    return 1;
}

static int hello_open(struct inode* inode,struct file* f)
{
    mutex_lock(&amp;lock);
    count++;
    printk(KERN_ALERT"O %d\n",count);
    mutex_unlock(&amp;lock);
    return 0;
}
static int hello_release(struct inode* inode,struct file* f)
{
    mutex_lock(&amp;lock);
    count--;
    printk(KERN_ALERT"C %d\n",count);
    mutex_unlock(&amp;lock);
    return 0;
}
const struct file_operations fops=
{
    .owner=THIS_MODULE,
    .read=hello_read,
    .write=hello_write,
    .open=hello_open,
    .release=hello_release
};

static int hello_init(void)
{
    int result=-1;

    mutex_init(&amp;lock);
    mutex_lock(&amp;lock);

    count=0;
    head=-1;

    result=alloc_chrdev_region(&amp;dev,0,1,"mhello");

    if(result&lt;0)
        printk(KERN_ALERT"Can't allocate major.\n");

    major=MAJOR(dev);
    printk(KERN_ALERT"Hello, my major no. is %d.\n",major);


    cdev_init(&amp;my_cdev,&amp;fops);
    my_cdev.owner=THIS_MODULE;


    cdev_add(&amp;my_cdev,dev,1);

    mutex_unlock(&amp;lock);
    return 0;
}
static void hello_exit(void)
{
    mutex_lock(&amp;lock);
    unregister_chrdev_region(dev,1);
    cdev_del(&amp;my_cdev);
    mutex_unlock(&amp;lock);
    printk(KERN_ALERT"Goodbye world\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("foo");
So, this isn't a full answer to your question, but maybe still relevant.

Included with the Linux sources is scripts/checkpatch.pl - which checks for things like coding style compliance, but also warns on use of outdated interfaces.

If you have a checked out (clean) git repository of the kernel, you can simply copy your source file into there and run

linux$ git diff HEAD | scripts/checkpatch.pl -


Doing that on the above code does point out a few things not just coding-style related.