staticint cis_tpl_parse(struct mmc_card *card, struct sdio_func *func, constchar *tpl_descr, conststruct cis_tpl *tpl, int tpl_count, unsignedchar code, constunsignedchar *buf, unsigned size)
{ int i, ret;
/* look for a matching code in the table */ for (i = 0; i < tpl_count; i++, tpl++) { if (tpl->code == code) break;
} if (i < tpl_count) { if (size >= tpl->min_size) { if (tpl->parse)
ret = tpl->parse(card, func, buf, size); else
ret = -EILSEQ; /* known tuple, not parsed */
} else { /* invalid tuple */
ret = -EINVAL;
} if (ret && ret != -EILSEQ && ret != -ENOENT) {
pr_err("%s: bad %s tuple 0x%02x (%u bytes)\n",
mmc_hostname(card->host), tpl_descr, code, size);
}
} else { /* unknown tuple */
ret = -ENOENT;
}
return ret;
}
staticint cistpl_funce_common(struct mmc_card *card, struct sdio_func *func, constunsignedchar *buf, unsigned size)
{ /* Only valid for the common CIS (function 0) */ if (func) return -EINVAL;
/* Only valid for the individual function's CIS (1-7) */ if (!func) return -EINVAL;
/* * This tuple has a different length depending on the SDIO spec * version.
*/
vsn = func->card->cccr.sdio_vsn;
min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
/* TPLFE_ENABLE_TIMEOUT_VAL, present in ver 1.1 and above */ if (vsn > SDIO_SDIO_REV_1_00)
func->enable_timeout = (buf[28] | (buf[29] << 8)) * 10; else
func->enable_timeout = jiffies_to_msecs(HZ);
return 0;
}
/* * Known TPLFE_TYPEs table for CISTPL_FUNCE tuples. * * Note that, unlike PCMCIA, CISTPL_FUNCE tuples are not parsed depending * on the TPLFID_FUNCTION value of the previous CISTPL_FUNCID as on SDIO * TPLFID_FUNCTION is always hardcoded to 0x0C.
*/ staticconststruct cis_tpl cis_tpl_funce_list[] = {
{ 0x00, 4, cistpl_funce_common },
{ 0x01, 0, cistpl_funce_func },
{ 0x04, 1+1+6, /* CISTPL_FUNCE_LAN_NODE_ID */ },
};
staticint sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
{ int ret; struct sdio_func_tuple *this, **prev; unsigned i, ptr = 0;
/* * Note that this works for the common CIS (function number 0) as * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS * have the same offset.
*/ for (i = 0; i < 3; i++) { unsignedchar x, fn;
if (func)
fn = func->num; else
fn = 0;
ret = mmc_io_rw_direct(card, 0, 0,
SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x); if (ret) return ret;
ptr |= x << (i * 8);
}
if (func)
prev = &func->tuples; else
prev = &card->tuples;
ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code); if (ret) break;
/* 0xff means we're done */ if (tpl_code == 0xff) break;
/* null entries have no link field or data */ if (tpl_code == 0x00) continue;
ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link); if (ret) break;
/* a size of 0xff also means we're done */ if (tpl_link == 0xff) break;
this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL); if (!this) return -ENOMEM;
for (i = 0; i < tpl_link; i++) {
ret = mmc_io_rw_direct(card, 0, 0,
ptr + i, 0, &this->data[i]); if (ret) break;
} if (ret) {
kfree(this); break;
}
/* Try to parse the CIS tuple */
ret = cis_tpl_parse(card, func, "CIS",
cis_tpl_list, ARRAY_SIZE(cis_tpl_list),
tpl_code, this->data, tpl_link); if (ret == -EILSEQ || ret == -ENOENT) { /* * The tuple is unknown or known but not parsed. * Queue the tuple for the function driver.
*/
this->next = NULL;
this->code = tpl_code;
this->size = tpl_link;
*prev = this;
prev = &this->next;
if (ret == -ENOENT) {
if (time_after(jiffies, timeout)) break;
#define FMT(type) "%s: queuing " type " CIS tuple 0x%02x [%*ph] (%u bytes)\n" /* * Tuples in this range are reserved for * vendors, so don't warn about them
*/ if (tpl_code >= 0x80 && tpl_code <= 0x8f)
pr_debug_ratelimited(FMT("vendor"),
mmc_hostname(card->host),
tpl_code, tpl_link, this->data,
tpl_link); else
pr_warn_ratelimited(FMT("unknown"),
mmc_hostname(card->host),
tpl_code, tpl_link, this->data,
tpl_link);
}
/* keep on analyzing tuples */
ret = 0;
} else { /* * We don't need the tuple anymore if it was * successfully parsed by the SDIO core or if it is * not going to be queued for a driver.
*/
kfree(this);
}
ptr += tpl_link;
} while (!ret);
/* * Link in all unknown tuples found in the common CIS so that * drivers don't have to go digging in two places.
*/ if (func)
*prev = card->tuples;
return ret;
}
int sdio_read_common_cis(struct mmc_card *card)
{ return sdio_read_cis(card, NULL);
}
int sdio_read_func_cis(struct sdio_func *func)
{ int ret;
ret = sdio_read_cis(func->card, func); if (ret) return ret;
/* * Vendor/device id is optional for function CIS, so * copy it from the card structure as needed.
*/ if (func->vendor == 0) {
func->vendor = func->card->cis.vendor;
func->device = func->card->cis.device;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.