te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>c - How to achieve low level access to SD card to send raw mmc commands? - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - How to achieve low level access to SD card to send raw mmc commands? - Stack Overflow

programmeradmin3浏览0评论

I am trying to send raw mmc commands to SD card using Linux MMC subsystem mmc-utils and ioctl and running into Connection timed out (errno: 110). The SD card is micro-sd card that is used in raspberry pi 4B. The binary will be executed in initramfs stage on the raspberry pi.

Below is the source files

test_mmc.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/mmc/ioctl.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include "test_debug.h"
#include "test_protocol.h"

static int mmc_fd = -1;
static int retry_count = 0;
int debug_level = DEBUG_ERROR;

// Function prototypes
static int init_mmc(const char *device);
static int transmit_apdu(uint8_t *block);
static ssize_t test_cmd(const uint8_t *request, size_t request_len,
    uint8_t *response, size_t response_len);
static int get_status(STATUS_RESPONSE *pres);


// MMC device initialization
static int init_mmc(const char *device)
{
    mmc_fd = open(device, O_RDWR);
    if (mmc_fd < 0) {
        LOGD(DEBUG_INFO, "%s%s\n", "Failed to open MMC device: ", device);
        return -1;
    }
    return 0;
}

static void close_mmc(void)
{
    if (mmc_fd >= 0) {
        close(mmc_fd);
        mmc_fd = -1;
    }
}

// MMC command helper
static int send_cmd13(void) {
    struct mmc_ioc_cmd ioc = {0};
    unsigned int response = 0;
    int loop_counter = 10;
    
    // Setup CMD13
    memset(&ioc, 0, sizeof(ioc));
    ioc.write_flag = 0;
    ioc.opcode = MMC_CMD_SEND_STATUS;    // CMD13
    ioc.arg = 1 << 16;                 // RCA in upper 16 bits
    ioc.flags = MMC_RSP_R1 | MMC_RSP_SPI_S1;
    ioc.blksz = 0;
    ioc.blocks = 0;

    do {
        int ret = ioctl(mmc_fd, MMC_IOC_CMD, &ioc);
        if (ret < 0) {
            LOGD(DEBUG_ERROR, "CMD13 ioctl failed: %s (errno: %d)\n", 
                 strerror(errno), errno);
            return -1;
        }
        
        response = ioc.response[0];
        LOGD(DEBUG_VERBOSE, "CMD13 response: 0x%08x\n", response);
        
        // Check card state (bits 9:7 in R1 response)
        int card_state = (response >> 9) & 0xF;
        LOGD(DEBUG_VERBOSE, "Card state: %d\n", card_state);

        if (response == 0x900) {
            LOGD(DEBUG_VERBOSE, "Card ready\n");
            return 0;
        }
        
        loop_counter--;
        usleep(200000);  // 200ms delay

        LOGD(DEBUG_VERBOSE, "Retrying CMD13, attempts left: %d\n", loop_counter);
    } while (loop_counter > 0);

    LOGD(DEBUG_ERROR, "CMD13 timeout after %d attempts\n", 10 - loop_counter);
    return -1;
}

static int transmit_apdu(uint8_t *block) {
    struct mmc_ioc_cmd ioc = {0};
    int ret;
    CACHE_ALIGN uint8_t res[512];

    // Initial status check
    ret = send_cmd13();
    if (ret < 0) {
        LOGD(DEBUG_INFO, "%s", "Initial status check failed");
        return ret;
    }

    .
    .
    .

    return 0;
}

// High level APDU command handler
static ssize_t test_cmd(const uint8_t *request, size_t request_len,
                     uint8_t *response, size_t response_len)
{
    CACHE_ALIGN uint8_t block[512];
    uint16_t length;
    int retries = 3;
    int err;

    // Build request block
    size_t request_lenplus = request_len + 2;
    length = htons((uint16_t)request_lenplus);
       
    memset(block, 0x00, sizeof(block));    
    memcpy(block, &length, sizeof(length)); // 2 byte length of command
    memcpy(block+sizeof(length), request, request_len); // APDU

    do {
        err = transmit_apdu(block);
    } while (err && retries--);    

    if (err != 0)
        return err;
        
    .
    .
    .

    return length;
}

static int get_status(STATUS_RESPONSE *pres)
{
    static const uint8_t request[] = { 0xff, 0x70, 0x00, 0x00, 0x00 };
    
    LOGD(DEBUG_INFO, "%s", "Getting card status");

    ssize_t length = test_cmd(request, sizeof(request), (void *)pres,
                           sizeof(STATUS_RESPONSE));
    if (length != sizeof(STATUS_RESPONSE))
        return -1;

    if (ntohs(pres->status) != 0x9000)
        return -1;

    return 0;
}

int main(int argc, char *argv[])
{
    STATUS_RESPONSE status;
    const char *device = "/dev/mmcblk0";
    int ret, opt;

    printf("\nTest SD card communication\n\n");

    // Initialize MMC device
    if (init_mmc(device) < 0) {
        printf("No card found!\n");
        return 1;
    }

    // Get card status
    if (get_status(&status) < 0) {
        printf("Failed to get card status\n");
        close_mmc();
        return 1;
    }
    close_mmc();
    return 1;
}
test_protocol.h
#ifndef TEST_PROTOCOL_H
#define TEST_PROTOCOL_H

#include <stdint.h>

#define MMC_CMD_SEND_STATUS  13
#define MMC_CMD_SWITCH       6

// Response types
#define MMC_RSP_SPI_S1  (1 << 7)
#define MMC_RSP_PRESENT (1 << 0)
#define MMC_RSP_CRC     (1 << 2)
#define MMC_RSP_BUSY    (1 << 3)
#define MMC_RSP_OPCODE  (1 << 4)

#define MMC_RSP_NONE    (0)
#define MMC_RSP_R1  (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
#define MMC_RSP_R7      (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)

typedef struct _STATUS_RESPONSE {
    uint8_t mode;
    uint8_t state;
    int8_t counter;
    int8_t so_counter;
    uint32_t reset_counter;
    uint8_t rfu[2];
    uint32_t cdrom;
    uint8_t flags;
    uint16_t status;
} __attribute__((packed)) STATUS_RESPONSE;

#endif /* TEST_PROTOCOL_H */

cross-compiled in Ubuntu VM and added via init script to run in initramfs.

But I get error

[   24.888477] sdhci-iproc fe340000.mmc: mmc_blk_ioctl_cmd: cmd error -110
[   24.896115] sdhci-iproc fe340000.mmc: mmc_blk_ioctl_cmd: cmd error -110
[   24.903652] sdhci-iproc fe340000.mmc: mmc_blk_ioctl_cmd: cmd error -110
[   24.911243] sdhci-iproc fe340000.mmc: mmc_blk_ioctl_cmd: cmd error -110
/home/test/.../test_mmc/src/test_mmc.c:525:dp_status(): Getting card status/home/test/.../test_mmc/src/test_mmc.c:238:send_cmd13(): CMD13 ioctl failed: Connection timed out (errno: 110)
/home/test/.../test_mmc/src/test_mmc.c:274:transmit_apdu(): Initial status check failed/home/test/.../test_mmc/src/test_mmc.c:238:send_cmd13(): CMD13 ioctl failed: Connection timed out (errno: 110)
/home/test/.../test_mmc/src/test_mmc.c:274:transmit_a[   24.975333] mmc0: card 0001 removed
pdu(): I[   24.975404]  mmcblk0: unable to read partition table
/home/test/.../test_mmc/src/test_mmc.c:238:send_cmd13(): CMD13 ioctl failed: Connection timed out (errno: 110)
/home/test/.../test_mmc/src/test_mmc.c:274:transmit_apdu(): Initial status check failed/home/test/.../test_mmc/src/test_mmc.c:238:send_cmd13(): CMD13 ioctl failed: Connection timed out (errno: 110)
/home/test/.../test_mmc/src/test_mmc.c:274:transmit_apdu(): Initial status check failedFailed to get card status
(initramfs) [   25.212940] mmc0: new ultra high speed DDR50 SDHC card at address 0001
[   25.220392] mmcblk0: mmc0:0001 N1DP5 15.2 GiB
[   25.230203]  mmcblk0: p1 p2
[   25.233535] mmcblk0: mmc0:0001 N1DP5 15.2 GiB
[   25.240661] vc4-drm gpu: bound fe400000.hvs (ops vc4_hvs_ops [vc4])

what is the issue here? How can I achieve low level access to SD card?

In the initramfs shell, I tried mmc extcsd read /dev/mmcblk0 it returned

[  294.419709] sdhci-iproc fe340000.mmc: __mmc_blk_ioctl_cmd: cmd error -110
ioctl: Connection timed out
Cou[  294.429294]  mmcblk0: p1 p2
ld not read EXT_CSD from /dev/mmcblk0

(This mybe due to SD-cards not having the EXT_CSD registers,... I am not sure)

Thanks in advance.

P.S: please let me know if any info is missing

发布评论

评论列表(0)

  1. 暂无评论