aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/staging/greybus/sdio.c
diff options
context:
space:
mode:
authorRui Miguel Silva <rui.silva@linaro.org>2015-07-02 19:11:31 +0100
committerGreg Kroah-Hartman <gregkh@google.com>2015-07-06 11:15:42 -0700
commitc36d31cbc57635f7e66176d84d7b8688796a01d3 (patch)
tree327ab5713a39cbf9bf552a6044d4060dc01fcbb3 /drivers/staging/greybus/sdio.c
parentgreybus: sdio: split cmd_flags to there meaning (diff)
downloadwireguard-linux-c36d31cbc57635f7e66176d84d7b8688796a01d3.tar.xz
wireguard-linux-c36d31cbc57635f7e66176d84d7b8688796a01d3.zip
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.c86
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;