Analyzing the Elegant C Language Functions dev_get_drvdata and dev_set_drvdata in the Linux Kernel

Analyzing the Elegant C Language Functions dev_get_drvdata and dev_set_drvdata in the Linux Kernel

Hello everyone, I am the Intelligence Guy~

In Linux driver development, have you ever encountered the problem of how to save private data for different device instances? For example, a USB camera needs to store resolution parameters, and a GPIO device needs to record interrupt handler functions.

Directly modifying the <span>struct device</span> structure? This would obviously break the encapsulation of the code. Today, I will reveal two key functions, <span>dev_get_drvdata</span> and <span>dev_set_drvdata</span>, which act like a “safe” for private data, perfectly solving this problem!

1. The Functions’ Roles

  1. Function Summary in One Sentence

<span>dev_set_drvdata(dev, data)</span>: Binds custom data <span>data</span> to the device object <span>dev</span>.

<span>dev_get_drvdata(dev)</span>: Retrieves the bound data from the device object <span>dev</span>.

  1. Analogy with Real-Life Scenarios

Imagine you are at a supermarket checking in your package:

• Check-in: The front desk gives you a storage locker (<span>dev</span>), and you store your package (<span>data</span>) inside (<span>dev_set_drvdata</span>).

• Check-out: You retrieve your package (<span>dev_get_drvdata</span>) using the locker key (<span>dev</span>).

2. Why Do We Need These Two Functions?

  1. Background of the Problem

In the Linux kernel, device objects (<span>struct device</span>) are generic, but different devices (like cameras and network cards) need to store different private data (like register addresses and configuration parameters).

If we directly add fields to <span>struct device</span>:

• Breaks generality: The device structure becomes bloated.

• Cannot be extended: Third-party drivers cannot flexibly add custom data.

  1. Solution

By using <span>dev_set_drvdata</span> and <span>dev_get_drvdata</span>, developers can:

• Dynamically bind data: Attach any data to the device as needed.

• Isolate different devices: Different device instances do not interfere with each other and manage their private data independently.

3. How is This Code Implemented?

  1. Key Structure

In <span>include/linux/device.h</span>, the <span>struct device</span> defines a dedicated field:

struct device {
    // ...
    void *driver_data;  // Specifically used to store driver private data
    // ...
};
  1. Function Implementation (Simplified, Keeping Important Parts)
// drivers/base/core.c

// Store data: Assign the data pointer to dev->driver_data
void dev_set_drvdata(struct device *dev, void *data) {
    dev->driver_data = data;
}

// Retrieve data: Directly return dev->driver_data
void *dev_get_drvdata(const struct device *dev) {
    return dev->driver_data;
}

Simple, right? And very useful~

  1. Design Essence

• Lightweight and efficient: Directly operate on pointers, no complex logic.

• Type-agnostic: Uses <span>void*</span> generic pointers, supporting any data type.

4. Let’s Write a Driver for Hardware Register Operations

  1. Scenario Description

Assume we have a hardware device that needs to:

  1. Map the register address and save it during initialization (<span>probe</span> function).

  2. Read the register value in the interrupt handler function.

  3. Code Implementation

#include <linux/module.h>
#include <linux/device.h>

// Custom private data structure
struct mydev_priv {
    void __iomem *reg_base;  // Register base address
    int irq_num;             // Interrupt number
};

// Driver probe function (device initialization)
static int mydev_probe(struct device *dev) {
    struct mydev_priv *priv;

    // Allocate memory for private data (automatically freed)
    priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;

    // Map hardware registers (assumed to get address via device tree)
    priv->reg_base = devm_platform_ioremap_resource(to_platform_device(dev), 0);
    if (IS_ERR(priv->reg_base))
        return PTR_ERR(priv->reg_base);

    // Get interrupt number
    priv->irq_num = platform_get_irq(to_platform_device(dev), 0);
    if (priv->irq_num < 0)
        return priv->irq_num;

    // Key step: Bind private data to the device
    dev_set_drvdata(dev, priv);

    return 0;
}

// Interrupt handler function
static irqreturn_t mydev_irq_handler(int irq, void *dev_id) {
    struct device *dev = (struct device *)dev_id;
    struct mydev_priv *priv = dev_get_drvdata(dev); // Retrieve private data

    // Read register status
    u32 status = readl(priv->reg_base + 0x10);
    // Handle interrupt...

    return IRQ_HANDLED;
}

// Driver remove function
static void mydev_remove(struct device *dev) {
    // Resources allocated with devm will be automatically freed, no manual operation needed
}
  1. Code Explanation<span>devm_kzalloc</span>: A “managed” memory allocation function provided by the kernel, automatically frees memory when the device is unloaded.

• Private data should be allocated in <span>probe</span> and released in <span>remove</span> (if not using <span>devm_</span> series functions).

• Avoid using global variables: Prevent data conflicts between multiple device instances.

<span>dev_get_drvdata</span> and <span>dev_set_drvdata</span> elegantly solve the core problem of managing device private data. Mastering them not only allows you to write more robust driver code but also helps you deeply understand the Linux kernel’s design philosophy of “everything is an object”.

Finally

I have collected some embedded learning materials. Reply with [1024] in the public account to find the download link!

Recommended Articles
Click the blue text to jump
☞ Collection | Comprehensive Guide to Linux Application Programming
☞ Collection | Learn Some Networking Knowledge
☞ Collection | Handwritten C Language

☞ Collection | Handwritten C++ Language
☞ Collection | Experience Sharing
☞ Collection | From Microcontrollers to Linux
☞ Collection | Power Control Technology
☞ Collection | Essential Mathematics for Embedded Systems
☞ Collection | MCU Advanced Collection

☞ Collection | Embedded C Language Advanced Collection

☞ Collection | Experience Sharing

Leave a Comment