greybus: define connection state

Define the state of a connection.  A connection will not be
enabled until it has been successfully set up.  Once it starts
getting torn down its state will move to "being destroyed".

Don't send any operation request messages unless the connection is
enabled.  And drop any incoming messages if if the connection is
not enabled.

Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c
index 9bcda99..b1e933f 100644
--- a/drivers/staging/greybus/connection.c
+++ b/drivers/staging/greybus/connection.c
@@ -143,6 +143,7 @@
 	connection->interface = interface;	/* XXX refcount? */
 	connection->interface_cport_id = cport_id;
 	connection->protocol = protocol;
+	connection->state = GB_CONNECTION_STATE_DISABLED;
 
 	spin_lock_irq(&gb_connections_lock);
 	_gb_hd_connection_insert(hd, connection);
@@ -217,13 +218,20 @@
  */
 int gb_connection_init(struct gb_connection *connection)
 {
+	int ret;
+
+	/* Need to enable the connection to initialize it */
+	connection->state = GB_CONNECTION_STATE_ENABLED;
 	switch (connection->protocol) {
 	case GREYBUS_PROTOCOL_I2C:
-		return gb_i2c_device_init(connection);
+		ret = gb_i2c_device_init(connection);
+		break;
 	case GREYBUS_PROTOCOL_GPIO:
-		return gb_gpio_controller_init(connection);
+		ret = gb_gpio_controller_init(connection);
+		break;
 	case GREYBUS_PROTOCOL_BATTERY:
-		return gb_battery_device_init(connection);
+		ret = gb_battery_device_init(connection);
+		break;
 	case GREYBUS_PROTOCOL_CONTROL:
 	case GREYBUS_PROTOCOL_AP:
 	case GREYBUS_PROTOCOL_UART:
@@ -233,13 +241,20 @@
 	default:
 		gb_connection_err(connection, "unimplemented protocol %u",
 			(u32)connection->protocol);
+		ret = -ENXIO;
 		break;
 	}
-	return -ENXIO;
+
+	if (ret)
+		connection->state = GB_CONNECTION_STATE_ERROR;
+
+	return ret;
 }
 
 void gb_connection_exit(struct gb_connection *connection)
 {
+	connection->state = GB_CONNECTION_STATE_DESTROYING;
+
 	switch (connection->protocol) {
 	case GREYBUS_PROTOCOL_I2C:
 		gb_i2c_device_exit(connection);
diff --git a/drivers/staging/greybus/connection.h b/drivers/staging/greybus/connection.h
index b5901a1..a16e52a 100644
--- a/drivers/staging/greybus/connection.h
+++ b/drivers/staging/greybus/connection.h
@@ -13,6 +13,14 @@
 
 #include "greybus.h"
 
+enum gb_connection_state {
+	GB_CONNECTION_STATE_INVALID	= 0,
+	GB_CONNECTION_STATE_DISABLED	= 1,
+	GB_CONNECTION_STATE_ENABLED	= 2,
+	GB_CONNECTION_STATE_ERROR	= 3,
+	GB_CONNECTION_STATE_DESTROYING	= 4,
+};
+
 struct gb_connection {
 	struct greybus_host_device	*hd;
 	struct gb_interface		*interface;
@@ -22,6 +30,7 @@
 	struct rb_node			hd_node;
 	struct list_head		interface_links;
 	enum greybus_protocol		protocol;
+	enum gb_connection_state	state;
 
 	struct list_head		operations;
 	struct rb_root			pending;	/* awaiting reponse */
diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c
index afb42d5..5d23d19 100644
--- a/drivers/staging/greybus/operation.c
+++ b/drivers/staging/greybus/operation.c
@@ -417,6 +417,9 @@
 {
 	int ret;
 
+	if (operation->connection->state != GB_CONNECTION_STATE_ENABLED)
+		return -ENOTCONN;
+
 	/*
 	 * XXX
 	 * I think the order of operations is going to be
@@ -461,6 +464,9 @@
 	struct gbuf *gbuf;
 	u16 msg_size;
 
+	if (connection->state != GB_CONNECTION_STATE_ENABLED)
+		return;
+
 	if (size > GB_OPERATION_MESSAGE_SIZE_MAX) {
 		gb_connection_err(connection, "message too big");
 		return;