2013-03-25 40 views
40

trước đây tôi đã có một suy nghĩ về trình điều khiển nền tảng cũng như điều khiển thiết bị thông thường như:Sự khác nhau giữa trình điều khiển nền tảng Linux và trình điều khiển thiết bị thông thường là gì?

  • lái xe Platform là đối với những thiết bị có trên chip. và,
  • Trình điều khiển thiết bị thông thường dành cho những thiết bị được giao tiếp với chip proccesor. trước khi đi qua một trình điều khiển i2c.

    Nhưng ở đây, tôi đang đọc qua trình điều khiển đa chức năng i2c được định nghĩa là trình điều khiển nền tảng. Tôi đã trải qua https://www.kernel.org/doc/Documentation/driver-model/platform.txt. Nhưng vẫn không thể có được ý tưởng rõ ràng để đi đến một kết luận về cách xác định các trình điều khiển, giống như cho cả hai onchip cũng như các thiết bị giao tiếp. tôi đã đi qua liên kết này quá .. http://meld.org/discussion/general-discussion/platform-driver-vs-ordinary-device-drivers

Hãy ai đó giải thích.

+0

Thiết bị này là một thiết bị đa chức năng MFD-. có một trường trong 'platform_device'; 'struct mfd cell' không có trong cấu trúc' i2c_client'. Có lẽ vì lý do đó trình điều khiển được đăng ký làm trình điều khiển nền tảng. Hãy bình luận về điều này. !! – kzs

+0

http://www.atmel.com/Images/doc32098.pdf ..... kiểm tra điều này ... nó có thể giúp –

+0

Vâng tài liệu là tốt .. Tôi nghĩ rằng tôi có thể sử dụng tài liệu đó đôi khi sau đó. nhưng tôi chưa thể kết luận được. Tôi đã hỏi một Master giỏi trình điều khiển .. Tôi sẽ đăng ở đây một khi tôi nhận được câu trả lời. – kzs

Trả lời

65

Tham chiếu của bạn tốt nhưng thiếu định nghĩa thiết bị nền tảng là gì. Có một trên LWN. Những gì chúng ta có thể học hỏi từ trang này:

  1. thiết bị vBulletin là vốn đã không thể phát hiện, ví dụ: các phần cứng không thể nói "Này tôi là hiện tại!" vào phần mềm. Ví dụ điển hình là thiết bị i2c, kernel/Documentation/i2c/instantiating-devices tiểu bang:

    Không giống như thiết bị PCI hoặc USB, thiết bị I2C không được liệt kê ở cấp phần cứng (tại thời gian chạy). Thay vào đó, phần mềm phải biết (tại thời gian biên dịch) thiết bị nào được kết nối trên mỗi đoạn bus I2C. Vì vậy, USB và PCI là không phải là thiết bị nền tảng.

  2. thiết bị vBulletin đang bị ràng buộc để điều khiển bằng cách kết hợp tên,

  3. thiết bị vBulletin nên đăng ký rất sớm trong khi khởi động hệ thống. Bởi vì chúng thường rất quan trọng đối với phần còn lại của hệ thống (nền tảng) và các trình điều khiển của nó.

Vì vậy, về cơ bản, câu hỏi "nó là một nền tảng thiết bị hoặc một thiết bị tiêu chuẩn?" là hơn một câu hỏi trong đó xe buýt nó sử dụng. Để làm việc với một thiết bị nền tảng cụ thể, bạn phải:

  1. đăng ký trình điều khiển nền tảng sẽ quản lý thiết bị này. Nó phải xác định một tên độc đáo,
  2. đăng ký thiết bị nền tảng, xác định cùng tên với trình điều khiển.

Trình điều khiển nền tảng dành cho các thiết bị trên chip đó.

Không đúng (theo lý thuyết nhưng đúng trong thực tế). thiết bị i2c không phải là onChip, nhưng là thiết bị nền tảng vì chúng không thể phát hiện được. Ngoài ra, chúng tôi có thể nghĩ về thiết bị onChip là thiết bị bình thường. Ví dụ: chip PCI GPU tích hợp trên bộ vi xử lý x86 hiện đại. Nó có thể phát hiện được, do đó không phải là một thiết bị nền tảng.

Trình điều khiển thiết bị thông thường dành cho những thiết bị được giao tiếp với chip xử lý. trước khi đi qua một trình điều khiển i2c.

Không đúng sự thật. Nhiều thiết bị bình thường được giao tiếp với bộ xử lý, nhưng không phải thông qua xe buýt i2c. Ví dụ: chuột USB.

[EDIT] Trong trường hợp của bạn, có một cái nhìn để drivers/usb/host/ohci-pnx4008.c, mà là một nền tảng thiết bị điều khiển USB host (Ở đây bộ điều khiển USB là không thể phát hiện được, trong khi các thiết bị USB, mà sẽ kết nối đến nó, là). Đây là thiết bị nền tảng được đăng ký bởi tập tin bảng (arch/arm/mach-pnx4008/core.c:pnx4008_init). Và trong chức năng thăm dò của nó, nó đăng ký thiết bị i2c của nó lên xe buýt với i2c_register_driver. Chúng tôi có thể phỏng đoán rằng chipset bộ điều khiển Máy chủ USB đàm phán với CPU thông qua một bus i2c.

Tại sao kiến ​​trúc đó? Bởi vì một mặt, thiết bị này có thể được coi là một thiết bị i2c trần cung cấp một số chức năng cho hệ thống. Mặt khác, nó là một thiết bị USB Host có khả năng. Nó cần phải đăng ký vào ngăn xếp USB (usb_create_hcd). Vì vậy, thăm dò chỉ i2c sẽ không đủ. Hãy xem Documentation/i2c/instantiating-devices.

+0

Chính xác là bạn đã đúng. Tôi sẽ cung cấp cho +1 cho điều này: Vì vậy, về cơ bản, câu hỏi "nó là một thiết bị nền tảng hoặc một thiết bị tiêu chuẩn?" là một câu hỏi mà xe buýt nó sử dụng. Tôi có thể nhận và đồng ý với tất cả các điểm. nhưng tôi không thể hiểu hoặc liên quan đến điều này: Trình điều khiển thiết bị thông thường dành cho những người được giao tiếp với chip xử lý. trước khi đi qua một trình điều khiển i2c. Xin giải thích cho tôi một chiều hướng tốt hơn để nó có thể làm cho tôi hiểu. – kzs

+0

Tôi thấy ít trình điều khiển sử dụng i2c_driver_register và trong trường hợp i2c này tôi thấy platform_driver_register. Tôi có một câu hỏi mà một trong những sử dụng giữa hai người. – kzs

+1

@zair Trong phần ** EDIT ** của câu trả lời của tôi, 'platform_driver_register' đăng ký trình điều khiển Máy chủ USB với ngăn xếp USB, trong khi' i2c_driver_register' được sử dụng để cho phép CPU _talks_ tới Bộ điều khiển Máy chủ USB, thông qua giao thức i2c. Nếu bộ điều khiển USB có khả năng SPI, thay vào đó sẽ có 'platform_driver_register' và' spi_register_driver'. –

1

Minimal đang mô-đun ví dụ

Có lẽ sự khác biệt cũng sẽ trở nên rõ ràng hơn với một số ví dụ cụ thể.

nền tảng thiết bị dụ

Code:

ghi chú hội nhập sâu hơn tại địa chỉ: https://stackoverflow.com/a/44612957/895245

Xem cách:

  • đăng ký và gián đoạn địa chỉ được mã hóa trong cây thiết bị và phù hợp với mô tả máy qemu -M versatilepb, đại diện cho SoC
  • không có cách nào để xóa phần cứng thiết bị (vì nó là một phần của SoC)
  • đúng driver được chọn theo các compatible thiết bị sở hữu cây mà phù hợp platform_driver.name trong trình điều khiển
  • platform_driver_register là giao diện đăng ký chính
#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 phi nền tảng thiết bị dụ

Xem cách:

  • đăng ký và ngắt địa chỉ được cấp phát động bởi hệ thống PCI, không có cây thiết bị được sử dụng
  • trình điều khiển chính xác được lựa chọn bởi PCI vendor:device ID (QEMU_VENDOR_ID, EDU_DEVICE_ID ví dụ). Điều này được nướng vào mọi thiết bị và nhà cung cấp phải đảm bảo tính duy nhất.
  • chúng tôi có thể lắp và tháo thiết bị PCI với device_add edudevice_del edu như chúng ta có thể thực tế. Probing không tự động, nhưng có thể được thực hiện sau khi khởi động với echo 1 > /sys/bus/pci/rescan. Xem thêm: Why is the probe method needed in Linux device drivers in addition to 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); 
Các vấn đề liên quan