Created
September 20, 2013 03:48
-
-
Save gauthamkantharaju/6633067 to your computer and use it in GitHub Desktop.
Linked list usage in device drivers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 <[email protected]>"); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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