2016年5月14日 星期六

Linux kernel - platform_set_drvdata 和 platform_get_drvdata 用法

1. 當裝置的platform data在probe函數中定義為區域變數,如果我們想要在其它地方使用,核心提供了這個方法,使用platform_set_drvdata()可以將data保存成裝置的私有變數,等到之後要使用時,只需要呼叫platform_get_drvdata(),就可以取出data變數。

2. platform_set_drvdata() 和 platform_get_drvdata()函數被定義在include/linux/platform_device.h
static inline void *platform_get_drvdata(const struct platform_device *pdev)
{
        return dev_get_drvdata(&pdev->dev);
}

static inline void platform_set_drvdata(struct platform_device *pdev,
                                        void *data)
{
        dev_set_drvdata(&pdev->dev, data);
}
dev_get_drvdata() 和 dev_set_drvdata()函數被定義在include/linux/device.h
static inline void *dev_get_drvdata(const struct device *dev)
{
        return dev->driver_data;
}

static inline void dev_set_drvdata(struct device *dev, void *data)
{
        dev->driver_data = data;
}
3. 範例 drivers/leds/leds-gpio.c
static int gpio_led_probe(struct platform_device *pdev)
{
        struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct gpio_leds_priv *priv;
        int i, ret = 0;

        if (pdata && pdata->num_leds) {
                priv = devm_kzalloc(&pdev->dev,
                                sizeof_gpio_leds_priv(pdata->num_leds),
                                        GFP_KERNEL);
                if (!priv)
                        return -ENOMEM;

                priv->num_leds = pdata->num_leds;
                for (i = 0; i < priv->num_leds; i++) {
                        ret = create_gpio_led(&pdata->leds[i],
                                              &priv->leds[i],
                                              &pdev->dev, pdata->gpio_blink_set);
                        if (ret < 0) {
                                /* On failure: unwind the led creations */
                                for (i = i - 1; i >= 0; i--)
                                        delete_gpio_led(&priv->leds[i]);
                                return ret;
                        }
                }
        } else {
                priv = gpio_leds_create(pdev);
                if (IS_ERR(priv))
                        return PTR_ERR(priv);
        }

        platform_set_drvdata(pdev, priv);

        return 0;
}

static int gpio_led_remove(struct platform_device *pdev)
{
        struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
        int i;

        for (i = 0; i < priv->num_leds; i++)
                delete_gpio_led(&priv->leds[i]);

        return 0;
}

static struct platform_driver gpio_led_driver = {
        .probe          = gpio_led_probe,
        .remove         = gpio_led_remove,
        .driver         = {
                .name   = "leds-gpio",
                .of_match_table = of_gpio_leds_match,
        },
};

module_platform_driver(gpio_led_driver);

MODULE_AUTHOR("Raphael Assenat , Trent Piepho ");
MODULE_DESCRIPTION("GPIO LED driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:leds-gpio");

沒有留言:

張貼留言