Skip to content

Instantly share code, notes, and snippets.

@gauthamkantharaju
Created September 20, 2013 03:48
Show Gist options
  • Save gauthamkantharaju/6633067 to your computer and use it in GitHub Desktop.
Save gauthamkantharaju/6633067 to your computer and use it in GitHub Desktop.
Linked list usage in device drivers
#include "list.h"
/**
* Global variable declaration section
*/
struct todo_struct
{
S32 priority; /* driver specific */
S8 *name;
struct list_head list;
};
struct todo_struct first;
struct test
{
S32 priority;
S8 *name;
};
S32 major_no = 0;
/*-----------------------------------------------*/
void todo_add_entry(struct todo_struct *new)
{
#ifdef QUEUE
list_add_tail(&new->list, &first.list);
#else
list_add(&new->list, &first.list);
#endif
}
void todo_del_entry(struct todo_struct *new)
{
struct todo_struct *str, *temp;
list_for_each_entry_safe(str, temp, &first.list, list)
{
if((str->priority == new->priority) && (str->name == new->name))
{
list_del(&str->list);
#ifdef DEBUG
dmsg("Same:%d \t %d\n", str->priority, new->priority);
#endif
kfree(str);
}
}
}
static S32 list_minor_open(struct inode *inode, struct file *filp)
{
S32 res = 0;
INIT_LIST_HEAD(&first.list);
#ifdef DEBUG
dmsg("Size first:%ld \n", sizeof(first));
#endif
return res;
}
static ssize_t list_minor_write(struct file *filp, const char __user *buf,
size_t count, loff_t *fpos)
{
S32 res = 0;
return res;
}
static ssize_t list_minor_read(struct file *filp, char __user *buf,
size_t count, loff_t *fpos)
{
S32 res = 0;
struct todo_struct *entry;
/**
* TODO: To read the priority value from the list
*/
list_for_each_entry(entry, &first.list, list)
{
#ifdef DEBUG
dmsg("priority:%d \t name:%s \n", entry->priority, entry->name);
#endif
}
return res;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
static long
list_minor_ioctl(struct file *filp, U32 cmd, unsigned long arg)
#else
static int
list_minor_ioctl(struct inode *inode, struct file *filp, U32 cmd,
unsigned long arg)
#endif
{
S32 res = 0;
S32 err = 0;
struct todo_struct *new;
struct test *a;
if(_IOC_TYPE(cmd) != IOCTL_LIST_MAGIC)
return -ENOTTY;
if(_IOC_NR(cmd) > IOCTL_MAX_CMDS)
return -ENOTTY;
if(_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void __user*) arg, _IOC_SIZE(cmd));
if(_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ, (void __user*) arg, _IOC_SIZE(cmd));
if(err)
return -EFAULT;
new = kmalloc(sizeof(*new), GFP_KERNEL);
a = (struct test *) arg;
switch(cmd)
{
case IOCTL_LIST_ADD:
new->priority = a->priority;
new->name = a->name;
INIT_LIST_HEAD(&new->list);
todo_add_entry(new);
break;
case IOCTL_LIST_DEL:
new->priority = a->priority;
new->name = a->name;
#ifdef DEBUG
dmsg("prio:%d \t name:%s \n", new->priority, new->name);
#endif
todo_del_entry(new);
break;
default: /* Default case --> Ignore, will never get executed */
break;
}
return res;
}
static S32 list_minor_close(struct inode *inode, struct file *filp)
{
S32 res = 0;
struct todo_struct *str, *temp;
list_for_each_entry_safe(str, temp, &first.list, list)
{
list_del(&str->list);
#ifdef DEBUG
dmsg("Prio:%d \t Name:%s\n", str->priority, str->name);
#endif
kfree(str);
}
return res;
}
static struct file_operations list_minor_fops = {
.owner = THIS_MODULE,
.open = list_minor_open,
.release = list_minor_close,
.write = list_minor_write,
.read = list_minor_read,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
.unlock_ioctl = list_minor_ioctl
#else
.ioctl = list_minor_ioctl
#endif
};
static S32 list_major_open(struct inode *inode, struct file *filp)
{
S32 res = 0;
dmsg("Minor no specific file operations:%d \n", iminor(inode));
switch(iminor(inode))
{
case 0:
filp->f_op = &list_minor_fops;
break;
default:
dmsg("There is no minor no with this value : %d \n",
iminor(inode));
break;
}
if(filp->f_op && filp->f_op->open)
res = filp->f_op->open(inode, filp);
else
res = -1;
return res;
}
static struct file_operations list_fops = {
.owner = THIS_MODULE,
.open = list_major_open
};
static S32 __init list_init_module(void)
{
S32 major = 0;
S32 res = 0;
if((major = register_chrdev(DYNAMIC_MAJOR_ALLOC, DRVNAME, &list_fops)) < 1)
{
dmsg("Failed to register driver:%d \n", major);
}
else
{
major_no = major;
dmsg("Registered driver successfully:%d \n", major_no);
dmsg("Current info: id=%d \n", current->pid);
}
return res;
}
static void __exit list_cleanup_module(void)
{
unregister_chrdev(major_no, DRVNAME);
}
module_init(list_init_module);
module_exit(list_cleanup_module);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Simple linked list driver");
MODULE_AUTHOR("Gautham Kantharaju <gautham.kantharju@gmail.com>");
#ifndef _LIST_H_
#define _LIST_H_
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/debugfs.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/ioctl.h>
#include <linux/moduleparam.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
#include "common_typedef.h"
#define DRVNAME "list"
#define DYNAMIC_MAJOR_ALLOC 0
#define dmsg(string, args...) \
printk(KERN_DEBUG "%s: %s: %d:" string, DRVNAME, __FUNCTION__, \
__LINE__, ##args)
#define IOCTL_LIST_MAGIC 'l'
#define IOCTL_LIST_ADD _IO(IOCTL_LIST_MAGIC, 0)
#define IOCTL_LIST_DEL _IO(IOCTL_LIST_MAGIC, 1)
#define IOCTL_MAX_CMDS 2
#endif /* _LIST_H_ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment