diff options
author | Nicolas Pitre <nico@cam.org> | 2007-06-16 02:04:16 -0400 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-09-23 14:26:42 -0400 |
commit | b726126196d54cbbba0924191e5c4dd5ba747fa2 (patch) | |
tree | 75d0923f93947e083a7fc77dfa073817a30b1682 /drivers/mmc | |
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')
-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 | |||
10 | mmc_core-y := core.o sysfs.o bus.o host.o \ | 10 | mmc_core-y := core.o sysfs.o bus.o host.o \ |
11 | mmc.o mmc_ops.o sd.o sd_ops.o \ | 11 | mmc.o mmc_ops.o sd.o sd_ops.o \ |
12 | sdio.o sdio_ops.o sdio_bus.o \ | 12 | sdio.o sdio_ops.o sdio_bus.o \ |
13 | sdio_io.o | 13 | sdio_cis.o sdio_io.o |
14 | 14 | ||
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 @@ | |||
22 | #include "mmc_ops.h" | 22 | #include "mmc_ops.h" |
23 | #include "sd_ops.h" | 23 | #include "sd_ops.h" |
24 | #include "sdio_ops.h" | 24 | #include "sdio_ops.h" |
25 | #include "sdio_cis.h" | ||
25 | 26 | ||
26 | static int sdio_read_fbr(struct sdio_func *func) | 27 | static int sdio_read_fbr(struct sdio_func *func) |
27 | { | 28 | { |
@@ -65,6 +66,10 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) | |||
65 | if (ret) | 66 | if (ret) |
66 | goto fail; | 67 | goto fail; |
67 | 68 | ||
69 | ret = sdio_read_cis(func); | ||
70 | if (ret) | ||
71 | goto fail; | ||
72 | |||
68 | card->sdio_func[fn - 1] = func; | 73 | card->sdio_func[fn - 1] = func; |
69 | 74 | ||
70 | return 0; | 75 | 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 @@ | |||
1 | /* | ||
2 | * linux/drivers/mmc/core/sdio_cis.c | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Created: June 11, 2007 | ||
6 | * Copyright: MontaVista Software Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or (at | ||
11 | * your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | |||
16 | #include <linux/mmc/host.h> | ||
17 | #include <linux/mmc/sdio.h> | ||
18 | #include <linux/mmc/sdio_func.h> | ||
19 | |||
20 | #include "sdio_cis.h" | ||
21 | #include "sdio_ops.h" | ||
22 | |||
23 | static int cistpl_manfid(struct sdio_func *func, | ||
24 | const unsigned char *buf, | ||
25 | unsigned size) | ||
26 | { | ||
27 | /* TPLMID_MANF */ | ||
28 | func->vendor = buf[0] | (buf[1] << 8); | ||
29 | |||
30 | /* TPLMID_CARD */ | ||
31 | func->device = buf[2] | (buf[3] << 8); | ||
32 | |||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | struct cis_tpl { | ||
37 | unsigned char code; | ||
38 | unsigned char min_size; | ||
39 | int (*parse)(struct sdio_func *, const unsigned char *buf, unsigned size); | ||
40 | }; | ||
41 | |||
42 | static const struct cis_tpl cis_tpl_list[] = { | ||
43 | { 0x15, 3, /* cistpl_vers_1 */ }, | ||
44 | { 0x20, 4, cistpl_manfid }, | ||
45 | { 0x21, 2, /* cistpl_funcid */ }, | ||
46 | { 0x22, 0, /* cistpl_funce */ }, | ||
47 | }; | ||
48 | |||
49 | int sdio_read_cis(struct sdio_func *func) | ||
50 | { | ||
51 | int ret; | ||
52 | unsigned char *buf; | ||
53 | unsigned i, ptr = 0; | ||
54 | |||
55 | for (i = 0; i < 3; i++) { | ||
56 | unsigned char x; | ||
57 | ret = mmc_io_rw_direct(func->card, 0, 0, | ||
58 | func->num * 0x100 + SDIO_FBR_CIS + i, 0, &x); | ||
59 | if (ret) | ||
60 | return ret; | ||
61 | ptr |= x << (i * 8); | ||
62 | } | ||
63 | |||
64 | buf = kmalloc(256, GFP_KERNEL); | ||
65 | if (!buf) | ||
66 | return -ENOMEM; | ||
67 | |||
68 | do { | ||
69 | unsigned char tpl_code, tpl_link; | ||
70 | const struct cis_tpl *tpl; | ||
71 | |||
72 | ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code); | ||
73 | if (ret) | ||
74 | break; | ||
75 | |||
76 | /* 0xff means we're done */ | ||
77 | if (tpl_code == 0xff) | ||
78 | break; | ||
79 | |||
80 | ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_link); | ||
81 | if (ret) | ||
82 | break; | ||
83 | |||
84 | for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++) | ||
85 | if (cis_tpl_list[i].code == tpl_code) | ||
86 | break; | ||
87 | if (i >= ARRAY_SIZE(cis_tpl_list)) { | ||
88 | printk(KERN_WARNING | ||
89 | "%s: unknown CIS tuple 0x%02x of length %u\n", | ||
90 | sdio_func_id(func), tpl_code, tpl_link); | ||
91 | ptr += tpl_link; | ||
92 | continue; | ||
93 | } | ||
94 | tpl = cis_tpl_list + i; | ||
95 | |||
96 | if (tpl_link < tpl->min_size) { | ||
97 | printk(KERN_ERR | ||
98 | "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u\n", | ||
99 | sdio_func_id(func), tpl_code, tpl_link, tpl->min_size); | ||
100 | ret = -EINVAL; | ||
101 | break; | ||
102 | } | ||
103 | |||
104 | for (i = 0; i < tpl_link; i++) { | ||
105 | ret = mmc_io_rw_direct(func->card, 0, 0, ptr + i, 0, &buf[i]); | ||
106 | if (ret) | ||
107 | break; | ||
108 | } | ||
109 | if (ret) | ||
110 | break; | ||
111 | ptr += tpl_link; | ||
112 | |||
113 | if (tpl->parse) | ||
114 | ret = tpl->parse(func, buf, tpl_link); | ||
115 | } while (!ret); | ||
116 | |||
117 | kfree(buf); | ||
118 | return ret; | ||
119 | } | ||
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 @@ | |||
1 | /* | ||
2 | * linux/drivers/mmc/core/sdio_cis.h | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Created: June 11, 2007 | ||
6 | * Copyright: MontaVista Software Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or (at | ||
11 | * your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #ifndef _MMC_SDIO_CIS_H | ||
15 | #define _MMC_SDIO_CIS_H | ||
16 | |||
17 | int sdio_read_cis(struct sdio_func *func); | ||
18 | |||
19 | #endif | ||