aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc/core/sdio_cis.c
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2007-06-16 02:06:47 -0400
committerPierre Ossman <drzeus@drzeus.cx>2007-09-23 20:31:43 +0200
commitb1538bcf75e2e11459947ec4d4329ed04fbe2b2c (patch)
treeb190714969b66b1ca0cef1d96cb0547d5e959d0d /drivers/mmc/core/sdio_cis.c
parentb726126196d54cbbba0924191e5c4dd5ba747fa2 (diff)
sdio: link unknown CIS tuples to the sdio_func structure
This way those tuples that the core cares about are consumed by the core code, and tuples that only function drivers might make sense of are available to drivers. Signed-off-by: Nicolas Pitre <npitre@mvista.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/core/sdio_cis.c')
-rw-r--r--drivers/mmc/core/sdio_cis.c83
1 files changed, 54 insertions, 29 deletions
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index 114b600cd78..b6c7342572c 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -5,6 +5,8 @@
* Created: June 11, 2007
* Copyright: MontaVista Software Inc.
*
+ * Copyright 2007 Pierre Ossman
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
@@ -49,7 +51,7 @@ static const struct cis_tpl cis_tpl_list[] = {
int sdio_read_cis(struct sdio_func *func)
{
int ret;
- unsigned char *buf;
+ struct sdio_func_tuple *this, **prev;
unsigned i, ptr = 0;
for (i = 0; i < 3; i++) {
@@ -61,13 +63,11 @@ int sdio_read_cis(struct sdio_func *func)
ptr |= x << (i * 8);
}
- buf = kmalloc(256, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ /* find the list tail */
+ for (prev = &func->tuples; *prev; prev = &(*prev)->next);
do {
unsigned char tpl_code, tpl_link;
- const struct cis_tpl *tpl;
ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code);
if (ret)
@@ -81,39 +81,64 @@ int sdio_read_cis(struct sdio_func *func)
if (ret)
break;
- for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
- if (cis_tpl_list[i].code == tpl_code)
+ this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL);
+ if (!this)
+ return -ENOMEM;
+
+ for (i = 0; i < tpl_link; i++) {
+ ret = mmc_io_rw_direct(func->card, 0, 0,
+ ptr + i, 0, &this->data[i]);
+ if (ret)
break;
- if (i >= ARRAY_SIZE(cis_tpl_list)) {
- printk(KERN_WARNING
- "%s: unknown CIS tuple 0x%02x of length %u\n",
- sdio_func_id(func), tpl_code, tpl_link);
- ptr += tpl_link;
- continue;
}
- tpl = cis_tpl_list + i;
-
- if (tpl_link < tpl->min_size) {
- printk(KERN_ERR
- "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u\n",
- sdio_func_id(func), tpl_code, tpl_link, tpl->min_size);
- ret = -EINVAL;
+ if (ret) {
+ kfree(this);
break;
}
- for (i = 0; i < tpl_link; i++) {
- ret = mmc_io_rw_direct(func->card, 0, 0, ptr + i, 0, &buf[i]);
- if (ret)
+ for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
+ if (cis_tpl_list[i].code == tpl_code)
break;
+ if (i >= ARRAY_SIZE(cis_tpl_list)) {
+ /* this tuple is unknown to the core */
+ this->next = NULL;
+ this->code = tpl_code;
+ this->size = tpl_link;
+ *prev = this;
+ prev = &this->next;
+ printk(KERN_DEBUG
+ "%s: queuing CIS tuple 0x%02x length %u\n",
+ sdio_func_id(func), tpl_code, tpl_link);
+ } else {
+ const struct cis_tpl *tpl = cis_tpl_list + i;
+ if (tpl_link < tpl->min_size) {
+ printk(KERN_ERR
+ "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n",
+ sdio_func_id(func), tpl_code, tpl_link, tpl->min_size);
+ ret = -EINVAL;
+ } else if (tpl->parse)
+ ret = tpl->parse(func, this->data, tpl_link);
+ kfree(this);
}
- if (ret)
- break;
- ptr += tpl_link;
- if (tpl->parse)
- ret = tpl->parse(func, buf, tpl_link);
+ ptr += tpl_link;
} while (!ret);
- kfree(buf);
return ret;
}
+
+void sdio_free_cis(struct sdio_func *func)
+{
+ struct sdio_func_tuple *tuple, *victim;
+
+ tuple = func->tuples;
+
+ while (tuple) {
+ victim = tuple;
+ tuple = tuple->next;
+ kfree(victim);
+ }
+
+ func->tuples = NULL;
+}
+