Was ist der Unterschied zwischen einem Linux-Plattformtreiber und einem normalen Gerätetreiber?

Lesezeit: 10 Minuten

Benutzeravatar von kzs
kzs

Früher hatte ich angenommen:

  • Der Plattformtreiber ist für die Geräte, die sich auf dem Chip befinden.
  • Normale Gerätetreiber sind für diejenigen, die mit dem Prozessorchip verbunden sind.

Bevor ich auf einen i2c-Treiber stoße … Aber hier lese ich den multifunktionalen i2c-Treiber durch, der als Plattformtreiber definiert ist. Ich war durchgegangen https://www.kernel.org/doc/Documentation/driver-model/platform.txt. Aber ich konnte immer noch keine klare Vorstellung davon bekommen, wie man Treiber definiert, sowohl für Onchip- als auch für Schnittstellengeräte.

Bitte jemand erklären.

  • Das Gerät ist ein MFD-Multifunktionsgerät. Da ist ein Feld drin platform_device; struct mfd cell was nicht drin ist i2c_client Struktur. Vielleicht ist aus diesem Grund der Treiber als Plattformtreiber registriert. Bitte kommentieren Sie dies. !!

    – kzs

    28. März 2013 um 8:21 Uhr

  • atmel.com/Images/doc32098.pdf ….. check this out … es könnte helfen

    – Kinjal Patel

    28. März 2013 um 9:56 Uhr

  • Ja, das Dokument war gut. Ich denke, ich könnte dieses Dokument irgendwann später verwenden. aber ich konnte noch nicht zu einem Schluss kommen. Ich habe einen Meister gefragt, der gut im Fahren ist. Ich werde hier posten, sobald ich die Antworten habe.

    – kzs

    29. März 2013 um 9:33 Uhr

  • linuxseekernel.blogspot.com/2014/05/…

    – Jeyaram

    23. Mai 2014 um 4:14 Uhr

Benutzeravatar von m-ric
m-ric

Ihre Referenzen sind gut, aber es fehlt eine Definition von Was ist ein Plattformgerät. Da ist einer dran LWN. Was wir von dieser Seite lernen können:

  1. Plattformgeräte sind grundsätzlich nicht auffindbardh die Hardware kann das nicht sagen “Hey! Ich bin anwesend!” zur Software. Typische Beispiele sind i2c-Geräte, kernel/Documentation/i2c/instantiating-devices Zustände:

    Im Gegensatz zu PCI- oder USB-Geräten werden I2C-Geräte nicht auf Hardwareebene (zur Laufzeit) aufgelistet. Stattdessen muss die Software (zur Kompilierzeit) wissen, welche Geräte an jedem I2C-Bussegment angeschlossen sind. Also USB und PCI nicht Plattformgeräte.

  2. Plattformgeräte sind an Treiber gebunden durch übereinstimmende Namen,

  3. Plattformgeräte sein sollten sehr früh angemeldet während des Systemstarts. Weil sie oft entscheidend für den Rest des Systems (Plattform) und seine Treiber sind.

Also im Grunde die Frage “ist es ein Plattformgerät oder ein Standardgerät?” ist eher eine Frage, welchen Bus es verwendet. Um mit einem bestimmten Plattformgerät zu arbeiten, müssen Sie:

  1. Registrieren Sie einen Plattformtreiber die dieses Gerät verwalten wird. Es sollte a definieren einzigartig Name,
  2. Registrieren Sie Ihr Plattformgerätdie den gleichen Namen wie der Treiber definiert.

Der Plattformtreiber ist für die Geräte, die sich auf dem Chip befinden.

Stimmt nicht (in der Theorie, aber in der Praxis). i2c-Geräte sind keine OnChip-, sondern Plattformgeräte, da sie nicht erkennbar sind. Wir können auch an OnChip-Geräte denken, die es sind normal Geräte. Beispiel: ein integrierter PCI-GPU-Chip auf einem modernen x86-Prozessor. Es ist erkennbar, also kein Plattformgerät.

Normale Gerätetreiber sind für diejenigen, die mit dem Prozessorchip verbunden sind. bevor Sie auf einen i2c-Treiber stoßen.

Nicht wahr. Viele normal Geräte sind mit dem Prozessor verbunden, jedoch nicht über einen i2c-Bus. Beispiel: eine USB-Maus.

[EDIT] Schau in deinem Fall mal nach drivers/usb/host/ohci-pnx4008.c, bei dem es sich um ein USB-Host-Controller-Plattformgerät handelt (hier ist der USB-Host-Controller nicht erkennbar, USB-Geräte, die sich mit ihm verbinden, sind es jedoch). Es ist ein von der registriertes Plattformgerät Board-Datei (arch/arm/mach-pnx4008/core.c:pnx4008_init). Und innerhalb seiner Probe-Funktion registriert es sein i2c-Gerät am Bus mit i2c_register_driver. Wir können daraus schließen, dass der USB-Host-Controller-Chipsatz redet mit die CPU über einen i2c-Bus.

Warum diese Architektur? Denn einerseits kann dieses Gerät als reines i2c-Gerät betrachtet werden, das einige Funktionen für das System bereitstellt. Andererseits ist es ein USB-Host-fähiges Gerät. Es muss sich beim USB-Stack registrieren (usb_create_hcd). Es wird also nicht ausreichen, nur i2c zu prüfen. Schau doch mal vorbei Documentation/i2c/instantiating-devices.

  • Genau da hast du recht. Ich würde dafür +1 geben: Also im Grunde ist die Frage “Ist es ein Plattformgerät oder ein Standardgerät?” ist eher eine Frage des verwendeten Busses. Ich konnte alle Punkte verstehen und zustimmen. aber ich konnte diesen nicht verstehen oder beziehen: Normale Gerätetreiber sind für diejenigen, die an den Prozessorchip angeschlossen sind. bevor Sie auf einen i2c-Treiber stoßen. Bitte erkläre es mir in einer besseren Dimension, damit ich es verstehen kann.

    – kzs

    3. April 2013 um 6:23 Uhr

  • Ich sehe einige Treiber, die i2c_driver_register verwenden, und in diesem i2c-Fall sehe ich platform_driver_register. Ich habe eine Frage, welche ich zwischen den beiden verwenden soll.

    – kzs

    3. April 2013 um 7:30 Uhr

  • @zair Im BEARBEITEN Teil meiner Antwort, platform_driver_register registriert den USB-Host-Treiber beim USB-Stack, wohingegen i2c_driver_register wird verwendet, um die CPU zuzulassen Gespräche an den USB-Host-Controller über das i2c-Protokoll. Wenn der USB-Controller SPI-fähig wäre, gäbe es eine platform_driver_register und spi_register_driver stattdessen.

    – m-ric

    11. April 2013 um 14:46 Uhr

  • Ausgezeichnet.. sehr klar. Danke, dass Sie sich Mühe gegeben haben, mich besser zu erklären. Ich würde +1 geben.

    – kzs

    12. April 2013 um 6:36 Uhr

  • Ich habe noch einen Zweifel. Ich habe die Vorstellung, dass “alle Busse, die keine erkennbaren Eigenschaften wie die ID-Leitung haben, auf einem Plattformbus-Framework basieren”, z. I2C hat nur Takt und Daten und basiert daher auf dem Plattformbus. Ist das wahr und wenn ja, können Sie einen anderen Bus nennen, der auf Plattformarchitektur basiert?

    – Shingaridawesch

    2. Mai 2013 um 9:50 Uhr

Ciro Santilli Benutzeravatar von OurBigBook.com
Ciro Santilli OurBigBook.com

Minimale Modulcodebeispiele

Vielleicht wird der Unterschied auch an einigen konkreten Beispielen deutlicher.

Beispiel für ein Plattformgerät

Code:

Weitere Integrationshinweise unter: https://stackoverflow.com/a/44612957/895245

Siehe wie:

  • Register- und Interrupt-Adressen sind im Gerätebaum fest codiert und entsprechen der QEMU -M versatilepb Maschinenbeschreibung, die den SoC darstellt
  • Es gibt keine Möglichkeit, die Gerätehardware zu entfernen (da sie Teil des SoC ist)
  • der richtige Fahrer wird durch die ausgewählt compatible Gerätebaumeigenschaft, die übereinstimmt platform_driver.name im Fahrer
  • platform_driver_register ist die Hauptregisterschnittstelle
#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)

Beispiel für ein plattformunabhängiges PCI-Gerät

Siehe wie:

  • Register- und Interrupt-Adressen werden vom PCI-System dynamisch zugewiesen, es wird kein Gerätebaum verwendet
  • der richtige Treiber wird von der PCI ausgewählt vendor:device ICH WÜRDE (QEMU_VENDOR_ID, EDU_DEVICE_ID am Beispiel). Dies ist in jedes Gerät eingebrannt, und die Anbieter müssen die Einzigartigkeit sicherstellen.
  • wir können das PCI-Gerät mit einfügen und entfernen device_add edu und device_del edu wie wir es im wirklichen Leben können. Das Testen erfolgt nicht automatisch, kann aber nach dem Booten mit durchgeführt werden echo 1 > /sys/bus/pci/rescan. Siehe auch: Warum wird die Prüfmethode in Linux-Gerätetreibern zusätzlich zu init benötigt?
#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);

1414260cookie-checkWas ist der Unterschied zwischen einem Linux-Plattformtreiber und einem normalen Gerätetreiber?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy