탐구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,
};
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Windows 네트워크 드라이브 경로를 전체 경로로 변환Windows 네트워크 드라이브는 매우 편리합니다. 하지만, 문서나 메일에 그 파일의 패스를 그대로 삽입하면, 타인은 그 파일의 패스를 인식할 수 없지요. 이 때문에 아래의 툴을 만들어 데스크탑 등에서 파일을 툴의 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.