greybus: sdio: rework of event handler
authorRui Miguel Silva <rui.silva@linaro.org>
Thu, 2 Jul 2015 18:11:31 +0000 (19:11 +0100)
committerGreg Kroah-Hartman <gregkh@google.com>
Mon, 6 Jul 2015 18:15:42 +0000 (11:15 -0700)
Between the time connection with module is up and the host is added,
we can receive events (card inserted/removed, write protection
switch), so until the setup is complete we queue the events received
and handle them after.

Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/sdio.c

index e842cae7a5bdc586e7ac15ed78f41f005fe012a6..53cb46f6f7c88f11c8513ef129b23394e256f814 100644 (file)
@@ -28,6 +28,7 @@ struct gb_sdio_host {
        spinlock_t              xfer;   /* lock to cancel ongoing transfer */
        bool                    xfer_stop;
        struct work_struct      mrqwork;
+       u8                      queued_events;
        bool                    removed;
        bool                    card_present;
        bool                    read_only;
@@ -121,54 +122,40 @@ static int gb_sdio_get_caps(struct gb_sdio_host *host)
        return 0;
 }
 
-static int gb_sdio_event_recv(u8 type, struct gb_operation *op)
+static void _gb_queue_event(struct gb_sdio_host *host, u8 event)
 {
-       struct gb_connection *connection = op->connection;
-       struct gb_sdio_host *host = connection->private;
-       struct gb_message *request;
-       struct gb_sdio_event_request *payload;
-       u8 state_changed = 0;
-       u8 event;
-
-       if (type != GB_SDIO_TYPE_EVENT) {
-               dev_err(&connection->dev,
-                       "unsupported unsolicited event: %u\n", type);
-               return -EINVAL;
-       }
-
-       request = op->request;
+       if (event & GB_SDIO_CARD_INSERTED)
+               host->queued_events &= ~GB_SDIO_CARD_REMOVED;
+       else if (event & GB_SDIO_CARD_REMOVED)
+               host->queued_events &= ~GB_SDIO_CARD_INSERTED;
 
-       if (request->payload_size != sizeof(*payload)) {
-               dev_err(mmc_dev(host->mmc), "wrong event size received\n");
-               return -EINVAL;
-       }
+       host->queued_events |= event;
+}
 
-       payload = request->payload;
-       event = payload->event;
+static int _gb_sdio_process_events(struct gb_sdio_host *host, u8 event)
+{
+       u8 state_changed = 0;
 
-       switch (event) {
-       case GB_SDIO_CARD_INSERTED:
+       if (event & GB_SDIO_CARD_INSERTED) {
                if (!mmc_card_is_removable(host->mmc))
                        return 0;
                if (host->card_present)
                        return 0;
                host->card_present = true;
                state_changed = 1;
-               break;
-       case GB_SDIO_CARD_REMOVED:
+       }
+
+       if (event & GB_SDIO_CARD_REMOVED) {
                if (!mmc_card_is_removable(host->mmc))
                        return 0;
                if (!(host->card_present))
                        return 0;
                host->card_present = false;
                state_changed = 1;
-               break;
-       case GB_SDIO_WP:
+       }
+
+       if (event & GB_SDIO_WP) {
                host->read_only = true;
-               break;
-       default:
-               dev_err(mmc_dev(host->mmc), "wrong event received %d\n", event);
-               return -EINVAL;
        }
 
        if (state_changed) {
@@ -180,6 +167,39 @@ static int gb_sdio_event_recv(u8 type, struct gb_operation *op)
        return 0;
 }
 
+static int gb_sdio_event_recv(u8 type, struct gb_operation *op)
+{
+       struct gb_connection *connection = op->connection;
+       struct gb_sdio_host *host = connection->private;
+       struct gb_message *request;
+       struct gb_sdio_event_request *payload;
+       int ret =  0;
+       u8 event;
+
+       if (type != GB_SDIO_TYPE_EVENT) {
+               dev_err(&connection->dev,
+                       "unsupported unsolicited event: %u\n", type);
+               return -EINVAL;
+       }
+
+       request = op->request;
+
+       if (request->payload_size != sizeof(*payload)) {
+               dev_err(mmc_dev(host->mmc), "wrong event size received\n");
+               return -EINVAL;
+       }
+
+       payload = request->payload;
+       event = payload->event;
+
+       if (host->removed)
+               _gb_queue_event(host, event);
+       else
+               ret = _gb_sdio_process_events(host, event);
+
+       return ret;
+}
+
 static int gb_sdio_set_ios(struct gb_sdio_host *host,
                           struct gb_sdio_set_ios_request *request)
 {
@@ -649,6 +669,7 @@ static int gb_sdio_connection_init(struct gb_connection *connection)
 
        host = mmc_priv(mmc);
        host->mmc = mmc;
+       host->removed = true;
 
        host->connection = connection;
        connection->private = host;
@@ -683,6 +704,9 @@ static int gb_sdio_connection_init(struct gb_connection *connection)
        ret = mmc_add_host(mmc);
        if (ret < 0)
                goto free_work;
+       host->removed = false;
+       ret = _gb_sdio_process_events(host, host->queued_events);
+       host->queued_events = 0;
 
        return ret;