linux/drivers/mmc/core/sdio_cis.c
<<
>>
Prefs
   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#include <linux/slab.h>
  18
  19#include <linux/mmc/host.h>
  20#include <linux/mmc/card.h>
  21#include <linux/mmc/sdio.h>
  22#include <linux/mmc/sdio_func.h>
  23
  24#include "sdio_cis.h"
  25#include "sdio_ops.h"
  26
  27static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
  28                         const unsigned char *buf, unsigned size)
  29{
  30        unsigned i, nr_strings;
  31        char **buffer, *string;
  32
  33        /* Find all null-terminated (including zero length) strings in
  34           the TPLLV1_INFO field. Trailing garbage is ignored. */
  35        buf += 2;
  36        size -= 2;
  37
  38        nr_strings = 0;
  39        for (i = 0; i < size; i++) {
  40                if (buf[i] == 0xff)
  41                        break;
  42                if (buf[i] == 0)
  43                        nr_strings++;
  44        }
  45        if (nr_strings == 0)
  46                return 0;
  47
  48        size = i;
  49
  50        buffer = kzalloc(sizeof(char*) * nr_strings + size, GFP_KERNEL);
  51        if (!buffer)
  52                return -ENOMEM;
  53
  54        string = (char*)(buffer + nr_strings);
  55
  56        for (i = 0; i < nr_strings; i++) {
  57                buffer[i] = string;
  58                strcpy(string, buf);
  59                string += strlen(string) + 1;
  60                buf += strlen(buf) + 1;
  61        }
  62
  63        if (func) {
  64                func->num_info = nr_strings;
  65                func->info = (const char**)buffer;
  66        } else {
  67                card->num_info = nr_strings;
  68                card->info = (const char**)buffer;
  69        }
  70
  71        return 0;
  72}
  73
  74static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func,
  75                         const unsigned char *buf, unsigned size)
  76{
  77        unsigned int vendor, device;
  78
  79        /* TPLMID_MANF */
  80        vendor = buf[0] | (buf[1] << 8);
  81
  82        /* TPLMID_CARD */
  83        device = buf[2] | (buf[3] << 8);
  84
  85        if (func) {
  86                func->vendor = vendor;
  87                func->device = device;
  88        } else {
  89                card->cis.vendor = vendor;
  90                card->cis.device = device;
  91        }
  92
  93        return 0;
  94}
  95
  96static const unsigned char speed_val[16] =
  97        { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
  98static const unsigned int speed_unit[8] =
  99        { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
 100
 101
 102typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,
 103                           const unsigned char *, unsigned);
 104
 105struct cis_tpl {
 106        unsigned char code;
 107        unsigned char min_size;
 108        tpl_parse_t *parse;
 109};
 110
 111static int cis_tpl_parse(struct mmc_card *card, struct sdio_func *func,
 112                         const char *tpl_descr,
 113                         const struct cis_tpl *tpl, int tpl_count,
 114                         unsigned char code,
 115                         const unsigned char *buf, unsigned size)
 116{
 117        int i, ret;
 118
 119        /* look for a matching code in the table */
 120        for (i = 0; i < tpl_count; i++, tpl++) {
 121                if (tpl->code == code)
 122                        break;
 123        }
 124        if (i < tpl_count) {
 125                if (size >= tpl->min_size) {
 126                        if (tpl->parse)
 127                                ret = tpl->parse(card, func, buf, size);
 128                        else
 129                                ret = -EILSEQ;  /* known tuple, not parsed */
 130                } else {
 131                        /* invalid tuple */
 132                        ret = -EINVAL;
 133                }
 134                if (ret && ret != -EILSEQ && ret != -ENOENT) {
 135                        printk(KERN_ERR "%s: bad %s tuple 0x%02x (%u bytes)\n",
 136                               mmc_hostname(card->host), tpl_descr, code, size);
 137                }
 138        } else {
 139                /* unknown tuple */
 140                ret = -ENOENT;
 141        }
 142
 143        return ret;
 144}
 145
 146static int cistpl_funce_common(struct mmc_card *card, struct sdio_func *func,
 147                               const unsigned char *buf, unsigned size)
 148{
 149        /* Only valid for the common CIS (function 0) */
 150        if (func)
 151                return -EINVAL;
 152
 153        /* TPLFE_FN0_BLK_SIZE */
 154        card->cis.blksize = buf[1] | (buf[2] << 8);
 155
 156        /* TPLFE_MAX_TRAN_SPEED */
 157        card->cis.max_dtr = speed_val[(buf[3] >> 3) & 15] *
 158                            speed_unit[buf[3] & 7];
 159
 160        return 0;
 161}
 162
 163static int cistpl_funce_func(struct mmc_card *card, struct sdio_func *func,
 164                             const unsigned char *buf, unsigned size)
 165{
 166        unsigned vsn;
 167        unsigned min_size;
 168
 169        /* Only valid for the individual function's CIS (1-7) */
 170        if (!func)
 171                return -EINVAL;
 172
 173        /*
 174         * This tuple has a different length depending on the SDIO spec
 175         * version.
 176         */
 177        vsn = func->card->cccr.sdio_vsn;
 178        min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
 179
 180        if (size < min_size)
 181                return -EINVAL;
 182
 183        /* TPLFE_MAX_BLK_SIZE */
 184        func->max_blksize = buf[12] | (buf[13] << 8);
 185
 186        /* TPLFE_ENABLE_TIMEOUT_VAL, present in ver 1.1 and above */
 187        if (vsn > SDIO_SDIO_REV_1_00)
 188                func->enable_timeout = (buf[28] | (buf[29] << 8)) * 10;
 189        else
 190                func->enable_timeout = jiffies_to_msecs(HZ);
 191
 192        return 0;
 193}
 194
 195/*
 196 * Known TPLFE_TYPEs table for CISTPL_FUNCE tuples.
 197 *
 198 * Note that, unlike PCMCIA, CISTPL_FUNCE tuples are not parsed depending
 199 * on the TPLFID_FUNCTION value of the previous CISTPL_FUNCID as on SDIO
 200 * TPLFID_FUNCTION is always hardcoded to 0x0C.
 201 */
 202static const struct cis_tpl cis_tpl_funce_list[] = {
 203        {       0x00,   4,      cistpl_funce_common             },
 204        {       0x01,   0,      cistpl_funce_func               },
 205        {       0x04,   1+1+6,  /* CISTPL_FUNCE_LAN_NODE_ID */  },
 206};
 207
 208static int cistpl_funce(struct mmc_card *card, struct sdio_func *func,
 209                        const unsigned char *buf, unsigned size)
 210{
 211        if (size < 1)
 212                return -EINVAL;
 213
 214        return cis_tpl_parse(card, func, "CISTPL_FUNCE",
 215                             cis_tpl_funce_list,
 216                             ARRAY_SIZE(cis_tpl_funce_list),
 217                             buf[0], buf, size);
 218}
 219
 220/* Known TPL_CODEs table for CIS tuples */
 221static const struct cis_tpl cis_tpl_list[] = {
 222        {       0x15,   3,      cistpl_vers_1           },
 223        {       0x20,   4,      cistpl_manfid           },
 224        {       0x21,   2,      /* cistpl_funcid */     },
 225        {       0x22,   0,      cistpl_funce            },
 226};
 227
 228static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
 229{
 230        int ret;
 231        struct sdio_func_tuple *this, **prev;
 232        unsigned i, ptr = 0;
 233
 234        /*
 235         * Note that this works for the common CIS (function number 0) as
 236         * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS
 237         * have the same offset.
 238         */
 239        for (i = 0; i < 3; i++) {
 240                unsigned char x, fn;
 241
 242                if (func)
 243                        fn = func->num;
 244                else
 245                        fn = 0;
 246
 247                ret = mmc_io_rw_direct(card, 0, 0,
 248                        SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x);
 249                if (ret)
 250                        return ret;
 251                ptr |= x << (i * 8);
 252        }
 253
 254        if (func)
 255                prev = &func->tuples;
 256        else
 257                prev = &card->tuples;
 258
 259        BUG_ON(*prev);
 260
 261        do {
 262                unsigned char tpl_code, tpl_link;
 263
 264                ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code);
 265                if (ret)
 266                        break;
 267
 268                /* 0xff means we're done */
 269                if (tpl_code == 0xff)
 270                        break;
 271
 272                /* null entries have no link field or data */
 273                if (tpl_code == 0x00)
 274                        continue;
 275
 276                ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link);
 277                if (ret)
 278                        break;
 279
 280                /* a size of 0xff also means we're done */
 281                if (tpl_link == 0xff)
 282                        break;
 283
 284                this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL);
 285                if (!this)
 286                        return -ENOMEM;
 287
 288                for (i = 0; i < tpl_link; i++) {
 289                        ret = mmc_io_rw_direct(card, 0, 0,
 290                                               ptr + i, 0, &this->data[i]);
 291                        if (ret)
 292                                break;
 293                }
 294                if (ret) {
 295                        kfree(this);
 296                        break;
 297                }
 298
 299                /* Try to parse the CIS tuple */
 300                ret = cis_tpl_parse(card, func, "CIS",
 301                                    cis_tpl_list, ARRAY_SIZE(cis_tpl_list),
 302                                    tpl_code, this->data, tpl_link);
 303                if (ret == -EILSEQ || ret == -ENOENT) {
 304                        /*
 305                         * The tuple is unknown or known but not parsed.
 306                         * Queue the tuple for the function driver.
 307                         */
 308                        this->next = NULL;
 309                        this->code = tpl_code;
 310                        this->size = tpl_link;
 311                        *prev = this;
 312                        prev = &this->next;
 313
 314                        if (ret == -ENOENT) {
 315                                /* warn about unknown tuples */
 316                                printk(KERN_WARNING "%s: queuing unknown"
 317                                       " CIS tuple 0x%02x (%u bytes)\n",
 318                                       mmc_hostname(card->host),
 319                                       tpl_code, tpl_link);
 320                        }
 321
 322                        /* keep on analyzing tuples */
 323                        ret = 0;
 324                } else {
 325                        /*
 326                         * We don't need the tuple anymore if it was
 327                         * successfully parsed by the SDIO core or if it is
 328                         * not going to be queued for a driver.
 329                         */
 330                        kfree(this);
 331                }
 332
 333                ptr += tpl_link;
 334        } while (!ret);
 335
 336        /*
 337         * Link in all unknown tuples found in the common CIS so that
 338         * drivers don't have to go digging in two places.
 339         */
 340        if (func)
 341                *prev = card->tuples;
 342
 343        return ret;
 344}
 345
 346int sdio_read_common_cis(struct mmc_card *card)
 347{
 348        return sdio_read_cis(card, NULL);
 349}
 350
 351void sdio_free_common_cis(struct mmc_card *card)
 352{
 353        struct sdio_func_tuple *tuple, *victim;
 354
 355        tuple = card->tuples;
 356
 357        while (tuple) {
 358                victim = tuple;
 359                tuple = tuple->next;
 360                kfree(victim);
 361        }
 362
 363        card->tuples = NULL;
 364}
 365
 366int sdio_read_func_cis(struct sdio_func *func)
 367{
 368        int ret;
 369
 370        ret = sdio_read_cis(func->card, func);
 371        if (ret)
 372                return ret;
 373
 374        /*
 375         * Since we've linked to tuples in the card structure,
 376         * we must make sure we have a reference to it.
 377         */
 378        get_device(&func->card->dev);
 379
 380        /*
 381         * Vendor/device id is optional for function CIS, so
 382         * copy it from the card structure as needed.
 383         */
 384        if (func->vendor == 0) {
 385                func->vendor = func->card->cis.vendor;
 386                func->device = func->card->cis.device;
 387        }
 388
 389        return 0;
 390}
 391
 392void sdio_free_func_cis(struct sdio_func *func)
 393{
 394        struct sdio_func_tuple *tuple, *victim;
 395
 396        tuple = func->tuples;
 397
 398        while (tuple && tuple != func->card->tuples) {
 399                victim = tuple;
 400                tuple = tuple->next;
 401                kfree(victim);
 402        }
 403
 404        func->tuples = NULL;
 405
 406        /*
 407         * We have now removed the link to the tuples in the
 408         * card structure, so remove the reference.
 409         */
 410        put_device(&func->card->dev);
 411}
 412
 413