debugfs.o \
ap.o \
manifest.o \
+ module.o \
interface.o \
bundle.o \
connection.o \
bundle->dev.type = &greybus_bundle_type;
bundle->dev.groups = bundle_groups;
device_initialize(&bundle->dev);
- dev_set_name(&bundle->dev, "%d:%d", intf->module_id, interface_id);
+ dev_set_name(&bundle->dev, "%s:%d", dev_name(&intf->dev), interface_id);
retval = device_add(&bundle->dev);
if (retval) {
vaf.va = &args;
pr_err("greybus: [%hhu:%hhu:%hu]: %pV\n",
- connection->bundle->intf->module_id,
+ connection->bundle->intf->module->module_id,
connection->bundle->id,
connection->bundle_cport_id, &vaf);
static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
+ struct gb_module *module = NULL;
struct gb_interface *intf = NULL;
struct gb_bundle *bundle = NULL;
struct gb_connection *connection = NULL;
- if (is_gb_interface(dev)) {
+ if (is_gb_module(dev)) {
+ module = to_gb_module(dev);
+ } else if (is_gb_interface(dev)) {
intf = to_gb_interface(dev);
} else if (is_gb_bundle(dev)) {
bundle = to_gb_bundle(dev);
#include "greybus_id.h"
#include "greybus_manifest.h"
#include "manifest.h"
+#include "module.h"
#include "interface.h"
#include "bundle.h"
#include "connection.h"
int svc_set_route_send(struct gb_bundle *bundle,
struct greybus_host_device *hd);
+extern struct device_type greybus_module_type;
extern struct device_type greybus_interface_type;
extern struct device_type greybus_bundle_type;
extern struct device_type greybus_connection_type;
+static inline int is_gb_module(const struct device *dev)
+{
+ return dev->type == &greybus_module_type;
+}
+
static inline int is_gb_interface(const struct device *dev)
{
return dev->type == &greybus_interface_type;
return NULL;
}
+// FIXME, odds are you don't want to call this function, rework the caller to
+// not need it please.
struct gb_interface *gb_interface_find(struct greybus_host_device *hd,
u8 module_id)
{
struct gb_interface *intf;
list_for_each_entry(intf, &hd->interfaces, links)
- if (intf->module_id == module_id)
+ if (intf->module->module_id == module_id)
return intf;
return NULL;
*
* Create a gb_interface structure to represent a discovered module.
* The position within the Endo is encoded in the "module_id" argument.
- * Returns a pointer to the new module or a null pointer if a
+ * Returns a pointer to the new interfce or a null pointer if a
* failure occurs due to memory exhaustion.
*/
static struct gb_interface *gb_interface_create(struct greybus_host_device *hd,
u8 module_id)
{
+ struct gb_module *module;
struct gb_interface *intf;
int retval;
+ u8 interface_id = module_id;
- intf = gb_interface_find(hd, module_id);
+ // FIXME we need an interface id here to check for this properly!
+ intf = gb_interface_find(hd, interface_id);
if (intf) {
dev_err(hd->parent, "Duplicate module id %d will not be created\n",
module_id);
return NULL;
}
+ module = gb_module_find_or_create(hd, module_id);
+ if (!module)
+ return NULL;
+
intf = kzalloc(sizeof(*intf), GFP_KERNEL);
if (!intf)
return NULL;
intf->hd = hd; /* XXX refcount? */
- intf->module_id = module_id;
+ intf->module = module;
INIT_LIST_HEAD(&intf->bundles);
- intf->dev.parent = hd->parent;
+ intf->dev.parent = &module->dev;
intf->dev.bus = &greybus_bus_type;
intf->dev.type = &greybus_interface_type;
intf->dev.groups = interface_groups;
intf->dev.dma_mask = hd->parent->dma_mask;
device_initialize(&intf->dev);
- dev_set_name(&intf->dev, "%d", module_id);
+ dev_set_name(&intf->dev, "%s:%d", dev_name(&module->dev), interface_id);
retval = device_add(&intf->dev);
if (retval) {
pr_err("failed to add module device for id 0x%02hhx\n",
module_id);
put_device(&intf->dev);
+ put_device(&module->dev);
kfree(intf);
return NULL;
}
kfree(intf->product_string);
kfree(intf->vendor_string);
+ put_device(&intf->module->dev);
/* kref_put(module->hd); */
device_del(&intf->dev);
struct list_head bundles;
struct list_head links; /* greybus_host_device->interfaces */
- u8 module_id; /* Physical location within the Endo */
+ u8 interface_id; /* Physical location within the Endo */
/* Information taken from the manifest module descriptor */
u16 vendor;
char *product_string;
u64 unique_id;
+ struct gb_module *module;
struct greybus_host_device *hd;
};
#define to_gb_interface(d) container_of(d, struct gb_interface, dev)
}
#endif
+#ifndef __ATTR_RW
+#define __ATTR_RW(_name) __ATTR(_name, (S_IWUSR | S_IRUGO), \
+ _name##_show, _name##_store)
+#endif
+
#ifndef DEVICE_ATTR_RO
#define DEVICE_ATTR_RO(_name) \
struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
#endif
+#ifndef DEVICE_ATTR_RW
+#define DEVICE_ATTR_RW(_name) \
+ struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
+#endif
+
#ifndef U8_MAX
#define U8_MAX ((u8)~0U)
#endif /* ! U8_MAX */
--- /dev/null
+/*
+ * Greybus module code
+ *
+ * Copyright 2014 Google Inc.
+ * Copyright 2014 Linaro Ltd.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include "greybus.h"
+
+
+/*
+ * List of modules in the system. We really should just walk the list the
+ * driver core provides us, but as we have lots of different things on the same
+ * "bus" at the same time, a single list of modules is simplest for now.
+ */
+static DEFINE_SPINLOCK(gb_modules_lock);
+static LIST_HEAD(module_list);
+
+/* module sysfs attributes */
+#define gb_module_attr(field, type) \
+static ssize_t field##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct gb_module *module = to_gb_module(dev); \
+ return sprintf(buf, "%"#type"\n", module->field); \
+} \
+static DEVICE_ATTR_RO(field)
+
+// FIXME, do we really need this attribute?
+gb_module_attr(module_id, x);
+
+static ssize_t epm_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ // FIXME, implement something here
+ return sprintf(buf, "1\n");
+}
+
+static ssize_t epm_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ // FIXME, implement something here.
+ return 0;
+}
+static DEVICE_ATTR_RW(epm);
+
+static struct attribute *module_attrs[] = {
+ &dev_attr_module_id.attr,
+ &dev_attr_epm.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(module);
+
+static void greybus_module_release(struct device *dev)
+{
+ struct gb_module *module = to_gb_module(dev);
+
+ spin_lock(&gb_modules_lock);
+ list_del(&module->list);
+ spin_unlock(&gb_modules_lock);
+
+ kfree(module);
+}
+
+struct device_type greybus_module_type = {
+ .name = "greybus_module",
+ .release = greybus_module_release,
+};
+
+/*
+ * Search the list of modules in the system. If one is found, return it, with
+ * the reference count incremented.
+ */
+static struct gb_module *gb_module_find(u8 module_id)
+{
+ struct gb_module *module;
+
+ spin_lock(&gb_modules_lock);
+ list_for_each_entry(module, &module_list, list) {
+ if (module->module_id == module_id) {
+ get_device(&module->dev);
+ goto exit;
+ }
+ }
+ module = NULL;
+exit:
+ spin_unlock(&gb_modules_lock);
+ return module;
+}
+
+static struct gb_module *gb_module_create(struct greybus_host_device *hd,
+ u8 module_id)
+{
+ struct gb_module *module;
+ int retval;
+
+ module = kzalloc(sizeof(*module), GFP_KERNEL);
+ if (!module)
+ return NULL;
+
+ module->module_id = module_id;
+ module->dev.parent = hd->parent;
+ module->dev.bus = &greybus_bus_type;
+ module->dev.type = &greybus_module_type;
+ module->dev.groups = module_groups;
+ module->dev.dma_mask = hd->parent->dma_mask;
+ device_initialize(&module->dev);
+ dev_set_name(&module->dev, "%d", module_id);
+
+ retval = device_add(&module->dev);
+ if (retval) {
+ pr_err("failed to add module device for id 0x%02hhx\n",
+ module_id);
+ put_device(&module->dev);
+ kfree(module);
+ return NULL;
+ }
+
+ spin_lock(&gb_modules_lock);
+ list_add_tail(&module->list, &module_list);
+ spin_unlock(&gb_modules_lock);
+
+ return module;
+}
+
+struct gb_module *gb_module_find_or_create(struct greybus_host_device *hd,
+ u8 module_id)
+{
+ struct gb_module *module;
+
+ module = gb_module_find(module_id);
+ if (module)
+ return module;
+
+ return gb_module_create(hd, module_id);
+}
+
--- /dev/null
+/*
+ * Greybus module code
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#ifndef __MODULE_H
+#define __MODULE_H
+
+/* Greybus "public" definitions" */
+struct gb_module {
+ struct device dev;
+
+ struct list_head list;
+ u8 module_id; /* Physical location within the Endo */
+};
+#define to_gb_module(d) container_of(d, struct gb_module, dev)
+
+struct greybus_host_device;
+
+/* Greybus "private" definitions */
+struct gb_module *gb_module_find_or_create(struct greybus_host_device *hd,
+ u8 module_id);
+
+
+#endif /* __MODULE_H */