device_create(...) argument 'void * drvdata' - linux-kernel

The function
struct device * device_create ( struct class * class,
struct device * parent,
dev_t devt,
void * drvdata,
const char * fmt,
...);
[link to documentation] takes an argument "void * drvdata". It is described as "the data to be added to the device for callbacks". What callbacks exactly are meant here? The file-operation-functions?

SysFS is one example of where this could be useful: whenever userspace communicates with the driver using SysFS (see "Reading/Writing Attribute Data" in the documentation), the kernel calls the corresponding callbacks. The void * drvdata pointer supplied during device_create can then be obtained by calling dev_get_drvdata(dev). The pointer could be used to refer to a structure containing driver's state for example.
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/device.h>
#include <linux/err.h>
MODULE_LICENSE("GPL");
static ssize_t show_period(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t set_period(struct device* dev,
struct device_attribute* attr,
const char* buf,
size_t count);
static DEVICE_ATTR(period, S_IWUSR | S_IRUSR, show_period, set_period);
static struct device *s_pDeviceObject;
static struct class *s_pDeviceClass;
static struct pwm_device_state
{
int m_Period;
} s_DeviceState;
static int __init pwmdriver_init(void)
{
int result;
s_pDeviceClass = class_create(THIS_MODULE, "pwmdriver");
BUG_ON(IS_ERR(s_pDeviceClass));
s_pDeviceObject = device_create(s_pDeviceClass, NULL, 0, &s_DeviceState, "channel");
result = device_create_file(s_pDeviceObject, &dev_attr_period);
BUG_ON(result < 0);
return result;
}
static ssize_t show_period(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pwm_device_state *pwm_device_data;
pwm_device_data = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%d\n", pwm_device_data->m_Period);
}
static ssize_t set_period(struct device* dev,
struct device_attribute* attr,
const char* buf,
size_t count)
{
long period_value = 0;
struct pwm_device_state *pwm_device_data;
if (kstrtol(buf, 10, &period_value) < 0)
return -EINVAL;
if (period_value < 10) //Safety check
return -EINVAL;
pwm_device_data = dev_get_drvdata(dev);
pwm_device_data->m_Period = period_value;
return count;
}
static void __exit pwmdriver_exit(void)
{
device_remove_file(s_pDeviceObject, &dev_attr_period);
device_destroy(s_pDeviceClass, 0);
class_destroy(s_pDeviceClass);
}
module_init(pwmdriver_init);
module_exit(pwmdriver_exit);

Related

in kernel driver, why does not mmap work in procfs?

I implement mmap function, and mount it to file operation.
And create a file in /proc.
but when I insmod, it responses "mmap_example2: Unknown symbol _page_cachable_default
insmod: can't insert 'mmap_example2.ko': unknown symbol in module, or unknown parameter"
when i remove mmap function from file operations, it can be inserted.
so do i neglect something? how to make mmap work in procfs?
the code is below
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#define FILE_NAME "test"
typedef enum ALLOC_TYPE
{
KMALLOC = 0, VMALLOC, MAX_ALLOC_TYPE,
} eAllocType;
static unsigned char array[10]={0,1,2,3,4,5,6,7,8,9};
static unsigned char *buffer;
static int file_open(struct inode *pInode, struct file *pFile)
{
printk("%s\n", __FUNCTION__);
return 0;
}
static int file_release(struct inode *pInode, struct file *pFile)
{
printk("%s\n", __FUNCTION__);
return 0;
}
static int file_mmap(struct file *pFile, struct vm_area_struct* pVMA)
{
unsigned long page;
unsigned char i;
unsigned long start = (unsigned long)pVMA->vm_start;
unsigned long size = (unsigned long)(pVMA->vm_end - pVMA->vm_start);
page = virt_to_phys(buffer);
if(remap_pfn_range(pVMA,start,page>>PAGE_SHIFT,size,PAGE_SHARED))
return -1;
for(i=0;i<10;i++)
buffer[i] = array[i];
return 0;
}
struct file_operations file_ops =
{
.open = file_open,
.release = file_release,
.mmap = file_mmap,
};
static int mmap_example2_init(void)
{
struct proc_dir_entry* entry = NULL;
printk("%s init\n", __FUNCTION__);
if(!(entry = create_proc_entry(FILE_NAME,0666,NULL)))
{
printk("%s fail to create proc file\n",__FUNCTION__);
return -EINVAL;
}
entry->proc_fops = &file_ops;
buffer = kmalloc(10,GFP_KERNEL);
if (!buffer)
{
printk("allocate mem error\n");
return -1;
}
SetPageReserved(virt_to_page(buffer));
return 0;
}
static void mmap_example2_exit(void)
{
printk("%s exit\n", __FUNCTION__);
remove_proc_entry(FILE_NAME,NULL);
ClearPageReserved(virt_to_page(buffer));
kfree(buffer);
}
module_init(mmap_example2_init);
module_exit(mmap_example2_exit);
To add file_operations use proc_create instead of create_proc_entry and pass it your file_operation object
static struct file_operations myops =
{
.read = myread,
.mmap = mymmap,
};
static int simple_init(void)
{
ent=proc_create("mytest",0660,NULL,&myops);
printk(KERN_ALERT "hello, module %d...\n",irq);
return 0;
}

Network hooks hanging the system

I was testing the network hook code given in https://en.wikipedia.org/wiki/Hooking . My kernel version is 3.11.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <net/ip.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/in.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
/* Port we want to drop packets on */
static const uint16_t port = 25;
/* This is the hook function itself */
static unsigned int hook_func(unsigned int hooknum,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *)){
struct iphdr *iph = ip_hdr(*pskb);
struct tcphdr *tcph, tcpbuf;
if (iph->protocol != IPPROTO_TCP)
return NF_ACCEPT;
tcph = skb_header_pointer(*pskb, ip_hdrlen(*pskb), sizeof(*tcph), &tcpbuf);
if (tcph == NULL)
return NF_ACCEPT;
return (tcph->dest == port) ? NF_DROP : NF_ACCEPT;
}
/* Used to register our hook function */
static struct nf_hook_ops nfho = {
.hook = hook_func,
.hooknum = NF_INET_PRE_ROUTING,
.pf = NFPROTO_IPV4,
.priority = NF_IP_PRI_FIRST,
};
static __init int my_init(void)
{
return nf_register_hook(&nfho);
}
static __exit void my_exit(void)
{
nf_unregister_hook(&nfho);
}
module_init(my_init);
module_exit(my_exit);
But after loading , the above code is freezing the system. Can anybody please tell, what is the reason for that?. I think that the above code might have already tested in some lower versions of kernel. So I doubt, some kernel parameters or features have been changed.

Copy data into buffer to print at stdout

I am writing a linux kernel module that creates a block device which lists the process list.
I am able to display the list in the kernel log file but now I am trying to display the output to stdout. My aim is to create a big string in dev_open() that contains all the processes and then copy that string to the buffer which goes to the dev_read() function.
However, I am trying the following code but I get a message to stdout saying "Killed".
What does this mean ? How can I solve this.
Code ::
#include <linux/module.h>
#include<linux/sched.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
static int dev_open(struct inode *, struct file *);
static int dev_rls(struct inode *, struct file *);
static ssize_t dev_read(struct file *, char *, size_t, loff_t *);
int len,temp;
char msg[1000];
int tem;
static struct file_operations fops =
{
.read = dev_read,
.open = dev_open,
.release = dev_rls,
};
int init_module(void)
{
int t = register_chrdev(81,"tempo",&fops);
if(t<0) printk(KERN_ALERT "Device failed to register!");
else printk(KERN_ALERT "Registered device...\n");
return t;
}
static int dev_open(struct inode *inod, struct file *fil)
{
struct task_struct *task;
for_each_process(task)
{
printk("%s [%d]\n",task->comm, task->pid);
strcat(&msg[0],task->comm);
len=strlen(msg);
temp=len;
tem++;
}
printk("%s [%d]\n",task->comm , task->pid);
return 0;
}
void cleanup_module(void)
{
unregister_chrdev(81,"tempo");
}
static ssize_t dev_read(struct file *filp,char *buf,size_t count,loff_t *offp)
{
printk("Hi\n");
if(count>temp)
{
count=temp;
}
temp=temp-count;
copy_to_user(buf,msg, count);
if(count==0)
temp=len;
return count;
//return 0;
}
static int dev_rls(struct inode *inod, struct file *fil)
{
printk(KERN_ALERT"Done with device\n");
return 0;
}

Linux kernel copy_to_user to user space display different result

There some bugs reading from the user space with this application. Is my copy_to_user dont correctly?
The following is the readout from terminal:
Press r to read from device or w to write the device r
0x-1075024108 0x15123440 0xe70401 0xe6f8dc 0xe73524
0x0 0x15037588 0xbfec6f14 0xe57612 0xbfec6f34
0x15037140 0x2 0xe57334 0xc6d690 0xd696910
0x-1075024080 0x15071734 0xc737c9 0x804835a 0x2
The following is the code from apps layer:
read(fd, read_buf, sizeof(read_buf));
for(i=0;i<=(BUFF_SIZE / sizeof(int));i+=5)
printf(" 0x%x 0x%x 0x%x 0x%x 0x%x \n",
read_buf[i],read_buf[i+1],read_buf[i+2],
read_buf[i+3],read_buf[i+4]);
break;
and the following is my driver code:
#include <linux/version.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#ifdef MODVERSIONS
# include <linux/modversions.h>
#endif
#include <asm/io.h>
#include <asm/uaccess.h> // required for copy_from and copy_to user
/* character device structures */
static dev_t mmap_dev;
static struct cdev mmap_cdev;
/* methods of the character device */
static int mmap_open(struct inode *inode, struct file *filp);
static int mmap_release(struct inode *inode, struct file *filp);
/* the file operations, i.e. all character device methods */
static struct file_operations mmap_fops = {
.open = mmap_open,
.release= mmap_release,
.owner = THIS_MODULE,
};
static int *vmalloc_area;
#define NPAGES 1//16
#define BUFF_SIZE 64 // bytes
/* character device open method */
static int mmap_open(struct inode *inode, struct file *filp)
{
return 0;
}
/* character device last close method */
static int mmap_release(struct inode *inode, struct file *filp)
{
return 0;
}
ssize_t read(struct file *filp, int *buff, size_t count, loff_t *offp)
{
unsigned long bytes_left;
printk("Inside read \n");
bytes_left = copy_to_user(buff, vmalloc_area , count);
if(bytes_left<0)
bytes_left = -EFAULT;
return bytes_left;
}
/* module initialization - called at module load time */
static int __init membuff_init(void)
{
int ret = 0, i =0;
printk(KERN_ERR "#membuff_init\n");
/* allocate a memory area with vmalloc. */
if ((vmalloc_area = vmalloc(BUFF_SIZE)) == NULL) {
ret = -ENOMEM;
goto out_vfree;
}
/* get the major number of the character device */
if( (ret = alloc_chrdev_region(&mmap_dev, 0, 1, "mmap")) < 0) {
printk(KERN_ERR "#membuff_init could not allocate major number for mmap\n");
goto out_vfree;
}
printk(KERN_ERR "#membuff_init Major number for mmap: %d\n",MAJOR(mmap_dev));
/* initialize the device structure and register the device with the kernel */
cdev_init(&mmap_cdev, &mmap_fops);
if ((ret = cdev_add(&mmap_cdev, mmap_dev, 1)) < 0) {
printk(KERN_ERR "#membuff_init could not allocate chrdev for mmap\n");
goto out_unalloc_region;
}
for (i = 0; i < (BUFF_SIZE / sizeof(int)); i +=1) {
vmalloc_area[i] = i;
printk(KERN_ERR "#membuff_init: %d\n",vmalloc_area[i]);
}
return ret;
out_unalloc_region:
unregister_chrdev_region(mmap_dev, 1);
out_vfree:
if(vmalloc_area)
vfree(vmalloc_area);
return ret;
}
/* module unload */
static void __exit mmap_exit(void)
{
if(vmalloc_area)
vfree(vmalloc_area);
/* remove the character deivce */
cdev_del(&mmap_cdev);
unregister_chrdev_region(mmap_dev, 1);
printk(KERN_ERR "#mmap_exit\n");
}
module_init(membuff_init);
module_exit(mmap_exit);
MODULE_DESCRIPTION("trying out copy_to_user");
MODULE_LICENSE("Dual BSD/GPL");

How to create proc entry under /proc/driver?

I want to create a file under a /proc/driver directory. I would like to use a macro like proc_root_driver (or something else provided) rather than use "driver/MODULE_NAME" explicitly. I use create_proc_entry :
struct proc_dir_entry *simpleproc_fops_entry;
simpleproc_fops_entry = create_proc_entry(MODULE_NAME, 0400, NULL /* proc_root_dir */);
After googling, I found suggestion to use proc_root_driver, but when I use it, I get the error
proc_root_driver undeclared in this function
And also, proc_root_driver is not available in linux/proc_fs.h.
I have tried to declare structure like this:
struct proc_dir_entry proc_root;
struct proc_dir_entry *proc_root_driver = &proc_root;
The compilation errors gone, but the file didn't appear under /proc/driver or /proc. How can I make create an entry in /proc?
Looking at proc_fs.h, proc_root_driver is defined as :
extern struct proc_dir_entry *proc_root_driver;
so long as CONFIG_PROC_FS is enabled. If you have CONFIG_PROC_FS selected when you configure your kernel, you should be able to use it as you suggested yourself i.e. :
#include <linux/proc_fs.h>
struct proc_dir_entry * procfile
procfile = create_proc_entry("myprocfile", 0400, proc_root_driver);
If this does not work, check that you have CONFIG_PROC_FS set. To make sure, you can compile your source file with the -E option and check that the create_proc_entry call includes a non NULL parameter as the last parameter. If it is NULL, or the call is not there at all, then CONFIG_PROC_FS is not enabled.
/* proc entries for ayyaz */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/ioctl.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#ifdef CONFIG_PROC_FS
/*====================================================================*/
/* Support for /proc/ayyaz */
static struct proc_dir_entry *proc_ayyaz;
DEFINE_MUTEX(ayyaz_table_mutex);
/*====================================================================*/
/* Init code */
static int ayyaz_read_proc (char *page, char **start, off_t off, int count,
int *eof, void *data_unused)
{
int len, l, i;
off_t begin = 0;
mutex_lock(&ayyaz_table_mutex);
len = sprintf(page, "hello ayyaz here\n");
mutex_unlock(&ayyaz_table_mutex);
if (off >= len+begin)
return 0;
*start = page + (off-begin);
return ((count < begin+len-off) ? count : begin+len-off);
}
static int __init init_ayyaz(void)
{
if ((proc_ayyaz = create_proc_entry( "ayyaz_maps", 0, NULL )))
proc_ayyaz->read_proc = ayyaz_read_proc;
return 0;
}
static void __exit cleanup_ayyaz(void)
{
if (proc_ayyaz)
remove_proc_entry( "ayyaz", NULL);
}
module_init(init_ayyaz);
module_exit(cleanup_ayyaz);
#else
#error "Please add CONFIG_PROC_FS=y in your .config "
#endif /* CONFIG_PROC_FS */
MODULE_LICENSE("proprietary");
MODULE_AUTHOR("Md.Ayyaz A Mulla <md.ayyaz#gmail.com>");
MODULE_DESCRIPTION("proc files for ayyaz");
Compile this driver. If it compiles sucessfully, then you will see /proc/ayyaz.
#define PROC_ENTRY_NAME "driver/XX"
static struct proc_dir_entry *proc_XX;
static int XX_read_proc (char *page, char **start, off_t off, int count,
int *eof, void *data_unused)
{
return 0;
}
static int XX_write_proc (struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
return 0;
}
static int __init XX_add_driver(void)
{
if ((proc_flash = XX_entry(PROC_ENTRY_NAME, 0, NULL))) {
proc_XX->read_proc = XX_read_proc;
proc_XX->write_proc = XX_write_proc;
}
...
}
static void __exit XX_remove(void)
{
if (proc_flash)
remove_proc_entry(PROC_ENTRY_NAME, NULL);
return;
}
Then you can find the /proc/driver/XX entry.

Resources