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.