aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorPierre Ossman <drzeus@drzeus.cx>2007-07-30 09:15:30 -0400
committerPierre Ossman <drzeus@drzeus.cx>2007-09-23 14:44:22 -0400
commit1a632f8cdc33e7f8edca352164f0c96a75d08f08 (patch)
tree6cc3174285ee11df586ae89cf0040ba2429a83f0 /drivers/mmc
parentb1538bcf75e2e11459947ec4d4329ed04fbe2b2c (diff)
sdio: split up common and function CIS parsing
Add a more clean separation between global, common CIS information and the function specific one as we need the common information in places where no specific function is specified. Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/bus.c3
-rw-r--r--drivers/mmc/core/sdio.c9
-rw-r--r--drivers/mmc/core/sdio_bus.c2
-rw-r--r--drivers/mmc/core/sdio_cis.c198
-rw-r--r--drivers/mmc/core/sdio_cis.h7
5 files changed, 193 insertions, 26 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 87a6070522f8..9be11ec05d86 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -19,6 +19,7 @@
19 19
20#include "sysfs.h" 20#include "sysfs.h"
21#include "core.h" 21#include "core.h"
22#include "sdio_cis.h"
22#include "bus.h" 23#include "bus.h"
23 24
24#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) 25#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
@@ -181,6 +182,8 @@ static void mmc_release_card(struct device *dev)
181{ 182{
182 struct mmc_card *card = dev_to_mmc_card(dev); 183 struct mmc_card *card = dev_to_mmc_card(dev);
183 184
185 sdio_free_common_cis(card);
186
184 kfree(card); 187 kfree(card);
185} 188}
186 189
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index c5baf76146b2..1fb36a340468 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -66,7 +66,7 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn)
66 if (ret) 66 if (ret)
67 goto fail; 67 goto fail;
68 68
69 ret = sdio_read_cis(func); 69 ret = sdio_read_func_cis(func);
70 if (ret) 70 if (ret)
71 goto fail; 71 goto fail;
72 72
@@ -287,6 +287,13 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
287 goto remove; 287 goto remove;
288 288
289 /* 289 /*
290 * Read the common CIS tuples.
291 */
292 err = sdio_read_common_cis(card);
293 if (err)
294 goto remove;
295
296 /*
290 * Initialize (but don't add) all present functions. 297 * Initialize (but don't add) all present functions.
291 */ 298 */
292 for (i = 0;i < funcs;i++) { 299 for (i = 0;i < funcs;i++) {
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 78e0381f55ac..461fe4837a9f 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -95,7 +95,7 @@ static void sdio_release_func(struct device *dev)
95{ 95{
96 struct sdio_func *func = dev_to_sdio_func(dev); 96 struct sdio_func *func = dev_to_sdio_func(dev);
97 97
98 sdio_free_cis(func); 98 sdio_free_func_cis(func);
99 99
100 kfree(func); 100 kfree(func);
101} 101}
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index b6c7342572c1..ec806a1229b6 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -16,60 +16,152 @@
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17 17
18#include <linux/mmc/host.h> 18#include <linux/mmc/host.h>
19#include <linux/mmc/card.h>
19#include <linux/mmc/sdio.h> 20#include <linux/mmc/sdio.h>
20#include <linux/mmc/sdio_func.h> 21#include <linux/mmc/sdio_func.h>
21 22
22#include "sdio_cis.h" 23#include "sdio_cis.h"
23#include "sdio_ops.h" 24#include "sdio_ops.h"
24 25
25static int cistpl_manfid(struct sdio_func *func, 26static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func,
26 const unsigned char *buf, 27 const unsigned char *buf, unsigned size)
27 unsigned size)
28{ 28{
29 unsigned int vendor, device;
30
29 /* TPLMID_MANF */ 31 /* TPLMID_MANF */
30 func->vendor = buf[0] | (buf[1] << 8); 32 vendor = buf[0] | (buf[1] << 8);
31 33
32 /* TPLMID_CARD */ 34 /* TPLMID_CARD */
33 func->device = buf[2] | (buf[3] << 8); 35 device = buf[2] | (buf[3] << 8);
36
37 if (func) {
38 func->vendor = vendor;
39 func->device = device;
40 } else {
41 card->cis.vendor = vendor;
42 card->cis.device = device;
43 }
44
45 return 0;
46}
47
48static const unsigned char speed_val[16] =
49 { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
50static const unsigned int speed_unit[8] =
51 { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
52
53static int cistpl_funce_common(struct mmc_card *card,
54 const unsigned char *buf, unsigned size)
55{
56 if (size < 0x04 || buf[0] != 0)
57 return -EINVAL;
58
59 /* TPLFE_FN0_BLK_SIZE */
60 card->cis.blksize = buf[1] | (buf[2] << 8);
61
62 /* TPLFE_MAX_TRAN_SPEED */
63 card->cis.max_dtr = speed_val[(buf[3] >> 3) & 15] *
64 speed_unit[buf[3] & 7];
65
66 return 0;
67}
68
69static int cistpl_funce_func(struct sdio_func *func,
70 const unsigned char *buf, unsigned size)
71{
72 unsigned vsn;
73 unsigned min_size;
74
75 vsn = func->card->cccr.sdio_vsn;
76 min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
77
78 if (size < min_size || buf[0] != 1)
79 return -EINVAL;
80
81 /* TPLFE_MAX_BLK_SIZE */
82 func->blksize = buf[12] | (buf[13] << 8);
34 83
35 return 0; 84 return 0;
36} 85}
37 86
87static int cistpl_funce(struct mmc_card *card, struct sdio_func *func,
88 const unsigned char *buf, unsigned size)
89{
90 int ret;
91
92 /*
93 * There should be two versions of the CISTPL_FUNCE tuple,
94 * one for the common CIS (function 0) and a version used by
95 * the individual function's CIS (1-7). Yet, the later has a
96 * different length depending on the SDIO spec version.
97 */
98 if (func)
99 ret = cistpl_funce_func(func, buf, size);
100 else
101 ret = cistpl_funce_common(card, buf, size);
102
103 if (ret) {
104 printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u "
105 "type %u\n", mmc_hostname(card->host), size, buf[0]);
106 return ret;
107 }
108
109 return 0;
110}
111
112typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,
113 const unsigned char *, unsigned);
114
38struct cis_tpl { 115struct cis_tpl {
39 unsigned char code; 116 unsigned char code;
40 unsigned char min_size; 117 unsigned char min_size;
41 int (*parse)(struct sdio_func *, const unsigned char *buf, unsigned size); 118 tpl_parse_t *parse;
42}; 119};
43 120
44static const struct cis_tpl cis_tpl_list[] = { 121static const struct cis_tpl cis_tpl_list[] = {
45 { 0x15, 3, /* cistpl_vers_1 */ }, 122 { 0x15, 3, /* cistpl_vers_1 */ },
46 { 0x20, 4, cistpl_manfid }, 123 { 0x20, 4, cistpl_manfid },
47 { 0x21, 2, /* cistpl_funcid */ }, 124 { 0x21, 2, /* cistpl_funcid */ },
48 { 0x22, 0, /* cistpl_funce */ }, 125 { 0x22, 0, cistpl_funce },
49}; 126};
50 127
51int sdio_read_cis(struct sdio_func *func) 128static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
52{ 129{
53 int ret; 130 int ret;
54 struct sdio_func_tuple *this, **prev; 131 struct sdio_func_tuple *this, **prev;
55 unsigned i, ptr = 0; 132 unsigned i, ptr = 0;
56 133
134 /*
135 * Note that this works for the common CIS (function number 0) as
136 * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS
137 * have the same offset.
138 */
57 for (i = 0; i < 3; i++) { 139 for (i = 0; i < 3; i++) {
58 unsigned char x; 140 unsigned char x, fn;
59 ret = mmc_io_rw_direct(func->card, 0, 0, 141
60 func->num * 0x100 + SDIO_FBR_CIS + i, 0, &x); 142 if (func)
143 fn = func->num;
144 else
145 fn = 0;
146
147 ret = mmc_io_rw_direct(card, 0, 0,
148 fn * 0x100 + SDIO_FBR_CIS + i, 0, &x);
61 if (ret) 149 if (ret)
62 return ret; 150 return ret;
63 ptr |= x << (i * 8); 151 ptr |= x << (i * 8);
64 } 152 }
65 153
66 /* find the list tail */ 154 if (func)
67 for (prev = &func->tuples; *prev; prev = &(*prev)->next); 155 prev = &func->tuples;
156 else
157 prev = &card->tuples;
158
159 BUG_ON(*prev);
68 160
69 do { 161 do {
70 unsigned char tpl_code, tpl_link; 162 unsigned char tpl_code, tpl_link;
71 163
72 ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code); 164 ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code);
73 if (ret) 165 if (ret)
74 break; 166 break;
75 167
@@ -77,7 +169,7 @@ int sdio_read_cis(struct sdio_func *func)
77 if (tpl_code == 0xff) 169 if (tpl_code == 0xff)
78 break; 170 break;
79 171
80 ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_link); 172 ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link);
81 if (ret) 173 if (ret)
82 break; 174 break;
83 175
@@ -86,7 +178,7 @@ int sdio_read_cis(struct sdio_func *func)
86 return -ENOMEM; 178 return -ENOMEM;
87 179
88 for (i = 0; i < tpl_link; i++) { 180 for (i = 0; i < tpl_link; i++) {
89 ret = mmc_io_rw_direct(func->card, 0, 0, 181 ret = mmc_io_rw_direct(card, 0, 0,
90 ptr + i, 0, &this->data[i]); 182 ptr + i, 0, &this->data[i]);
91 if (ret) 183 if (ret)
92 break; 184 break;
@@ -108,30 +200,45 @@ int sdio_read_cis(struct sdio_func *func)
108 prev = &this->next; 200 prev = &this->next;
109 printk(KERN_DEBUG 201 printk(KERN_DEBUG
110 "%s: queuing CIS tuple 0x%02x length %u\n", 202 "%s: queuing CIS tuple 0x%02x length %u\n",
111 sdio_func_id(func), tpl_code, tpl_link); 203 mmc_hostname(card->host), tpl_code, tpl_link);
112 } else { 204 } else {
113 const struct cis_tpl *tpl = cis_tpl_list + i; 205 const struct cis_tpl *tpl = cis_tpl_list + i;
114 if (tpl_link < tpl->min_size) { 206 if (tpl_link < tpl->min_size) {
115 printk(KERN_ERR 207 printk(KERN_ERR
116 "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n", 208 "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n",
117 sdio_func_id(func), tpl_code, tpl_link, tpl->min_size); 209 mmc_hostname(card->host),
210 tpl_code, tpl_link, tpl->min_size);
118 ret = -EINVAL; 211 ret = -EINVAL;
119 } else if (tpl->parse) 212 } else if (tpl->parse) {
120 ret = tpl->parse(func, this->data, tpl_link); 213 ret = tpl->parse(card, func,
214 this->data, tpl_link);
215 }
121 kfree(this); 216 kfree(this);
122 } 217 }
123 218
124 ptr += tpl_link; 219 ptr += tpl_link;
125 } while (!ret); 220 } while (!ret);
126 221
222 /*
223 * Link in all unknown tuples found in the common CIS so that
224 * drivers don't have to go digging in two places.
225 */
226 if (func)
227 *prev = card->tuples;
228
127 return ret; 229 return ret;
128} 230}
129 231
130void sdio_free_cis(struct sdio_func *func) 232int sdio_read_common_cis(struct mmc_card *card)
233{
234 return sdio_read_cis(card, NULL);
235}
236
237void sdio_free_common_cis(struct mmc_card *card)
131{ 238{
132 struct sdio_func_tuple *tuple, *victim; 239 struct sdio_func_tuple *tuple, *victim;
133 240
134 tuple = func->tuples; 241 tuple = card->tuples;
135 242
136 while (tuple) { 243 while (tuple) {
137 victim = tuple; 244 victim = tuple;
@@ -139,6 +246,53 @@ void sdio_free_cis(struct sdio_func *func)
139 kfree(victim); 246 kfree(victim);
140 } 247 }
141 248
249 card->tuples = NULL;
250}
251
252int sdio_read_func_cis(struct sdio_func *func)
253{
254 int ret;
255
256 ret = sdio_read_cis(func->card, func);
257 if (ret)
258 return ret;
259
260 /*
261 * Since we've linked to tuples in the card structure,
262 * we must make sure we have a reference to it.
263 */
264 get_device(&func->card->dev);
265
266 /*
267 * Vendor/device id is optional for function CIS, so
268 * copy it from the card structure as needed.
269 */
270 if (func->vendor == 0) {
271 func->vendor = func->card->cis.vendor;
272 func->device = func->card->cis.device;
273 }
274
275 return 0;
276}
277
278void sdio_free_func_cis(struct sdio_func *func)
279{
280 struct sdio_func_tuple *tuple, *victim;
281
282 tuple = func->tuples;
283
284 while (tuple && tuple != func->card->tuples) {
285 victim = tuple;
286 tuple = tuple->next;
287 kfree(victim);
288 }
289
142 func->tuples = NULL; 290 func->tuples = NULL;
291
292 /*
293 * We have now removed the link to the tuples in the
294 * card structure, so remove the reference.
295 */
296 put_device(&func->card->dev);
143} 297}
144 298
diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h
index 863d3d516371..4d903c2e425e 100644
--- a/drivers/mmc/core/sdio_cis.h
+++ b/drivers/mmc/core/sdio_cis.h
@@ -14,7 +14,10 @@
14#ifndef _MMC_SDIO_CIS_H 14#ifndef _MMC_SDIO_CIS_H
15#define _MMC_SDIO_CIS_H 15#define _MMC_SDIO_CIS_H
16 16
17int sdio_read_cis(struct sdio_func *func); 17int sdio_read_common_cis(struct mmc_card *card);
18void sdio_free_cis(struct sdio_func *func); 18void sdio_free_common_cis(struct mmc_card *card);
19
20int sdio_read_func_cis(struct sdio_func *func);
21void sdio_free_func_cis(struct sdio_func *func);
19 22
20#endif 23#endif