In precedenza avevo pensato al driver di piattaforma e al normale driver di dispositivo come:
I normali driver di dispositivo sono per quelli che sono interfacciati con il chip proccesor. prima di imbattersi in un driver i2c.
Ma qui, sto leggendo attraverso il driver i2c multi funzione definito come driver di piattaforma. Ero passato attraverso https://www.kernel.org/doc/Documentation/driver-model/platform.txt . Tuttavia, non è ancora ansible avere una chiara idea di giungere a una conclusione su come definire i driver, come per i dispositivi onchip e per quelli interfacciati. Ho seguito anche questo link. Http://meld.org/discussion/general-discussion/platform-driver-vs-ordinary-device-drivers
Per favore qualcuno lo spieghi.
I tuoi riferimenti sono buoni ma mancano di una definizione di cosa sia un dispositivo di piattaforma . Ce n’è uno su LWN . Cosa possiamo imparare da questa pagina:
I dispositivi della piattaforma non sono intrinsecamente individuabili , ovvero l’hardware non può dire “Ehi, sono presente!” al software. Esempi tipici sono i dispositivi i2c, kernel/Documentation/i2c/instantiating-devices
stati dei kernel/Documentation/i2c/instantiating-devices
:
A differenza dei dispositivi PCI o USB, i dispositivi I2C non sono enumerati a livello hardware (in fase di esecuzione). Invece, il software deve sapere (al momento della compilazione) quali dispositivi sono connessi su ciascun segmento di bus I2C. Quindi USB e PCI non sono dispositivi di piattaforma.
I dispositivi della piattaforma sono associati ai driver mediante nomi corrispondenti ,
Quindi, in sostanza, la domanda ” è un dispositivo di piattaforma o un dispositivo standard? ” È più una questione di quale bus utilizza . Per lavorare con un particolare dispositivo con piattaforma, devi:
Il driver di piattaforma è per quei dispositivi che sono su chip.
Non vero (in teoria, ma vero nella pratica). I dispositivi i2c non sono onChip, ma sono dispositivi di piattaforma perché non sono rilevabili. Inoltre possiamo pensare ai dispositivi onChip che sono normali dispositivi. Esempio: un chip PCI GPU integrato su un moderno processore x86. È rilevabile, quindi non un dispositivo di piattaforma.
I normali driver di dispositivo sono per quelli che sono interfacciati al chip del processore. prima di imbattersi in un driver i2c.
Non vero. Molti dispositivi normali sono interfacciati al processore, ma non tramite un bus i2c. Esempio: un mouse USB.
[EDIT] Nel tuo caso, dai un’occhiata ai drivers/usb/host/ohci-pnx4008.c
, che è un dispositivo con piattaforma host controller USB (qui il controller host USB non è individuabile, mentre i dispositivi USB, che si collegheranno ad esso , siamo). È un dispositivo di piattaforma registrato dal file di bordo ( arch/arm/mach-pnx4008/core.c:pnx4008_init
). E all’interno della sua funzione probe, registra il suo dispositivo i2c sul bus con i2c_register_driver
. Possiamo dedurre che il chipset del controller Host USB comunica con la CPU tramite un bus i2c.
Perché quell’architettura? Perché da un lato questo dispositivo può essere considerato un dispositivo i2c spoglio che fornisce alcune funzionalità al sistema. D’altra parte, è un dispositivo capace di ospitare USB. È necessario registrarsi allo stack USB ( usb_create_hcd
). Quindi sondare solo i2c sarà insufficiente. Documentation/i2c/instantiating-devices
un’occhiata a Documentation/i2c/instantiating-devices
.
Esempi di codice del modulo minimo
Forse la differenza diventerà anche più chiara con alcuni esempi concreti.
Esempio di dispositivo platform
Codice:
Ulteriori note di integrazione su: https://stackoverflow.com/a/44612957/895245
Vedi come:
-M versatilepb
QEMU -M versatilepb
, che rappresenta il SoC compatible
che corrisponde a platform_driver.name
nel driver platform_driver_register
è l’interfaccia di registro principale #include #include #include #include #include #include #include #include #include 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)
Esempio di dispositivo PCI non su piattaforma
Vedi come:
vendor:device
PCI vendor:device
ID vendor:device
( QEMU_VENDOR_ID, EDU_DEVICE_ID
sull’esempio). Questo viene inserito in ogni dispositivo e i fornitori devono garantire l’unicità. device_add edu
e device_del edu
come possiamo nella vita reale. L’analisi non è automatica, ma può essere eseguita dopo l’avvio con echo 1 > /sys/bus/pci/rescan
. Vedi anche: Perché il metodo probe è necessario nei driver di dispositivo Linux oltre a init? #include #include #include #include #include #include #include #include #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);