static int sdio_read_fbr(struct sdio_func *func) { int ret; uint8 data; ret = mmc_io_rw_direct(func->card, SDIO_R, SDIO_FUN_0, SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data); if (ret) goto out; data &= 0x0f;// The SDIO Standard Function code identifies those I/O functions if (data == SDIO_CLASS_NONE) return 0; if (data == 0x0f) { ret = mmc_io_rw_direct(func->card, SDIO_R, SDIO_FUN_0, SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF_EXT, 0, &data); if (ret) goto out; } func->func_class = data; out: return ret; }
/** * sdio_set_block_size - set the block size of an SDIO function * @func: SDIO function to change * @blksz: new block size or 0 to use the default. * * The default block size is the largest supported by both the function * and the host, with a maximum of 512 to ensure that arbitrarily sized * data transfer use the optimal (least) number of commands. * * A driver may call this to override the default block size set by the * core. This can be used to set a block size greater than the maximum * that reported by the card; it is the driver's responsibility to ensure * it uses a value that the card supports. * * Returns 0 on success, -EINVAL if the host does not support the * requested block size, or -EIO (etc.) if one of the resultant FBR block * size register writes failed. * */ int sdio_set_block_size(struct sdio_func *func, unsigned blksz) { int ret; if (blksz > func->card->host->max_blk_size) return -EINVAL; if (blksz == 0) { blksz = min(func->max_blksize, func->card->host->max_blk_size); blksz = min(blksz, 512u); } ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE, blksz & 0xff, NULL); if (ret) return ret; ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE + 1, (blksz >> 8) & 0xff, NULL); if (ret) return ret; func->cur_blksize = blksz; return 0; }
static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev) { int err_ret; u32 fbraddr; u8 func; brcmf_dbg(TRACE, "\n"); /* Get the Card's common CIS address */ sdiodev->func_cis_ptr[0] = brcmf_sdioh_get_cisaddr(sdiodev, SDIO_CCCR_CIS); brcmf_dbg(INFO, "Card's Common CIS Ptr = 0x%x\n", sdiodev->func_cis_ptr[0]); /* Get the Card's function CIS (for each function) */ for (fbraddr = SDIO_FBR_BASE(1), func = 1; func <= sdiodev->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { sdiodev->func_cis_ptr[func] = brcmf_sdioh_get_cisaddr(sdiodev, SDIO_FBR_CIS + fbraddr); brcmf_dbg(INFO, "Function %d CIS Ptr = 0x%x\n", func, sdiodev->func_cis_ptr[func]); } /* Enable Function 1 */ sdio_claim_host(sdiodev->func[1]); err_ret = sdio_enable_func(sdiodev->func[1]); sdio_release_host(sdiodev->func[1]); if (err_ret) brcmf_dbg(ERROR, "Failed to enable F1 Err: 0x%08x\n", err_ret); return false; }
#ifdef CONFIG_MMC_EMBEDDED_SDIO #include <linux/mmc/sdio_ids.h> #endif static int sdio_read_fbr(struct sdio_func *func) { int ret; unsigned char data; if (mmc_card_nonstd_func_interface(func->card)) { func->class = SDIO_CLASS_NONE; return 0; } ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data); if (ret) goto out; data &= 0x0f; if (data == 0x0f) { ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF_EXT, 0, &data); if (ret) goto out; } func->class = data; out:
static int 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++) { unsigned char 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; if (*prev) return -EINVAL; do { unsigned char tpl_code, tpl_link; 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) { /* warn about unknown tuples */ pr_warn_ratelimited("%s: queuing unknown" " CIS tuple 0x%02x (%u bytes)\n", mmc_hostname(card->host), tpl_code, 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; }
static int sdio_read_cis(struct mmc_host *host) { int ret = 0; unsigned int i, ptr = 0; unsigned int vendor, device; struct sdio_func_tuple *this; for (i = 0; i < 3; i++) { unsigned char x, fn = 0; ret = mmc_io_rw_direct(host, 0, 0, SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x); if (ret) return ret; ptr |= x << (i * 8); } DPRINT("ptr = 0x%x\n", ptr); do { unsigned char tpl_code, tpl_link; ret = mmc_io_rw_direct(host, 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(host, 0, 0, ptr++, 0, &tpl_link); if (ret) break; /* a size of 0xff also means we're done */ if (tpl_link == 0xff) break; this = malloc(sizeof(*this) + tpl_link); if (!this) return -ENOMEM; for (i = 0; i < tpl_link; i++) { ret = mmc_io_rw_direct(host, 0, 0, ptr + i, 0, &this->data[i]); if (ret) break; } if (ret) { free(this); break; } ptr += tpl_link; if (tpl_code == 0x20) { if (tpl_link < 4) { printf("bad CIS tuple len = %d\n", tpl_link); return -EINVAL; } vendor = this->data[0] | (this->data[1] << 8); device = this->data[2] | (this->data[3] << 8); printf("vendor = 0x%x, device = 0x%x\n", vendor, device); } } while (!ret); return ret; }
static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) { int ret; struct sdio_func_tuple *this, **prev; unsigned i, ptr = 0; /* */ for (i = 0; i < 3; i++) { unsigned char 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; BUG_ON(*prev); do { unsigned char tpl_code, tpl_link; ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code); if (ret) break; /* */ if (tpl_code == 0xff) break; /* */ if (tpl_code == 0x00) { if (card->cis.vendor == 0x70 && (card->cis.device == 0x2460 || card->cis.device == 0x0460 || card->cis.device == 0x23F1 || card->cis.device == 0x23F0)) break; else continue; } ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link); if (ret) break; /* */ 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; } /* */ 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) { /* */ this->next = NULL; this->code = tpl_code; this->size = tpl_link; *prev = this; prev = &this->next; if (ret == -ENOENT) { /* */ pr_warning("%s: queuing unknown" " CIS tuple 0x%02x (%u bytes)\n", mmc_hostname(card->host), tpl_code, tpl_link); } /* */ ret = 0; } else { /* */ kfree(this); } ptr += tpl_link; } while (!ret); /* */ if (func) *prev = card->tuples; return ret; }