diff options
author | Rui Miguel Silva <rui.silva@linaro.org> | 2015-07-02 19:11:31 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@google.com> | 2015-07-06 11:15:42 -0700 |
commit | c36d31cbc57635f7e66176d84d7b8688796a01d3 (patch) | |
tree | 327ab5713a39cbf9bf552a6044d4060dc01fcbb3 /drivers/staging/greybus/sdio.c | |
parent | ef0cc0ec8d80a18c83aec41321ebeba639cfa09a (diff) |
greybus: sdio: rework of event handler
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>
Diffstat (limited to 'drivers/staging/greybus/sdio.c')
-rw-r--r-- | drivers/staging/greybus/sdio.c | 86 |
1 files changed, 55 insertions, 31 deletions
diff --git a/drivers/staging/greybus/sdio.c b/drivers/staging/greybus/sdio.c index e842cae7a5bd..53cb46f6f7c8 100644 --- a/drivers/staging/greybus/sdio.c +++ b/drivers/staging/greybus/sdio.c @@ -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; |