diff options
author | Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> | 2011-07-21 13:44:04 +0800 |
---|---|---|
committer | Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> | 2011-07-21 13:44:04 +0800 |
commit | 85283965dc0977496d2159cbe7f25ac3d96187dd (patch) | |
tree | d7b5f5ec14232f0c18dabb824c5e0bbc993db4ee /drivers | |
parent | 522af7074a333508d8b73c25abd1d051d8672e5c (diff) | |
download | barebox-85283965dc0977496d2159cbe7f25ac3d96187dd.tar.gz barebox-85283965dc0977496d2159cbe7f25ac3d96187dd.tar.xz |
drivers/bus: move to drivers/base
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/base/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/driver.c | 418 | ||||
-rw-r--r-- | drivers/base/platform.c | 58 |
4 files changed, 479 insertions, 0 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 92b22bdaa9..16b3bb129f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -1,3 +1,4 @@ +obj-y += base/ obj-y += net/ obj-y += serial/ obj-y += mtd/ diff --git a/drivers/base/Makefile b/drivers/base/Makefile new file mode 100644 index 0000000000..2d94723f90 --- /dev/null +++ b/drivers/base/Makefile @@ -0,0 +1,2 @@ +obj-y += driver.o +obj-y += platform.o diff --git a/drivers/base/driver.c b/drivers/base/driver.c new file mode 100644 index 0000000000..b5166c82ef --- /dev/null +++ b/drivers/base/driver.c @@ -0,0 +1,418 @@ +/* + * driver.c - barebox driver model + * + * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @file + * @brief barebox's driver model, and devinfo command + */ + +#include <common.h> +#include <command.h> +#include <driver.h> +#include <malloc.h> +#include <linux/ctype.h> +#include <errno.h> +#include <fs.h> +#include <linux/list.h> + +LIST_HEAD(device_list); +EXPORT_SYMBOL(device_list); + +LIST_HEAD(driver_list); +EXPORT_SYMBOL(driver_list); + +static LIST_HEAD(active); + +struct device_d *get_device_by_name(const char *name) +{ + struct device_d *dev; + + for_each_device(dev) { + if(!strcmp(dev_name(dev), name)) + return dev; + } + + return NULL; +} + +static struct device_d *get_device_by_name_id(const char *name, int id) +{ + struct device_d *dev; + + for_each_device(dev) { + if(!strcmp(dev->name, name) && id == dev->id) + return dev; + } + + return NULL; +} + +int get_free_deviceid(const char *name_template) +{ + int i = 0; + + while (1) { + if (!get_device_by_name_id(name_template, i)) + return i; + i++; + }; +} + +static int match(struct driver_d *drv, struct device_d *dev) +{ + if (dev->driver) + return -1; + + dev->driver = drv; + + if (dev->bus != drv->bus) + goto err_out; + if (dev->bus->match(dev, drv)) + goto err_out; + if (dev->bus->probe(dev)) + goto err_out; + + list_add(&dev->active, &active); + + return 0; +err_out: + dev->driver = NULL; + return -1; +} + +int register_device(struct device_d *new_device) +{ + struct driver_d *drv; + + /* if no map_base available use the first resource if available + * so we do not need to duplicate it + * Temporary fixup until we get rid of map_base and size + */ + if (new_device->map_base) { + if (new_device->resource) { + dev_err(new_device, "map_base and resource specifed\n"); + return -EIO; + } + dev_warn(new_device, "uses map_base. Please convert to use resources\n"); + new_device->resource = xzalloc(sizeof(struct resource)); + new_device->resource[0].start = new_device->map_base; + new_device->resource[0].size = new_device->size; + new_device->resource[0].flags = IORESOURCE_MEM; + new_device->num_resources = 1; + } else if (new_device->resource) { + new_device->map_base = new_device->resource[0].start; + new_device->size = new_device->resource[0].size; + } + + if (new_device->id < 0) { + new_device->id = get_free_deviceid(new_device->name); + } else { + if (get_device_by_name_id(new_device->name, new_device->id)) { + eprintf("register_device: already registered %s\n", + dev_name(new_device)); + return -EINVAL; + } + } + + debug ("register_device: %s\n", dev_name(new_device)); + + if (!new_device->bus) { +// dev_err(new_device, "no bus type associated. Needs fixup\n"); + new_device->bus = &platform_bus; + } + + list_add_tail(&new_device->list, &device_list); + INIT_LIST_HEAD(&new_device->children); + INIT_LIST_HEAD(&new_device->cdevs); + INIT_LIST_HEAD(&new_device->parameters); + + for_each_driver(drv) { + if (!match(drv, new_device)) + break; + } + + return 0; +} +EXPORT_SYMBOL(register_device); + +int unregister_device(struct device_d *old_dev) +{ + debug("unregister_device: %s\n", dev_name(old_dev)); + + if (!list_empty(&old_dev->children)) { + errno = -EBUSY; + return errno; + } + + if (old_dev->driver) + old_dev->bus->remove(old_dev); + + list_del(&old_dev->list); + list_del(&old_dev->active); + + /* remove device from parents child list */ + if (old_dev->parent) + list_del(&old_dev->sibling); + + return 0; +} +EXPORT_SYMBOL(unregister_device); + +int dev_add_child(struct device_d *dev, struct device_d *child) +{ + child->parent = dev; + + list_add_tail(&child->sibling, &dev->children); + + return 0; +} +EXPORT_SYMBOL(dev_add_child); + +struct driver_d *get_driver_by_name(const char *name) +{ + struct driver_d *drv; + + for_each_driver(drv) { + if(!strcmp(name, drv->name)) + return drv; + } + + return NULL; +} + +static void noinfo(struct device_d *dev) +{ + printf("no info available for %s\n", dev_name(dev)); +} + +static void noshortinfo(struct device_d *dev) +{ +} + +int register_driver(struct driver_d *drv) +{ + struct device_d *dev = NULL; + + debug("register_driver: %s\n", drv->name); + + if (!drv->bus) { +// pr_err("driver %s has no bus type associated. Needs fixup\n", drv->name); + drv->bus = &platform_bus; + } + + list_add_tail(&drv->list, &driver_list); + + if (!drv->info) + drv->info = noinfo; + if (!drv->shortinfo) + drv->shortinfo = noshortinfo; + + for_each_device(dev) + match(drv, dev); + + return 0; +} +EXPORT_SYMBOL(register_driver); + +void __iomem *dev_get_mem_region(struct device_d *dev, int num) +{ + int i, n = 0; + + for (i = 0; i < dev->num_resources; i++) { + struct resource *res = &dev->resource[i]; + if (resource_type(res) == IORESOURCE_MEM) { + if (n == num) + return (void __force __iomem *)res->start; + n++; + } + } + + return NULL; +} +EXPORT_SYMBOL(dev_get_mem_region); + +int dev_protect(struct device_d *dev, size_t count, unsigned long offset, int prot) +{ + printf("%s: currently broken\n", __func__); + return -EINVAL; +} + +int generic_memmap_ro(struct cdev *cdev, void **map, int flags) +{ + if (!cdev->dev) + return -EINVAL; + + if (flags & PROT_WRITE) + return -EACCES; + *map = (void *)cdev->dev->map_base; + return 0; +} + +int generic_memmap_rw(struct cdev *cdev, void **map, int flags) +{ + if (!cdev->dev) + return -EINVAL; + + *map = (void *)cdev->dev->map_base; + return 0; +} + +int dummy_probe(struct device_d *dev) +{ + return 0; +} +EXPORT_SYMBOL(dummy_probe); + +const char *dev_id(const struct device_d *dev) +{ + static char buf[sizeof(unsigned long) * 2]; + + sprintf(buf, FORMAT_DRIVER_MANE_ID, dev->name, dev->id); + + return buf; +} + +void devices_shutdown(void) +{ + struct device_d *dev; + + list_for_each_entry(dev, &active, active) { + if (dev->driver->remove) + dev->driver->remove(dev); + } +} + +#ifdef CONFIG_CMD_DEVINFO +static int do_devinfo_subtree(struct device_d *dev, int depth, char edge) +{ + struct device_d *child; + struct cdev *cdev; + int i; + + for (i = 0; i < depth; i++) + printf("| "); + + printf("%c----%s", edge, dev_name(dev)); + if (!list_empty(&dev->cdevs)) { + printf(" ("); + list_for_each_entry(cdev, &dev->cdevs, devices_list) { + printf("%s", cdev->name); + if (!list_is_last(&cdev->devices_list, &dev->cdevs)) + printf(", "); + } + printf(")"); + } + printf("\n"); + + if (!list_empty(&dev->children)) { + device_for_each_child(dev, child) { + do_devinfo_subtree(child, depth + 1, + list_is_last(&child->sibling, + &dev->children) ? '`' : '|'); + } + } + + return 0; +} + +static int do_devinfo(struct command *cmdtp, int argc, char *argv[]) +{ + struct device_d *dev; + struct driver_d *drv; + struct param_d *param; + + if (argc == 1) { + printf("devices:\n"); + + for_each_device(dev) { + if (!dev->parent) + do_devinfo_subtree(dev, 0, '|'); + } + + printf("\ndrivers:\n"); + for_each_driver(drv) + printf("%10s\n",drv->name); + } else { + dev = get_device_by_name(argv[1]); + + if (!dev) { + printf("no such device: %s\n",argv[1]); + return -1; + } + + printf("base : 0x%08x\nsize : 0x%08x\ndriver: %s\n\n", + dev->map_base, dev->size, + dev->driver ? + dev->driver->name : "none"); + + if (dev->driver) + dev->driver->info(dev); + + printf("%s\n", list_empty(&dev->parameters) ? + "no parameters available" : "Parameters:"); + + list_for_each_entry(param, &dev->parameters, list) + printf("%16s = %s\n", param->name, param->value); + } + + return 0; +} + +BAREBOX_CMD_HELP_START(devinfo) +BAREBOX_CMD_HELP_USAGE("devinfo [DEVICE]\n") +BAREBOX_CMD_HELP_SHORT("Output device information.\n") +BAREBOX_CMD_HELP_END + +/** + * @page devinfo_command + +If called without arguments, devinfo shows a summary of the known +devices and drivers. + +If called with a device path being the argument, devinfo shows more +default information about this device and its parameters. + +Example from an MPC5200 based system: + +@verbatim + barebox:/ devinfo /dev/eth0 + base : 0x1002b000 + size : 0x00000000 + driver: fec_mpc5xxx + + no info available for eth0 + Parameters: + ipaddr = 192.168.23.197 + ethaddr = 80:81:82:83:84:86 + gateway = 192.168.23.1 + netmask = 255.255.255.0 + serverip = 192.168.23.2 +@endverbatim + */ + +BAREBOX_CMD_START(devinfo) + .cmd = do_devinfo, + .usage = "Show information about devices and drivers.", + BAREBOX_CMD_HELP(cmd_devinfo_help) +BAREBOX_CMD_END +#endif + diff --git a/drivers/base/platform.c b/drivers/base/platform.c new file mode 100644 index 0000000000..e0dd9ea58e --- /dev/null +++ b/drivers/base/platform.c @@ -0,0 +1,58 @@ +/* + * bus.c - barebox driver model + * + * Copyright (c) 2009 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <common.h> +#include <driver.h> + +static int platform_match(struct device_d *dev, struct driver_d *drv) +{ + return strcmp(dev->name, drv->name) ? -1 : 0; +} + +static int platform_probe(struct device_d *dev) +{ + return dev->driver->probe(dev); +} + +static void platform_remove(struct device_d *dev) +{ + dev->driver->remove(dev); +} + +struct bus_type platform_bus = { + .name = "platform", + .match = platform_match, + .probe = platform_probe, + .remove = platform_remove, +}; + +#if 0 +LIST_HEAD(bus_list); +EXPORT_SYMBOL(bus_list); + +int bus_register(struct bus_type *bus) +{ + list_add_tail(&bus->list, &bus_list); + + return 0; +} +#endif + |