sirven - que es un driver en computacion
¿Cuál es la diferencia entre un controlador de plataforma Linux y un controlador de dispositivo normal? (2)
Anteriormente pensé en el controlador de la plataforma y en el controlador de dispositivo normal como:
- El controlador de la plataforma es para aquellos dispositivos que están en el chip. y,
El controlador de dispositivo normal es para aquellos que están interconectados con el chip del procesador. Antes de encontrar un controlador i2c.
Pero aquí, estoy leyendo a través del controlador i2c multifunción definido como controlador de plataforma. Había pasado por https://www.kernel.org/doc/Documentation/driver-model/platform.txt . Pero todavía no se pudo obtener una idea clara para llegar a una conclusión sobre cómo definir los controladores, como para los dispositivos con interfaz tanto como con el chip. También visité este enlace ... http://meld.org/discussion/general-discussion/platform-driver-vs-ordinary-device-drivers
Por favor alguien explique.
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:
Los dispositivos de plataforma son intrínsecamente no detectables , es decir, el hardware no puede decir "¡Hola! ¡Estoy presente!" al software. Los ejemplos típicos son dispositivos i2c,
kernel/Documentation/i2c/instantiating-devices
estados:A diferencia de los dispositivos PCI o USB, los dispositivos I2C no se enumeran en el 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 no son dispositivos de plataforma.
Los dispositivos de plataforma están vinculados a los controladores por nombres coincidentes ,
- Los dispositivos de plataforma se deben registrar muy temprano durante el inicio del sistema. Porque a menudo son críticos para el resto del sistema (plataforma) y sus controladores.
Entonces, básicamente, la pregunta "¿ es un dispositivo de plataforma o un dispositivo estándar? " Es más bien una cuestión de qué bus utiliza . Para trabajar con un dispositivo de plataforma particular, tienes que:
- Registre un controlador de plataforma que gestione este dispositivo. Debe definir un nombre único ,
- Registre su dispositivo de plataforma , definiendo el mismo nombre que el controlador.
El controlador de la plataforma es para aquellos dispositivos que están en el chip.
No es cierto (en teoría, pero sí en la práctica). Los dispositivos i2c no están enChip, pero son dispositivos de plataforma porque no son detectables. También podemos pensar en los dispositivos onChip que son dispositivos normales . Ejemplo: un chip PCI GPU integrado en un moderno procesador x86. Es detectable, por lo tanto no es un dispositivo de plataforma.
Los controladores de dispositivos normales son para aquellos que están conectados al chip del procesador. Antes de encontrar un controlador i2c.
No es verdad. Muchos dispositivos normales están conectados 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 es drivers/usb/host/ohci-pnx4008.c
, mientras que los dispositivos USB, que se conectarán , 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 conjunto de chips del controlador host USB se comunica con la CPU a través de un bus i2c.
¿Por qué esa arquitectura? Debido a que, 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. Debe registrarse en la pila USB ( usb_create_hcd
). Por lo tanto, probar solo i2c será insuficiente. Eche un vistazo a Documentation/i2c/instantiating-devices
.
Ejemplos de código de módulo mínimo
Quizás la diferencia también se aclare con algunos ejemplos concretos.
Ejemplo de dispositivo de plataforma
Código:
- conductor aguas arriba
- Dispositivo virtual QEMU mínimo accionado .
- Modificaciones de entrada DTS en el kernel de Linux
Otras notas de integración en: https://.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 la descripción de la máquina QEMU
-M versatilepb
, que representa el SoC - no hay manera de eliminar el hardware del dispositivo (ya que es parte del SoC)
- el controlador correcto es seleccionado por la propiedad de árbol de dispositivo
compatible
que coincide conplatform_driver.name
en el controlador -
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 no plataforma PCI
Ver cómo:
- el sistema PCI asigna dinámicamente las direcciones de registro e interrupción, no se utiliza ningún árbol de dispositivos
- el
vendor:device
PCI selecciona el controlador correctovendor:device
ID devendor:device
(QEMU_VENDOR_ID, EDU_DEVICE_ID
en el ejemplo). Esto se incluye en todos los dispositivos, y los proveedores deben garantizar la singularidad. - Podemos insertar y eliminar el dispositivo PCI con
device_add edu
ydevice_del edu
como podamos en la vida real. El sondeo no es automático, pero se puede hacer después del arranque conecho 1 > /sys/bus/pci/rescan
. Vea también: ¿Por qué es necesario el método de la sonda 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);