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