]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/mmc/core/sdio_cis.c
sdio: add SDIO_FBR_BASE(f) macro
[net-next-2.6.git] / drivers / mmc / core / sdio_cis.c
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  * Copyright 2007 Pierre Ossman
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or (at
13  * your option) any later version.
14  */
15
16 #include <linux/kernel.h>
17
18 #include <linux/mmc/host.h>
19 #include <linux/mmc/card.h>
20 #include <linux/mmc/sdio.h>
21 #include <linux/mmc/sdio_func.h>
22
23 #include "sdio_cis.h"
24 #include "sdio_ops.h"
25
26 static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func,
27                          const unsigned char *buf, unsigned size)
28 {
29         unsigned int vendor, device;
30
31         /* TPLMID_MANF */
32         vendor = buf[0] | (buf[1] << 8);
33
34         /* TPLMID_CARD */
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
48 static const unsigned char speed_val[16] =
49         { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
50 static const unsigned int speed_unit[8] =
51         { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
52
53 static 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
69 static 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);
83
84         return 0;
85 }
86
87 static 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
112 typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,
113                            const unsigned char *, unsigned);
114
115 struct cis_tpl {
116         unsigned char code;
117         unsigned char min_size;
118         tpl_parse_t *parse;
119 };
120
121 static const struct cis_tpl cis_tpl_list[] = {
122         {       0x15,   3,      /* cistpl_vers_1 */     },
123         {       0x20,   4,      cistpl_manfid           },
124         {       0x21,   2,      /* cistpl_funcid */     },
125         {       0x22,   0,      cistpl_funce            },
126 };
127
128 static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
129 {
130         int ret;
131         struct sdio_func_tuple *this, **prev;
132         unsigned i, ptr = 0;
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          */
139         for (i = 0; i < 3; i++) {
140                 unsigned char x, fn;
141
142                 if (func)
143                         fn = func->num;
144                 else
145                         fn = 0;
146
147                 ret = mmc_io_rw_direct(card, 0, 0,
148                         SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x);
149                 if (ret)
150                         return ret;
151                 ptr |= x << (i * 8);
152         }
153
154         if (func)
155                 prev = &func->tuples;
156         else
157                 prev = &card->tuples;
158
159         BUG_ON(*prev);
160
161         do {
162                 unsigned char tpl_code, tpl_link;
163
164                 ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code);
165                 if (ret)
166                         break;
167
168                 /* 0xff means we're done */
169                 if (tpl_code == 0xff)
170                         break;
171
172                 ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link);
173                 if (ret)
174                         break;
175
176                 this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL);
177                 if (!this)
178                         return -ENOMEM;
179
180                 for (i = 0; i < tpl_link; i++) {
181                         ret = mmc_io_rw_direct(card, 0, 0,
182                                                ptr + i, 0, &this->data[i]);
183                         if (ret)
184                                 break;
185                 }
186                 if (ret) {
187                         kfree(this);
188                         break;
189                 }
190
191                 for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
192                         if (cis_tpl_list[i].code == tpl_code)
193                                 break;
194                 if (i >= ARRAY_SIZE(cis_tpl_list)) {
195                         /* this tuple is unknown to the core */
196                         this->next = NULL;
197                         this->code = tpl_code;
198                         this->size = tpl_link;
199                         *prev = this;
200                         prev = &this->next;
201                         printk(KERN_DEBUG
202                                "%s: queuing CIS tuple 0x%02x length %u\n",
203                                mmc_hostname(card->host), tpl_code, tpl_link);
204                 } else {
205                         const struct cis_tpl *tpl = cis_tpl_list + i;
206                         if (tpl_link < tpl->min_size) {
207                                 printk(KERN_ERR
208                                        "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n",
209                                        mmc_hostname(card->host),
210                                        tpl_code, tpl_link, tpl->min_size);
211                                 ret = -EINVAL;
212                         } else if (tpl->parse) {
213                                 ret = tpl->parse(card, func,
214                                                  this->data, tpl_link);
215                         }
216                         kfree(this);
217                 }
218
219                 ptr += tpl_link;
220         } while (!ret);
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
229         return ret;
230 }
231
232 int sdio_read_common_cis(struct mmc_card *card)
233 {
234         return sdio_read_cis(card, NULL);
235 }
236
237 void sdio_free_common_cis(struct mmc_card *card)
238 {
239         struct sdio_func_tuple *tuple, *victim;
240
241         tuple = card->tuples;
242
243         while (tuple) {
244                 victim = tuple;
245                 tuple = tuple->next;
246                 kfree(victim);
247         }
248
249         card->tuples = NULL;
250 }
251
252 int 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
278 void 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
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);
297 }
298