block_dev.c 13.7 KB
Newer Older
1
/*
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
5 6
 *
 * Change Logs:
Y
yiyue.fang 已提交
7 8
 * Date           Author        Notes
 * 2011-07-25     weety     first version
9 10 11 12 13
 */

#include <rtthread.h>
#include <dfs_fs.h>

14
#include <drivers/mmcsd_core.h>
15

16
#define DBG_TAG               "SDIO"
17
#ifdef RT_SDIO_DEBUG
18
#define DBG_LVL               DBG_LOG
19
#else
20
#define DBG_LVL               DBG_INFO
21 22 23
#endif /* RT_SDIO_DEBUG */
#include <rtdbg.h>

24

25 26
#define BLK_MIN(a, b) ((a) < (b) ? (a) : (b))

27 28
struct mmcsd_blk_device
{
Y
yiyue.fang 已提交
29 30 31 32 33
    struct rt_mmcsd_card *card;
    rt_list_t list;
    struct rt_device dev;
    struct dfs_partition part;
    struct rt_device_blk_geometry geometry;
34
    rt_size_t max_req_size;
35 36 37 38 39 40
};

#ifndef RT_MMCSD_MAX_PARTITION
#define RT_MMCSD_MAX_PARTITION 16
#endif

41
rt_int32_t mmcsd_num_wr_blocks(struct rt_mmcsd_card *card)
42
{
Y
yiyue.fang 已提交
43 44
    rt_int32_t err;
    rt_uint32_t blocks;
45

Y
yiyue.fang 已提交
46 47 48 49
    struct rt_mmcsd_req req;
    struct rt_mmcsd_cmd cmd;
    struct rt_mmcsd_data data;
    rt_uint32_t timeout_us;
50

Y
yiyue.fang 已提交
51
    rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
52

Y
yiyue.fang 已提交
53 54 55
    cmd.cmd_code = APP_CMD;
    cmd.arg = card->rca << 16;
    cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_AC;
56

Y
yiyue.fang 已提交
57 58 59 60 61
    err = mmcsd_send_cmd(card->host, &cmd, 0);
    if (err)
        return -RT_ERROR;
    if (!controller_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
        return -RT_ERROR;
62

Y
yiyue.fang 已提交
63
    rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
64

Y
yiyue.fang 已提交
65 66 67
    cmd.cmd_code = SD_APP_SEND_NUM_WR_BLKS;
    cmd.arg = 0;
    cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
68

Y
yiyue.fang 已提交
69
    rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
70

Y
yiyue.fang 已提交
71 72
    data.timeout_ns = card->tacc_ns * 100;
    data.timeout_clks = card->tacc_clks * 100;
73

Y
yiyue.fang 已提交
74 75 76
    timeout_us = data.timeout_ns / 1000;
    timeout_us += data.timeout_clks * 1000 /
        (card->host->io_cfg.clock / 1000);
77

78
    if (timeout_us > 100000)
Y
yiyue.fang 已提交
79 80 81 82
    {
        data.timeout_ns = 100000000;
        data.timeout_clks = 0;
    }
83

Y
yiyue.fang 已提交
84 85 86 87
    data.blksize = 4;
    data.blks = 1;
    data.flags = DATA_DIR_READ;
    data.buf = &blocks;
88

Y
yiyue.fang 已提交
89
    rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
90

Y
yiyue.fang 已提交
91 92
    req.cmd = &cmd;
    req.data = &data;
93

Y
yiyue.fang 已提交
94
    mmcsd_send_request(card->host, &req);
95

Y
yiyue.fang 已提交
96 97
    if (cmd.err || data.err)
        return -RT_ERROR;
98

Y
yiyue.fang 已提交
99
    return blocks;
100 101
}

Y
yiyue.fang 已提交
102 103 104 105 106
static rt_err_t rt_mmcsd_req_blk(struct rt_mmcsd_card *card,
                                 rt_uint32_t           sector,
                                 void                 *buf,
                                 rt_size_t             blks,
                                 rt_uint8_t            dir)
107
{
Y
yiyue.fang 已提交
108 109 110 111 112 113 114 115 116 117 118 119 120
    struct rt_mmcsd_cmd  cmd, stop;
    struct rt_mmcsd_data  data;
    struct rt_mmcsd_req  req;
    struct rt_mmcsd_host *host = card->host;
    rt_uint32_t r_cmd, w_cmd;

    mmcsd_host_lock(host);
    rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
    rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
    rt_memset(&stop, 0, sizeof(struct rt_mmcsd_cmd));
    rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
    req.cmd = &cmd;
    req.data = &data;
121

Y
yiyue.fang 已提交
122
    cmd.arg = sector;
123
    if (!(card->flags & CARD_FLAG_SDHC))
Y
yiyue.fang 已提交
124 125 126 127 128 129 130 131
    {
        cmd.arg <<= 9;
    }
    cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;

    data.blksize = SECTOR_SIZE;
    data.blks  = blks;

132
    if (blks > 1)
Y
yiyue.fang 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145
    {
        if (!controller_is_spi(card->host) || !dir)
        {
            req.stop = &stop;
            stop.cmd_code = STOP_TRANSMISSION;
            stop.arg = 0;
            stop.flags = RESP_SPI_R1B | RESP_R1B | CMD_AC;
        }
        r_cmd = READ_MULTIPLE_BLOCK;
        w_cmd = WRITE_MULTIPLE_BLOCK;
    }
    else
    {
W
weety 已提交
146
        req.stop = RT_NULL;
Y
yiyue.fang 已提交
147 148 149 150
        r_cmd = READ_SINGLE_BLOCK;
        w_cmd = WRITE_BLOCK;
    }

151
    if (!dir)
Y
yiyue.fang 已提交
152 153 154 155 156 157 158 159 160 161 162 163 164 165
    {
        cmd.cmd_code = r_cmd;
        data.flags |= DATA_DIR_READ;
    }
    else
    {
        cmd.cmd_code = w_cmd;
        data.flags |= DATA_DIR_WRITE;
    }

    mmcsd_set_data_timeout(&data, card);
    data.buf = buf;
    mmcsd_send_request(host, &req);

166
    if (!controller_is_spi(card->host) && dir != 0)
Y
yiyue.fang 已提交
167
    {
168
        do
Y
yiyue.fang 已提交
169 170 171 172 173 174 175
        {
            rt_int32_t err;

            cmd.cmd_code = SEND_STATUS;
            cmd.arg = card->rca << 16;
            cmd.flags = RESP_R1 | CMD_AC;
            err = mmcsd_send_cmd(card->host, &cmd, 5);
176
            if (err)
Y
yiyue.fang 已提交
177
            {
178
                LOG_E("error %d requesting status", err);
Y
yiyue.fang 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191
                break;
            }
            /*
             * Some cards mishandle the status bits,
             * so make sure to check both the busy
             * indication and the card state.
             */
         } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
            (R1_CURRENT_STATE(cmd.resp[0]) == 7));
    }

    mmcsd_host_unlock(host);

192
    if (cmd.err || data.err || stop.err)
Y
yiyue.fang 已提交
193
    {
194 195
        LOG_E("mmcsd request blocks error");
        LOG_E("%d,%d,%d, 0x%08x,0x%08x",
Y
yiyue.fang 已提交
196 197 198 199 200 201
                   cmd.err, data.err, stop.err, data.flags, sector);

        return -RT_ERROR;
    }

    return RT_EOK;
202 203 204 205
}

static rt_err_t rt_mmcsd_init(rt_device_t dev)
{
Y
yiyue.fang 已提交
206
    return RT_EOK;
207 208 209 210
}

static rt_err_t rt_mmcsd_open(rt_device_t dev, rt_uint16_t oflag)
{
Y
yiyue.fang 已提交
211
    return RT_EOK;
212 213 214 215
}

static rt_err_t rt_mmcsd_close(rt_device_t dev)
{
Y
yiyue.fang 已提交
216
    return RT_EOK;
217 218
}

B
bernard 已提交
219
static rt_err_t rt_mmcsd_control(rt_device_t dev, int cmd, void *args)
220
{
Y
yiyue.fang 已提交
221 222 223 224 225 226 227 228 229 230
    struct mmcsd_blk_device *blk_dev = (struct mmcsd_blk_device *)dev->user_data;
    switch (cmd)
    {
    case RT_DEVICE_CTRL_BLK_GETGEOME:
        rt_memcpy(args, &blk_dev->geometry, sizeof(struct rt_device_blk_geometry));
        break;
    default:
        break;
    }
    return RT_EOK;
231 232
}

Y
yiyue.fang 已提交
233 234 235 236
static rt_size_t rt_mmcsd_read(rt_device_t dev,
                               rt_off_t    pos,
                               void       *buffer,
                               rt_size_t   size)
237
{
238
    rt_err_t err = 0;
239 240 241 242
    rt_size_t offset = 0;
    rt_size_t req_size = 0;
    rt_size_t remain_size = size;
    void *rd_ptr = (void *)buffer;
Y
yiyue.fang 已提交
243 244 245 246 247
    struct mmcsd_blk_device *blk_dev = (struct mmcsd_blk_device *)dev->user_data;
    struct dfs_partition *part = &blk_dev->part;

    if (dev == RT_NULL)
    {
B
bernard 已提交
248
        rt_set_errno(-EINVAL);
Y
yiyue.fang 已提交
249 250 251 252
        return 0;
    }

    rt_sem_take(part->lock, RT_WAITING_FOREVER);
253 254
    while (remain_size)
    {
255
        req_size = (remain_size > blk_dev->max_req_size) ? blk_dev->max_req_size : remain_size;
256 257 258 259
        err = rt_mmcsd_req_blk(blk_dev->card, part->offset + pos + offset, rd_ptr, req_size, 0);
        if (err)
            break;
        offset += req_size;
W
weety 已提交
260
        rd_ptr = (void *)((rt_uint8_t *)rd_ptr + (req_size << 9));
261 262
        remain_size -= req_size;
    }
Y
yiyue.fang 已提交
263 264 265
    rt_sem_release(part->lock);

    /* the length of reading must align to SECTOR SIZE */
266
    if (err)
Y
yiyue.fang 已提交
267
    {
B
bernard 已提交
268
        rt_set_errno(-EIO);
Y
yiyue.fang 已提交
269 270
        return 0;
    }
271
    return size - remain_size;
272 273
}

Y
yiyue.fang 已提交
274 275 276 277
static rt_size_t rt_mmcsd_write(rt_device_t dev,
                                rt_off_t    pos,
                                const void *buffer,
                                rt_size_t   size)
278
{
279
    rt_err_t err = 0;
280 281 282 283
    rt_size_t offset = 0;
    rt_size_t req_size = 0;
    rt_size_t remain_size = size;
    void *wr_ptr = (void *)buffer;
Y
yiyue.fang 已提交
284 285 286 287 288
    struct mmcsd_blk_device *blk_dev = (struct mmcsd_blk_device *)dev->user_data;
    struct dfs_partition *part = &blk_dev->part;

    if (dev == RT_NULL)
    {
B
bernard 已提交
289
        rt_set_errno(-EINVAL);
Y
yiyue.fang 已提交
290 291 292 293
        return 0;
    }

    rt_sem_take(part->lock, RT_WAITING_FOREVER);
294 295
    while (remain_size)
    {
296
        req_size = (remain_size > blk_dev->max_req_size) ? blk_dev->max_req_size : remain_size;
297 298 299 300
        err = rt_mmcsd_req_blk(blk_dev->card, part->offset + pos + offset, wr_ptr, req_size, 1);
        if (err)
            break;
        offset += req_size;
W
weety 已提交
301
        wr_ptr = (void *)((rt_uint8_t *)wr_ptr + (req_size << 9));
302 303
        remain_size -= req_size;
    }
Y
yiyue.fang 已提交
304 305 306
    rt_sem_release(part->lock);

    /* the length of reading must align to SECTOR SIZE */
307
    if (err)
Y
yiyue.fang 已提交
308
    {
B
bernard 已提交
309
        rt_set_errno(-EIO);
Y
yiyue.fang 已提交
310 311 312

        return 0;
    }
313
    return size - remain_size;
314 315 316 317
}

static rt_int32_t mmcsd_set_blksize(struct rt_mmcsd_card *card)
{
Y
yiyue.fang 已提交
318 319 320 321 322 323 324 325 326 327 328 329 330 331
    struct rt_mmcsd_cmd cmd;
    int err;

    /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
    if (card->flags & CARD_FLAG_SDHC)
        return 0;

    mmcsd_host_lock(card->host);
    cmd.cmd_code = SET_BLOCKLEN;
    cmd.arg = 512;
    cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_AC;
    err = mmcsd_send_cmd(card->host, &cmd, 5);
    mmcsd_host_unlock(card->host);

332
    if (err)
Y
yiyue.fang 已提交
333
    {
334
        LOG_E("MMCSD: unable to set block size to %d: %d", cmd.arg, err);
Y
yiyue.fang 已提交
335 336 337 338 339

        return -RT_ERROR;
    }

    return 0;
340 341
}

B
Bernard Xiong 已提交
342
#ifdef RT_USING_DEVICE_OPS
343
const static struct rt_device_ops mmcsd_blk_ops =
B
Bernard Xiong 已提交
344 345 346 347 348 349 350 351 352 353
{
    rt_mmcsd_init,
    rt_mmcsd_open,
    rt_mmcsd_close,
    rt_mmcsd_read,
    rt_mmcsd_write,
    rt_mmcsd_control
};
#endif

W
Wayne Lin 已提交
354

W
Wayne Lin 已提交
355
static struct mmcsd_blk_device * rt_mmcsd_create_blkdev(struct rt_mmcsd_card *card, const char* dname, struct dfs_partition* psPart)
W
Wayne Lin 已提交
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
{
    struct mmcsd_blk_device *blk_dev;
    char sname[12];

    blk_dev = rt_calloc(1, sizeof(struct mmcsd_blk_device));
    if (!blk_dev)
    {
        LOG_E("mmcsd:malloc memory failed!");
        return RT_NULL;
    }

    if (psPart != RT_NULL)
    {
        rt_memcpy(&blk_dev->part, psPart, sizeof(struct dfs_partition));
        blk_dev->geometry.sector_count = psPart->size;
    }
    else
    {
        blk_dev->part.offset = 0;
        blk_dev->part.size   = 0;
        blk_dev->geometry.sector_count = card->card_capacity * (1024 / 512);
    }

    blk_dev->geometry.bytes_per_sector = 1<<9;
    blk_dev->geometry.block_size = card->card_blksize;

W
Wayne Lin 已提交
382
    rt_snprintf(sname, sizeof(sname), "sem_%s", dname);
W
Wayne Lin 已提交
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
    blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);

    blk_dev->max_req_size = BLK_MIN((card->host->max_dma_segs *
                                     card->host->max_seg_size) >> 9,
                                    (card->host->max_blk_count *
                                     card->host->max_blk_size) >> 9);

    /* register mmcsd device */
    blk_dev->dev.type = RT_Device_Class_Block;
#ifdef RT_USING_DEVICE_OPS
    blk_dev->dev.ops  = &mmcsd_blk_ops;
#else
    blk_dev->dev.init = rt_mmcsd_init;
    blk_dev->dev.open = rt_mmcsd_open;
    blk_dev->dev.close = rt_mmcsd_close;
    blk_dev->dev.read = rt_mmcsd_read;
    blk_dev->dev.write = rt_mmcsd_write;
    blk_dev->dev.control = rt_mmcsd_control;
#endif
    blk_dev->dev.user_data = blk_dev;

    blk_dev->card = card;

    rt_device_register(&blk_dev->dev, dname,
        RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);

    /* Insert to list. */
    rt_list_insert_after(&card->blk_devices, &blk_dev->list);

#ifdef RT_USING_DFS_MNTTABLE
W
Wayne Lin 已提交
413
    if ( blk_dev )
W
Wayne Lin 已提交
414 415 416 417 418 419 420 421 422 423
    {
        LOG_I("try to mount file system!");
        /* try to mount file system on this block device */
        dfs_mount_device(&(blk_dev->dev));
    }
#endif

    return blk_dev;
}

424 425
rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card)
{
Y
yiyue.fang 已提交
426
    rt_int32_t err = 0;
427
    rt_err_t status;
Y
yiyue.fang 已提交
428 429 430
    rt_uint8_t *sector;

    err = mmcsd_set_blksize(card);
431
    if(err)
Y
yiyue.fang 已提交
432 433 434 435
    {
        return err;
    }

436
    LOG_D("probe mmcsd block device!");
437

Y
yiyue.fang 已提交
438 439 440 441
    /* get the first sector to read partition table */
    sector = (rt_uint8_t *)rt_malloc(SECTOR_SIZE);
    if (sector == RT_NULL)
    {
442
        LOG_E("allocate partition sector buffer failed!");
Y
yiyue.fang 已提交
443 444 445 446 447 448 449

        return -RT_ENOMEM;
    }

    status = rt_mmcsd_req_blk(card, 0, sector, 1, 0);
    if (status == RT_EOK)
    {
W
Wayne Lin 已提交
450
        rt_uint8_t i;
W
Wayne Lin 已提交
451 452 453
        char dname[8];
        struct dfs_partition part;
        struct mmcsd_blk_device *blk_dev = RT_NULL;
454 455 456 457
        rt_int32_t host_id = card->host->id;

        /* Initial blk_device link-list. */
        rt_list_init(&card->blk_devices);
W
Wayne Lin 已提交
458

Y
yiyue.fang 已提交
459 460
        for (i = 0; i < RT_MMCSD_MAX_PARTITION; i++)
        {
W
Wayne Lin 已提交
461 462
            /* Get the first partition */
            status = dfs_filesystem_get_partition(&part, sector, i);
Y
yiyue.fang 已提交
463 464
            if (status == RT_EOK)
            {
W
Wayne Lin 已提交
465 466
                /* Given name is with allocated host id and its partition index. */
                rt_snprintf(dname, sizeof(dname), "sd%dp%d", host_id, i);
W
Wayne Lin 已提交
467
                blk_dev = rt_mmcsd_create_blkdev(card, (const char*)dname, &part);
W
Wayne Lin 已提交
468
                if ( blk_dev == RT_NULL )
Y
yiyue.fang 已提交
469
                {
W
Wayne Lin 已提交
470 471
                    err = -RT_ENOMEM;
                    goto exit_rt_mmcsd_blk_probe;
Y
yiyue.fang 已提交
472 473
                }
            }
W
Wayne Lin 已提交
474
            else
475
            {
W
Wayne Lin 已提交
476
                break;
477
            }
W
Wayne Lin 已提交
478
        }
W
Wayne Lin 已提交
479 480 481

        /* Always create the super node, given name is with allocated host id. */
        rt_snprintf(dname, sizeof(dname), "sd%d", host_id);
W
Wayne Lin 已提交
482
        blk_dev = rt_mmcsd_create_blkdev(card, (const char*)dname, RT_NULL);
W
Wayne Lin 已提交
483 484 485 486
        if ( blk_dev == RT_NULL )
        {
            err = -RT_ENOMEM;
            goto exit_rt_mmcsd_blk_probe;
Y
yiyue.fang 已提交
487 488 489 490
        }
    }
    else
    {
491
        LOG_E("read mmcsd first sector failed");
Y
yiyue.fang 已提交
492 493
        err = -RT_ERROR;
    }
494

W
Wayne Lin 已提交
495 496
exit_rt_mmcsd_blk_probe:

Y
yiyue.fang 已提交
497 498
    /* release sector buffer */
    rt_free(sector);
499

Y
yiyue.fang 已提交
500
    return err;
501 502 503 504
}

void rt_mmcsd_blk_remove(struct rt_mmcsd_card *card)
{
505
    rt_list_t *l, *n;
Y
yiyue.fang 已提交
506
    struct mmcsd_blk_device *blk_dev;
507

508 509 510 511 512 513 514 515 516 517 518 519
    if(card == RT_NULL)
    {
        LOG_E("card is null!");
        return;
    }

    if(rt_list_isempty(&card->blk_devices))
    {
        LOG_E("card blk_devices is empty!");
        return;
    }

520
    for (l = (&card->blk_devices)->next, n = l->next; l != &card->blk_devices; l = n, n=n->next)
Y
yiyue.fang 已提交
521 522
    {
        blk_dev = (struct mmcsd_blk_device *)rt_list_entry(l, struct mmcsd_blk_device, list);
523
        if (blk_dev->card == card)
Y
yiyue.fang 已提交
524
        {
525 526 527 528
            /* unmount file system */
            const char * mounted_path = dfs_filesystem_get_mounted_path(&(blk_dev->dev));
            if (mounted_path)
            {
H
hichard 已提交
529 530
                  dfs_unmount(mounted_path);
                  LOG_D("unmount file system %s for device %s.\r\n", mounted_path, blk_dev->dev.parent.name);
531
            }
H
hichard 已提交
532
            rt_sem_delete(blk_dev->part.lock);
Y
yiyue.fang 已提交
533 534 535 536 537
            rt_device_unregister(&blk_dev->dev);
            rt_list_remove(&blk_dev->list);
            rt_free(blk_dev);
        }
    }
538
}