123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789 |
- /*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2007-12-02 Yi.Qiu the first version
- * 2010-01-01 Bernard Modify for mini2440
- * 2010-10-13 Wangmeng Added sep4020 support
- */
- #include <rtthread.h>
- #include "sdcard.h"
- #ifdef RT_USING_DFS
- volatile rt_int32_t RCA;
- /* RT-Thread Device Driver Interface */
- #include <dfs_fs.h>
- /*GLOBAL SD DEVICE PONITER*/
- static struct sd_device *ptr_sddev;
- static rt_uint8_t gsec_buf[SECTOR_SIZE];
- #define USE_TIMEOUT
- /*This file is to power on/off the SEP4020 SDC*/
- /**
- * This function will power on/off the SEP4020 SDC
- *
- * @param sd_ctl: 0/power on; 1/power off
- * @return none
- *
- */
- static void sd_pwr(int sd_ctl)
- {
- if (sd_ctl)
- {
- *(RP)GPIO_PORTA_SEL |= 0x0200;
- *(RP)GPIO_PORTA_DIR &= (~0x0200);
- *(RP)GPIO_PORTA_DATA |= 0x0200;
- }
- else
- {
- *(RP)GPIO_PORTA_SEL |= 0x0200;
- *(RP)GPIO_PORTA_DIR &= (~0x0200);
- *(RP)GPIO_PORTA_DATA &= (~0x0200);
- }
- }
- /*a nop operation to delay*/
- static void delay(U32 j)
- {
- U32 i;
- for (i = 0; i < j; i++)
- {
- /* nothing */
- }
- }
- /*
- * Send the command to set the data transfer mode
- * @param cmd:the command to sent
- * @param arg:the argument of the command
- * @param mode:SDC transfer mode
- * @param blk_len:the block size of each data
- * @param num:number of blocks
- * @param mask:sdc interrupt mask
- */
- static rt_err_t cmd_data(U16 cmd, U32 arg, U16 mode, U16 blk_len, U16 num, U16 mask)
- {
- U32 i;
- #ifdef USE_TIMEOUT
- U32 to = 10000;
- #endif
- *(RP)SDC_CLOCK_CONTROL = 0Xff00;
- *(RP)SDC_CLOCK_CONTROL = 0Xff04;
- *(RP)SDC_INTERRUPT_STATUS_MASK = mask;
- *(RP)SDC_TRANSFER_MODE = mode;
- *(RP)SDC_BLOCK_SIZE = blk_len;
- *(RP)SDC_BLOCK_COUNT = num;
- *(RP)SDC_ARGUMENT = arg;
- *(RP)SDC_COMMAND = cmd;
- delay(10);
- i = *(RP)SDC_INTERRUPT_STATUS & 0x1000;
- while (i != 0x1000)
- {
- i = *(RP)SDC_INTERRUPT_STATUS & 0x1000;
- #ifdef USE_TIMEOUT
- to --;
- if (!to)
- {
- EOUT("%s TIMEOUT\n", __FUNCTION__);
- return RT_ETIMEOUT;
- }
- #endif
- }
- delay(160);
- return *(RP)SDC_RESPONSE0;
- }
- static rt_err_t cmd_response(U16 Cmd, U32 Arg, U16 TransMode, U16 BlkLen, U16 Nob, U16 IntMask)
- {
- U32 i;
- #ifdef USE_TIMEOUT
- U32 to = 50000;
- #endif
- *(RP)SDC_CLOCK_CONTROL = 0Xff00;
- *(RP)SDC_CLOCK_CONTROL = 0Xff04;
- *(RP)SDC_INTERRUPT_STATUS_MASK = IntMask;
- *(RP)SDC_TRANSFER_MODE = TransMode;
- *(RP)SDC_BLOCK_SIZE = BlkLen;
- *(RP)SDC_BLOCK_COUNT = Nob;
- *(RP)SDC_ARGUMENT = Arg;
- *(RP)SDC_COMMAND = Cmd;
- delay(10);
- i = *(RP)SDC_INTERRUPT_STATUS & 0x1040;
- while (i != 0x1040)
- {
- i = *(RP)SDC_INTERRUPT_STATUS & 0x1040;
- #ifdef USE_TIMEOUT
- to--;
- if (!to)
- {
- EOUT("%s Timeout\n", __FUNCTION__);
- return RT_ETIMEOUT;
- }
- #endif
- }
- //DBOUT("cmd_response TO is %d\n",to);
- delay(100);
- return RT_EOK;
- }
- static rt_err_t cmd_wait(U16 Cmd, U32 Arg, U16 IntMask)
- {
- int i;
- #ifdef USE_TIMEOUT
- U32 to = 200000;
- #endif
- *(RP)SDC_CLOCK_CONTROL = 0Xff00;
- *(RP)SDC_CLOCK_CONTROL = 0Xff04;
- *(RP)SDC_COMMAND = Cmd;
- *(RP)SDC_INTERRUPT_STATUS_MASK = IntMask;
- *(RP)SDC_ARGUMENT = Arg;
- i = *(RP)SDC_INTERRUPT_STATUS & 0x1000;
- while (i != 0x1000)
- {
- i = *(RP)SDC_INTERRUPT_STATUS & 0x1000;
- #ifdef USE_TIMEOUT
- to--;
- if (!to)
- {
- EOUT("%s Timeout\n", __FUNCTION__);
- return RT_ETIMEOUT;
- }
- #endif
- }
- //DBOUT("cmd_wait TO is %d\n",to);
- delay(10);
- return RT_EOK;
- }
- /**
- * This function will set a hook function, which will be invoked when a memory
- * block is allocated from heap memory.
- *
- * @param hook the hook function
- */
- static rt_err_t sd_init(void)
- {
- rt_err_t err;
- #ifdef USE_TIMEOUT
- rt_uint32_t to = 1000;
- #endif
- sd_pwr(1);
- *(RP)SDC_SOFTWARE_RESET = 0x0;
- delay(200);
- *(RP)SDC_SOFTWARE_RESET = 0x1;
- delay(200);
- cmd_wait(0x08, 0x0, 0xfff);
- do
- {
- err = cmd_wait(0x6ea, 0x0, 0xfff);
- #ifdef USE_TIMEOUT
- if (err != RT_EOK)
- {
- EOUT("cmd_wait err in %s\n", __FUNCTION__);
- return RT_ETIMEOUT;
- }
- #endif
- delay(3);
- err = cmd_wait(0x52a, 0x80ff8000, 0xfff);
- if (err != RT_EOK)
- {
- EOUT("cmd_wait err in %s\n", __FUNCTION__);
- return RT_ETIMEOUT;
- }
- #ifdef USE_TIMEOUT
- to--;
- if (!to)
- {
- EOUT("%s timeout\n", __FUNCTION__);
- return RT_ETIMEOUT;
- }
- #endif
- }
- while (*(RP)SDC_RESPONSE0 < 0X80008000);
- cmd_data(0x49, 0X0, 0X0, 0x0, 0x0, 0Xfff);
- cmd_data(0x6a, 0X0, 0X0, 0x0, 0x0, 0Xfff);
- RCA = *(RP)SDC_RESPONSE0;
- cmd_data(0xea, RCA, 0X0, 0x0, 0x0, 0Xfff);
- return RT_EOK;
- }
- /**
- * This function will set a hook function, which will be invoked when a memory
- * block is allocated from heap memory.
- *
- * @param hook the hook function
- */
- static rt_err_t sd_readblock(rt_uint32_t address, rt_uint8_t *buf)
- {
- U32 complete, i;
- rt_uint8_t temp;
- rt_err_t err;
- rt_uint32_t discard;
- #ifdef USE_TIMEOUT
- rt_uint32_t to = 10;
- #endif
- RT_UNUSED(discard);
- //rt_kprintf("in readblock:%x\n",address);
- //Clear all the errors & interrups
- *(RP)DMAC_INTINTERRCLR |= 0x1;
- *(RP)DMAC_INTINTERRCLR &= ~0x1;
- *(RP)DMAC_INTTCCLEAR |= 0x1;
- *(RP)DMAC_INTTCCLEAR &= ~0x1;
- /*Clear read fifo*/
- *(RP)(SDC_INTERRUPT_STATUS_MASK) = ~(0x1 << 9); //don't mask fifo empty
- while ((*(RP)SDC_INTERRUPT_STATUS) & 0x200 != 0x200)
- discard = *(RP)SDC_READ_BUFER_ACCESS;
- /*DMAC2,word,size=0x80*/
- *(RP)DMAC_C2SRCADDR = SDC_READ_BUFER_ACCESS;
- *(RP)DMAC_C2DESTADDR = (rt_uint32_t)buf;
- *(RP)DMAC_C2CONTROL = 0x20249b;
- *(RP)DMAC_C2CONFIGURATION = 0x38d;
- err = cmd_wait(0x6ea, RCA, 0xfff);
- if (err != RT_EOK)
- {
- rt_set_errno(err);
- return err;
- }
- err = cmd_wait(0xca, 0x2, 0xfff);
- if (err != RT_EOK)
- {
- rt_set_errno(err);
- return err;
- }
- err = cmd_response(0x22e, address, 0X1, 0x0200, 0x1, 0Xfff); //CMD17 4bit mode
- if (err != RT_EOK)
- {
- rt_set_errno(err);
- return err;
- }
- complete = *(RP)SDC_INTERRUPT_STATUS;
- /*CRC*/
- if ((complete | 0xfffffffd) != 0xfffffffd)
- {
- rt_kprintf("CRC ERROR!!!\n");
- complete = *(RP)SDC_INTERRUPT_STATUS;
- }
- while (((*(RP)(DMAC_INTTCSTATUS)) & 0x4) != 0x4)
- {
- delay(10);
- #ifdef USE_TIMEOUT
- to--;
- if (!to)
- {
- EOUT("%s TIMEOUT\n", __FUNCTION__);
- return RT_ETIMEOUT;
- }
- #endif
- }
- #ifdef USE_TIMEOUT
- //DBOUT("%s timeout is %d\n",__FUNCTION__,to);
- #endif
- /*for the buf is big-endian we must reverse it*/
- for (i = 0; i < 0x80; i++)
- {
- temp = buf[0];
- buf[0] = buf[3];
- buf[3] = temp;
- temp = buf[1];
- buf[1] = buf[2];
- buf[2] = temp;
- buf += 4;
- }
- return RT_EOK;
- }
- static rt_uint8_t sd_readmultiblock(rt_uint32_t address, rt_uint8_t *buf, rt_uint32_t size)
- {
- rt_int32_t index;
- rt_uint8_t status = RT_EOK;
- for (index = 0; index < size; index++)
- {
- status = sd_readblock(address + index * SECTOR_SIZE, buf + index * SECTOR_SIZE);
- if (status != RT_EOK)
- break;
- }
- return status;
- }
- /**
- * This function will set a hook function, which will be invoked when a memory
- * block is allocated from heap memory.
- *
- * @param hook the hook function
- */
- static rt_uint8_t sd_writeblock(rt_uint32_t address, rt_uint8_t *buf)
- {
- U32 complete;
- rt_uint8_t temp;
- rt_uint8_t *ptr = buf;
- rt_err_t err;
- #ifdef USE_TIMEOUT
- rt_uint32_t to = 10;
- #endif
- int i;
- rt_kprintf("in writeblock:%x\n", address);
- /*for the buf is big-endian we must reverse it*/
- for (i = 0; i < 0x80; i++)
- {
- temp = ptr[0];
- ptr[0] = ptr[3];
- ptr[3] = temp;
- temp = ptr[1];
- ptr[1] = ptr[2];
- ptr[2] = temp;
- ptr += 4;
- }
- //Clear all the errors & interrups
- *(RP)DMAC_INTINTERRCLR |= 0x1;
- *(RP)DMAC_INTINTERRCLR &= ~0x1;
- *(RP)DMAC_INTTCCLEAR |= 0x1;
- *(RP)DMAC_INTTCCLEAR &= ~0x1;
- *(RP)DMAC_C2SRCADDR = (U32)buf;
- *(RP)DMAC_C2DESTADDR = SDC_WRITE_BUFER_ACCESS;
- *(RP)DMAC_C2CONTROL = 0x20149b;
- *(RP)DMAC_C2CONFIGURATION = 0x380b;
- err = cmd_wait(0x6ea, RCA, 0xfff);
- if (err != RT_EOK)
- {
- rt_set_errno(err);
- return err;
- }
- err = cmd_wait(0xca, 0x2, 0xfff);
- if (err != RT_EOK)
- {
- rt_set_errno(err);
- return err;
- }
- err = cmd_response(0x30e, address, 0X3, 0x0200, 0x1, 0Xfff); //CMD24 1bit mode
- if (err != RT_EOK)
- {
- rt_set_errno(err);
- return err;
- }
- complete = *(RP)SDC_INTERRUPT_STATUS;
- if ((complete | 0xfffffffe) != 0xfffffffe)
- {
- //printf("CRC ERROR");
- complete = *(RP)SDC_INTERRUPT_STATUS;
- }
- while (((*(RP)(DMAC_INTTCSTATUS)) & 0x4) != 0x4)
- {
- delay(10);
- #ifdef USE_TIMEOUT
- to--;
- if (!to)
- {
- EOUT("%s TIMEOUT\n", __FUNCTION__);
- }
- #endif
- }
- #ifdef USE_TIMEOUT
- //DBOUT("%s timeout is %d\n",__FUNCTION__,to);
- #endif
- return RT_EOK;
- }
- /**
- * This function will set a hook function, which will be invoked when a memory
- * block is allocated from heap memory.
- *
- * @param hook the hook function
- */
- static rt_err_t rt_sdcard_init(rt_device_t dev)
- {
- return 0;
- }
- /**
- * This function will set a hook function, which will be invoked when a memory
- * block is allocated from heap memory.
- *
- * @param hook the hook function
- */
- static rt_err_t rt_sdcard_open(rt_device_t dev, rt_uint16_t oflag)
- {
- return 0;
- }
- /**
- * This function will set a hook function, which will be invoked when a memory
- * block is allocated from heap memory.
- *
- * @param hook the hook function
- */
- static rt_err_t rt_sdcard_close(rt_device_t dev)
- {
- return 0;
- }
- /**
- * This function will set a hook function, which will be invoked when a memory
- * block is allocated from heap memory.
- *
- * @param hook the hook function
- */
- static rt_err_t rt_sdcard_control(rt_device_t dev, int cmd, void *args)
- {
- rt_kprintf("cmd = %d\n", cmd);
- RT_ASSERT(dev != RT_NULL);
- if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
- {
- struct rt_device_blk_geometry *geometry;
- geometry = (struct rt_device_blk_geometry *)args;
- if (geometry == RT_NULL) return -RT_ERROR;
- geometry->bytes_per_sector = 512;
- geometry->block_size = 0x200000;
- //if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)
- // geometry->sector_count = (SDCardInfo.SD_csd.DeviceSize + 1) * 1024;
- //else
- geometry->sector_count = 0x200000;//SDCardInfo.CardCapacity/SDCardInfo.CardBlockSize;
- }
- return RT_EOK;
- }
- /**
- * This function will set a hook function, which will be invoked when a memory
- * block is allocated from heap memory.
- *
- * @param hook the hook function
- */
- static rt_size_t rt_sdcard_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
- {
- rt_uint32_t retry = 3;
- rt_uint8_t status;
- rt_uint32_t index;
- struct dfs_partition *part;
- if (dev == RT_NULL)
- {
- rt_set_errno(-DFS_STATUS_EINVAL);
- return 0;
- }
- part = (struct dfs_partition *)dev->user_data;
- // take the semaphore
- rt_sem_take(part->lock, RT_WAITING_FOREVER);
- while (retry--)
- {
- if (((rt_uint32_t)buffer % 4 != 0) ||
- ((rt_uint32_t)buffer > 0x20080000))
- {
- for (index = 0; index < size; index++)
- {
- status = sd_readblock((part->offset + pos) * SECTOR_SIZE, ptr_sddev->sec_buf);
- if (status != RT_EOK)
- break;
- rt_memcpy((rt_uint8_t *)buffer + (index * SECTOR_SIZE), ptr_sddev->sec_buf, SECTOR_SIZE);
- }
- }
- else
- {
- for (index = 0; index < size; index++)
- {
- status = sd_readblock((pos) * SECTOR_SIZE, (rt_uint8_t *)buffer + index * SECTOR_SIZE);
- if (status != RT_EOK)
- break;
- }
- }
- }
- rt_sem_release(part->lock);
- if (status == RT_EOK)
- return size;
- rt_kprintf("read failed: %d, buffer 0x%08x\n", status, buffer);
- return 0;
- }
- /**
- * This function will set a hook function, which will be invoked when a memory
- * block is allocated from heap memory.
- *
- * @param hook the hook function
- */
- static rt_size_t rt_sdcard_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
- {
- int i;
- rt_uint8_t status;
- struct dfs_partition *part;
- if (dev == RT_NULL)
- {
- rt_set_errno(-DFS_STATUS_EINVAL);
- return 0;
- }
- part = (struct dfs_partition *)dev->user_data;
- rt_sem_take(part->lock, RT_WAITING_FOREVER);
- if (((rt_uint32_t)buffer % 4 != 0) ||
- ((rt_uint32_t)buffer > 0x20080000))
- {
- rt_uint32_t index;
- for (index = 0; index < size; index++)
- {
- rt_memcpy(ptr_sddev->sec_buf, ((rt_uint8_t *)buffer + index * SECTOR_SIZE), SECTOR_SIZE);
- status = sd_writeblock((part->offset + index + pos) * SECTOR_SIZE, ptr_sddev->sec_buf);
- }
- }
- else
- {
- for (i = 0; i < size; i++)
- {
- status = sd_writeblock((part->offset + i + pos) * SECTOR_SIZE,
- (rt_uint8_t *)((rt_uint8_t *)buffer + i * SECTOR_SIZE));
- if (status != RT_EOK) break;
- }
- }
- rt_sem_release(part->lock);
- if (status == RT_EOK)
- return size;
- rt_kprintf("read failed: %d, buffer 0x%08x\n", status, buffer);
- return 0;
- }
- rt_err_t rt_hw_sdcard_exit()
- {
- if (ptr_sddev->device != RT_NULL)
- rt_free(ptr_sddev->device);
- if (ptr_sddev->part != RT_NULL)
- rt_free(ptr_sddev->part);
- if (ptr_sddev != RT_NULL)
- rt_free(ptr_sddev);
- return RT_EOK;
- }
- /**
- * This function will init sd card
- *
- * @param void
- */
- rt_err_t rt_hw_sdcard_init()
- {
- /*For test*/
- rt_err_t err;
- rt_int32_t i;
- char dname[4];
- char sname[8];
- /*Initialize structure*/
- ptr_sddev = (struct sd_device *)rt_malloc(sizeof(struct sd_device));
- if (ptr_sddev == RT_NULL)
- {
- EOUT("Failed to allocate sdcard device structure\n");
- return RT_ENOMEM;
- }
- /*sdcard intialize*/
- err = sd_init();
- if (err != RT_EOK)
- goto FAIL2;
- /*set sector buffer*/
- ptr_sddev->sec_buf = gsec_buf;
- ptr_sddev->buf_size = SECTOR_SIZE;
- ptr_sddev->sdc = (struct sd_c *)SD_BASE;
- //DBOUT("allocate partition sector buffer OK!");
- err = sd_readblock(0, ptr_sddev->sec_buf);
- if (err != RT_EOK)
- {
- EOUT("read first block error\n");
- goto FAIL2;
- }
- /*sdcard driver initialize*/
- ptr_sddev->part = (struct dfs_partition *)rt_malloc(4 * sizeof(struct dfs_partition));
- if (ptr_sddev->part == RT_NULL)
- {
- EOUT("allocate partition failed\n");
- err = RT_ENOMEM;
- goto FAIL2;
- }
- /*alloc device buffer*/
- ptr_sddev->device = (struct rt_device *)rt_malloc(4 * sizeof(struct rt_device));
- if (ptr_sddev->device == RT_NULL)
- {
- EOUT("allocate device failed\n");
- err = RT_ENOMEM;
- goto FAIL1;
- }
- ptr_sddev->part_num = 0;
- err = sd_readblock(0, ptr_sddev->sec_buf);
- if (err != RT_EOK)
- {
- EOUT("Read block 0 to initialize ERROR\n");
- goto FAIL1;
- }
- for (i = 0; i < 4; i++)
- {
- /* get the first partition */
- err = dfs_filesystem_get_partition(&(ptr_sddev->part[i]), ptr_sddev->sec_buf, i);
- if (err == RT_EOK)
- {
- rt_snprintf(dname, 4, "sd%d", i);
- rt_snprintf(sname, 8, "sem_sd%d", i);
- ptr_sddev->part[i].lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
- /* register sdcard device */
- ptr_sddev->device[i].init = rt_sdcard_init;
- ptr_sddev->device[i].open = rt_sdcard_open;
- ptr_sddev->device[i].close = rt_sdcard_close;
- ptr_sddev->device[i].read = rt_sdcard_read;
- ptr_sddev->device[i].write = rt_sdcard_write;
- ptr_sddev->device[i].control = rt_sdcard_control;
- ptr_sddev->device[i].user_data = &ptr_sddev->part[i];
- err = rt_device_register(&ptr_sddev->device[i], dname,
- RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
- if (err == RT_EOK)
- ptr_sddev->part_num++;
- }
- else
- {
- if (i == 0)
- {
- /* there is no partition table */
- ptr_sddev->part[0].offset = 0;
- ptr_sddev->part[0].size = 0;
- ptr_sddev->part[0].lock = rt_sem_create("sem_sd0", 1, RT_IPC_FLAG_FIFO);
- /* register sdcard device */
- ptr_sddev->device[0].init = rt_sdcard_init;
- ptr_sddev->device[0].open = rt_sdcard_open;
- ptr_sddev->device[0].close = rt_sdcard_close;
- ptr_sddev->device[0].read = rt_sdcard_read;
- ptr_sddev->device[0].write = rt_sdcard_write;
- ptr_sddev->device[0].control = rt_sdcard_control;
- ptr_sddev->device[0].user_data = &ptr_sddev->part[0];
- err = rt_device_register(&ptr_sddev->device[0], "sd0",
- RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
- if (err == RT_EOK)
- ptr_sddev->part_num++;
- break;
- }
- }
- }
- if (ptr_sddev->part_num == 0)
- goto FAIL0;
- return err;
- FAIL0:
- rt_free(ptr_sddev->device);
- ptr_sddev->device = RT_NULL;
- FAIL1:
- rt_free(ptr_sddev->part);
- ptr_sddev->part = RT_NULL;
- FAIL2:
- rt_free(ptr_sddev);
- ptr_sddev = RT_NULL;
- return err;
- }
- #endif
|