1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author      Notes
8  * 2007-12-02     Yi.Qiu      the first version
9  * 2010-01-01     Bernard     Modify for mini2440
10  * 2010-10-13     Wangmeng    Added sep4020 support
11  */
12 
13 #include <rtthread.h>
14 
15 #include "sdcard.h"
16 
17 #ifdef RT_USING_DFS
18 volatile rt_int32_t RCA;
19 
20 /* RT-Thread Device Driver Interface */
21 #include <dfs_fs.h>
22 
23 /*GLOBAL SD DEVICE PONITER*/
24 static struct sd_device *ptr_sddev;
25 static rt_uint8_t gsec_buf[SECTOR_SIZE];
26 
27 #define USE_TIMEOUT
28 
29 /*This file is to power on/off the SEP4020 SDC*/
30 /**
31  * This function will power on/off the SEP4020 SDC
32  *
33  * @param sd_ctl: 0/power on; 1/power off
34  * @return none
35  *
36  */
sd_pwr(int sd_ctl)37 static void sd_pwr(int sd_ctl)
38 {
39     if (sd_ctl)
40     {
41         *(RP)GPIO_PORTA_SEL  |= 0x0200;
42         *(RP)GPIO_PORTA_DIR  &= (~0x0200);
43         *(RP)GPIO_PORTA_DATA |= 0x0200;
44     }
45     else
46     {
47 
48         *(RP)GPIO_PORTA_SEL |= 0x0200;
49         *(RP)GPIO_PORTA_DIR &= (~0x0200);
50         *(RP)GPIO_PORTA_DATA &= (~0x0200);
51     }
52 }
53 
54 /*a nop operation to delay*/
delay(U32 j)55 static void delay(U32 j)
56 {
57     U32 i;
58 
59     for (i = 0; i < j; i++)
60     {
61         /* nothing */
62     }
63 }
64 
65 /*
66 * Send the command to set the data transfer mode
67 * @param cmd:the command to sent
68 * @param arg:the argument of the command
69 * @param mode:SDC transfer mode
70 * @param blk_len:the block size of each data
71 * @param num:number of blocks
72 * @param mask:sdc interrupt mask
73 */
cmd_data(U16 cmd,U32 arg,U16 mode,U16 blk_len,U16 num,U16 mask)74 static rt_err_t cmd_data(U16 cmd, U32 arg, U16 mode, U16 blk_len, U16 num, U16 mask)
75 {
76     U32 i;
77 #ifdef USE_TIMEOUT
78     U32 to = 10000;
79 #endif
80 
81     *(RP)SDC_CLOCK_CONTROL = 0Xff00;
82     *(RP)SDC_CLOCK_CONTROL = 0Xff04;
83     *(RP)SDC_INTERRUPT_STATUS_MASK = mask;
84 
85     *(RP)SDC_TRANSFER_MODE = mode;
86 
87     *(RP)SDC_BLOCK_SIZE = blk_len;
88     *(RP)SDC_BLOCK_COUNT = num;
89     *(RP)SDC_ARGUMENT = arg;
90     *(RP)SDC_COMMAND = cmd;
91 
92     delay(10);
93 
94     i = *(RP)SDC_INTERRUPT_STATUS & 0x1000;
95 
96     while (i != 0x1000)
97     {
98         i = *(RP)SDC_INTERRUPT_STATUS & 0x1000;
99 #ifdef USE_TIMEOUT
100         to --;
101         if (!to)
102         {
103             EOUT("%s TIMEOUT\n", __FUNCTION__);
104             return -RT_ETIMEOUT;
105         }
106 #endif
107     }
108     delay(160);
109 
110     return *(RP)SDC_RESPONSE0;
111 }
112 
cmd_response(U16 Cmd,U32 Arg,U16 TransMode,U16 BlkLen,U16 Nob,U16 IntMask)113 static rt_err_t cmd_response(U16 Cmd, U32 Arg, U16 TransMode, U16 BlkLen, U16 Nob, U16 IntMask)
114 {
115     U32 i;
116 #ifdef USE_TIMEOUT
117     U32 to = 50000;
118 #endif
119 
120     *(RP)SDC_CLOCK_CONTROL = 0Xff00;
121 
122     *(RP)SDC_CLOCK_CONTROL = 0Xff04;
123 
124 
125     *(RP)SDC_INTERRUPT_STATUS_MASK = IntMask;
126     *(RP)SDC_TRANSFER_MODE = TransMode;
127     *(RP)SDC_BLOCK_SIZE = BlkLen;
128     *(RP)SDC_BLOCK_COUNT = Nob;
129     *(RP)SDC_ARGUMENT = Arg;
130     *(RP)SDC_COMMAND = Cmd;
131 
132     delay(10);
133 
134     i = *(RP)SDC_INTERRUPT_STATUS & 0x1040;
135 
136     while (i != 0x1040)
137     {
138         i = *(RP)SDC_INTERRUPT_STATUS & 0x1040;
139 #ifdef USE_TIMEOUT
140         to--;
141         if (!to)
142         {
143             EOUT("%s Timeout\n", __FUNCTION__);
144             return -RT_ETIMEOUT;
145         }
146 #endif
147     }
148 
149     //DBOUT("cmd_response TO is %d\n",to);
150     delay(100);
151 
152     return RT_EOK;
153 }
154 
cmd_wait(U16 Cmd,U32 Arg,U16 IntMask)155 static rt_err_t cmd_wait(U16 Cmd, U32 Arg, U16 IntMask)
156 {
157     int i;
158 #ifdef USE_TIMEOUT
159     U32 to = 200000;
160 #endif
161 
162     *(RP)SDC_CLOCK_CONTROL = 0Xff00;
163 
164     *(RP)SDC_CLOCK_CONTROL = 0Xff04;
165 
166     *(RP)SDC_COMMAND = Cmd;
167 
168     *(RP)SDC_INTERRUPT_STATUS_MASK = IntMask;
169 
170     *(RP)SDC_ARGUMENT = Arg;
171 
172     i = *(RP)SDC_INTERRUPT_STATUS & 0x1000;
173 
174     while (i != 0x1000)
175     {
176         i = *(RP)SDC_INTERRUPT_STATUS & 0x1000;
177 #ifdef USE_TIMEOUT
178         to--;
179         if (!to)
180         {
181             EOUT("%s Timeout\n", __FUNCTION__);
182             return -RT_ETIMEOUT;
183         }
184 #endif
185 
186     }
187 
188     //DBOUT("cmd_wait TO is %d\n",to);
189 
190     delay(10);
191 
192     return RT_EOK;
193 }
194 
195 /**
196  * This function will set a hook function, which will be invoked when a memory
197  * block is allocated from heap memory.
198  *
199  * @param hook the hook function
200  */
sd_init(void)201 static rt_err_t sd_init(void)
202 {
203     rt_err_t err;
204 #ifdef USE_TIMEOUT
205     rt_uint32_t to = 1000;
206 #endif
207     sd_pwr(1);
208 
209     *(RP)SDC_SOFTWARE_RESET = 0x0;
210     delay(200);
211     *(RP)SDC_SOFTWARE_RESET = 0x1;
212     delay(200);
213 
214     cmd_wait(0x08, 0x0, 0xfff);
215 
216     do
217     {
218         err = cmd_wait(0x6ea, 0x0, 0xfff);
219 
220 #ifdef USE_TIMEOUT
221         if (err != RT_EOK)
222         {
223             EOUT("cmd_wait err in %s\n", __FUNCTION__);
224             return -RT_ETIMEOUT;
225         }
226 #endif
227 
228         delay(3);
229         err = cmd_wait(0x52a, 0x80ff8000, 0xfff);
230         if (err != RT_EOK)
231         {
232             EOUT("cmd_wait err in %s\n", __FUNCTION__);
233             return -RT_ETIMEOUT;
234         }
235 #ifdef USE_TIMEOUT
236         to--;
237         if (!to)
238         {
239             EOUT("%s timeout\n", __FUNCTION__);
240             return -RT_ETIMEOUT;
241         }
242 #endif
243 
244     }
245     while (*(RP)SDC_RESPONSE0 < 0X80008000);
246 
247     cmd_data(0x49, 0X0, 0X0, 0x0, 0x0, 0Xfff);
248     cmd_data(0x6a, 0X0, 0X0, 0x0, 0x0, 0Xfff);
249     RCA = *(RP)SDC_RESPONSE0;
250     cmd_data(0xea, RCA, 0X0, 0x0, 0x0, 0Xfff);
251 
252     return RT_EOK;
253 }
254 
255 /**
256  * This function will set a hook function, which will be invoked when a memory
257  * block is allocated from heap memory.
258  *
259  * @param hook the hook function
260  */
sd_readblock(rt_uint32_t address,rt_uint8_t * buf)261 static rt_err_t sd_readblock(rt_uint32_t address, rt_uint8_t *buf)
262 {
263     U32 complete, i;
264     rt_uint8_t temp;
265     rt_err_t err;
266     rt_uint32_t discard;
267 #ifdef USE_TIMEOUT
268     rt_uint32_t to = 10;
269 #endif
270 
271     RT_UNUSED(discard);
272 
273     //rt_kprintf("in readblock:%x\n",address);
274     //Clear all the errors & interrups
275     *(RP)DMAC_INTINTERRCLR  |= 0x1;
276     *(RP)DMAC_INTINTERRCLR  &= ~0x1;
277     *(RP)DMAC_INTTCCLEAR    |= 0x1;
278     *(RP)DMAC_INTTCCLEAR    &= ~0x1;
279 
280     /*Clear read fifo*/
281     *(RP)(SDC_INTERRUPT_STATUS_MASK) = ~(0x1 << 9); //don't mask fifo empty
282     while ((*(RP)SDC_INTERRUPT_STATUS) & 0x200 != 0x200)
283         discard = *(RP)SDC_READ_BUFER_ACCESS;
284 
285     /*DMAC2,word,size=0x80*/
286     *(RP)DMAC_C2SRCADDR  = SDC_READ_BUFER_ACCESS;
287     *(RP)DMAC_C2DESTADDR = (rt_uint32_t)buf;
288     *(RP)DMAC_C2CONTROL  = 0x20249b;
289     *(RP)DMAC_C2CONFIGURATION = 0x38d;
290 
291     err = cmd_wait(0x6ea, RCA, 0xfff);
292     if (err != RT_EOK)
293     {
294         rt_set_errno(err);
295         return err;
296     }
297 
298     err = cmd_wait(0xca, 0x2, 0xfff);
299     if (err != RT_EOK)
300     {
301         rt_set_errno(err);
302         return err;
303     }
304 
305     err = cmd_response(0x22e, address, 0X1, 0x0200, 0x1, 0Xfff); //CMD17 4bit mode
306     if (err != RT_EOK)
307     {
308         rt_set_errno(err);
309         return err;
310     }
311 
312     complete = *(RP)SDC_INTERRUPT_STATUS;
313 
314     /*CRC*/
315     if ((complete | 0xfffffffd) != 0xfffffffd)
316     {
317         rt_kprintf("CRC ERROR!!!\n");
318         complete = *(RP)SDC_INTERRUPT_STATUS;
319     }
320     while (((*(RP)(DMAC_INTTCSTATUS)) & 0x4) != 0x4)
321     {
322         delay(10);
323 #ifdef USE_TIMEOUT
324         to--;
325         if (!to)
326         {
327             EOUT("%s TIMEOUT\n", __FUNCTION__);
328             return -RT_ETIMEOUT;
329         }
330 #endif
331     }
332 #ifdef USE_TIMEOUT
333     //DBOUT("%s timeout is %d\n",__FUNCTION__,to);
334 #endif
335     /*for the buf is big-endian we must reverse it*/
336     for (i = 0; i < 0x80; i++)
337     {
338         temp = buf[0];
339         buf[0] = buf[3];
340         buf[3] = temp;
341 
342         temp = buf[1];
343         buf[1] = buf[2];
344         buf[2] = temp;
345 
346         buf += 4;
347     }
348 
349     return RT_EOK;
350 }
351 
sd_readmultiblock(rt_uint32_t address,rt_uint8_t * buf,rt_uint32_t size)352 static rt_uint8_t sd_readmultiblock(rt_uint32_t address, rt_uint8_t *buf, rt_uint32_t size)
353 {
354     rt_int32_t index;
355     rt_uint8_t status = RT_EOK;
356 
357     for (index = 0; index < size; index++)
358     {
359         status = sd_readblock(address + index * SECTOR_SIZE, buf + index * SECTOR_SIZE);
360         if (status != RT_EOK)
361             break;
362     }
363     return status;
364 }
365 
366 /**
367  * This function will set a hook function, which will be invoked when a memory
368  * block is allocated from heap memory.
369  *
370  * @param hook the hook function
371  */
sd_writeblock(rt_uint32_t address,rt_uint8_t * buf)372 static rt_uint8_t sd_writeblock(rt_uint32_t address, rt_uint8_t *buf)
373 {
374     U32 complete;
375     rt_uint8_t temp;
376     rt_uint8_t *ptr = buf;
377     rt_err_t err;
378 #ifdef USE_TIMEOUT
379     rt_uint32_t to = 10;
380 #endif
381 
382     int i;
383 
384     rt_kprintf("in writeblock:%x\n", address);
385 
386     /*for the buf is big-endian we must reverse it*/
387     for (i = 0; i < 0x80; i++)
388     {
389         temp = ptr[0];
390         ptr[0] = ptr[3];
391         ptr[3] = temp;
392 
393         temp = ptr[1];
394         ptr[1] = ptr[2];
395         ptr[2] = temp;
396 
397         ptr += 4;
398     }
399     //Clear all the errors & interrups
400     *(RP)DMAC_INTINTERRCLR  |= 0x1;
401     *(RP)DMAC_INTINTERRCLR  &= ~0x1;
402     *(RP)DMAC_INTTCCLEAR    |= 0x1;
403     *(RP)DMAC_INTTCCLEAR    &= ~0x1;
404 
405     *(RP)DMAC_C2SRCADDR  = (U32)buf;
406     *(RP)DMAC_C2DESTADDR = SDC_WRITE_BUFER_ACCESS;
407     *(RP)DMAC_C2CONTROL  = 0x20149b;
408     *(RP)DMAC_C2CONFIGURATION = 0x380b;
409 
410 
411     err = cmd_wait(0x6ea, RCA, 0xfff);
412     if (err != RT_EOK)
413     {
414         rt_set_errno(err);
415         return err;
416     }
417 
418     err = cmd_wait(0xca, 0x2, 0xfff);
419     if (err != RT_EOK)
420     {
421         rt_set_errno(err);
422         return err;
423     }
424 
425     err = cmd_response(0x30e, address, 0X3, 0x0200, 0x1, 0Xfff); //CMD24  1bit mode
426     if (err != RT_EOK)
427     {
428         rt_set_errno(err);
429         return err;
430     }
431 
432     complete = *(RP)SDC_INTERRUPT_STATUS;
433 
434     if ((complete | 0xfffffffe) != 0xfffffffe)
435     {
436         //printf("CRC ERROR");
437         complete = *(RP)SDC_INTERRUPT_STATUS;
438     }
439 
440     while (((*(RP)(DMAC_INTTCSTATUS)) & 0x4) != 0x4)
441     {
442         delay(10);
443 #ifdef USE_TIMEOUT
444         to--;
445         if (!to)
446         {
447             EOUT("%s TIMEOUT\n", __FUNCTION__);
448         }
449 #endif
450     }
451 #ifdef USE_TIMEOUT
452     //DBOUT("%s timeout is %d\n",__FUNCTION__,to);
453 #endif
454 
455     return RT_EOK;
456 }
457 
458 
459 /**
460  * This function will set a hook function, which will be invoked when a memory
461  * block is allocated from heap memory.
462  *
463  * @param hook the hook function
464  */
rt_sdcard_init(rt_device_t dev)465 static rt_err_t rt_sdcard_init(rt_device_t dev)
466 {
467     return 0;
468 }
469 
470 /**
471  * This function will set a hook function, which will be invoked when a memory
472  * block is allocated from heap memory.
473  *
474  * @param hook the hook function
475  */
rt_sdcard_open(rt_device_t dev,rt_uint16_t oflag)476 static rt_err_t rt_sdcard_open(rt_device_t dev, rt_uint16_t oflag)
477 {
478     return 0;
479 }
480 
481 /**
482  * This function will set a hook function, which will be invoked when a memory
483  * block is allocated from heap memory.
484  *
485  * @param hook the hook function
486  */
rt_sdcard_close(rt_device_t dev)487 static rt_err_t rt_sdcard_close(rt_device_t dev)
488 {
489     return 0;
490 }
491 
492 /**
493  * This function will set a hook function, which will be invoked when a memory
494  * block is allocated from heap memory.
495  *
496  * @param hook the hook function
497  */
rt_sdcard_control(rt_device_t dev,int cmd,void * args)498 static rt_err_t rt_sdcard_control(rt_device_t dev, int cmd, void *args)
499 {
500     rt_kprintf("cmd = %d\n", cmd);
501     RT_ASSERT(dev != RT_NULL);
502 
503     if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
504     {
505         struct rt_device_blk_geometry *geometry;
506 
507         geometry = (struct rt_device_blk_geometry *)args;
508         if (geometry == RT_NULL) return -RT_ERROR;
509 
510         geometry->bytes_per_sector = 512;
511         geometry->block_size = 0x200000;
512         //if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)
513         //  geometry->sector_count = (SDCardInfo.SD_csd.DeviceSize + 1)  * 1024;
514         //else
515         geometry->sector_count = 0x200000;//SDCardInfo.CardCapacity/SDCardInfo.CardBlockSize;
516     }
517 
518     return RT_EOK;
519 }
520 
521 /**
522  * This function will set a hook function, which will be invoked when a memory
523  * block is allocated from heap memory.
524  *
525  * @param hook the hook function
526  */
rt_sdcard_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)527 static rt_ssize_t rt_sdcard_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
528 {
529     rt_uint32_t retry = 3;
530     rt_uint8_t  status;
531     rt_uint32_t index;
532 
533     struct dfs_partition *part;
534 
535     if (dev == RT_NULL)
536     {
537         rt_set_errno(-DFS_STATUS_EINVAL);
538         return 0;
539     }
540 
541     part = (struct dfs_partition *)dev->user_data;
542     // take the semaphore
543     rt_sem_take(part->lock, RT_WAITING_FOREVER);
544     while (retry--)
545     {
546         if (((rt_uint32_t)buffer % 4 != 0) ||
547                 ((rt_uint32_t)buffer > 0x20080000))
548         {
549             for (index = 0; index < size; index++)
550             {
551                 status = sd_readblock((part->offset + pos) * SECTOR_SIZE, ptr_sddev->sec_buf);
552                 if (status != RT_EOK)
553                     break;
554 
555                 rt_memcpy((rt_uint8_t *)buffer + (index * SECTOR_SIZE), ptr_sddev->sec_buf, SECTOR_SIZE);
556             }
557         }
558         else
559         {
560             for (index = 0; index < size; index++)
561             {
562                 status = sd_readblock((pos) * SECTOR_SIZE, (rt_uint8_t *)buffer + index * SECTOR_SIZE);
563                 if (status != RT_EOK)
564                     break;
565             }
566         }
567 
568     }
569     rt_sem_release(part->lock);
570 
571     if (status == RT_EOK)
572         return size;
573 
574     rt_kprintf("read failed: %d, buffer 0x%08x\n", status, buffer);
575     return 0;
576 
577 }
578 
579 /**
580  * This function will set a hook function, which will be invoked when a memory
581  * block is allocated from heap memory.
582  *
583  * @param hook the hook function
584  */
rt_sdcard_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)585 static rt_ssize_t rt_sdcard_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
586 {
587     int i;
588     rt_uint8_t status;
589     struct dfs_partition *part;
590 
591     if (dev == RT_NULL)
592     {
593         rt_set_errno(-DFS_STATUS_EINVAL);
594         return 0;
595     }
596 
597     part = (struct dfs_partition *)dev->user_data;
598 
599     rt_sem_take(part->lock, RT_WAITING_FOREVER);
600 
601     if (((rt_uint32_t)buffer % 4 != 0) ||
602             ((rt_uint32_t)buffer > 0x20080000))
603     {
604         rt_uint32_t index;
605 
606         for (index = 0; index < size; index++)
607         {
608             rt_memcpy(ptr_sddev->sec_buf, ((rt_uint8_t *)buffer + index * SECTOR_SIZE), SECTOR_SIZE);
609             status = sd_writeblock((part->offset + index + pos) * SECTOR_SIZE, ptr_sddev->sec_buf);
610         }
611     }
612     else
613     {
614 
615         for (i = 0; i < size; i++)
616         {
617             status = sd_writeblock((part->offset + i + pos) * SECTOR_SIZE,
618                                    (rt_uint8_t *)((rt_uint8_t *)buffer + i * SECTOR_SIZE));
619             if (status != RT_EOK) break;
620         }
621     }
622 
623     rt_sem_release(part->lock);
624 
625     if (status == RT_EOK)
626         return size;
627 
628     rt_kprintf("read failed: %d, buffer 0x%08x\n", status, buffer);
629     return 0;
630 }
631 
632 
rt_hw_sdcard_exit()633 rt_err_t rt_hw_sdcard_exit()
634 {
635     if (ptr_sddev->device != RT_NULL)
636         rt_free(ptr_sddev->device);
637     if (ptr_sddev->part != RT_NULL)
638         rt_free(ptr_sddev->part);
639     if (ptr_sddev != RT_NULL)
640         rt_free(ptr_sddev);
641 
642     return RT_EOK;
643 }
644 
645 /**
646  * This function will init sd card
647  *
648  * @param void
649  */
rt_hw_sdcard_init()650 rt_err_t rt_hw_sdcard_init()
651 {
652     /*For test*/
653     rt_err_t err;
654     rt_int32_t i;
655 
656     char dname[4];
657     char sname[8];
658 
659     /*Initialize structure*/
660 
661     ptr_sddev = (struct sd_device *)rt_malloc(sizeof(struct sd_device));
662     if (ptr_sddev == RT_NULL)
663     {
664         EOUT("Failed to allocate sdcard device structure\n");
665         return -RT_ENOMEM;
666     }
667 
668     /*sdcard intialize*/
669     err = sd_init();
670     if (err != RT_EOK)
671         goto FAIL2;
672 
673     /*set sector buffer*/
674     ptr_sddev->sec_buf = gsec_buf;
675     ptr_sddev->buf_size = SECTOR_SIZE;
676     ptr_sddev->sdc = (struct sd_c *)SD_BASE;
677 
678     //DBOUT("allocate partition sector buffer OK!");
679 
680     err = sd_readblock(0, ptr_sddev->sec_buf);
681     if (err != RT_EOK)
682     {
683         EOUT("read first block error\n");
684         goto FAIL2;
685     }
686 
687     /*sdcard driver initialize*/
688     ptr_sddev->part = (struct dfs_partition *)rt_malloc(4 * sizeof(struct dfs_partition));
689     if (ptr_sddev->part == RT_NULL)
690     {
691         EOUT("allocate partition failed\n");
692         err =  -RT_ENOMEM;
693         goto FAIL2;
694     }
695 
696     /*alloc device buffer*/
697     ptr_sddev->device = (struct rt_device *)rt_malloc(4 * sizeof(struct rt_device));
698     if (ptr_sddev->device == RT_NULL)
699     {
700         EOUT("allocate device failed\n");
701         err = -RT_ENOMEM;
702         goto FAIL1;
703     }
704 
705     ptr_sddev->part_num = 0;
706 
707     err = sd_readblock(0, ptr_sddev->sec_buf);
708 
709     if (err != RT_EOK)
710     {
711         EOUT("Read block 0 to initialize ERROR\n");
712         goto FAIL1;
713     }
714 
715     for (i = 0; i < 4; i++)
716     {
717         /* get the first partition */
718         err = dfs_filesystem_get_partition(&(ptr_sddev->part[i]), ptr_sddev->sec_buf, i);
719         if (err == RT_EOK)
720         {
721             rt_snprintf(dname, 4, "sd%d",  i);
722             rt_snprintf(sname, 8, "sem_sd%d",  i);
723             ptr_sddev->part[i].lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
724 
725             /* register sdcard device */
726             ptr_sddev->device[i].init = rt_sdcard_init;
727             ptr_sddev->device[i].open = rt_sdcard_open;
728             ptr_sddev->device[i].close = rt_sdcard_close;
729             ptr_sddev->device[i].read = rt_sdcard_read;
730             ptr_sddev->device[i].write = rt_sdcard_write;
731             ptr_sddev->device[i].control = rt_sdcard_control;
732             ptr_sddev->device[i].user_data = &ptr_sddev->part[i];
733 
734             err = rt_device_register(&ptr_sddev->device[i], dname,
735                                      RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
736 
737             if (err == RT_EOK)
738                 ptr_sddev->part_num++;
739         }
740         else
741         {
742             if (i == 0)
743             {
744                 /* there is no partition table */
745                 ptr_sddev->part[0].offset = 0;
746                 ptr_sddev->part[0].size   = 0;
747                 ptr_sddev->part[0].lock = rt_sem_create("sem_sd0", 1, RT_IPC_FLAG_FIFO);
748 
749                 /* register sdcard device */
750                 ptr_sddev->device[0].init = rt_sdcard_init;
751                 ptr_sddev->device[0].open = rt_sdcard_open;
752                 ptr_sddev->device[0].close = rt_sdcard_close;
753                 ptr_sddev->device[0].read = rt_sdcard_read;
754                 ptr_sddev->device[0].write = rt_sdcard_write;
755                 ptr_sddev->device[0].control = rt_sdcard_control;
756                 ptr_sddev->device[0].user_data = &ptr_sddev->part[0];
757 
758                 err = rt_device_register(&ptr_sddev->device[0], "sd0",
759                                          RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
760 
761                 if (err == RT_EOK)
762                     ptr_sddev->part_num++;
763 
764                 break;
765             }
766         }
767     }
768 
769     if (ptr_sddev->part_num == 0)
770         goto FAIL0;
771 
772     return err;
773 
774 FAIL0:
775     rt_free(ptr_sddev->device);
776     ptr_sddev->device = RT_NULL;
777 
778 FAIL1:
779     rt_free(ptr_sddev->part);
780     ptr_sddev->part = RT_NULL;
781 
782 FAIL2:
783     rt_free(ptr_sddev);
784     ptr_sddev = RT_NULL;
785 
786     return err;
787 }
788 
789 #endif
790