Writing a Sysfs module - linux

I'm attempting to learn how to write a sysfs module, and am confused at the basic initialization. In this document looking at the kobject.h file, there are several different functions related to creating a sysfs entry.
From the looks of it, the function "kobject_init_and_add" seems like the right thing to use, which takes the following:
90 int kobject_init_and_add(struct kobject *kobj,
91 struct kobj_type *ktype, struct kobject *parent,
92 const char *fmt, ...);
struct kobject and struct kobj_type are straightforward enough, but I don't understand what the *parent kobject and *fmt cstring are supposed to be.
Further, after initializing these objects, I would need to remove them at the exit_module function, but there are two options that seem possible: kobject_del and kobject_puts. What are the differences between these?
Part of my confusion comes from the fact that while googling for the answer, I see tutorials which says to use functions like kobject_register instead, but that function doesn't actually exist.

Yes there are lot of example on mainline kernel which you can refers for your implementatin. For Your doubts I am adding the some example code"
Module Probe/init function
static struct kobject *module_kobject;
module_kobject=kobject_create_and_add("module_status",NULL);
sysfs_create_group(module_kobject,&module_attr);
Module Remove/exit function
sysfs_remove_group(module_kobject,&module_attr);
kobject_put(module_kobject);
If you want to expose more than one attribute on the user space; than you need to define the group as well
static struct attribute_group module_attr={
.attrs = module_attribute,
};
There is some more implementation and function you may need like:
static ssize_t module_show_status(struct kobject *kobj,struct kobj_attribute *attr,char *buf);
static ssize_t module_store__status(struct kobject *kobj,struct kobj_attribute *attr,const char *buf,size_t len);
I think you can start your sysfs module implementation based on the above code and Feel free for any help.

There are many kernel modules that create sysfs entries. For example,
http://lxr.free-electrons.com/source/net/bridge/br_sysfs_br.c
This module uses kobject_create_and_add(), which gets as a parameter a kobject instance, created by sysfs_create_group(). I believe that looking into such module, and trying to code step by step, following the patterns in that module, can help. Also look in
http://lxr.free-electrons.com/source/Documentation/kobject.txt
Rami Rosen

Related

dev_err() function definition

I can see that dev_*() family of functions such as dev_err() are given as prototype in include/linux/device.h, but no where I could find its definition. I have visited sites like lxr.free-electrons, but without success. Used tags in the source code of linux kernel, even then failed.
What I am trying to find is how the dev_err(const struct device *dev, const char *fmt, ...) is able to get the device information such as pci bus, etc from just giving const struct device *dev as argument to print in logs.
Description of the device is constructed in function create_syslog_header, defined in drivers/base/core.c. The function just extracts some fields from struct device object, and emits them via snprintf() into the string.
The function dev_err is implemented via define_dev_printk_level macro in the same file (drivers/base/core.c).

Declare multiple devices in a driver module

I have to declare multiple devices inside the open call. Now is there a way I could fix the minor nos to 0,1,2,3 so that I can just extract that from filp->f_dentry->inode and put that in the array of struct scull_dev[] everytime I make an open read write or close call and then life becomes easy :P. Or is their a way to make life easier ?
If I understand what you need, you shouldn't have ever to access your devices directly except for initialization and cleanup. Take a look at:
http://www.cs.uni.edu/~diesburg/courses/dd/code/scull/pipe.c
In open function, you can get the current device you need to open via:
struct scull_pipe *dev;
dev = container_of(inode->i_cdev, struct scull_pipe, cdev);
You can see in other functions how the device is accessed via arguments that kernel is passing to these functions. For example:
static ssize_t scull_p_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
struct scull_pipe *dev = filp->private_data;

How do you link a device to a custom sysfs class?

I'm writing drivers for several pieces of custom hardware. All of the devices are attached via PCIe to a host computer. For convenience I would like to group all of these custom devices together into a sysfs class (which I believe is an acceptable thing to do?). Unfortunately the information in LDD3 is way out of date and I'm having trouble finding current documentation that discusses what I'm attempting to do.
Creating my custom class is easy enough:
struct class MY_CLASS = class_create(THIS_MODULE, "myclass")
And inside of my probe calls I've got access to the struct dev:
static int probe(struct pci_dev *pcidev, const struct pci_device_id *id)
{
...
struct dev *my_dev = &pcidev->dev;
...
}
My question is this: now that I've got the class and the dev, how do I create a link between the two?
The device_create() basically does what I want, but since I've already got a struct dev my understanding is that I shouldn't call device_create (i.e. create a new device) again.
I've done a little more tracing and found that device_add() which is called by device_create(), calls device_add_class_symlinks() (not exported unfortunately) which does something like this:
...
sysfs_create_link(&dev->class->p->subsys.kobj,&dev->kobj, dev_name(dev));
...
I tried something like this directly in my drivers to create the links I want but I can't get it to compile because struct subsys_private (the "p" member in the class struct) is not exposed anywhere?
Any help is greatly appreciated!
Are your drivers sitting on the specific bus? If no, what purpose of the specific class?
Anyway, for starter
struct class devclass = {…}
probe()
{
struct device *dev = …
dev->class = &devclass;
}
init()
{
class_register(&devclass);
}
I've encountered the same issue.
if i called device_register with my class pointer assigned to the device class member. it will create a subsystem in my device directory, which is what device_add_class_symlinks do. but in my device directory there is already subsystem directory which is the link to the bus my device is attached to.
don't know if you got a method

net_device get_stats function, how to use?

this is how the function looks like:
struct net_device_stats* (*get_stats)(struct net_device *dev);
I simply need to call this function in my code and get it's results in a net_device_stats struct I declared earlier. Can anyone give a simple implementation code for this?
This is not a function. Its the declaration of a function pointer get_stats which points to a function which receives a pointer to the structure net_device and returns a pointer to a structure of type net_device_stats
Here is one use case
struct net_device *dev;
struct net_device_stats *device;
device = get_stats(dev);
EDIT From your comments, I see you are using an older version of the kernel. IN later kernels , structure net_device still resides in linux/netdevice.h but there's no get_stats function pointer. Its changed into ndo_get_stats and it is now under another structure net_device_ops
So start using these new function pointers.

Accessing the proc_dir_entry from proc_fops.open?

I writing a linux kernel module that does some work with /proc... I'm trying to use the new seq methods for returning the data for /proc... Anyhow, after I call proc_create_data() I have a proc_dir_entry (whose ->data member is pointing at my supplied context)... Anyhow, the file_operations structure is also passed and I really need to know how to access either the proc_dir_entry or the proc_dir_entry->data from the open() file operation...
The answer was to use the PDE macro to convert the inode* into a pointer to the proc_dir_entry, which of course had a "data" member pointing at what I needed.
struct proc_dir_entry* pde = PDE( inode );

Resources