diff --git a/drivers/Makefile b/drivers/Makefile index 92b22bd..16b3bb1 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 0000000..2d94723 --- /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 0000000..b5166c8 --- /dev/null +++ b/drivers/base/driver.c @@ -0,0 +1,418 @@ +/* + * driver.c - barebox driver model + * + * Copyright (c) 2007 Sascha Hauer , 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 +#include +#include +#include +#include +#include +#include +#include + +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 0000000..e0dd9ea --- /dev/null +++ b/drivers/base/platform.c @@ -0,0 +1,58 @@ +/* + * bus.c - barebox driver model + * + * Copyright (c) 2009 Sascha Hauer , 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 +#include + +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 + diff --git a/lib/Makefile b/lib/Makefile index 8b986d2..d96cfe7 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -5,8 +5,6 @@ obj-y += vsprintf.o obj-y += div64.o obj-y += misc.o -obj-y += driver.o -obj-y += bus.o obj-y += parameter.o obj-y += xfuncs.o obj-y += getopt.o diff --git a/lib/bus.c b/lib/bus.c deleted file mode 100644 index e0dd9ea..0000000 --- a/lib/bus.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * bus.c - barebox driver model - * - * Copyright (c) 2009 Sascha Hauer , 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 -#include - -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 - diff --git a/lib/driver.c b/lib/driver.c deleted file mode 100644 index b5166c8..0000000 --- a/lib/driver.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * driver.c - barebox driver model - * - * Copyright (c) 2007 Sascha Hauer , 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 -#include -#include -#include -#include -#include -#include -#include - -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 -