Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
TASTE
uPython-mirror
Commits
56506fd6
Commit
56506fd6
authored
Jan 29, 2017
by
Damien George
Browse files
cc3200: Convert to use new VFS sub-system and new ooFatFs library.
parent
6eafa544
Changes
16
Hide whitespace changes
Inline
Side-by-side
cc3200/Makefile
View file @
56506fd6
...
...
@@ -23,6 +23,7 @@ CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -march=armv7e-m -mabi=aapcs -mcpu=co
CFLAGS
=
-Wall
-Wpointer-arith
-Werror
-ansi
-std
=
gnu99
-nostdlib
$(CFLAGS_CORTEX_M4)
-Os
CFLAGS
+=
-g
-ffunction-sections
-fdata-sections
-fno-common
-fsigned-char
-mno-unaligned-access
CFLAGS
+=
-Iboards
/
$(BOARD)
CFLAGS
+=
$(CFLAGS_MOD)
LDFLAGS
=
-Wl
,-nostdlib
-Wl
,--gc-sections
-Wl
,-Map
=
$@
.map
...
...
cc3200/application.mk
View file @
56506fd6
...
...
@@ -18,7 +18,6 @@ APP_INC += -Iutil
APP_INC
+=
-Ibootmgr
APP_INC
+=
-I
$(BUILD)
APP_INC
+=
-I
$(BUILD)
/genhdr
APP_INC
+=
-I
../lib/fatfs
APP_INC
+=
-I
../lib/mp-readline
APP_INC
+=
-I
../lib/netutils
APP_INC
+=
-I
../lib/timeutils
...
...
@@ -29,9 +28,6 @@ APP_CPPDEFINES = -Dgcc -DTARGET_IS_CC3200 -DSL_FULL -DUSE_FREERTOS
APP_FATFS_SRC_C
=
$(
addprefix
fatfs/src/,
\
drivers/sflash_diskio.c
\
drivers/sd_diskio.c
\
option/syscall.c
\
diskio.c
\
ffconf.c
\
)
APP_RTOS_SRC_C
=
$(
addprefix
FreeRTOS/Source/,
\
...
...
@@ -98,6 +94,7 @@ APP_MODS_SRC_C = $(addprefix mods/,\
pybpin.c
\
pybi2c.c
\
pybrtc.c
\
pybflash.c
\
pybsd.c
\
pybsleep.c
\
pybspi.c
\
...
...
@@ -143,11 +140,12 @@ APP_MAIN_SRC_C = \
main.c
\
mptask.c
\
mpthreadport.c
\
serverstask.c
serverstask.c
\
fatfs_port.c
\
APP_LIB_SRC_C
=
$(
addprefix
lib/,
\
fatfs/ff.c
\
fatfs/option/
ccsbcs
.c
\
oo
fatfs/ff.c
\
oo
fatfs/option/
unicode
.c
\
libc/string0.c
\
mp-readline/readline.c
\
netutils/netutils.c
\
...
...
cc3200/fatfs/src/diskio.c
deleted
100644 → 0
View file @
6eafa544
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2014 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include
<stdint.h>
#include
<stdbool.h>
#include
"py/mpconfig.h"
#include
"py/runtime.h"
#include
"py/obj.h"
#include
"lib/fatfs/ff.h"
#include
"lib/fatfs/diskio.h"
/* FatFs lower layer API */
#include
"sflash_diskio.h"
/* Serial flash disk IO API */
#include
"sd_diskio.h"
/* SDCARD disk IO API */
#include
"inc/hw_types.h"
#include
"inc/hw_ints.h"
#include
"inc/hw_memmap.h"
#include
"rom_map.h"
#include
"prcm.h"
#include
"pybrtc.h"
#include
"timeutils.h"
#include
"pybsd.h"
#include
"moduos.h"
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS
disk_status
(
BYTE
pdrv
/* Physical drive nmuber to identify the drive */
)
{
if
(
pdrv
==
PD_FLASH
)
{
return
sflash_disk_status
();
}
else
{
os_fs_mount_t
*
mount_obj
;
if
((
mount_obj
=
osmount_find_by_volume
(
pdrv
)))
{
if
(
mount_obj
->
writeblocks
[
0
]
==
MP_OBJ_NULL
)
{
return
STA_PROTECT
;
}
return
0
;
}
}
return
STA_NODISK
;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS
disk_initialize
(
BYTE
pdrv
/* Physical drive nmuber to identify the drive */
)
{
if
(
pdrv
==
PD_FLASH
)
{
if
(
RES_OK
!=
sflash_disk_init
())
{
return
STA_NOINIT
;
}
}
else
{
os_fs_mount_t
*
mount_obj
;
if
((
mount_obj
=
osmount_find_by_volume
(
pdrv
)))
{
if
(
mount_obj
->
writeblocks
[
0
]
==
MP_OBJ_NULL
)
{
return
STA_PROTECT
;
}
return
0
;
}
}
return
STA_NODISK
;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT
disk_read
(
BYTE
pdrv
,
/* Physical drive nmuber to identify the drive */
BYTE
*
buff
,
/* Data buffer to store read data */
DWORD
sector
,
/* Sector address in LBA */
UINT
count
/* Number of sectors to read */
)
{
if
(
pdrv
==
PD_FLASH
)
{
return
sflash_disk_read
(
buff
,
sector
,
count
);
}
else
{
os_fs_mount_t
*
mount_obj
;
if
((
mount_obj
=
osmount_find_by_volume
(
pdrv
)))
{
// optimization for the built-in sd card device
if
(
mount_obj
->
device
==
(
mp_obj_t
)
&
pybsd_obj
)
{
return
sd_disk_read
(
buff
,
sector
,
count
);
}
mount_obj
->
readblocks
[
2
]
=
MP_OBJ_NEW_SMALL_INT
(
sector
);
mount_obj
->
readblocks
[
3
]
=
mp_obj_new_bytearray_by_ref
(
count
*
512
,
buff
);
return
mp_obj_get_int
(
mp_call_method_n_kw
(
2
,
0
,
mount_obj
->
readblocks
));
}
// nothing mounted
return
RES_ERROR
;
}
return
RES_PARERR
;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if _USE_WRITE
DRESULT
disk_write
(
BYTE
pdrv
,
/* Physical drive nmuber to identify the drive */
const
BYTE
*
buff
,
/* Data to be written */
DWORD
sector
,
/* Sector address in LBA */
UINT
count
/* Number of sectors to write */
)
{
if
(
pdrv
==
PD_FLASH
)
{
return
sflash_disk_write
(
buff
,
sector
,
count
);
}
else
{
os_fs_mount_t
*
mount_obj
;
if
((
mount_obj
=
osmount_find_by_volume
(
pdrv
)))
{
// optimization for the built-in sd card device
if
(
mount_obj
->
device
==
(
mp_obj_t
)
&
pybsd_obj
)
{
return
sd_disk_write
(
buff
,
sector
,
count
);
}
mount_obj
->
writeblocks
[
2
]
=
MP_OBJ_NEW_SMALL_INT
(
sector
);
mount_obj
->
writeblocks
[
3
]
=
mp_obj_new_bytearray_by_ref
(
count
*
512
,
(
void
*
)
buff
);
return
mp_obj_get_int
(
mp_call_method_n_kw
(
2
,
0
,
mount_obj
->
writeblocks
));
}
// nothing mounted
return
RES_ERROR
;
}
return
RES_PARERR
;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
#if _USE_IOCTL
DRESULT
disk_ioctl
(
BYTE
pdrv
,
/* Physical drive nmuber (0..) */
BYTE
cmd
,
/* Control code */
void
*
buff
/* Buffer to send/receive control data */
)
{
if
(
pdrv
==
PD_FLASH
)
{
switch
(
cmd
)
{
case
CTRL_SYNC
:
return
sflash_disk_flush
();
case
GET_SECTOR_COUNT
:
*
((
DWORD
*
)
buff
)
=
SFLASH_SECTOR_COUNT
;
return
RES_OK
;
case
GET_SECTOR_SIZE
:
*
((
DWORD
*
)
buff
)
=
SFLASH_SECTOR_SIZE
;
return
RES_OK
;
case
GET_BLOCK_SIZE
:
*
((
DWORD
*
)
buff
)
=
1
;
// high-level sector erase size in units of the block size
return
RES_OK
;
}
}
else
{
os_fs_mount_t
*
mount_obj
;
if
((
mount_obj
=
osmount_find_by_volume
(
pdrv
)))
{
switch
(
cmd
)
{
case
CTRL_SYNC
:
if
(
mount_obj
->
sync
[
0
]
!=
MP_OBJ_NULL
)
{
mp_call_method_n_kw
(
0
,
0
,
mount_obj
->
sync
);
}
return
RES_OK
;
case
GET_SECTOR_COUNT
:
// optimization for the built-in sd card device
if
(
mount_obj
->
device
==
(
mp_obj_t
)
&
pybsd_obj
)
{
*
((
DWORD
*
)
buff
)
=
sd_disk_info
.
ulNofBlock
*
(
sd_disk_info
.
ulBlockSize
/
512
);
}
else
{
*
((
DWORD
*
)
buff
)
=
mp_obj_get_int
(
mp_call_method_n_kw
(
0
,
0
,
mount_obj
->
count
));
}
return
RES_OK
;
case
GET_SECTOR_SIZE
:
*
((
DWORD
*
)
buff
)
=
SD_SECTOR_SIZE
;
// Sector size is fixed to 512 bytes, as with SD cards
return
RES_OK
;
case
GET_BLOCK_SIZE
:
*
((
DWORD
*
)
buff
)
=
1
;
// high-level sector erase size in units of the block size
return
RES_OK
;
}
}
// nothing mounted
return
RES_ERROR
;
}
return
RES_PARERR
;
}
#endif
#if !_FS_READONLY && !_FS_NORTC
DWORD
get_fattime
(
void
)
{
timeutils_struct_time_t
tm
;
timeutils_seconds_since_2000_to_struct_time
(
pyb_rtc_get_seconds
(),
&
tm
);
return
((
tm
.
tm_year
-
1980
)
<<
25
)
|
((
tm
.
tm_mon
)
<<
21
)
|
((
tm
.
tm_mday
)
<<
16
)
|
((
tm
.
tm_hour
)
<<
11
)
|
((
tm
.
tm_min
)
<<
5
)
|
(
tm
.
tm_sec
>>
1
);
}
#endif
cc3200/fatfs/src/drivers/sd_diskio.c
View file @
56506fd6
...
...
@@ -39,11 +39,12 @@
#include
"py/mpconfig.h"
#include
"py/mphal.h"
#include
"lib/oofatfs/ff.h"
#include
"lib/oofatfs/diskio.h"
#include
"hw_types.h"
#include
"hw_memmap.h"
#include
"hw_ints.h"
#include
"rom_map.h"
#include
"diskio.h"
#include
"sd_diskio.h"
#include
"sdhost.h"
#include
"pin.h"
...
...
cc3200/fatfs/src/drivers/sflash_diskio.c
View file @
56506fd6
...
...
@@ -4,8 +4,9 @@
#include
"py/mpconfig.h"
#include
"py/obj.h"
#include
"lib/oofatfs/ff.h"
#include
"lib/oofatfs/diskio.h"
#include
"simplelink.h"
#include
"diskio.h"
#include
"sflash_diskio.h"
#include
"debug.h"
#include
"modnetwork.h"
...
...
cc3200/fatfs/src/option/syscall.c
deleted
100644 → 0
View file @
6eafa544
/*------------------------------------------------------------------------*/
/* Sample code of OS dependent controls for FatFs */
/* (C)ChaN, 2014 */
/*------------------------------------------------------------------------*/
#include
"ff.h"
#if _FS_REENTRANT
/*------------------------------------------------------------------------*/
/* Create a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to create a new
/ synchronization object, such as semaphore and mutex. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int
ff_cre_syncobj
(
/* !=0:Function succeeded, ==0:Could not create due to any error */
BYTE
vol
,
/* Corresponding logical drive being processed */
_SYNC_t
*
sobj
/* Pointer to return the created sync object */
)
{
int
ret
;
//
// *sobj = CreateMutex(NULL, FALSE, NULL); /* Win32 */
// ret = (int)(*sobj != INVALID_HANDLE_VALUE);
// *sobj = SyncObjects[vol]; /* uITRON (give a static created sync object) */
// ret = 1; /* The initial value of the semaphore must be 1. */
// *sobj = OSMutexCreate(0, &err); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
vSemaphoreCreateBinary
(
(
*
sobj
)
);
/* FreeRTOS */
ret
=
(
int
)(
*
sobj
!=
NULL
);
return
ret
;
}
/*------------------------------------------------------------------------*/
/* Delete a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to delete a synchronization
/ object that created with ff_cre_syncobj function. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int
ff_del_syncobj
(
/* !=0:Function succeeded, ==0:Could not delete due to any error */
_SYNC_t
sobj
/* Sync object tied to the logical drive to be deleted */
)
{
int
ret
;
// ret = CloseHandle(sobj); /* Win32 */
// ret = 1; /* uITRON (nothing to do) */
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
vSemaphoreDelete
(
sobj
);
/* FreeRTOS */
ret
=
1
;
return
ret
;
}
/*------------------------------------------------------------------------*/
/* Request Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on entering file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int
ff_req_grant
(
/* 1:Got a grant to access the volume, 0:Could not get a grant */
_SYNC_t
sobj
/* Sync object to wait */
)
{
int
ret
;
// ret = (int)(WaitForSingleObject(sobj, _FS_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */
// ret = (int)(wai_sem(sobj) == E_OK); /* uITRON */
// OSMutexPend(sobj, _FS_TIMEOUT, &err)); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
ret
=
(
int
)(
xSemaphoreTake
(
sobj
,
_FS_TIMEOUT
)
==
pdTRUE
);
/* FreeRTOS */
return
ret
;
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/
void
ff_rel_grant
(
_SYNC_t
sobj
/* Sync object to be signaled */
)
{
// ReleaseMutex(sobj); /* Win32 */
// sig_sem(sobj); /* uITRON */
// OSMutexPost(sobj); /* uC/OS-II */
xSemaphoreGive
(
sobj
);
/* FreeRTOS */
}
#endif
#if _USE_LFN == 3
/* LFN with a working buffer on the heap */
/*------------------------------------------------------------------------*/
/* Allocate a memory block */
/*------------------------------------------------------------------------*/
/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE.
*/
void
*
ff_memalloc
(
/* Returns pointer to the allocated memory block */
UINT
msize
/* Number of bytes to allocate */
)
{
return
pvPortMalloc
(
msize
);
/* Allocate a new memory block with POSIX API */
}
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void
ff_memfree
(
void
*
mblock
/* Pointer to the memory block to free */
)
{
vPortFree
(
mblock
);
/* Discard the memory block with POSIX API */
}
#endif
cc3200/fatfs
/src/ffconf
.c
→
cc3200/fatfs
_port
.c
View file @
56506fd6
/*
* This file is part of the Micro
Python project, http://micropython.org/
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2013-2017 Damien P. George
* Parts of this file are (C)ChaN, 2014, from FatFs option/syscall.c
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
...
...
@@ -24,70 +25,50 @@
* THE SOFTWARE.
*/
#include
<string.h>
#include
"py/runtime.h"
#include
"lib/oofatfs/ff.h"
#include
"lib/timeutils/timeutils.h"
#include
"mods/pybrtc.h"
#i
nclude
"py/mpstate.h"
#include
"lib/fatfs/ff.h"
#include
"lib/fatfs/ffconf.h"
#include
"lib/fatfs/diskio.h"
#include
"moduos.h"
#if _FS_RPATH
extern
BYTE
ff_CurrVol
;
#endif
#i
f _FS_REENTRANT
// Create a Synchronization Object
// This function is called in f_mount() function to create a new
// synchronization object, such as semaphore and mutex.
// A return of 0 indicates failure, and then f_mount() fails with FR_INT_ERR.
int
ff_cre_syncobj
(
FATFS
*
fatfs
,
_SYNC_t
*
sobj
)
{
vSemaphoreCreateBinary
((
*
sobj
));
return
(
int
)(
*
sobj
!=
NULL
)
;
}
STATIC
bool
check_path
(
const
TCHAR
**
path
,
const
char
*
mount_point_str
,
mp_uint_t
mount_point_len
)
{
if
(
strncmp
(
*
path
,
mount_point_str
,
mount_point_len
)
==
0
)
{
if
((
*
path
)[
mount_point_len
]
==
'/'
)
{
*
path
+=
mount_point_len
;
return
true
;
}
else
if
((
*
path
)[
mount_point_len
]
==
'\0'
)
{
*
path
=
"/"
;
return
true
;
}
}
return
false
;
// Delete a Synchronization Object
// This function is called in f_mount() function to delete a synchronization
// object that created with ff_cre_syncobj function.
// A return of 0 indicates failure, and then f_mount() fails with FR_INT_ERR.
int
ff_del_syncobj
(
_SYNC_t
sobj
)
{
vSemaphoreDelete
(
sobj
);
return
1
;
}
//
"path" is the path to lookup; will advance this pointer beyond
the
v
olume
name.
//
Returns logical drive number (-1 means invalid path)
.
int
ff_get_ldnumber
(
const
TCHAR
**
path
)
{
if
(
!
(
*
path
)
)
{
return
-
1
;
}
//
Request Grant to Access
the
V
olume
//
This function is called on entering file functions to lock the volume
.
// When a 0 is returned, the file function fails with FR_TIMEOUT.
int
ff_req_grant
(
_SYNC_t
sobj
)
{
return
(
int
)(
xSemaphoreTake
(
sobj
,
_FS_TIMEOUT
)
==
pdTRUE
)
;
}
if
(
**
path
!=
'/'
)
{
#if _FS_RPATH
return
ff_CurrVol
;
#else
return
-
1
;
#endif
}
// Release Grant to Access the Volume
// This function is called on leaving file functions to unlock the volume.
void
ff_rel_grant
(
_SYNC_t
sobj
)
{
xSemaphoreGive
(
sobj
);
}
if
(
check_path
(
path
,
"/flash"
,
6
))
{
return
PD_FLASH
;
}
else
{
for
(
mp_uint_t
i
=
0
;
i
<
MP_STATE_PORT
(
mount_obj_list
).
len
;
i
++
)
{
os_fs_mount_t
*
mount_obj
=
((
os_fs_mount_t
*
)(
MP_STATE_PORT
(
mount_obj_list
).
items
[
i
]));
if
(
check_path
(
path
,
mount_obj
->
path
,
mount_obj
->
pathlen
))
{
return
mount_obj
->
vol
;
}
}
}
#endif
return
-
1
;
}
DWORD
get_fattime
(
void
)
{
timeutils_struct_time_t
tm
;
timeutils_seconds_since_2000_to_struct_time
(
pyb_rtc_get_seconds
(),
&
tm
);
void
ff_get_volname
(
BYTE
vol
,
TCHAR
**
dest
)
{
if
(
vol
==
PD_FLASH
)
{
memcpy
(
*
dest
,
"/flash"
,
6
);
*
dest
+=
6
;
}
else
{
os_fs_mount_t
*
mount_obj
;
if
((
mount_obj
=
osmount_find_by_volume
(
vol
)))
{
memcpy
(
*
dest
,
mount_obj
->
path
,
mount_obj
->
pathlen
);
*
dest
+=
mount_obj
->
pathlen
;
}
}
return
((
tm
.
tm_year
-
1980
)
<<
25
)
|
((
tm
.
tm_mon
)
<<
21
)
|
((
tm
.
tm_mday
)
<<
16
)
|
((
tm
.
tm_hour
)
<<
11
)
|
((
tm
.
tm_min
)
<<
5
)
|
(
tm
.
tm_sec
>>
1
);
}
cc3200/ftp/ftp.c
View file @
56506fd6
...
...
@@ -30,6 +30,9 @@
#include
"py/mpstate.h"
#include
"py/obj.h"
#include
"lib/oofatfs/ff.h"
#include
"extmod/vfs.h"
#include
"extmod/fsusermount.h"
#include
"inc/hw_types.h"
#include
"inc/hw_ints.h"
#include
"inc/hw_memmap.h"
...
...
@@ -43,7 +46,6 @@
#include
"modusocket.h"
#include
"debug.h"
#include
"serverstask.h"
#include
"ff.h"
#include
"fifo.h"
#include
"socketfifo.h"
#include
"updater.h"
...
...
@@ -115,7 +117,7 @@ typedef struct {
uint8_t
*
dBuffer
;
uint32_t
ctimeout
;
union
{
DIR
dp
;
FF_
DIR
dp
;
FIL
fp
;
};
int16_t
lc_sd
;
...
...
@@ -192,6 +194,80 @@ static const ftp_month_t ftp_month[] = { { "Jan" }, { "Feb" }, { "Mar" }, { "Apr
static
SocketFifoElement_t
ftp_fifoelements
[
FTP_SOCKETFIFO_ELEMENTS_MAX
];
static
FIFO_t
ftp_socketfifo
;
/******************************************************************************
DEFINE VFS WRAPPER FUNCTIONS
******************************************************************************/
// These wrapper functions are used so that the FTP server can access the
// mounted FATFS devices directly without going through the costly mp_vfs_XXX
// functions. The latter may raise exceptions and we would then need to wrap
// all calls in an nlr handler. The wrapper functions below assume that there
// are only FATFS filesystems mounted.
STATIC
FATFS
*
lookup_path
(
const
TCHAR
**
path
)
{
mp_vfs_mount_t
*
fs
=
mp_vfs_lookup_path
(
*
path
,
path
);
if
(
fs
==
MP_VFS_NONE
||
fs
==
MP_VFS_ROOT
)
{
return
NULL
;
}
// here we assume that the mounted device is FATFS
return
&
((
fs_user_mount_t
*
)
MP_OBJ_TO_PTR
(
fs
->
obj
))
->
fatfs
;
}
STATIC
FRESULT
f_open_helper
(
FIL
*
fp
,
const
TCHAR
*
path
,
BYTE
mode
)
{
FATFS
*
fs
=
lookup_path
(
&
path
);
if
(
fs
==
NULL
)
{
return
FR_NO_PATH
;
}
return
f_open
(
fs
,
fp
,
path
,
mode
);
}
STATIC
FRESULT
f_opendir_helper
(
FF_DIR
*
dp
,
const
TCHAR
*
path
)
{
FATFS
*
fs
=
lookup_path
(
&
path
);
if
(
fs
==
NULL
)
{
return
FR_NO_PATH
;
}
return
f_opendir
(
fs
,
dp
,
path
);
}
STATIC
FRESULT
f_stat_helper
(
const
TCHAR
*
path
,
FILINFO
*
fno
)
{