diff options
author | Nicolas Pitre <nico@cam.org> | 2007-06-16 02:04:16 -0400 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-09-23 20:26:42 +0200 |
commit | b726126196d54cbbba0924191e5c4dd5ba747fa2 (patch) | |
tree | 75d0923f93947e083a7fc77dfa073817a30b1682 /drivers/mmc/core | |
parent | 0597007f1b22bbb5d4234ca09c045f9bb2711270 (diff) |
sdio: initial CIS parsing code
Signed-off-by: Nicolas Pitre <npitre@mvista.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r-- | drivers/mmc/core/Makefile | 2 | ||||
-rw-r--r-- | drivers/mmc/core/sdio.c | 5 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_cis.c | 119 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_cis.h | 19 |
4 files changed, 144 insertions, 1 deletions
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index bf7a00248039..05d69fc72c18 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -10,5 +10,5 @@ obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o sysfs.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ - sdio_io.o + sdio_cis.o sdio_io.o diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index be623856f288..c5baf76146b2 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -22,6 +22,7 @@ #include "mmc_ops.h" #include "sd_ops.h" #include "sdio_ops.h" +#include "sdio_cis.h" static int sdio_read_fbr(struct sdio_func *func) { @@ -65,6 +66,10 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) if (ret) goto fail; + ret = sdio_read_cis(func); + if (ret) + goto fail; + card->sdio_func[fn - 1] = func; return 0; diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c new file mode 100644 index 000000000000..114b600cd788 --- /dev/null +++ b/drivers/mmc/core/sdio_cis.c @@ -0,0 +1,119 @@ +/* + * linux/drivers/mmc/core/sdio_cis.c + * + * Author: Nicolas Pitre + * Created: June 11, 2007 + * Copyright: MontaVista Software Inc. + * + * 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 + * your option) any later version. + */ + +#include <linux/kernel.h> + +#include <linux/mmc/host.h> +#include <linux/mmc/sdio.h> +#include <linux/mmc/sdio_func.h> + +#include "sdio_cis.h" +#include "sdio_ops.h" + +static int cistpl_manfid(struct sdio_func *func, + const unsigned char *buf, + unsigned size) +{ + /* TPLMID_MANF */ + func->vendor = buf[0] | (buf[1] << 8); + + /* TPLMID_CARD */ + func->device = buf[2] | (buf[3] << 8); + + return 0; +} + +struct cis_tpl { + unsigned char code; + unsigned char min_size; + int (*parse)(struct sdio_func *, const unsigned char *buf, unsigned size); +}; + +static const struct cis_tpl cis_tpl_list[] = { + { 0x15, 3, /* cistpl_vers_1 */ }, + { 0x20, 4, cistpl_manfid }, + { 0x21, 2, /* cistpl_funcid */ }, + { 0x22, 0, /* cistpl_funce */ }, +}; + +int sdio_read_cis(struct sdio_func *func) +{ + int ret; + unsigned char *buf; + unsigned i, ptr = 0; + + for (i = 0; i < 3; i++) { + unsigned char x; + ret = mmc_io_rw_direct(func->card, 0, 0, + func->num * 0x100 + SDIO_FBR_CIS + i, 0, &x); + if (ret) + return ret; + ptr |= x << (i * 8); + } + + buf = kmalloc(256, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + 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) + break; + + /* 0xff means we're done */ + if (tpl_code == 0xff) + break; + + ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_link); + if (ret) + break; + + 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)) { + 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; + break; + } + + for (i = 0; i < tpl_link; i++) { + ret = mmc_io_rw_direct(func->card, 0, 0, ptr + i, 0, &buf[i]); + if (ret) + break; + } + if (ret) + break; + ptr += tpl_link; + + if (tpl->parse) + ret = tpl->parse(func, buf, tpl_link); + } while (!ret); + + kfree(buf); + return ret; +} diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h new file mode 100644 index 000000000000..df21c495d133 --- /dev/null +++ b/drivers/mmc/core/sdio_cis.h @@ -0,0 +1,19 @@ +/* + * linux/drivers/mmc/core/sdio_cis.h + * + * Author: Nicolas Pitre + * Created: June 11, 2007 + * Copyright: MontaVista Software Inc. + * + * 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 + * your option) any later version. + */ + +#ifndef _MMC_SDIO_CIS_H +#define _MMC_SDIO_CIS_H + +int sdio_read_cis(struct sdio_func *func); + +#endif |