greybus: define greybus interface abstraction

Define new source files "interface.h" and "interface.c" to contain
the definitions of the Greybus interface abstraction.  A Greybus
interface represents a UniPro device present in a UniPro module.
For Project Ara, each interface block on a module implements a
UniPro interface.

Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile
index 9b5d8e9..21f6358 100644
--- a/drivers/staging/greybus/Makefile
+++ b/drivers/staging/greybus/Makefile
@@ -4,6 +4,7 @@
 		debugfs.o	\
 		ap.o		\
 		module.o	\
+		interface.o	\
 		i2c-gb.o	\
 		gpio-gb.o	\
 		sdio-gb.o	\
diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h
index a4fad87..c82c630 100644
--- a/drivers/staging/greybus/greybus.h
+++ b/drivers/staging/greybus/greybus.h
@@ -21,6 +21,7 @@
 #include "greybus_id.h"
 #include "greybus_manifest.h"
 #include "module.h"
+#include "interface.h"
 
 
 /* Matches up with the Greybus Protocol specification document */
diff --git a/drivers/staging/greybus/interface.c b/drivers/staging/greybus/interface.c
new file mode 100644
index 0000000..a6e6e0e
--- /dev/null
+++ b/drivers/staging/greybus/interface.c
@@ -0,0 +1,58 @@
+/*
+ * Greybus interfaces
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include "greybus.h"
+
+/* 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_module *gmod, u8 interface_id)
+{
+	struct gb_interface *interface;
+
+	interface = kzalloc(sizeof(*interface), GFP_KERNEL);
+	if (!interface)
+		return NULL;
+
+	interface->gmod = gmod;		/* XXX refcount? */
+	interface->interface_id = interface_id;
+
+	spin_lock_irq(&gb_interfaces_lock);
+	list_add_tail(&interface->links, &gmod->interfaces);
+	spin_unlock_irq(&gb_interfaces_lock);
+
+	return interface;
+}
+
+/*
+ * Tear down a previously set up interface.
+ */
+void gb_interface_destroy(struct gb_interface *interface)
+{
+	if (WARN_ON(!interface))
+		return;
+
+	spin_lock_irq(&gb_interfaces_lock);
+	list_del(&interface->links);
+	spin_unlock_irq(&gb_interfaces_lock);
+
+	/* kref_put(gmod); */
+	kfree(interface);
+}
diff --git a/drivers/staging/greybus/interface.h b/drivers/staging/greybus/interface.h
new file mode 100644
index 0000000..63ae762
--- /dev/null
+++ b/drivers/staging/greybus/interface.h
@@ -0,0 +1,24 @@
+/*
+ * Greybus interfaces
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#ifndef __INTERFACE_H
+#define __INTERFACE_H
+
+#include <linux/list.h>
+
+struct gb_interface {
+	struct gb_module	*gmod;
+	u8			interface_id;
+
+	struct list_head	links;	/* module->interfaces */
+};
+
+struct gb_interface *gb_interface_create(struct gb_module *gmod, u8 module_id);
+void gb_interface_destroy(struct gb_interface *interface);
+
+#endif /* __INTERFACE_H */
diff --git a/drivers/staging/greybus/module.c b/drivers/staging/greybus/module.c
index 31017c2..e777912 100644
--- a/drivers/staging/greybus/module.c
+++ b/drivers/staging/greybus/module.c
@@ -67,6 +67,7 @@
 
 	module->hd = hd;		/* XXX refcount? */
 	module->module_id = module_id;
+	INIT_LIST_HEAD(&module->interfaces);
 
 	spin_lock_irq(&gb_modules_lock);
 	list_add_tail(&module->links, &hd->modules);
diff --git a/drivers/staging/greybus/module.h b/drivers/staging/greybus/module.h
index 0d0f19f..921c001 100644
--- a/drivers/staging/greybus/module.h
+++ b/drivers/staging/greybus/module.h
@@ -16,6 +16,7 @@
 struct gb_module {
 	struct device dev;
 
+	struct list_head interfaces;
 	struct list_head links;	/* greybus_host_device->modules */
 	u8 module_id;		/* Physical location within the Endo */