sdmmc_io.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. /*
  2. * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
  3. * Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <inttypes.h>
  18. #include "sdmmc_common.h"
  19. #include "esp_attr.h"
  20. #include "esp_compiler.h"
  21. #define CIS_TUPLE(NAME) (cis_tuple_t) {.code=CISTPL_CODE_##NAME, .name=#NAME, .func=&cis_tuple_func_default, }
  22. #define CIS_TUPLE_WITH_FUNC(NAME, FUNC) (cis_tuple_t) {.code=CISTPL_CODE_##NAME, .name=#NAME, .func=&(FUNC), }
  23. #define CIS_CHECK_SIZE(SIZE, MINIMAL) do {int store_size = (SIZE); if((store_size) < (MINIMAL)) return ESP_ERR_INVALID_SIZE;} while(0)
  24. #define CIS_CHECK_UNSUPPORTED(COND) do {if(!(COND)) return ESP_ERR_NOT_SUPPORTED;} while(0)
  25. #define CIS_GET_MINIMAL_SIZE 32
  26. typedef esp_err_t (*cis_tuple_info_func_t)(const void* tuple_info, uint8_t* data, FILE* fp);
  27. typedef struct {
  28. int code;
  29. const char *name;
  30. cis_tuple_info_func_t func;
  31. } cis_tuple_t;
  32. static const char* TAG = "sdmmc_io";
  33. static esp_err_t cis_tuple_func_default(const void* p, uint8_t* data, FILE* fp);
  34. static esp_err_t cis_tuple_func_manfid(const void* p, uint8_t* data, FILE* fp);
  35. static esp_err_t cis_tuple_func_cftable_entry(const void* p, uint8_t* data, FILE* fp);
  36. static esp_err_t cis_tuple_func_end(const void* p, uint8_t* data, FILE* fp);
  37. static const cis_tuple_t cis_table[] = {
  38. CIS_TUPLE(NULL),
  39. CIS_TUPLE(DEVICE),
  40. CIS_TUPLE(CHKSUM),
  41. CIS_TUPLE(VERS1),
  42. CIS_TUPLE(ALTSTR),
  43. CIS_TUPLE(CONFIG),
  44. CIS_TUPLE_WITH_FUNC(CFTABLE_ENTRY, cis_tuple_func_cftable_entry),
  45. CIS_TUPLE_WITH_FUNC(MANFID, cis_tuple_func_manfid),
  46. CIS_TUPLE(FUNCID),
  47. CIS_TUPLE(FUNCE),
  48. CIS_TUPLE(VENDER_BEGIN),
  49. CIS_TUPLE(VENDER_END),
  50. CIS_TUPLE(SDIO_STD),
  51. CIS_TUPLE(SDIO_EXT),
  52. CIS_TUPLE_WITH_FUNC(END, cis_tuple_func_end),
  53. };
  54. esp_err_t sdmmc_io_reset(sdmmc_card_t* card)
  55. {
  56. uint8_t sdio_reset = CCCR_CTL_RES;
  57. esp_err_t err = sdmmc_io_rw_direct(card, 0, SD_IO_CCCR_CTL, SD_ARG_CMD52_WRITE, &sdio_reset);
  58. if (err == ESP_ERR_TIMEOUT || (host_is_spi(card) && err == ESP_ERR_NOT_SUPPORTED)) {
  59. /* Non-IO cards are allowed to time out (in SD mode) or
  60. * return "invalid command" error (in SPI mode).
  61. */
  62. } else if (err == ESP_ERR_NOT_FOUND) {
  63. ESP_LOGD(TAG, "%s: card not present", __func__);
  64. return err;
  65. } else if (err != ESP_OK) {
  66. ESP_LOGE(TAG, "%s: unexpected return: 0x%x", __func__, err );
  67. return err;
  68. }
  69. return ESP_OK;
  70. }
  71. esp_err_t sdmmc_init_io(sdmmc_card_t* card)
  72. {
  73. /* IO_SEND_OP_COND(CMD5), Determine if the card is an IO card.
  74. * Non-IO cards will not respond to this command.
  75. */
  76. esp_err_t err = sdmmc_io_send_op_cond(card, 0, &card->ocr);
  77. if (err != ESP_OK) {
  78. ESP_LOGD(TAG, "%s: io_send_op_cond (1) returned 0x%x; not IO card", __func__, err);
  79. card->is_sdio = 0;
  80. card->is_mem = 1;
  81. } else {
  82. card->is_sdio = 1;
  83. if (card->ocr & SD_IO_OCR_MEM_PRESENT) {
  84. ESP_LOGD(TAG, "%s: Combination card", __func__);
  85. card->is_mem = 1;
  86. } else {
  87. ESP_LOGD(TAG, "%s: IO-only card", __func__);
  88. card->is_mem = 0;
  89. }
  90. card->num_io_functions = SD_IO_OCR_NUM_FUNCTIONS(card->ocr);
  91. ESP_LOGD(TAG, "%s: number of IO functions: %d", __func__, card->num_io_functions);
  92. if (card->num_io_functions == 0) {
  93. card->is_sdio = 0;
  94. }
  95. uint32_t host_ocr = get_host_ocr(card->host.io_voltage);
  96. host_ocr &= card->ocr;
  97. err = sdmmc_io_send_op_cond(card, host_ocr, &card->ocr);
  98. if (err != ESP_OK) {
  99. ESP_LOGE(TAG, "%s: sdmmc_io_send_op_cond (1) returned 0x%x", __func__, err);
  100. return err;
  101. }
  102. err = sdmmc_io_enable_int(card);
  103. if (err != ESP_OK) {
  104. ESP_LOGD(TAG, "%s: sdmmc_enable_int failed (0x%x)", __func__, err);
  105. }
  106. }
  107. return ESP_OK;
  108. }
  109. esp_err_t sdmmc_init_io_bus_width(sdmmc_card_t* card)
  110. {
  111. esp_err_t err;
  112. card->log_bus_width = 0;
  113. if (card->host.flags & SDMMC_HOST_FLAG_4BIT) {
  114. uint8_t card_cap = 0;
  115. err = sdmmc_io_rw_direct(card, 0, SD_IO_CCCR_CARD_CAP,
  116. SD_ARG_CMD52_READ, &card_cap);
  117. if (err != ESP_OK) {
  118. ESP_LOGE(TAG, "%s: sdmmc_io_rw_direct (read SD_IO_CCCR_CARD_CAP) returned 0x%0x", __func__, err);
  119. return err;
  120. }
  121. ESP_LOGD(TAG, "IO card capabilities byte: %02x", card_cap);
  122. if (!(card_cap & CCCR_CARD_CAP_LSC) ||
  123. (card_cap & CCCR_CARD_CAP_4BLS)) {
  124. // This card supports 4-bit bus mode
  125. uint8_t bus_width = CCCR_BUS_WIDTH_4;
  126. err = sdmmc_io_rw_direct(card, 0, SD_IO_CCCR_BUS_WIDTH,
  127. SD_ARG_CMD52_WRITE, &bus_width);
  128. if (err != ESP_OK) {
  129. ESP_LOGE(TAG, "%s: sdmmc_io_rw_direct (write SD_IO_CCCR_BUS_WIDTH) returned 0x%0x", __func__, err);
  130. return err;
  131. }
  132. card->log_bus_width = 2;
  133. }
  134. }
  135. return ESP_OK;
  136. }
  137. esp_err_t sdmmc_io_enable_hs_mode(sdmmc_card_t* card)
  138. {
  139. /* If the host is configured to use low frequency, don't attempt to switch */
  140. if (card->host.max_freq_khz < SDMMC_FREQ_DEFAULT) {
  141. card->max_freq_khz = card->host.max_freq_khz;
  142. return ESP_OK;
  143. } else if (card->host.max_freq_khz < SDMMC_FREQ_HIGHSPEED) {
  144. card->max_freq_khz = SDMMC_FREQ_DEFAULT;
  145. return ESP_OK;
  146. }
  147. /* For IO cards, do write + read operation on "High Speed" register,
  148. * setting EHS bit. If both EHS and SHS read back as set, then HS mode
  149. * has been enabled.
  150. */
  151. uint8_t val = CCCR_HIGHSPEED_ENABLE;
  152. esp_err_t err = sdmmc_io_rw_direct(card, 0, SD_IO_CCCR_HIGHSPEED,
  153. SD_ARG_CMD52_WRITE | SD_ARG_CMD52_EXCHANGE, &val);
  154. if (err != ESP_OK) {
  155. ESP_LOGD(TAG, "%s: sdmmc_io_rw_direct returned 0x%x", __func__, err);
  156. return err;
  157. }
  158. ESP_LOGD(TAG, "%s: CCCR_HIGHSPEED=0x%02x", __func__, val);
  159. const uint8_t hs_mask = CCCR_HIGHSPEED_ENABLE | CCCR_HIGHSPEED_SUPPORT;
  160. if ((val & hs_mask) != hs_mask) {
  161. return ESP_ERR_NOT_SUPPORTED;
  162. }
  163. card->max_freq_khz = SDMMC_FREQ_HIGHSPEED;
  164. return ESP_OK;
  165. }
  166. esp_err_t sdmmc_io_send_op_cond(sdmmc_card_t* card, uint32_t ocr, uint32_t *ocrp)
  167. {
  168. esp_err_t err = ESP_OK;
  169. sdmmc_command_t cmd = {
  170. .flags = SCF_CMD_BCR | SCF_RSP_R4,
  171. .arg = ocr,
  172. .opcode = SD_IO_SEND_OP_COND
  173. };
  174. for (size_t i = 0; i < 100; i++) {
  175. err = sdmmc_send_cmd(card, &cmd);
  176. if (err != ESP_OK) {
  177. break;
  178. }
  179. if ((MMC_R4(cmd.response) & SD_IO_OCR_MEM_READY) ||
  180. ocr == 0) {
  181. break;
  182. }
  183. err = ESP_ERR_TIMEOUT;
  184. vTaskDelay(SDMMC_IO_SEND_OP_COND_DELAY_MS / portTICK_PERIOD_MS);
  185. }
  186. if (err == ESP_OK && ocrp != NULL)
  187. *ocrp = MMC_R4(cmd.response);
  188. return err;
  189. }
  190. esp_err_t sdmmc_io_rw_direct(sdmmc_card_t* card, int func,
  191. uint32_t reg, uint32_t arg, uint8_t *byte)
  192. {
  193. esp_err_t err;
  194. sdmmc_command_t cmd = {
  195. .flags = SCF_CMD_AC | SCF_RSP_R5,
  196. .arg = 0,
  197. .opcode = SD_IO_RW_DIRECT
  198. };
  199. arg |= (func & SD_ARG_CMD52_FUNC_MASK) << SD_ARG_CMD52_FUNC_SHIFT;
  200. arg |= (reg & SD_ARG_CMD52_REG_MASK) << SD_ARG_CMD52_REG_SHIFT;
  201. arg |= (*byte & SD_ARG_CMD52_DATA_MASK) << SD_ARG_CMD52_DATA_SHIFT;
  202. cmd.arg = arg;
  203. err = sdmmc_send_cmd(card, &cmd);
  204. if (err != ESP_OK) {
  205. ESP_LOGV(TAG, "%s: sdmmc_send_cmd returned 0x%x", __func__, err);
  206. return err;
  207. }
  208. *byte = SD_R5_DATA(cmd.response);
  209. return ESP_OK;
  210. }
  211. esp_err_t sdmmc_io_read_byte(sdmmc_card_t* card, uint32_t function,
  212. uint32_t addr, uint8_t *out_byte)
  213. {
  214. esp_err_t ret = sdmmc_io_rw_direct(card, function, addr, SD_ARG_CMD52_READ, out_byte);
  215. if (unlikely(ret != ESP_OK)) {
  216. ESP_LOGE(TAG, "%s: sdmmc_io_rw_direct (read 0x%" PRIx32 ") returned 0x%x", __func__, addr, ret);
  217. }
  218. return ret;
  219. }
  220. esp_err_t sdmmc_io_write_byte(sdmmc_card_t* card, uint32_t function,
  221. uint32_t addr, uint8_t in_byte, uint8_t* out_byte)
  222. {
  223. uint8_t tmp_byte = in_byte;
  224. esp_err_t ret = sdmmc_io_rw_direct(card, function, addr,
  225. SD_ARG_CMD52_WRITE | SD_ARG_CMD52_EXCHANGE, &tmp_byte);
  226. if (unlikely(ret != ESP_OK)) {
  227. ESP_LOGE(TAG, "%s: sdmmc_io_rw_direct (write 0x%" PRIu32 ") returned 0x%x", __func__, addr, ret);
  228. return ret;
  229. }
  230. if (out_byte != NULL) {
  231. *out_byte = tmp_byte;
  232. }
  233. return ESP_OK;
  234. }
  235. esp_err_t sdmmc_io_rw_extended(sdmmc_card_t* card, int func,
  236. uint32_t reg, int arg, void *datap, size_t datalen)
  237. {
  238. esp_err_t err;
  239. const size_t max_byte_transfer_size = 512;
  240. sdmmc_command_t cmd = {
  241. .flags = SCF_CMD_AC | SCF_RSP_R5,
  242. .arg = 0,
  243. .opcode = SD_IO_RW_EXTENDED,
  244. .data = datap,
  245. .datalen = datalen,
  246. .blklen = max_byte_transfer_size /* TODO: read max block size from CIS */
  247. };
  248. uint32_t count; /* number of bytes or blocks, depending on transfer mode */
  249. if (arg & SD_ARG_CMD53_BLOCK_MODE) {
  250. if (cmd.datalen % cmd.blklen != 0) {
  251. return ESP_ERR_INVALID_SIZE;
  252. }
  253. count = cmd.datalen / cmd.blklen;
  254. } else {
  255. if (datalen > max_byte_transfer_size) {
  256. /* TODO: split into multiple operations? */
  257. return ESP_ERR_INVALID_SIZE;
  258. }
  259. if (datalen == max_byte_transfer_size) {
  260. count = 0; // See 5.3.1 SDIO simplifed spec
  261. } else {
  262. count = datalen;
  263. }
  264. cmd.blklen = datalen;
  265. }
  266. arg |= (func & SD_ARG_CMD53_FUNC_MASK) << SD_ARG_CMD53_FUNC_SHIFT;
  267. arg |= (reg & SD_ARG_CMD53_REG_MASK) << SD_ARG_CMD53_REG_SHIFT;
  268. arg |= (count & SD_ARG_CMD53_LENGTH_MASK) << SD_ARG_CMD53_LENGTH_SHIFT;
  269. cmd.arg = arg;
  270. if ((arg & SD_ARG_CMD53_WRITE) == 0) {
  271. cmd.flags |= SCF_CMD_READ;
  272. }
  273. err = sdmmc_send_cmd(card, &cmd);
  274. if (err != ESP_OK) {
  275. ESP_LOGE(TAG, "%s: sdmmc_send_cmd returned 0x%x", __func__, err);
  276. return err;
  277. }
  278. return ESP_OK;
  279. }
  280. esp_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function,
  281. uint32_t addr, void* dst, size_t size)
  282. {
  283. /* host quirk: SDIO transfer with length not divisible by 4 bytes
  284. * has to be split into two transfers: one with aligned length,
  285. * the other one for the remaining 1-3 bytes.
  286. */
  287. uint8_t *pc_dst = dst;
  288. while (size > 0) {
  289. size_t size_aligned = size & (~3);
  290. size_t will_transfer = size_aligned > 0 ? size_aligned : size;
  291. // Note: sdmmc_io_rw_extended has an internal timeout,
  292. // typically SDMMC_DEFAULT_CMD_TIMEOUT_MS
  293. esp_err_t err = sdmmc_io_rw_extended(card, function, addr,
  294. SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT,
  295. pc_dst, will_transfer);
  296. if (unlikely(err != ESP_OK)) {
  297. return err;
  298. }
  299. pc_dst += will_transfer;
  300. size -= will_transfer;
  301. addr += will_transfer;
  302. }
  303. return ESP_OK;
  304. }
  305. esp_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function,
  306. uint32_t addr, const void* src, size_t size)
  307. {
  308. /* same host quirk as in sdmmc_io_read_bytes */
  309. const uint8_t *pc_src = (const uint8_t*) src;
  310. while (size > 0) {
  311. size_t size_aligned = size & (~3);
  312. size_t will_transfer = size_aligned > 0 ? size_aligned : size;
  313. // Note: sdmmc_io_rw_extended has an internal timeout,
  314. // typically SDMMC_DEFAULT_CMD_TIMEOUT_MS
  315. esp_err_t err = sdmmc_io_rw_extended(card, function, addr,
  316. SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT,
  317. (void*) pc_src, will_transfer);
  318. if (unlikely(err != ESP_OK)) {
  319. return err;
  320. }
  321. pc_src += will_transfer;
  322. size -= will_transfer;
  323. addr += will_transfer;
  324. }
  325. return ESP_OK;
  326. }
  327. esp_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function,
  328. uint32_t addr, void* dst, size_t size)
  329. {
  330. if (unlikely(size % 4 != 0)) {
  331. return ESP_ERR_INVALID_SIZE;
  332. }
  333. return sdmmc_io_rw_extended(card, function, addr,
  334. SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE,
  335. dst, size);
  336. }
  337. esp_err_t sdmmc_io_write_blocks(sdmmc_card_t* card, uint32_t function,
  338. uint32_t addr, const void* src, size_t size)
  339. {
  340. if (unlikely(size % 4 != 0)) {
  341. return ESP_ERR_INVALID_SIZE;
  342. }
  343. return sdmmc_io_rw_extended(card, function, addr,
  344. SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE,
  345. (void*) src, size);
  346. }
  347. esp_err_t sdmmc_io_enable_int(sdmmc_card_t* card)
  348. {
  349. if (card->host.io_int_enable == NULL) {
  350. return ESP_ERR_NOT_SUPPORTED;
  351. }
  352. return (*card->host.io_int_enable)(card->host.slot);
  353. }
  354. esp_err_t sdmmc_io_wait_int(sdmmc_card_t* card, TickType_t timeout_ticks)
  355. {
  356. if (card->host.io_int_wait == NULL) {
  357. return ESP_ERR_NOT_SUPPORTED;
  358. }
  359. return (*card->host.io_int_wait)(card->host.slot, timeout_ticks);
  360. }
  361. /*
  362. * Print the CIS information of a CIS card, currently only ESP slave supported.
  363. */
  364. static esp_err_t cis_tuple_func_default(const void* p, uint8_t* data, FILE* fp)
  365. {
  366. const cis_tuple_t* tuple = (const cis_tuple_t*)p;
  367. uint8_t code = *(data++);
  368. int size = *(data++);
  369. if (tuple) {
  370. fprintf(fp, "TUPLE: %s, size: %d: ", tuple->name, size);
  371. } else {
  372. fprintf(fp, "TUPLE: unknown(%02X), size: %d: ", code, size);
  373. }
  374. for (int i = 0; i < size; i++) fprintf(fp, "%02X ", *(data++));
  375. fprintf(fp, "\n");
  376. return ESP_OK;
  377. }
  378. static esp_err_t cis_tuple_func_manfid(const void* p, uint8_t* data, FILE* fp)
  379. {
  380. const cis_tuple_t* tuple = (const cis_tuple_t*)p;
  381. data++;
  382. int size = *(data++);
  383. fprintf(fp, "TUPLE: %s, size: %d\n", tuple->name, size);
  384. CIS_CHECK_SIZE(size, 4);
  385. fprintf(fp, " MANF: %04X, CARD: %04X\n", *(uint16_t*)(data), *(uint16_t*)(data+2));
  386. return ESP_OK;
  387. }
  388. static esp_err_t cis_tuple_func_end(const void* p, uint8_t* data, FILE* fp)
  389. {
  390. const cis_tuple_t* tuple = (const cis_tuple_t*)p;
  391. fprintf(fp, "TUPLE: %s\n", tuple->name);
  392. return ESP_OK;
  393. }
  394. static esp_err_t cis_tuple_func_cftable_entry(const void* p, uint8_t* data, FILE* fp)
  395. {
  396. const cis_tuple_t* tuple = (const cis_tuple_t*)p;
  397. data++;
  398. int size = *(data++);
  399. fprintf(fp, "TUPLE: %s, size: %d\n", tuple->name, size);
  400. CIS_CHECK_SIZE(size, 2);
  401. CIS_CHECK_SIZE(size--, 1);
  402. bool interface = data[0] & BIT(7);
  403. bool def = data[0] & BIT(6);
  404. int conf_ent_num = data[0] & 0x3F;
  405. fprintf(fp, " INDX: %02X, Intface: %d, Default: %d, Conf-Entry-Num: %d\n", *(data++), interface, def, conf_ent_num);
  406. if (interface) {
  407. CIS_CHECK_SIZE(size--, 1);
  408. fprintf(fp, " IF: %02X\n", *(data++));
  409. }
  410. CIS_CHECK_SIZE(size--, 1);
  411. bool misc = data[0] & BIT(7);
  412. int mem_space = (data[0] >> 5 )&(0x3);
  413. bool irq = data[0] & BIT(4);
  414. bool io_sp = data[0] & BIT(3);
  415. bool timing = data[0] & BIT(2);
  416. int power = data[0] & 3;
  417. fprintf(fp, " FS: %02X, misc: %d, mem_space: %d, irq: %d, io_space: %d, timing: %d, power: %d\n", *(data++), misc, mem_space, irq, io_sp, timing, power);
  418. CIS_CHECK_UNSUPPORTED(power == 0); //power descriptor is not handled yet
  419. CIS_CHECK_UNSUPPORTED(!timing); //timing descriptor is not handled yet
  420. CIS_CHECK_UNSUPPORTED(!io_sp); //io space descriptor is not handled yet
  421. if (irq) {
  422. CIS_CHECK_SIZE(size--, 1);
  423. bool mask = data[0] & BIT(4);
  424. fprintf(fp, " IR: %02X, mask: %d, ",*(data++), mask);
  425. if (mask) {
  426. CIS_CHECK_SIZE(size, 2);
  427. size-=2;
  428. fprintf(fp, " IRQ: %02X %02X\n", data[0], data[1]);
  429. data+=2;
  430. }
  431. }
  432. if (mem_space) {
  433. CIS_CHECK_SIZE(size, 2);
  434. size-=2;
  435. CIS_CHECK_UNSUPPORTED(mem_space==1); //other cases not handled yet
  436. int len = *(uint16_t*)data;
  437. fprintf(fp, " LEN: %04X\n", len);
  438. data+=2;
  439. }
  440. CIS_CHECK_UNSUPPORTED(misc==0); //misc descriptor is not handled yet
  441. return ESP_OK;
  442. }
  443. static const cis_tuple_t* get_tuple(uint8_t code)
  444. {
  445. for (int i = 0; i < sizeof(cis_table)/sizeof(cis_tuple_t); i++) {
  446. if (code == cis_table[i].code) return &cis_table[i];
  447. }
  448. return NULL;
  449. }
  450. esp_err_t sdmmc_io_print_cis_info(uint8_t* buffer, size_t buffer_size, FILE* fp)
  451. {
  452. ESP_LOG_BUFFER_HEXDUMP("CIS", buffer, buffer_size, ESP_LOG_DEBUG);
  453. if (!fp) fp = stdout;
  454. uint8_t* cis = buffer;
  455. do {
  456. const cis_tuple_t* tuple = get_tuple(cis[0]);
  457. int size = cis[1];
  458. esp_err_t ret = ESP_OK;
  459. if (tuple) {
  460. ret = tuple->func(tuple, cis, fp);
  461. } else {
  462. ret = cis_tuple_func_default(NULL, cis, fp);
  463. }
  464. if (ret != ESP_OK) return ret;
  465. cis += 2 + size;
  466. if (tuple && tuple->code == CISTPL_CODE_END) break;
  467. } while (cis < buffer + buffer_size) ;
  468. return ESP_OK;
  469. }
  470. /**
  471. * Check tuples in the buffer.
  472. *
  473. * @param buf Buffer to check
  474. * @param buffer_size Size of the buffer
  475. * @param inout_cis_offset
  476. * - input: the last cis_offset, relative to the beginning of the buf. -1 if
  477. * this buffer begin with the tuple length, otherwise should be no smaller than
  478. * zero.
  479. * - output: when the end tuple found, output offset of the CISTPL_CODE_END
  480. * byte + 1 (relative to the beginning of the buffer; when not found, output
  481. * the address of next tuple code.
  482. *
  483. * @return true if found, false if haven't.
  484. */
  485. static bool check_tuples_in_buffer(uint8_t* buf, int buffer_size, int* inout_cis_offset)
  486. {
  487. int cis_offset = *inout_cis_offset;
  488. if (cis_offset == -1) {
  489. //the CIS code is checked in the last buffer, skip to next tuple
  490. cis_offset += buf[0] + 2;
  491. }
  492. assert(cis_offset >= 0);
  493. while (1) {
  494. if (cis_offset < buffer_size) {
  495. //A CIS code in the buffer, check it
  496. if (buf[cis_offset] == CISTPL_CODE_END) {
  497. *inout_cis_offset = cis_offset + 1;
  498. return true;
  499. }
  500. }
  501. if (cis_offset + 1 < buffer_size) {
  502. cis_offset += buf[cis_offset+1] + 2;
  503. } else {
  504. break;
  505. }
  506. }
  507. *inout_cis_offset = cis_offset;
  508. return false;
  509. }
  510. esp_err_t sdmmc_io_get_cis_data(sdmmc_card_t* card, uint8_t* out_buffer, size_t buffer_size, size_t* inout_cis_size)
  511. {
  512. esp_err_t ret = ESP_OK;
  513. WORD_ALIGNED_ATTR uint8_t buf[CIS_GET_MINIMAL_SIZE];
  514. /* Pointer to size is a mandatory parameter */
  515. assert(inout_cis_size);
  516. /*
  517. * CIS region exist in 0x1000~0x17FFF of FUNC 0, get the start address of it
  518. * from CCCR register.
  519. */
  520. uint32_t addr;
  521. ret = sdmmc_io_read_bytes(card, 0, 9, &addr, 3);
  522. if (ret != ESP_OK) return ret;
  523. //the sdmmc_io driver reads 4 bytes, the most significant byte is not the address.
  524. addr &= 0xffffff;
  525. if (addr < 0x1000 || addr > 0x17FFF) {
  526. return ESP_ERR_INVALID_RESPONSE;
  527. }
  528. /*
  529. * To avoid reading too long, take the input value as limitation if
  530. * existing.
  531. */
  532. size_t max_reading = UINT32_MAX;
  533. if (*inout_cis_size != 0) {
  534. max_reading = *inout_cis_size;
  535. }
  536. /*
  537. * Parse the length while reading. If find the end tuple, or reaches the
  538. * limitation, read no more and return both the data and the size already
  539. * read.
  540. */
  541. int buffer_offset = 0;
  542. int cur_cis_offset = 0;
  543. bool end_tuple_found = false;
  544. do {
  545. ret = sdmmc_io_read_bytes(card, 0, addr + buffer_offset, &buf, CIS_GET_MINIMAL_SIZE);
  546. if (ret != ESP_OK) return ret;
  547. //calculate relative to the beginning of the buffer
  548. int offset = cur_cis_offset - buffer_offset;
  549. bool finish = check_tuples_in_buffer(buf, CIS_GET_MINIMAL_SIZE, &offset);
  550. int remain_size = buffer_size - buffer_offset;
  551. int copy_len;
  552. if (finish) {
  553. copy_len = MIN(offset, remain_size);
  554. end_tuple_found = true;
  555. } else {
  556. copy_len = MIN(CIS_GET_MINIMAL_SIZE, remain_size);
  557. }
  558. if (copy_len > 0) {
  559. memcpy(out_buffer + buffer_offset, buf, copy_len);
  560. }
  561. cur_cis_offset = buffer_offset + offset;
  562. buffer_offset += CIS_GET_MINIMAL_SIZE;
  563. } while (!end_tuple_found && buffer_offset < max_reading);
  564. if (end_tuple_found) {
  565. *inout_cis_size = cur_cis_offset;
  566. if (cur_cis_offset > buffer_size) {
  567. return ESP_ERR_INVALID_SIZE;
  568. } else {
  569. return ESP_OK;
  570. }
  571. } else {
  572. return ESP_ERR_NOT_FOUND;
  573. }
  574. }