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

11 minutos de lectura

avatar de usuario
kzs

Antes había asumido que:

  • El controlador de plataforma es para aquellos dispositivos que están en chip.
  • Los controladores de dispositivos normales son para aquellos que están interconectados con el chip del procesador.

Antes de encontrarme con un controlador i2c… Pero aquí, estoy leyendo el controlador i2c multifunción definido como controlador de plataforma. yo había pasado https://www.kernel.org/doc/Documentation/driver-model/platform.txt. Pero todavía no pude tener una idea clara para llegar a una conclusión sobre cómo definir los controladores, tanto para dispositivos en chip como para dispositivos con interfaz.

Por favor alguien explique.

  • El dispositivo es un dispositivo multifunción MFD. hay un campo en platform_device; struct mfd cell que no está ahí en i2c_client estructura. Tal vez por eso el controlador está registrado como controlador de plataforma. Por favor comenta sobre esto.!!

    – kzs

    28 de marzo de 2013 a las 8:21

  • atmel.com/Images/doc32098.pdf ….. echa un vistazo a esto … podría ayudar

    -Kinjal Patel

    28 de marzo de 2013 a las 9:56

  • Sí, el documento era bueno… Creo que podría hacer uso de ese documento más adelante. pero no pude llegar a una conclusión todavía. Le he preguntado a un maestro que es bueno para los conductores. Publicaré aquí una vez que obtenga las respuestas.

    – kzs

    29 de marzo de 2013 a las 9:33

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

    – Jeyaram

    23 de mayo de 2014 a las 4:14

avatar de usuario
m-ric

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 plataforma son inherentemente no detectablees decir, el hardware no puede decir “¡Oye! ¡Estoy presente!” al software. Los 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. Entonces USB y PCI son no dispositivos de la plataforma.

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

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

Básicamente, la pregunta “¿Es un dispositivo de plataforma o un dispositivo estándar?” es más una cuestión de qué bus usa. Para trabajar con un dispositivo de plataforma en particular, debe:

  1. registrar un controlador de plataforma que administrará este dispositivo. Debe definir un único nombre,
  2. registre su dispositivo de plataformadefiniendo 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 se pueden detectar. También podemos pensar en dispositivos onChip que son normal dispositivos. Ejemplo: un chip PCI GPU integrado en un procesador x86 moderno. Es detectable, por lo tanto, no es un dispositivo de plataforma.

Los controladores de dispositivos normales son para aquellos que están interconectados con el chip del procesador. antes de encontrar un controlador i2c.

No es verdad. Muchos normal los dispositivos están conectados al procesador, pero no a través de un bus i2c. Ejemplo: un ratón USB.

[EDIT] En tu caso, echa 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 detectar, mientras que los dispositivos USB, que se conectarán a él, sí). Es un dispositivo de plataforma registrado por el archivo del tablero (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 conjunto de chips del controlador USB Host 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 simple que proporciona algunas funcionalidades al sistema. Por otro lado, es un dispositivo compatible con USB Host. Necesita registrarse en la pila USB (usb_create_hcd). Por lo tanto, probar solo i2c será insuficiente. echa un vistazo a Documentation/i2c/instantiating-devices.

  • Exacto tienes razón. Daría +1 por esto: Básicamente, la pregunta “¿es un dispositivo de plataforma o un dispositivo estándar?” es más una cuestión de qué bus usa. Podría conseguir y estar de acuerdo con todos los puntos. pero no pude entender o relacionar este: el controlador de dispositivo normal es para aquellos que están conectados al chip del procesador. antes de encontrar un controlador i2c. Por favor explícame en una mejor dimensión para que pueda hacerme entender.

    – kzs

    3 de abril de 2013 a las 6:23

  • Veo pocos controladores que usan i2c_driver_register y en este caso de i2c veo platform_driver_register. Tengo una duda de cuál usar entre los dos.

    – kzs

    3 de abril de 2013 a las 7:30

  • @zair en el EDITAR sección de mi respuesta, platform_driver_register registra el controlador USB Host contra la pila USB, mientras que i2c_driver_register se utiliza para permitir que la CPU negociaciones al controlador de host USB, a través del protocolo i2c. Si el controlador USB fuera compatible con SPI, habría un platform_driver_register y spi_register_driver en lugar de.

    – m-ric

    11 de abril de 2013 a las 14:46

  • Excelente.. muy claro. gracias por esforzarte en explicarme mejor… daría +1.

    – kzs

    12 de abril de 2013 a las 6:36

  • tengo una duda mas. Tengo la noción de que “Todos los buses que no tienen una propiedad detectable como la línea de identificación se basarán en el marco de bus de la plataforma”, por ejemplo. I2C solo tiene reloj y datos, por lo que se basa en el bus de la plataforma. ¿Es esto cierto y, en caso afirmativo, puede nombrar algún otro bus que se base en la arquitectura de la plataforma?

    – shingaridavesh

    2 mayo 2013 a las 9:50

avatar de usuario
Ciro Santilli Путлер Капут 六四事

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

Tal vez la diferencia también se aclare con algunos ejemplos concretos.

Ejemplo de dispositivo de plataforma

Código:

Más notas de integración en: https://stackoverflow.com/a/44612957/895245

Ver cómo:

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

Ejemplo de dispositivo sin plataforma PCI

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 PCI vendor:device IDENTIFICACIÓN (QEMU_VENDOR_ID, EDU_DEVICE_ID en el ejemplo). Esto está integrado en todos los dispositivos y los proveedores deben garantizar la exclusividad.
  • 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 realizar después del arranque con echo 1 > /sys/bus/pci/rescan. Consulte también: ¿Por qué se necesita el método de sondeo en los controladores de dispositivos de 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);

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad