當flag為IORESOURCE_MEM時,start、end表示platform device使用的記憶體開始位址和結束位址‧
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
當flag為IORESOURCE_IRQ時,start、end表示platform device使用的中斷號的開始值和結束值‧
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
2. include/linux/ioport.h
/* * Resources are tree-like, allowing * nesting etc.. */ struct resource { resource_size_t start; resource_size_t end; const char *name; unsigned long flags; struct resource *parent, *sibling, *child; }; /* * IO resources have these defined flags. */ #define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ #define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */ #define IORESOURCE_IO 0x00000100 /* PCI/ISA I/O ports */ #define IORESOURCE_MEM 0x00000200 #define IORESOURCE_REG 0x00000300 /* Register offsets */ #define IORESOURCE_IRQ 0x00000400 #define IORESOURCE_DMA 0x00000800 #define IORESOURCE_BUS 0x00001000 #define IORESOURCE_PREFETCH 0x00002000 /* No side effects */ #define IORESOURCE_READONLY 0x00004000 #define IORESOURCE_CACHEABLE 0x00008000 #define IORESOURCE_RANGELENGTH 0x00010000 #define IORESOURCE_SHADOWABLE 0x00020000 #define IORESOURCE_SIZEALIGN 0x00040000 /* size indicates alignment */ #define IORESOURCE_STARTALIGN 0x00080000 /* start field is alignment */ #define IORESOURCE_MEM_64 0x00100000 #define IORESOURCE_WINDOW 0x00200000 /* forwarded by bridge */ #define IORESOURCE_MUXED 0x00400000 /* Resource is software muxed */ #define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */ #define IORESOURCE_DISABLED 0x10000000 #define IORESOURCE_UNSET 0x20000000 /* No address assigned yet */ #define IORESOURCE_AUTO 0x40000000 #define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */3. 當resouce中定義了兩個以上的記憶體空間和一個中斷號資源
/* device tree 定義方式 */ test: test@09100000 { compatible = "uio"; reg = <0x09100000 0x10000>, <0x09200000 0x10000>; interrupts = <0 29 0x4>; }; /* 結構定義方式 */ static struct resource cns3xxx_usb_ehci_resources[] = { [0] = { .start = CNS3XXX_USB0_BASE, .end = CNS3XXX_USB0_BASE + SZ_16M - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = CNS3XXX_USB1_BASE, .end = CNS3XXX_USB1_BASE + SZ_16M - 1, .flags = IORESOURCE_MEM, }, [2] = { .start = IRQ_CNS3XXX_USB_EHCI, .flags = IORESOURCE_IRQ, }, };可透過platform_get_resouice第三個參數指定index
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 1); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);4. 在使用IRQ資源,platform_get_irq封裝了platform_get_resource,也可以使用platform_get_irq(struct platform_device *dev, unsigned int num);去取得中斷號資源,
drivers/base/platform.c
/** * platform_get_resource - get a resource for a device * @dev: platform device * @type: resource type * @num: resource index */ struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num) { int i; for (i = 0; i < dev->num_resources; i++) { struct resource *r = &dev->resource[i]; if (type == resource_type(r) && num-- == 0) return r; } return NULL; } EXPORT_SYMBOL_GPL(platform_get_resource); /** * platform_get_irq - get an IRQ for a device * @dev: platform device * @num: IRQ number index */ int platform_get_irq(struct platform_device *dev, unsigned int num) { #ifdef CONFIG_SPARC /* sparc does not have irqs represented as IORESOURCE_IRQ resources */ if (!dev || num >= dev->archdata.num_irqs) return -ENXIO; return dev->archdata.irqs[num]; #else struct resource *r; if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { int ret; ret = of_irq_get(dev->dev.of_node, num); if (ret >= 0 || ret == -EPROBE_DEFER) return ret; } r = platform_get_resource(dev, IORESOURCE_IRQ, num); /* * The resources may pass trigger flags to the irqs that need * to be set up. It so happens that the trigger flags for * IORESOURCE_BITS correspond 1-to-1 to the IRQF_TRIGGER* * settings. */ if (r && r->flags & IORESOURCE_BITS) irqd_set_trigger_type(irq_get_irq_data(r->start), r->flags & IORESOURCE_BITS); return r ? r->start : -ENXIO; #endif }5. 範例
#include <linux/module.h> #include <linux/kernel.h> #include <linux/platform_device.h> struct sample_timer { void __iomem *base; void __iomem *memory; int irq; }; static int sample_probe(struct platform_device *pdev) { struct resource *base_res, *memory_res; static struct sample_timer *timer; pr_alert("%s\n", __FUNCTION__); timer = devm_kzalloc(&pdev->dev, sizeof(struct sample_timer), GFP_KERNEL); if (NULL == timer) { dev_err(&pdev->dev, "cannot allocate memory\n"); return -ENOMEM; } base_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (NULL == base_res) { dev_err(&pdev->dev, "cannot get IORESOUCE_MEM\n"); return -ENOENT; } memory_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (NULL == memory_res) { dev_err(&pdev->dev, "cannot get IORESOUCE_MEM\n"); return -ENOENT; } timer->base = devm_ioremap_resource(&pdev->dev, base_res); timer->memory = devm_ioremap_resource(&pdev->dev, memory_res); if ((IS_ERR((const void *)(timer->base))) || (IS_ERR((const void *)(timer->memory)))) { dev_err(&pdev->dev, "cannot get ioremap\n"); return -ENOENT; } timer->irq = platform_get_irq(pdev, 0); if (timer->irq < 0) { dev_err(&pdev->dev, "no irq specified\n"); return -ENOENT; } return 0; } static int sample_remove(struct platform_device *pdev) { return 0; } #define sample_suspend NULL #define sample_resume NULL static const struct of_device_id sample_dt_ids[] = { {.compatible = "sample,timer",}, { } }; MODULE_DEVICE_TABLE(of, sample_dt_ids); static struct platform_driver sample_driver = { .probe = sample_probe, .remove = sample_remove, .suspend = sample_suspend, .resume = sample_resume, .driver = { .name = "sample", .owner = THIS_MODULE, .of_match_table = sample_dt_ids, }, }; static int __init sample_init(void) { int ret; ret = platform_driver_register(&sample_driver); return ret; } static void __exit sample_exit(void) { platform_driver_unregister(&sample_driver); } module_init(sample_init); module_exit(sample_exit); MODULE_AUTHOR("Allen"); MODULE_DESCRIPTION("sample"); MODULE_LICENSE("GPL");6. 參考來源
platform设备驱动全透析 http://www.bianceng.cn/OS/Linux/201301/34910_3.htm