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;
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) {
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)
{
host = mmc_priv(mmc);
host->mmc = mmc;
+ host->removed = true;
host->connection = connection;
connection->private = host;
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;