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
  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
  26static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
  27                         const unsigned char *buf, unsigned size)
  28{
  29        unsigned i, nr_strings;
  30        char **buffer, *string;
  31
  32        buf += 2;
  33        size -= 2;
  34
  35        nr_strings = 0;
  36        for (i = 0; i < size; i++) {
  37                if (buf[i] == 0xff)
  38                        break;
  39                if (buf[i] == 0)
  40                        nr_strings++;
  41        }
  42
  43        if (buf[i-1] != '\0') {
  44                printk(KERN_WARNING "SDIO: ignoring broken CISTPL_VERS_1\n");
  45                return 0;
  46        }
  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
 101static int cistpl_funce_common(struct mmc_card *card,
 102                               const unsigned char *buf, unsigned size)
 103{
 104        if (size < 0x04 || buf[0] != 0)
 105                return -EINVAL;
 106
 107        /* TPLFE_FN0_BLK_SIZE */
 108        card->cis.blksize = buf[1] | (buf[2] << 8);
 109
 110        /* TPLFE_MAX_TRAN_SPEED */
 111        card->cis.max_dtr = speed_val[(buf[3] >> 3) & 15] *
 112                            speed_unit[buf[3] & 7];
 113
 114        return 0;
 115}
 116
 117static int cistpl_funce_func(struct sdio_func *func,
 118                             const unsigned char *buf, unsigned size)
 119{
 120        unsigned vsn;
 121        unsigned min_size;
 122
 123        vsn = func->card->cccr.sdio_vsn;
 124        min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
 125
 126        if (size < min_size || buf[0] != 1)
 127                return -EINVAL;
 128
 129        /* TPLFE_MAX_BLK_SIZE */
 130        func->max_blksize = buf[12] | (buf[13] << 8);
 131
 132        /* TPLFE_ENABLE_TIMEOUT_VAL, present in ver 1.1 and above */
 133        if (vsn > SDIO_SDIO_REV_1_00)
 134                func->enable_timeout = (buf[28] | (buf[29] << 8)) * 10;
 135        else
 136                func->enable_timeout = jiffies_to_msecs(HZ);
 137
 138        return 0;
 139}
 140
 141static int cistpl_funce(struct mmc_card *card, struct sdio_func *func,
 142                        const unsigned char *buf, unsigned size)
 143{
 144        int ret;
 145
 146        /*
 147         * There should be two versions of the CISTPL_FUNCE tuple,
 148         * one for the common CIS (function 0) and a version used by
 149         * the individual function's CIS (1-7). Yet, the later has a
 150         * different length depending on the SDIO spec version.
 151         */
 152        if (func)
 153                ret = cistpl_funce_func(func, buf, size);
 154        else
 155                ret = cistpl_funce_common(card, buf, size);
 156
 157        if (ret) {
 158                printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u "
 159                       "type %u\n", mmc_hostname(card->host), size, buf[0]);
 160                return ret;
 161        }
 162
 163        return 0;
 164}
 165
 166typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,
 167                           const unsigned char *, unsigned);
 168
 169struct cis_tpl {
 170        unsigned char code;
 171        unsigned char min_size;
 172        tpl_parse_t *parse;
 173};
 174
 175static const struct cis_tpl cis_tpl_list[] = {
 176        {       0x15,   3,      cistpl_vers_1           },
 177        {       0x20,   4,      cistpl_manfid           },
 178        {       0x21,   2,      /* cistpl_funcid */     },
 179        {       0x22,   0,      cistpl_funce            },
 180};
 181
 182static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
 183{
 184        int ret;
 185        struct sdio_func_tuple *this, **prev;
 186        unsigned i, ptr = 0;
 187
 188        /*
 189         * Note that this works for the common CIS (function number 0) as
 190         * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS
 191         * have the same offset.
 192         */
 193        for (i = 0; i < 3; i++) {
 194                unsigned char x, fn;
 195
 196                if (func)
 197                        fn = func->num;
 198                else
 199                        fn = 0;
 200
 201                ret = mmc_io_rw_direct(card, 0, 0,
 202                        SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x);
 203                if (ret)
 204                        return ret;
 205                ptr |= x << (i * 8);
 206        }
 207
 208        if (func)
 209                prev = &func->tuples;
 210        else
 211                prev = &card->tuples;
 212
 213        BUG_ON(*prev);
 214
 215        do {
 216                unsigned char tpl_code, tpl_link;
 217
 218                ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code);
 219                if (ret)
 220                        break;
 221
 222                /* 0xff means we're done */
 223                if (tpl_code == 0xff)
 224                        break;
 225
 226                /* null entries have no link field or data */
 227                if (tpl_code == 0x00)
 228                        continue;
 229
 230                ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link);
 231                if (ret)
 232                        break;
 233
 234                /* a size of 0xff also means we're done */
 235                if (tpl_link == 0xff)
 236                        break;
 237
 238                this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL);
 239                if (!this)
 240                        return -ENOMEM;
 241
 242                for (i = 0; i < tpl_link; i++) {
 243                        ret = mmc_io_rw_direct(card, 0, 0,
 244                                               ptr + i, 0, &this->data[i]);
 245                        if (ret)
 246                                break;
 247                }
 248                if (ret) {
 249                        kfree(this);
 250                        break;
 251                }
 252
 253                for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
 254                        if (cis_tpl_list[i].code == tpl_code)
 255                                break;
 256                if (i >= ARRAY_SIZE(cis_tpl_list)) {
 257                        /* this tuple is unknown to the core */
 258                        this->next = NULL;
 259                        this->code = tpl_code;
 260                        this->size = tpl_link;
 261                        *prev = this;
 262                        prev = &this->next;
 263                        printk(KERN_DEBUG
 264                               "%s: queuing CIS tuple 0x%02x length %u\n",
 265                               mmc_hostname(card->host), tpl_code, tpl_link);
 266                } else {
 267                        const struct cis_tpl *tpl = cis_tpl_list + i;
 268                        if (tpl_link < tpl->min_size) {
 269                                printk(KERN_ERR
 270                                       "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n",
 271                                       mmc_hostname(card->host),
 272                                       tpl_code, tpl_link, tpl->min_size);
 273                                ret = -EINVAL;
 274                        } else if (tpl->parse) {
 275                                ret = tpl->parse(card, func,
 276                                                 this->data, tpl_link);
 277                        }
 278                        kfree(this);
 279                }
 280
 281                ptr += tpl_link;
 282        } while (!ret);
 283
 284        /*
 285         * Link in all unknown tuples found in the common CIS so that
 286         * drivers don't have to go digging in two places.
 287         */
 288        if (func)
 289                *prev = card->tuples;
 290
 291        return ret;
 292}
 293
 294int sdio_read_common_cis(struct mmc_card *card)
 295{
 296        return sdio_read_cis(card, NULL);
 297}
 298
 299void sdio_free_common_cis(struct mmc_card *card)
 300{
 301        struct sdio_func_tuple *tuple, *victim;
 302
 303        tuple = card->tuples;
 304
 305        while (tuple) {
 306                victim = tuple;
 307                tuple = tuple->next;
 308                kfree(victim);
 309        }
 310
 311        card->tuples = NULL;
 312}
 313
 314int sdio_read_func_cis(struct sdio_func *func)
 315{
 316        int ret;
 317
 318        ret = sdio_read_cis(func->card, func);
 319        if (ret)
 320                return ret;
 321
 322        /*
 323         * Since we've linked to tuples in the card structure,
 324         * we must make sure we have a reference to it.
 325         */
 326        get_device(&func->card->dev);
 327
 328        /*
 329         * Vendor/device id is optional for function CIS, so
 330         * copy it from the card structure as needed.
 331         */
 332        if (func->vendor == 0) {
 333                func->vendor = func->card->cis.vendor;
 334                func->device = func->card->cis.device;
 335        }
 336
 337        return 0;
 338}
 339
 340void sdio_free_func_cis(struct sdio_func *func)
 341{
 342        struct sdio_func_tuple *tuple, *victim;
 343
 344        tuple = func->tuples;
 345
 346        while (tuple && tuple != func->card->tuples) {
 347                victim = tuple;
 348                tuple = tuple->next;
 349                kfree(victim);
 350        }
 351
 352        func->tuples = NULL;
 353
 354        /*
 355         * We have now removed the link to the tuples in the
 356         * card structure, so remove the reference.
 357         */
 358        put_device(&func->card->dev);
 359}
 360
 361
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.