diff options
author | Greg Kroah-Hartman <greg@kroah.com> | 2014-12-12 17:10:16 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <greg@kroah.com> | 2014-12-13 13:35:33 -0500 |
commit | 3bdec69931d889f2ee5dccafbc8cee6a364bb249 (patch) | |
tree | 3494f92a6d47e84893939d8b9f7c904da3bbcd2d /drivers/staging/greybus/bundle.c | |
parent | a46e96719dc9180e80fe0cb81f4cdd3757b1e9cd (diff) |
greybus: bundle: rename interface.[c|h] to bundle.[c|h]
We are renameing the "interface" term to "bundle" so rename the files
before we start changing structure names to make it easier for people to
see what really is happening in the changes.
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
Reviewed-by: Alex Elder <elder@linaro.org>
Diffstat (limited to 'drivers/staging/greybus/bundle.c')
-rw-r--r-- | drivers/staging/greybus/bundle.c | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/drivers/staging/greybus/bundle.c b/drivers/staging/greybus/bundle.c new file mode 100644 index 000000000000..742781ceb135 --- /dev/null +++ b/drivers/staging/greybus/bundle.c @@ -0,0 +1,186 @@ +/* + * Greybus interfaces + * + * Copyright 2014 Google Inc. + * Copyright 2014 Linaro Ltd. + * + * Released under the GPLv2 only. + */ + +#include "greybus.h" + +static ssize_t device_id_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct gb_interface *interface = to_gb_interface(dev); + + return sprintf(buf, "%d", interface->device_id); +} +static DEVICE_ATTR_RO(device_id); + +static struct attribute *interface_attrs[] = { + &dev_attr_device_id.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(interface); + +static void gb_interface_release(struct device *dev) +{ + struct gb_interface *interface = to_gb_interface(dev); + + kfree(interface); +} + +struct device_type greybus_interface_type = { + .name = "greybus_interface", + .release = gb_interface_release, +}; + + +/* XXX This could be per-host device or per-module */ +static DEFINE_SPINLOCK(gb_interfaces_lock); + +/* + * A Greybus interface represents a UniPro device present on a + * module. For Project Ara, each active Interface Block on a module + * implements a UniPro device, and therefore a Greybus interface. A + * Greybus module has at least one interface, but can have two (or + * even more). + * + * Create a gb_interface structure to represent a discovered + * interface. Returns a pointer to the new interface or a null + * pointer if a failure occurs due to memory exhaustion. + */ +struct gb_interface * +gb_interface_create(struct gb_interface_block *gb_ib, u8 interface_id) +{ + struct gb_interface *interface; + int retval; + + interface = kzalloc(sizeof(*interface), GFP_KERNEL); + if (!interface) + return NULL; + + interface->gb_ib = gb_ib; + interface->id = interface_id; + interface->device_id = 0xff; /* Invalid device id to start with */ + INIT_LIST_HEAD(&interface->connections); + + /* Build up the interface device structures and register it with the + * driver core */ + interface->dev.parent = &gb_ib->dev; + interface->dev.bus = &greybus_bus_type; + interface->dev.type = &greybus_interface_type; + interface->dev.groups = interface_groups; + device_initialize(&interface->dev); + dev_set_name(&interface->dev, "%d:%d", gb_ib->module_id, interface_id); + + retval = device_add(&interface->dev); + if (retval) { + pr_err("failed to add interface device for id 0x%02hhx\n", + interface_id); + put_device(&interface->dev); + kfree(interface); + return NULL; + } + + spin_lock_irq(&gb_interfaces_lock); + list_add_tail(&interface->links, &gb_ib->interfaces); + spin_unlock_irq(&gb_interfaces_lock); + + return interface; +} + +/* + * Tear down a previously set up interface. + */ +void gb_interface_destroy(struct gb_interface_block *gb_ib) +{ + struct gb_interface *interface; + struct gb_interface *temp; + + if (WARN_ON(!gb_ib)) + return; + + spin_lock_irq(&gb_interfaces_lock); + list_for_each_entry_safe(interface, temp, &gb_ib->interfaces, links) { + list_del(&interface->links); + gb_interface_connections_exit(interface); + device_del(&interface->dev); + } + spin_unlock_irq(&gb_interfaces_lock); +} + +int gb_interface_init(struct gb_interface_block *gb_ib, u8 interface_id, u8 device_id) +{ + struct gb_interface *interface; + int ret; + + interface = gb_interface_find(gb_ib, interface_id); + if (!interface) { + dev_err(gb_ib->hd->parent, "module %hhu not found\n", + interface_id); + return -ENOENT; + } + interface->device_id = device_id; + + ret = svc_set_route_send(interface, gb_ib->hd); + if (ret) { + dev_err(gb_ib->hd->parent, "failed to set route (%d)\n", ret); + return ret; + } + + ret = gb_interface_connections_init(interface); + if (ret) { + dev_err(gb_ib->hd->parent, "module interface init error %d\n", + ret); + /* XXX clear route */ + return ret; + } + + return 0; +} + +struct gb_interface *gb_interface_find(struct gb_interface_block *gb_ib, + u8 interface_id) +{ + struct gb_interface *interface; + + spin_lock_irq(&gb_interfaces_lock); + list_for_each_entry(interface, &gb_ib->interfaces, links) + if (interface->id == interface_id) { + spin_unlock_irq(&gb_interfaces_lock); + return interface; + } + spin_unlock_irq(&gb_interfaces_lock); + + return NULL; +} + +int gb_interface_connections_init(struct gb_interface *interface) +{ + struct gb_connection *connection; + int ret = 0; + + list_for_each_entry(connection, &interface->connections, + interface_links) { + ret = gb_connection_init(connection); + if (ret) + break; + } + + return ret; +} + +void gb_interface_connections_exit(struct gb_interface *interface) +{ + struct gb_connection *connection; + struct gb_connection *next; + + list_for_each_entry_safe(connection, next, &interface->connections, + interface_links) { + gb_connection_exit(connection); + gb_connection_destroy(connection); + } +} |