Hello all, I've visited this site several times but this is my first time posting. I've been assigned to write a basic character device driver, which will use kprint() to output a message after a certain amount of time has elapsed. Not too overwhelming, but as part of the assignment, I am supposed to write a user-space application which can be called from the command line. Depending on the options passed with the call, the user program will either print a list of all of the current 'timers' that have been created (indexed by the message they are going to print, followed by the amount of seconds until expiration). The other option is to pass a string followed by an integer, which will create a new timer to print the string after the inputted amount of seconds.
I have been reading/leafing through Linux Device Drivers 3, and hunting around the resources on the internet, but most of what I've come across is either too basic or way over my head. Here is what I have so far, but this does very little and is basically a sloppy attempt at merging a timer module and a simple buffer module which can store chars.

Code:
/* Necessary includes for device drivers */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */


MODULE_LICENSE("GPL");


/* Declaration of memory.c functions */
static int mytimer_open(struct inode *inode, struct file *filp);
static int mytimer_release(struct inode *inode, struct file *filp);
static ssize_t mytimer_read(struct file *filp,
                char *buf, size_t count, loff_t *f_pos);
static ssize_t mytimer_write(struct file *filp,
                const char *buf, size_t count, loff_t *f_pos);
static void mytimer_exit(void);
static int mytimer_init(void);


/* Structure that declares the usual file */
/* access functions */
struct file_operations mytimer_fops = {
        read: mytimer_read,
        write: mytimer_write,
        open: mytimer_open,
        release: mytimer_release
};


/* Declaration of the init and exit functions */
module_init(mytimer_init);
module_exit(mytimer_exit);


static unsigned capacity = 128;
static unsigned bite = 128;


/* Global variables of the driver */
/* Major number */
static int mytimer_major = 61;


/* Buffer to store data */
static char *mytimer_buffer;
/* length of the current message */
static int mytimer_len;


static int mytimer_init(void)
{
        int result;


        /* Registering device */
        result = register_chrdev(mytimer_major, "mytimer", &mytimer_fops);
        if (result < 0)
        {
                printk(KERN_ALERT
                        "mytimer: cannot obtain major number %d\n", mytimer_major);
                return result;
        }


        /* Allocating mytimer for the buffer */
        mytimer_buffer = kmalloc(capacity, GFP_KERNEL);
        if (!mytimer_buffer)
        {
                printk(KERN_ALERT "Insufficient kernel memory\n");
                result = -ENOMEM;
                goto fail;
        }
        memset(mytimer_buffer, 0, capacity);
        mytimer_len = 0;


        printk(KERN_ALERT "Inserting mytimer module\n");
        return 0;


fail:
        mytimer_exit();
        return result;
}


static void mytimer_exit(void)
{
        /* Freeing the major number */
        unregister_chrdev(mytimer_major, "mytimer");


        /* Freeing buffer memory */
        if (nibbmytimerler_buffer)
        {
                kfree(mytimer_buffer);
        }


        printk(KERN_ALERT "Removing mytimer module\n");


}


static int mytimer_open(struct inode *inode, struct file *filp)
{
        printk(KERN_INFO "open called: process id %d, command %s\n",
                current->pid, current->comm);
        /* Success */
        return 0;
}


static int mytimer_release(struct inode *inode, struct file *filp)
{
        printk(KERN_INFO "release called: process id %d, command %s\n",
                current->pid, current->comm);
        /* Success */
        return 0;
}


static ssize_t mytimer_read(struct file *filp, char *buf,
                                                        size_t count, loff_t *f_pos)
{
        int temp;
        char tbuf[256], *tbptr = tbuf;


        /* end of buffer reached */
        if (*f_pos >= mytimer_len)
        {
                return 0;
        }


        /* do not go over then end */
        if (count > mytimer_len - *f_pos)
                count = mytimer_len - *f_pos;


        /* do not send back more than a bite */
        if (count > bite) count = bite;


        /* Transfering data to user space */
        if (copy_to_user(buf, mytimer_buffer + *f_pos, count))
        {
                return -EFAULT;
        }


        tbptr += sprintf(tbptr,                                                 
                "read called: process id %d, command %s, count %d, chars ",
                current->pid, current->comm, count);


        for (temp = *f_pos; temp < count + *f_pos; temp++)                      
                tbptr += sprintf(tbptr, "%c", mytimer_buffer[temp]);


        printk(KERN_INFO "%s\n", tbuf);


        /* Changing reading position as best suits */
        *f_pos += count;
        return count;
}


static ssize_t mytimer_write(struct file *filp, const char *buf,
                                                        size_t count, loff_t *f_pos)
{
        int temp;
        char tbuf[256], *tbptr = tbuf;


        /* end of buffer reached */
        if (*f_pos >= capacity)
        {
                printk(KERN_INFO
                        "write called: process id %d, command %s, count %d, buffer full\n",
                        current->pid, current->comm, count);
                return -ENOSPC;
        }


        /* do not eat more than a bite */
        if (count > bite) count = bite;


        /* do not go over the end */
        if (count > capacity - *f_pos)
                count = capacity - *f_pos;


        if (copy_from_user(mytimer_buffer + *f_pos, buf, count))
        {
                return -EFAULT;
        }


        tbptr += sprintf(tbptr,                                                 
                "write called: process id %d, command %s, count %d, chars ",
                current->pid, current->comm, count);


        for (temp = *f_pos; temp < count + *f_pos; temp++)                      
                tbptr += sprintf(tbptr, "%c", mytimer_buffer[temp]);


        printk(KERN_INFO "%s\n", tbuf);


        *f_pos += count;
        mytimer_len = *f_pos;


        return count;
}
Any advice/ help would be really appreciated. I don't have any code started for the user application, but I figured that would be far simpler as it would only require echoing to/ catting from /dev/mytimer and printing out some strings to the user. I have more experience in C++ than in C, and I'm currently feeling like I dove into the deep end of linux programming without properly wetting my feet.