탐구platformdriver에서'다태적'사상

14467 단어 driver
문제는 처음에 다음 두 단락의 코드에서 나왔다.
static struct platform_driver sonypi_driver = {
    .driver        = {
        .name    = "sonypi",
        .owner    = THIS_MODULE,
    },
    .probe        = sonypi_probe,
    .remove        = __devexit_p(sonypi_remove),
    .shutdown    = sonypi_shutdown,
    .suspend    = sonypi_suspend,
    .resume        = sonypi_resume,
};
static const struct dev_pm_ops aa5302_pm_ops = {
    .suspend    = aa5302_suspend,
    .resume        = aa5302_resume,
};
#endif

static struct platform_driver aa5302_driver = {
    .driver = {
        .name  = "aa5302",
        .owner = THIS_MODULE,
#ifdef CONFIG_PM
        .pm    = &aa5302_pm_ops,
#endif
    },
    .probe = aa5302_probe,
    .remove = __devexit_p(aa5302_remove),
    .shutdown = aa5302_shutdown,
};

이 두 드라이브는 모두platform driver이지만 전원 관리에 대한 정의 방식은 다르다는 것을 알 수 있다. 전자는 직접platformdriver의suspend/resume 필드, 후자 간접 할당driver.pm 필드.지금까지 제가 접한 원공장 구동은 대부분이 뒤에 정의된 방식이어서 그 정의방식이 번거롭다고 생각했습니다. 이번에는 잘 연구해야 합니다.
여기.http://lists.kernelnewbies.org/pipermail/kernelnewbies/2013-October/009074.html어떤 사람이 비슷한 문제를 물었는데, 아쉽게도 대답이 없었다!
먼저kernel/include/linux/platformdevice.h의 정의:
struct platform_driver {
    int (*probe)(struct platform_device *);
    int (*remove)(struct platform_device *);
    void (*shutdown)(struct platform_device *);
    int (*suspend)(struct platform_device *, pm_message_t state);
    int (*resume)(struct platform_device *);
    struct device_driver driver;
    const struct platform_device_id *id_table;
};

kernel/include/linux/device.h의 정의:
struct device_driver {
    const char        *name;
    struct bus_type        *bus;
    struct module        *owner;
    const char        *mod_name;    /* used for built-in modules */
    bool suppress_bind_attrs;    /* disables bind/unbind via sysfs */
    const struct of_device_id    *of_match_table;
    int (*probe) (struct device *dev);
    int (*remove) (struct device *dev);
    void (*shutdown) (struct device *dev);
    int (*suspend) (struct device *dev, pm_message_t state);
    int (*resume) (struct device *dev);
    const struct attribute_group **groups;
    const struct dev_pm_ops *pm;
    struct driver_private *p;
};

처음 봤을 때, 그것들은 모두 프로브,remove를 정의했다.등함수이지만 platformdriver에 device 가 포함되어 있습니다.driver 구조체, 즉platformdriver 중 실제로 두 세트의probe,remove...왜 이러지?drivers/base/platform을 다시 봅시다.c에서 platform에 관한driver_register의 정의:
int platform_driver_register(struct platform_driver *drv)
{
    drv->driver.bus = &platform_bus_type;
    if (drv->probe)
        drv->driver.probe = platform_drv_probe;
    if (drv->remove)
        drv->driver.remove = platform_drv_remove;
    if (drv->shutdown)
        drv->driver.shutdown = platform_drv_shutdown;

    return driver_register(&drv->driver);
}

이쯤 되면 더 궁금할지도 몰라, 이건 사족을 그리는 거 아니야?platformdriver의probe,remove 필드는driver의 해당 필드에 값을 부여합니다. 최종 효과는 이 두 세트의probe,remove...실제로 가리키는 것은 각각 같은 리셋 함수다!사실,platform을 자세히 보면driver 및 devicedriver의probe,remove 바늘의 정의는 다음과 같습니다.
int (*probe)(struct platform_device *);int (*probe) (struct device *dev);
바로, 매개 변수의 유형이 다르다는 것이다!전자는platformdevice, 후자는 device!만약 네가 C++언어를 배운 적이 있다면 머릿속에'계승'과'다태적'이라는 개념이 있다. 나는 네가 왜 이렇게 하는지 이미 알고 있다고 믿는다:)
이렇게 말하자면, device와 devicedriver는 각각 드라이브의 기본 클래스이고platformdevice 및 platformdriver는 PLATFORM BUS 체계에 대응하는 파생류이다.device_driver의probe는 기본 클래스의 허함수,platformdriver의probe는 파생 클래스의 재부팅 함수입니다.platform 장치 드라이브라고 쓰려면 platformdriver의 리셋 함수 성명 형식으로 자신의 리셋 함수를 정의합니다.
따라서sonypi가 제어하는 shutdown 함수는 다음과 같이 정의됩니다.
 
static void sonypi_shutdown(struct platform_device *dev)
{
    sonypi_disable();
}

 
대신 다음과 같습니다.
static void sonypi_shutdown(struct device *dev)
{
    sonypi_disable();
}

만약 당신이 굳이 이 "기본 함수"를 사용하려고 한다면, 그것도 방법이 있습니다.platformdriver를 할 때 아래의 방식으로 추측만 하고 검증을 하지 않았습니다.
static struct platform_driver sonypi_driver = {
    .driver        = {
        .name    = "sonypi",
        .owner    = THIS_MODULE,
        .shutdown = sonypi_shutdown,
    },
    .probe        = sonypi_probe,
    .remove        = __devexit_p(sonypi_remove),
    .suspend    = sonypi_suspend,
    .resume        = sonypi_resume,
};

 
------------------------------------------------------화려한 분할선 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
다음은 전원 관리에 대한 문제입니다.sonypi 드라이브는platform을 사용합니다driver.suspend/resume의 방식으로 리셋 함수를 정의하고 aa5302 드라이브는platformdriver.driver.pm.suspend/resume의 방식으로 리셋을 정의합니다. 이것은 위에서 말한 '다태적' 과 완전히 일치하지 않는 것 같습니다.확실히 그렇다. 여기는 또 다른legacy의 문제와 관련된다. Stackoverflow의 한 편은 명확하게 설명했다.http://stackoverflow.com/questions/19462639/which-suspend-resume-pointer-is-the-right-one-to-useplatform 한번 봅시다.pm_만약driver.pm 필드가 비어 있지 않으면 사용합니다.pm에서 제공하는 리셋, 그렇지 않으면 platformdriver.suspend가 정의한lagacy 방식의 리셋입니다.
int platform_pm_suspend(struct device *dev)
{
    struct device_driver *drv = dev->driver;
    int ret = 0;

    if (!drv)
        return 0;

    if (drv->pm) {
        if (drv->pm->suspend)
            ret = drv->pm->suspend(dev);
    } else {
        ret = platform_legacy_suspend(dev, PMSG_SUSPEND);
    }

    return ret;
}

device_driver.suspend/resume는 낡은 방식입니다. 그들은devpm_ops가 탄생하기 전부터 존재했습니다. 우리의 새로운 드라이브에dev 를 사용해야 합니다.pm_ops에서 리셋 함수를 정의합니다.stackoverflow에서 언급한 i2c 드라이브와 여기 있는 2개의platformdriver는 아직 완전히 같지 않아, i2cdriver는 단지 하나의 통신 인터페이스를 제공할 뿐 장치의 제어 논리를 제공하지 않는다. 오디오 코드c에서 매우 뚜렷하게 나타난다. 오디오 코드c는 본질적으로 I2C칩이고probe 함수에 더욱 고급스러운 제어 장치를 등록했다. 코드c, 제어 논리는 코드c가 완성한다.그래서 그 i2cdriver에는 전원 관리 기능이 제공되지 않습니다.
static struct i2c_driver wm8900_i2c_driver = {
    .driver = {
        .name = "WM8900",
        .owner = THIS_MODULE,
    },
    .probe = wm8900_i2c_probe,
    .remove = __devexit_p(wm8900_i2c_remove),
    .shutdown = wm8900_i2c_shutdown,
    .id_table = wm8900_i2c_id,
};

대신 코드c로 이동:
static struct snd_soc_codec_driver soc_codec_dev_wm8900 = {
    .probe =    wm8900_probe,
    .remove =    wm8900_remove,
    .suspend = wm8900_suspend,
    .resume = wm8900_resume,
    .set_bias_level = wm8900_set_bias_level,
    .volatile_register = wm8900_volatile_register,
    .reg_cache_size = ARRAY_SIZE(wm8900_reg_defaults),
    .reg_word_size = sizeof(u16),
    .reg_cache_default = wm8900_reg_defaults,
};

좋은 웹페이지 즐겨찾기