詳解platform_device_系列函數(頁(yè) 1) - 文檔專(zhuān)區 - 程序開(kāi)發(fā) - Linux論壇 - Powered by Discuz! Archiver
詳解platform_device_系列函數
platform_device_系列函數,實(shí)際上是注冊了一個(gè)叫platform的虛擬總線(xiàn)。使用約定是如果一個(gè)不屬于任何總線(xiàn)的設備,例如藍牙,串口等設備,都需要掛在這個(gè)虛擬總線(xiàn)上。
driver/base/platform.c
//platform設備聲明
struct device platform_bus = {
.bus_id = "platform",
};
EXPORT_SYMBOL_GPL(platform_bus);
//platform總線(xiàn)設備聲明
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.suspend = platform_suspend,
.suspend_late = platform_suspend_late,
.resume_early = platform_resume_early,
.resume = platform_resume,
};
EXPORT_SYMBOL_GPL(platform_bus_type);
int __init platform_bus_init(void)
{
int error;
error = device_register(&platform_bus);//注冊了"platform"的設備
if (error)
return error;
error = bus_register(&platform_bus_type);//注冊了叫"platform"的總線(xiàn)
if (error)
device_unregister(&platform_bus);
return error;
}
//這里在platform總線(xiàn)上掛設備
int platform_device_add(struct platform_device *pdev)
{
int i, ret = 0;
if (!pdev)
return -EINVAL;
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;//父設備設置為platform_bus
pdev->dev.bus = &platform_bus_type;//設置掛在platform總線(xiàn)上
if (pdev->id != -1)
snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
pdev->id);
else
strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
for (i = 0; i num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL)
r->name = pdev->dev.bus_id;
p = r->parent;
if (!p) {
if (r->flags & IORESOURCE_MEM)
p = &iomem_resource;
else if (r->flags & IORESOURCE_IO)
p = &ioport_resource;
}
if (p && insert_resource(p, r)) {
printk(KERN_ERR
"%s: failed to claim resource %d\n",
pdev->dev.bus_id, i);
ret = -EBUSY;
goto failed;
}
}
pr_debug("Registering platform device '%s'. Parent at %s\n",
pdev->dev.bus_id, pdev->dev.parent->bus_id);
ret = device_add(&pdev->dev);
if (ret == 0)
return ret;
failed:
while (--i >= 0)
if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))
release_resource(&pdev->resource[i]);
return ret;
}
EXPORT_SYMBOL_GPL(platform_device_add);
//常用的platform_device_register,內部調用了platform_device_add,將設備掛在了platform總線(xiàn)上
/**
* platform_device_register - add a platform-level device
* @pdev: platform device we're adding
*/
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_register);
要用注冊一個(gè)platform驅動(dòng)的步驟:1,注冊設備platform_device_register2,注冊驅動(dòng)platform_driver_register注冊時(shí)候的兩個(gè)名字必須一樣,才能match上,才能work,例如:
struct platform_device pxa3xx_device_nand = {
.name = "pxa3xx-nand",
.id = -1,
.dev = {
.dma_mask = &pxa3xx_nand_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.resource = pxa3xx_resource_nand,
.num_resources = ARRAY_SIZE(pxa3xx_resource_nand),
};
static struct platform_driver pxa3xx_nand_driver = {
.driver = {
.name = "pxa3xx-nand",
},
.probe = pxa3xx_nand_probe,
.remove = pxa3xx_nand_remove,
#ifdef CONFIG_PM
.suspend = pxa3xx_nand_suspend,
.resume = pxa3xx_nand_resume,
#endif
};
而且device注冊的時(shí)候,可以給driver傳參數
struct device {
struct klist klist_children;
struct klist_node knode_parent; /* node in sibling list */
struct klist_node knode_driver;
struct klist_node knode_bus;
struct device *parent;
struct kobject kobj;
char bus_id[BUS_ID_SIZE]; /* position on parent bus */
struct device_type *type;
unsigned is_registered:1;
unsigned uevent_suppress:1;
struct semaphore sem; /* semaphore to synchronize calls to
* its driver.
*/
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
void *driver_data; /* data private to the driver */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
struct dev_pm_info power;
#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
/* arch specific additions */
struct dev_archdata archdata;
spinlock_t devres_lock;
struct list_head devres_head;
/* class_device migration path */
struct list_head node;
struct class *class;
dev_t devt; /* dev_t, creates the sysfs "dev" */
struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
};
傳參數都是通過(guò)platform_data傳,所以定義為void * void *platform_data; /* Platform specific data, device
static struct pxa3xx_nand_platform_data XXX_nand_info = {
.parts = android_256m_v75_partitions,
.nr_parts = ARRAY_SIZE(android_256m_v75_partitions),
};
static void __init XXX_init_nand(void)
{
pxa3xx_device_nand.dev.platform_data = &XXX_nand_info;
platform_device_register(&pxa3xx_device_nand);
}
static int __init pxa3xx_nand_probe(struct platform_device *pdev)
{
struct pxa3xx_nand_platform_data *pdata;
struct nand_chip *this;
struct pxa3xx_nand_info *info;
struct resource *res;
struct clk *clk = NULL, *smc_clk = NULL;
int status = -1;
struct mtd_partition *parts;
unsigned int data_buf_len;
#ifdef CONFIG_MTD_NAND_PXA3xx_DMA
unsigned int buf_len;
#endif
int i, ret = 0;
#ifdef CONFIG_MTD_PARTITIONS
int err;
#endif
pdata = pdev->dev.platform_data;
....
....
....
}
下面解釋一下pxa_register_device函數
pxa_set_ohci_info(&XXX_ohci_info);
void __init pxa_set_ohci_info(struct pxaohci_platform_data *info)
{
pxa_register_device(&pxa27x_device_ohci, info);
}
void __init pxa_register_device(struct platform_device *dev, void *data)
{
int ret;
dev->dev.platform_data = data;
ret = platform_device_register(dev);
if (ret)
dev_err(&dev->dev, "unable to register device: %d\n", ret);
}
其實(shí)上,也就是給driver傳參數,通過(guò)dev.platform_data。
到這里,platform_device系列函數,基本算通了,系列函數還有一堆設置的函數,和device_register同級別的那些功能函數,用法基本差不多,只不過(guò)都將設備掛在了platform總線(xiàn)上。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請
點(diǎn)擊舉報。