¿Cuál es la diferencia entre un controlador de plataforma Linux y un controlador de dispositivo normal?


Anteriormente tuve un pensamiento sobre el controlador de la plataforma, así como el controlador de dispositivo normal como:

Por favor, alguien explique.

2 answers

Sus referencias son buenas pero carecen de una definición de qué es un dispositivo de plataforma. Hay uno en LWN . Lo que podemos aprender de esta página:

  1. Los dispositivos de la plataforma son inherentemente no detectables , es decir, el hardware no puede decir "¡Hey! Estoy presente!" al software. Ejemplos típicos son los dispositivos i2c, kernel/Documentation/i2c/instantiating-devices estados:

    A diferencia de los dispositivos PCI o USB, los dispositivos I2C no se enumeran a nivel de hardware (en tiempo de ejecución). En su lugar, el software debe saber (en tiempo de compilación) qué dispositivos están conectados en cada segmento de bus I2C. Así que USB y PCI son no dispositivos de plataforma.

  2. Los dispositivos de la plataforma están vinculados a los controladores mediante nombres coincidentes,

  3. Los dispositivos de la plataforma deben registrarse muy pronto durante el arranque del sistema. Porque a menudo son críticos para el resto del sistema (plataforma) y sus controladores.

Así que, básicamente, la pregunta "es una plataforma dispositivo o un dispositivo estándar?" es más una cuestión de qué bus utiliza. Para trabajar con un dispositivo de plataforma en particular, tienes que:

  1. registre un controlador de plataforma que administrará este dispositivo. Debe definir un nombre único ,
  2. registre su dispositivo de plataforma , definiendo el mismo nombre que el controlador.

El controlador de plataforma es para aquellos dispositivos que están en chip.

No es cierto (en teoría, pero es cierto en la práctica). los dispositivos i2c no son OnChip, pero son dispositivos de plataforma porque no son detectables. También podemos pensar en dispositivos OnChip que son dispositivos normales . Ejemplo: un chip GPU PCI integrado en un procesador x86 moderno. Es detectable, por lo tanto no es un dispositivo de plataforma.

Los controladores de dispositivo normales son para aquellos que están interconectados con el chip del procesador. antes de venir a través de un controlador i2c.

No es cierto. Muchos dispositivos normales están interconectados al procesador, pero no a través de un bus i2c. Ejemplo: un ratón USB.

[EDITAR] En su caso, eche un vistazo a drivers/usb/host/ohci-pnx4008.c, que es un dispositivo de plataforma de controlador de host USB (Aquí el controlador de host USB no se puede descubrir, mientras que los dispositivos USB, que se conectarán a él, lo son). Es un dispositivo de plataforma registrado por el archivo de placa (arch/arm/mach-pnx4008/core.c:pnx4008_init). Y dentro de su función de sonda, registra su dispositivo i2c en el bus con i2c_register_driver. Podemos inferir que el chipset controlador Host USB habla con la CPU a través de un bus i2c.

¿Por qué esa arquitectura? Porque por un lado, este dispositivo puede considerarse un dispositivo i2c desnudo que proporciona algunas funcionalidades al sistema. Por otro lado, es un dispositivo capaz de host USB. Necesita registrarse en la pila USB (usb_create_hcd). Así que sondear solo i2c será insuficiente. Echa un vistazo a Documentation/i2c/instantiating-devices.

 74
Author: m-ric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-03 15:23:13

Ejemplos de código de módulo mínimo

Tal vez la diferencia también se haga más clara con algunos ejemplos concretos.

Ejemplo de dispositivo de plataforma

Código:

Notas adicionales de integración en: https://stackoverflow.com/a/44612957/895245

Ver cómo:

  • las direcciones de registro e interrupción se codifican en el árbol de dispositivos y coinciden con la descripción de la máquina QEMU -M versatilepb, que representa el SoC
  • no hay forma de eliminar el hardware del dispositivo (ya que es parte del SoC)
  • el controlador correcto es seleccionado por la propiedad compatible device tree que coincide con platform_driver.name en el controlador
  • platform_driver_register es el registro principal interfaz
#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 ejemplo de dispositivo sin plataforma

Ver cómo:

  • las direcciones de registro e interrupción son asignadas dinámicamente por el sistema PCI, no se utiliza ningún árbol de dispositivos
  • el controlador correcto es seleccionado por el ID PCI vendor:device (QEMU_VENDOR_ID, EDU_DEVICE_ID por ejemplo). Esto se cuece en todos los dispositivos, y los proveedores deben garantizar singularidad.
  • podemos insertar y quitar el dispositivo PCI con device_add edu y device_del edu como podemos en la vida real. El sondeo no es automático, pero se puede hacer después del arranque con echo 1 > /sys/bus/pci/rescan. Ver también: ¿Por qué se necesita el método probe en los controladores de dispositivos Linux además de 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);
 1
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-11 10:12:07