Linux 플랫폼 드라이버와 일반 디바이스 드라이버의 차이점은 무엇입니까?
이전에는 다음과 같이 상정하고 있었습니다.
- 플랫폼 드라이버는 칩에 내장된 디바이스용입니다.
- 통상의 디바이스 드라이버는, 프로세서 칩에 인터페이스 되어 있는 드라이버입니다.
i2c 드라이버를 발견하기 전에...하지만 여기서는 플랫폼 드라이버로 정의된 다기능 i2c 드라이버를 읽고 있습니다.저는 https://www.kernel.org/doc/Documentation/driver-model/platform.txt에 접속했습니다.그러나, 온칩 디바이스와 인터페이스 디바이스의 양쪽 모두에 대해서, 드라이버를 정의하는 방법에 대해서는 명확한 결론을 내릴 수 없었습니다.
누가 설명 좀 해주세요.
레퍼런스는 좋지만 플랫폼디바이스에 대한 정의가 부족합니다.LWN에 하나 있어요.이 페이지에서 알 수 있는 내용:
플랫폼 디바이스는 본질적으로 검출할 수 없습니다.즉, 하드웨어에서는 "Hey! 내가 있어!"라고 말합니다.전형적인 예는 i2c 디바이스입니다.
kernel/Documentation/i2c/instantiating-devices
상태:PCI 또는 USB 디바이스와 달리 I2C 디바이스는 하드웨어 수준(실행 시)에서 열거되지 않습니다.대신 소프트웨어는 (컴파일 시) 각 I2C 버스 세그먼트에 어떤 디바이스가 연결되어 있는지 알아야 합니다.따라서 USB와 PCI는 플랫폼 디바이스가 아닙니다.
플랫폼 디바이스는 일치하는 이름으로 드라이버에 바인드됩니다.
- 플랫폼 디바이스는 시스템 부팅 시 매우 일찍 등록해야 합니다.대부분의 경우 시스템(플랫폼)과 드라이버에 매우 중요하기 때문입니다.
따라서 기본적으로 "플랫폼 디바이스냐 표준 디바이스냐"라는 질문은 어떤 버스를 사용하는지에 대한 질문입니다.특정 플랫폼디바이스에서 작업하려면 다음 작업을 수행해야 합니다.
- 이 디바이스를 관리하는 플랫폼드라이버를 등록합니다.고유한 이름을 정의해야 합니다.
- 플랫폼 디바이스를 등록하고, 드라이버와 같은 이름을 정의합니다.
플랫폼 드라이버는 칩에 내장된 디바이스용입니다.
사실이 아니다(이론적으로는 그렇지만 실제로는 사실이다).i2c 디바이스는 온칩이 아니라 검출할 수 없기 때문에 플랫폼 디바이스입니다.또한 일반적인 장치인 온칩 장치도 생각할 수 있습니다.예: 최신 x86 프로세서에 내장된 PCI GPU 칩.검출이 가능하기 때문에 플랫폼디바이스가 아닙니다.
통상의 디바이스 드라이버는, 1개의 i2c 드라이버를 사용하기 전에, 프로세서 칩에 접속되어 있는 드라이버를 대상으로 하고 있습니다.
그렇지 않아요.많은 일반 디바이스는 프로세서와 인터페이스되지만 i2c 버스를 통해서는 인터페이스되지 않습니다.예: USB 마우스.
[편집] 당신의 경우는drivers/usb/host/ohci-pnx4008.c
USB 호스트 컨트롤러 플랫폼 디바이스(여기서는 USB 호스트 컨트롤러는 검출할 수 없지만 접속하는 USB 디바이스는 검출할 수 있습니다).보드 파일로 등록된 플랫폼 장치입니다.arch/arm/mach-pnx4008/core.c:pnx4008_init
기능 를 버스에 i2c_register_driver
USB 호스트 컨트롤러 칩셋은 i2c 버스를 통해 CPU와 통신하는 것으로 추측할 수 있습니다.
왜런그 키키?왜냐하면 이 장치는 시스템에 몇 가지 기능을 제공하는 베어 i2c 장치로 간주될 수 있기 때문입니다.편 usb usb, USB 호대대 usb usb usb usb usb usb usb usb usb usb usb usb. 스택USB 스택)에 .usb_create_hcd
따라서 i2c만 프로빙하는 것으로는 불충분합니다.Documentation/i2c/instantiating-devices
.
최소 모듈 코드 예시
구체적인 예를 들면, 그 차이는 더욱 명확해질지도 모른다.
플랫폼 디바이스의 예시
코드:
통합에 관한 자세한 내용은 https://stackoverflow.com/a/44612957/895245를 참조해 주십시오.
자세한 것은 이쪽:
- 합니다.
-M versatilepb
SoCSoC를 - 디바이스 하드웨어를 제거할 방법이 없습니다(SoC의 일부이므로).
- 는 바바에 의해 된다.
compatible
으로, 「」와 일치합니다.platform_driver.name
platform_driver_register
입니다.
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
MODULE_LICENSE("GPL");
static struct resource res;
static unsigned int irq;
static void __iomem *map;
static irqreturn_t lkmc_irq_handler(int irq, void *dev)
{
/* TODO this 34 and not 18 as in the DTS, likely the interrupt controller moves it around.
* Understand precisely. 34 = 18 + 16. */
pr_info("lkmc_irq_handler irq = %d dev = %llx\n", irq, *(unsigned long long *)dev);
/* ACK the IRQ. */
iowrite32(0x9ABCDEF0, map + 4);
return IRQ_HANDLED;
}
static int lkmc_platform_device_probe(struct platform_device *pdev)
{
int asdf;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
dev_info(dev, "probe\n");
/* Play with our custom poperty. */
if (of_property_read_u32(np, "lkmc-asdf", &asdf) ) {
dev_err(dev, "of_property_read_u32\n");
return -EINVAL;
}
if (asdf != 0x12345678) {
dev_err(dev, "asdf = %llx\n", (unsigned long long)asdf);
return -EINVAL;
}
/* IRQ. */
irq = irq_of_parse_and_map(dev->of_node, 0);
if (request_irq(irq, lkmc_irq_handler, 0, "lkmc_platform_device", dev) < 0) {
dev_err(dev, "request_irq");
return -EINVAL;
}
dev_info(dev, "irq = %u\n", irq);
/* MMIO. */
if (of_address_to_resource(pdev->dev.of_node, 0, &res)) {
dev_err(dev, "of_address_to_resource");
return -EINVAL;
}
if (!request_mem_region(res.start, resource_size(&res), "lkmc_platform_device")) {
dev_err(dev, "request_mem_region");
return -EINVAL;
}
map = of_iomap(pdev->dev.of_node, 0);
if (!map) {
dev_err(dev, "of_iomap");
return -EINVAL;
}
dev_info(dev, "res.start = %llx resource_size = %llx\n",
(unsigned long long)res.start, (unsigned long long)resource_size(&res));
/* Test MMIO and IRQ. */
iowrite32(0x12345678, map);
return 0;
}
static int lkmc_platform_device_remove(struct platform_device *pdev)
{
dev_info(&pdev->dev, "remove\n");
free_irq(irq, &pdev->dev);
iounmap(map);
release_mem_region(res.start, resource_size(&res));
return 0;
}
static const struct of_device_id of_lkmc_platform_device_match[] = {
{ .compatible = "lkmc_platform_device", },
{},
};
MODULE_DEVICE_TABLE(of, of_lkmc_platform_device_match);
static struct platform_driver lkmc_plaform_driver = {
.probe = lkmc_platform_device_probe,
.remove = lkmc_platform_device_remove,
.driver = {
.name = "lkmc_platform_device",
.of_match_table = of_lkmc_platform_device_match,
.owner = THIS_MODULE,
},
};
static int lkmc_platform_device_init(void)
{
pr_info("lkmc_platform_device_init\n");
return platform_driver_register(&lkmc_plaform_driver);
}
static void lkmc_platform_device_exit(void)
{
pr_info("lkmc_platform_device_exit\n");
platform_driver_unregister(&lkmc_plaform_driver);
}
module_init(lkmc_platform_device_init)
module_exit(lkmc_platform_device_exit)
PCI 비플랫폼디바이스 예시
자세한 것은 이쪽:
- 레지스터 및 인터럽트 주소는 PCI 시스템에 의해 동적으로 할당되며 디바이스 트리는 사용되지 않습니다.
- 됩니다.
vendor:device
이)QEMU_VENDOR_ID, EDU_DEVICE_ID
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★이것은 모든 디바이스에 내장되어 있어 벤더는 일의성을 확보할 필요가 있습니다. - 합니다.
device_add edu
★★★★★★★★★★★★★★★★★」device_del edu
부팅 에 실행할 수 .echo 1 > /sys/bus/pci/rescan
. 다음 항목도 참조하십시오.Linux 디바이스 드라이버에 init 이외에 프로브 방식이 필요한 이유는 무엇입니까?
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#define BAR 0
#define CDEV_NAME "lkmc_hw_pci_min"
#define EDU_DEVICE_ID 0x11e9
#define QEMU_VENDOR_ID 0x1234
MODULE_LICENSE("GPL");
static struct pci_device_id id_table[] = {
{ PCI_DEVICE(QEMU_VENDOR_ID, EDU_DEVICE_ID), },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, id_table);
static int major;
static struct pci_dev *pdev;
static void __iomem *mmio;
static struct file_operations fops = {
.owner = THIS_MODULE,
};
static irqreturn_t irq_handler(int irq, void *dev)
{
pr_info("irq_handler irq = %d dev = %d\n", irq, *(int *)dev);
iowrite32(0, mmio + 4);
return IRQ_HANDLED;
}
static int probe(struct pci_dev *dev, const struct pci_device_id *id)
{
pr_info("probe\n");
major = register_chrdev(0, CDEV_NAME, &fops);
pdev = dev;
if (pci_enable_device(dev) < 0) {
dev_err(&(pdev->dev), "pci_enable_device\n");
goto error;
}
if (pci_request_region(dev, BAR, "myregion0")) {
dev_err(&(pdev->dev), "pci_request_region\n");
goto error;
}
mmio = pci_iomap(pdev, BAR, pci_resource_len(pdev, BAR));
pr_info("dev->irq = %u\n", dev->irq);
if (request_irq(dev->irq, irq_handler, IRQF_SHARED, "pci_irq_handler0", &major) < 0) {
dev_err(&(dev->dev), "request_irq\n");
goto error;
}
iowrite32(0x12345678, mmio);
return 0;
error:
return 1;
}
static void remove(struct pci_dev *dev)
{
pr_info("remove\n");
free_irq(dev->irq, &major);
pci_release_region(dev, BAR);
unregister_chrdev(major, CDEV_NAME);
}
static struct pci_driver pci_driver = {
.name = CDEV_NAME,
.id_table = id_table,
.probe = probe,
.remove = remove,
};
static int myinit(void)
{
if (pci_register_driver(&pci_driver) < 0) {
return 1;
}
return 0;
}
static void myexit(void)
{
pci_unregister_driver(&pci_driver);
}
module_init(myinit);
module_exit(myexit);
언급URL : https://stackoverflow.com/questions/15610570/what-is-the-difference-between-a-linux-platform-driver-and-normal-device-driver
'itsource' 카테고리의 다른 글
visual studio 2017 스파 템플릿 vue js 누락 (0) | 2022.08.15 |
---|---|
gcc - O0은 여전히 "미사용" 코드를 최적화합니다.그것을 변경할 수 있는 컴파일 플래그가 있습니까? (0) | 2022.08.15 |
C의 함수 포인터에 대한 typedef 이해 (0) | 2022.08.15 |
스프링 부트:Embedded Servlet Container Factory 빈이 없어 Embedded Web Application Context를 시작할 수 없습니다. (0) | 2022.08.15 |
비동기 상태 변경 후 Vuex 기능 실행 (0) | 2022.08.15 |