2012-06-20 08:42:16 +02:00
|
|
|
/*
|
|
|
|
* \brief Linux platform_device emulation
|
|
|
|
* \author Sebastian Sumpf
|
|
|
|
* \date 2012-06-18
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2012-2013 Genode Labs GmbH
|
2012-06-20 08:42:16 +02:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
2017-01-30 11:35:12 +01:00
|
|
|
#include <base/attached_io_mem_dataspace.h>
|
2012-06-20 08:42:16 +02:00
|
|
|
#include <lx_emul.h>
|
2015-05-12 15:16:19 +02:00
|
|
|
|
2016-06-21 12:59:11 +02:00
|
|
|
#include <lx_kit/malloc.h>
|
2012-06-20 08:42:16 +02:00
|
|
|
|
|
|
|
#define to_platform_driver(drv) (container_of((drv), struct platform_driver, \
|
|
|
|
driver))
|
|
|
|
|
|
|
|
static int platform_match(struct device *dev, struct device_driver *drv)
|
|
|
|
{
|
|
|
|
if (!dev->name)
|
|
|
|
return 0;
|
|
|
|
|
2014-06-02 13:50:17 +02:00
|
|
|
|
|
|
|
printk("MATCH %s %s\n", dev->name, drv->name);
|
2012-06-20 08:42:16 +02:00
|
|
|
return (strcmp(dev->name, drv->name) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int platform_drv_probe(struct device *_dev)
|
|
|
|
{
|
|
|
|
struct platform_driver *drv = to_platform_driver(_dev->driver);
|
|
|
|
struct platform_device *dev = to_platform_device(_dev);
|
|
|
|
|
|
|
|
return drv->probe(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct bus_type platform_bus_type = {
|
|
|
|
.name = "platform",
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int platform_driver_register(struct platform_driver *drv)
|
|
|
|
{
|
2015-05-12 15:16:19 +02:00
|
|
|
/* init plarform_bus_type */
|
|
|
|
platform_bus_type.match = platform_match;
|
|
|
|
platform_bus_type.probe = platform_drv_probe;
|
|
|
|
|
2012-06-20 08:42:16 +02:00
|
|
|
drv->driver.bus = &platform_bus_type;
|
|
|
|
if (drv->probe)
|
|
|
|
drv->driver.probe = platform_drv_probe;
|
|
|
|
|
2014-06-02 13:50:17 +02:00
|
|
|
printk("Register: %s\n", drv->driver.name);
|
2012-06-20 08:42:16 +02:00
|
|
|
return driver_register(&drv->driver);
|
|
|
|
}
|
|
|
|
|
2013-05-16 12:17:03 +02:00
|
|
|
|
2013-02-20 12:06:16 +01:00
|
|
|
struct resource *platform_get_resource(struct platform_device *dev,
|
|
|
|
unsigned int type, unsigned int num)
|
|
|
|
{
|
2015-05-12 15:16:19 +02:00
|
|
|
unsigned i;
|
2013-02-20 12:06:16 +01:00
|
|
|
|
|
|
|
for (i = 0; i < dev->num_resources; i++) {
|
|
|
|
struct resource *r = &dev->resource[i];
|
|
|
|
|
|
|
|
if ((type & r->flags) && num-- == 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-06-20 08:42:16 +02:00
|
|
|
|
2013-05-16 12:17:03 +02:00
|
|
|
|
2012-06-20 08:42:16 +02:00
|
|
|
struct resource *platform_get_resource_byname(struct platform_device *dev,
|
|
|
|
unsigned int type,
|
|
|
|
const char *name)
|
|
|
|
{
|
2015-05-12 15:16:19 +02:00
|
|
|
unsigned i;
|
2012-06-20 08:42:16 +02:00
|
|
|
|
|
|
|
for (i = 0; i < dev->num_resources; i++) {
|
|
|
|
struct resource *r = &dev->resource[i];
|
|
|
|
|
|
|
|
if (type == r->flags && !strcmp(r->name, name))
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int platform_get_irq_byname(struct platform_device *dev, const char *name)
|
|
|
|
{
|
|
|
|
struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
|
|
|
|
return r ? r->start : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-02-20 12:06:16 +01:00
|
|
|
int platform_get_irq(struct platform_device *dev, unsigned int num)
|
|
|
|
{
|
|
|
|
struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, 0);
|
|
|
|
return r ? r->start : -1;
|
|
|
|
}
|
|
|
|
|
2013-05-16 12:17:03 +02:00
|
|
|
|
2012-06-20 08:42:16 +02:00
|
|
|
int platform_device_register(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
pdev->dev.bus = &platform_bus_type;
|
|
|
|
pdev->dev.name = pdev->name;
|
2014-06-02 13:50:17 +02:00
|
|
|
/*Set parent to ourselfs */
|
2013-05-16 12:17:03 +02:00
|
|
|
if (!pdev->dev.parent)
|
2014-06-02 13:50:17 +02:00
|
|
|
pdev->dev.parent = &pdev->dev;
|
2012-06-20 08:42:16 +02:00
|
|
|
device_add(&pdev->dev);
|
|
|
|
return 0;
|
|
|
|
}
|
2013-05-16 12:17:03 +02:00
|
|
|
|
|
|
|
|
|
|
|
struct platform_device *platform_device_alloc(const char *name, int id)
|
|
|
|
{
|
2015-05-12 15:16:19 +02:00
|
|
|
platform_device *pdev = (platform_device *)kzalloc(sizeof(struct platform_device), GFP_KERNEL);
|
2013-05-16 12:17:03 +02:00
|
|
|
|
|
|
|
if (!pdev)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int len = strlen(name);
|
2015-05-12 15:16:19 +02:00
|
|
|
pdev->name = (char *)kzalloc(len + 1, GFP_KERNEL);
|
2013-05-16 12:17:03 +02:00
|
|
|
|
|
|
|
if (!pdev->name) {
|
|
|
|
kfree(pdev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(pdev->name, name, len);
|
|
|
|
pdev->name[len] = 0;
|
|
|
|
pdev->id = id;
|
|
|
|
|
|
|
|
return pdev;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int platform_device_add_data(struct platform_device *pdev, const void *data,
|
|
|
|
size_t size)
|
|
|
|
{
|
|
|
|
void *d = NULL;
|
|
|
|
|
|
|
|
if (data && !(d = kmemdup(data, size, GFP_KERNEL)))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
kfree(pdev->dev.platform_data);
|
|
|
|
pdev->dev.platform_data = d;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int platform_device_add(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
return platform_device_register(pdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
int platform_device_add_resources(struct platform_device *pdev,
|
|
|
|
const struct resource *res, unsigned int num)
|
|
|
|
{
|
|
|
|
struct resource *r = NULL;
|
|
|
|
|
|
|
|
if (res) {
|
2015-05-12 15:16:19 +02:00
|
|
|
r = (resource *)kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);
|
2013-05-16 12:17:03 +02:00
|
|
|
if (!r)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(pdev->resource);
|
|
|
|
pdev->resource = r;
|
|
|
|
pdev->num_resources = num;
|
|
|
|
return 0;
|
|
|
|
}
|
2014-06-02 13:50:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
void *platform_get_drvdata(const struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
return dev_get_drvdata(&pdev->dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void platform_set_drvdata(struct platform_device *pdev, void *data)
|
|
|
|
{
|
|
|
|
dev_set_drvdata(&pdev->dev, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-13 14:29:00 +02:00
|
|
|
/**********************
|
|
|
|
** asm-generic/io.h **
|
|
|
|
**********************/
|
|
|
|
|
2016-05-18 18:51:11 +02:00
|
|
|
void *_ioremap(phys_addr_t phys_addr, unsigned long size, int wc)
|
2015-04-13 14:29:00 +02:00
|
|
|
{
|
2015-05-12 15:16:19 +02:00
|
|
|
try {
|
2016-06-21 12:59:11 +02:00
|
|
|
Genode::Attached_io_mem_dataspace *ds = new(Lx::Malloc::mem())
|
2015-05-12 15:16:19 +02:00
|
|
|
Genode::Attached_io_mem_dataspace(phys_addr, size, !!wc);
|
2015-09-08 20:43:39 +02:00
|
|
|
return ds->local_addr<void>();
|
2015-05-12 15:16:19 +02:00
|
|
|
} catch (...) {
|
2016-05-18 18:51:11 +02:00
|
|
|
panic("Failed to request I/O memory: [%lx,%lx)", phys_addr, phys_addr + size);
|
2015-04-13 14:29:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-18 18:51:11 +02:00
|
|
|
void *ioremap(phys_addr_t offset, unsigned long size)
|
2015-04-13 14:29:00 +02:00
|
|
|
{
|
|
|
|
return _ioremap(offset, size, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void *devm_ioremap(struct device *dev, resource_size_t offset,
|
|
|
|
unsigned long size)
|
|
|
|
{
|
|
|
|
return _ioremap(offset, size, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void *devm_ioremap_nocache(struct device *dev, resource_size_t offset,
|
|
|
|
unsigned long size)
|
|
|
|
{
|
|
|
|
return _ioremap(offset, size, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void *devm_ioremap_resource(struct device *dev, struct resource *res)
|
|
|
|
{
|
|
|
|
return _ioremap(res->start, res->end - res->start, 0);
|
|
|
|
}
|