Linux kernel device model - Which devices are following it? - linux

My question is about linux device model. I did some digging myself in the source code and found that the device model works around many structures out of which some of them are:
struct device
struct device_driver
struct bus_type
There are more related to power management.
But when I looked into the char drivers implemented in linux kernel (or if I implement my own char driver) linux kernel is only implementing "struct device" and all other structures are just NULL. I have checked this through some debugging and with friendly neighbourhood API printk().
So my question is then why char drivers are not completely following the device model?
Also which drivers are completely following linux device model?

Linux Device Model uses kobject as it's base which act as a glue to held it together.
The structures you mentioned come at a layer above kobject.
So, we can say that kobject is something that you will (almost) never come across but is still embedded everywhere.
And char drivers are no excuse:
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
All drivers are following device model even without you know it, hence char drivers are no exception here too.
Look at implementation of cdev_add() and you will get your answer.
I suggest you go through this article and dig again inside LDM code.

Related

Change the ifindex of netdev

I have the following requirement. I want with a kernel module to change the ifindex of a netdev with one of my choice. I know that it acts as a key and cannot be change during runtime. Created interfaces are based on Intel e1000 driver.
In order to achieve the change the following has been thought:
unregister_netdev(dev);
//Change the dev->ifindex
//bring back network device to operational state somehow, tried register_netdev but this results in kernel panic of course
Can you please inform me if this is somehow possible? I am very new to linux kernel drivers.
Thank you!
I think I have found a trick/way to tackle this issue:
create a dummy network namespace
use dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) to move device to this namespace
then use __dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat, int new_ifindex) to move dev to init_net with the
desired new_ifindex
delete dummy network namespace
In my kernel __dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat, int new_ifindex) does not exist but it is not though so hard to be created since it only pickups a new_ifindex in case it is not provided, or checks the provided one if it is currently used inside namespace
Not tested yet, but it will be very soon.

Handling multiple i2c_clients in one driver module (with sysfs)

I want to create a kernel driver for tmp102 temperature sensors.
In one project I have only 1 sensor, in the other - 2 sensors. I want my kernel module to be able to support N sensors, not a fixed number. I have a problem with managing more than 1 struct i2c_client and creating sysfs entries for each of them. Here's how I'm doing it:
In the probe() function I get struct i2c_client* for each of the devices that I provide I2C_BOARD_INFO() for.
I then kobject_create_and_add("tmp102", kernel_kobj) to get the main directory for the modules in sysfs.
For each device I'm creating sysfs_create_group() which gets the pointer to statically created attributes. The attributes have the (*show)() and (*store)() pointers set to static functions, e.g.
static ssize_t tmp102_sysfs_thigh_get_one(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
In this function I want to read via I2C. The problem is... I don't know how to get the struct i2c_client * for the device which should be somehow linked to this sysfs entry, and the I2C address is there!
How should I properly "link" i2c_client with sysfs entries, so that I can get the I2C address inside the functions?
Ideally, I would like to have just one set of functions (one for each of the attributes). The sysfs tree should look like that:
/sysfs/kernel/tmp102
|
|-> <hex i2c address, e.g. /48>
| |
| |-> temperature
|
|
|-> /49
|
|-> temperature
I want both 'temperature' attributes to use the same function, which is able to determine the I2C address, to which it should write.
Or maybe my architecture is plain wrong? If so, how should it look like for a driver that needs to handle multiple i2c_clients?
EDIT:
I decided to use struct device_attribute instead of regular attributes. To my understanding, it is not easy to get the struct device pointer when using the regular attributes, same with struct i2c_client. They are not easily "linked" with kobjects from /sys/kernel, where I need to have my attributes for this project. device_attributes can be found in /sys/devices - I used sysfs_create_group and linked my device's kobject with the device_attribute group. I used sysfs_create_link, and linked my device's kobject with the /sys/kernel/tmp102. This way I could create a folder (link) for each of the devices, which points to the original attributes folder in /sys/devices.
First, you should know that there is already a kernel driver for the tmp102 that has a sysfs interface. Have a look at drivers/hwmon/tmp102.c.
Now, for your issue, you have a struct kobject that is passed to you sysfs callback. You can call kobj_to_dev() to get a pointer to the device. Then, for example, you could use dev_get_drvdata() to get a pointer to your own private structure that would contain a pointer to the i2c client. Don't forget to set it first with dev_set_drvdata() in your probe.
You have can find an example in drivers/rtc/rtc-ds1343.c but it is using an spi_driver.

Where the probe() function's argument comes from?

I'm studying linux device driver. currently, I understand flows of device driver approximatively, but I dont know how probe() function gets its arguments.
For example, here is my code and this is based on kernel 3.10.
static int gpio_led_probe(struct platform_device *pdev) {
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
struct gpio_leds_priv *priv;
....
priv = gpio_leds_create_of(pdev);
....
}
As like this, the argument 'pdev' is using for various point of source. I'm understading when probe() called and it's role, but I cannot find where the data 'pdev' comes from.
thanks for read my thread, and sorry that my english is not good.
platform device specific data while probing comes from the platform setup code or from device tree.
you can find the related code in arch/arm/borad/device files
struct platform_device embedded with platform_data structure where you will pass the platform related data to the drivers.
in modern kernels platform data is passed to device drivers through device tree. device tree can be found in /arch/arm/boot/dts/your_device
You can provide the platform device information by filling the platform_device structure or you have to provide your device information in device tree, during system bootup, platform_device structure gets populated based on the device tree information.In latest kernel usually we use device tree to get the device information.

Linux Kernel 3.13: How to list gendisk's?

I'm reading the online book about Linux Kernel drivers, which looks very obsolete to me. For example, the Linux Cross Reference can't find a variable gendisk_head (in kernel 3.13), which is supposed to point to a list of gendisk structures, available inside the kernel.
How can I list all the currently allocated gendisk structures from inside the kernel 3.13?
Take a look at the following code:
void __init printk_all_partitions(void)
{
struct class_dev_iter iter;
struct device *dev;
class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
while ((dev = class_dev_iter_next(&iter))) {
struct gendisk *disk = dev_to_disk(dev);

Linux cdev vs register_chrdev

I am reworking a driver and came across the cdev interface in LDD3. After reading http://lwn.net/Articles/195805/ I am more confused than enlightened. From the comments there
In order the device to actually appear in the file system, you have to call device_create (class, parent_dev, devno, device_name).
In order to call device_create you need to have a device class object: either use one of the existing classes, or create your own with create_class (THIS_MODULE, class_name)
I think this is for sysfs only.
So, is the new interface an attempt to change something that failed,
and is it thus recommended to continue using device_create?
If cdev is recommended how do I create the sysfs entry?
I never quite understood the benefit of having a device class, is
there a point in having one and if so how do I implement it with
cdev?
cdev is the char device representation of the kernel. The general idea is to associate cdev with a set of file_operations. These file_operations are performed on a device node, typically present under /dev. cdev_init() is used to associate/link a cdev with a set of file_operations. Finally cdev_add() is called on the device to make it live, such that, the user could access them.
Now, while this is done, it doesn't mean that the device node is created for you. This is done manually by using mknod utility(as explained in LDD3). In general, the drivers are supposed to create the device nodes. This is achieved using device_create() function. Device nodes are generally associated with a class. Thus, we need to create a class first(using class_create()) and then create device nodes using that class.
Let me explain this through an example. Consider only the init function(error handling is avoided here to maintain clarity) :
struct class *my_class;
struct cdev my_cdev[N_MINORS];
dev_t dev_num;
static int __init my_init(void)
{
int i;
dev_t curr_dev;
/* Request the kernel for N_MINOR devices */
alloc_chrdev_region(&dev_num, 0, N_MINORS, "my_driver");
/* Create a class : appears at /sys/class */
my_class = class_create(THIS_MODULE, "my_driver_class");
/* Initialize and create each of the device(cdev) */
for (i = 0; i < N_MINORS; i++) {
/* Associate the cdev with a set of file_operations */
cdev_init(&my_cdev[i], &fops);
/* Build up the current device number. To be used further */
curr_dev = MKDEV(MAJOR(dev_num), MINOR(dev_num) + i);
/* Create a device node for this device. Look, the class is
* being used here. The same class is associated with N_MINOR
* devices. Once the function returns, device nodes will be
* created as /dev/my_dev0, /dev/my_dev1,... You can also view
* the devices under /sys/class/my_driver_class.
*/
device_create(my_class, NULL, curr_dev, NULL, "my_dev%d", i);
/* Now make the device live for the users to access */
cdev_add(&my_cdev[i], curr_dev, 1);
}
return 0;
}
Now, answering to your questions one by one :
So, is the new interface an attempt to change something that failed, and is it thus recommended to continue using device_create?
This isn't a new interface. This can be said as an extension, generally used to create device nodes. It also gives us the advantage of creating sysfs attributes, which provides much flexible means to access kernel resources. The functions device_create() returns a pointer to struct device which has a very powerful meaning in the kernel. Take a look at the chapter on 'Linux Device Model' in LDD3.
If cdev is recommended how do I create the sysfs entry?
cdev and sysfs entries are independent of one another. You can create sysfs entries even without cdev. Again, look at the chapter on 'Linux Device Model' in LDD3. You may also look at this sample code for creating sysfs entries : http://lxr.free-electrons.com/source/samples/kobject/kobject-example.c
I never quite understood the benefit of having a device class, is there a point in having one and if so how do I implement it with cdev?
I hope the above code answers this question.
In general, you may not use cdev at all in your drivers. cdev is a very low level representation. Using cdev many powerful frameworks are built for the types of devices, such as, input, tty, ALSA, IIO, etc etc. All these frameworks are built upon cdev. So, you may not use cdev directly. Instead, you could register with these frameworks and access your device in a much more efficient way. Registering to these frameworks also create device nodes and sysfs entries for you.
Hope this helped.

Resources