forked from len0rd/rockbox
samsungypr0: Support or mounting the microsd
A thread polls the appropriate GPIO pin for sd card presence and mounts using the mount system call. Change-Id: I31ab41c4120f4af64eb6998b7e7b6f9051585efb
This commit is contained in:
parent
46137ebd4d
commit
f6c26d33a4
6 changed files with 272 additions and 36 deletions
|
|
@ -48,6 +48,7 @@
|
|||
#undef rmdir
|
||||
#undef dirent
|
||||
#undef DIR
|
||||
#undef readlink
|
||||
|
||||
#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
|
||||
static const char rbhome[] = "/sdcard";
|
||||
|
|
@ -61,6 +62,9 @@ const char *rbhome;
|
|||
* over the ones where Rockbox is installed to. Classic example would be
|
||||
* $HOME/.config/rockbox.org vs /usr/share/rockbox */
|
||||
#define HAVE_SPECIAL_DIRS
|
||||
#define IS_HOME(p) (!strcmp(p, rbhome))
|
||||
#else
|
||||
#define IS_HOME(p) (!strcmp(p, HOME_DIR))
|
||||
#endif
|
||||
|
||||
/* flags for get_user_file_path() */
|
||||
|
|
@ -70,6 +74,35 @@ const char *rbhome;
|
|||
/* file or directory? */
|
||||
#define IS_FILE (1<<1)
|
||||
|
||||
#ifdef HAVE_MULTIDRIVE
|
||||
/* A special link is created under e.g. HOME_DIR/<microSD1>, e.g. to access
|
||||
* external storage in a convinient location, much similar to the mount
|
||||
* point on our native targets. Here they are treated as symlink (one which
|
||||
* doesn't actually exist in the filesystem and therefore we have to override
|
||||
* readlink() */
|
||||
static const char *handle_special_links(const char* link, unsigned flags,
|
||||
char *buf, const size_t bufsize)
|
||||
{
|
||||
(void) flags;
|
||||
char vol_string[VOL_ENUM_POS + 8];
|
||||
int len = sprintf(vol_string, VOL_NAMES, 1);
|
||||
|
||||
/* link might be passed with or without HOME_DIR expanded. To handle
|
||||
* both perform substring matching (VOL_NAMES is unique enough) */
|
||||
const char *begin = strstr(link, vol_string);
|
||||
if (begin)
|
||||
{
|
||||
/* begin now points to the start of vol_string within link,
|
||||
* we want to copy the remainder of the paths, prefixed by
|
||||
* the actual mount point (the remainder might be "") */
|
||||
snprintf(buf, bufsize, MULTIDRIVE_DIR"%s", begin + len);
|
||||
return buf;
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SPECIAL_DIRS
|
||||
void paths_init(void)
|
||||
{
|
||||
|
|
@ -156,26 +189,7 @@ static const char* _get_user_file_path(const char *path,
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static const char* handle_special_dirs(const char* dir, unsigned flags,
|
||||
char *buf, const size_t bufsize)
|
||||
{
|
||||
if (!strncmp(HOME_DIR, dir, HOME_DIR_LEN))
|
||||
{
|
||||
const char *p = dir + HOME_DIR_LEN;
|
||||
while (*p == '/') p++;
|
||||
snprintf(buf, bufsize, "%s/%s", rbhome, p);
|
||||
return buf;
|
||||
}
|
||||
else if (!strncmp(ROCKBOX_DIR, dir, ROCKBOX_DIR_LEN))
|
||||
return _get_user_file_path(dir, flags, buf, bufsize);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
#else /* !HAVE_SPECIAL_DIRS */
|
||||
|
||||
#ifndef paths_init
|
||||
#elif !defined(paths_init)
|
||||
void paths_init(void) { }
|
||||
#endif
|
||||
|
||||
|
|
@ -183,11 +197,23 @@ static const char* handle_special_dirs(const char* dir, unsigned flags,
|
|||
char *buf, const size_t bufsize)
|
||||
{
|
||||
(void) flags; (void) buf; (void) bufsize;
|
||||
#ifdef HAVE_SPECIAL_DIRS
|
||||
if (!strncmp(HOME_DIR, dir, HOME_DIR_LEN))
|
||||
{
|
||||
const char *p = dir + HOME_DIR_LEN;
|
||||
while (*p == '/') p++;
|
||||
snprintf(buf, bufsize, "%s/%s", rbhome, p);
|
||||
dir = buf;
|
||||
}
|
||||
else if (!strncmp(ROCKBOX_DIR, dir, ROCKBOX_DIR_LEN))
|
||||
dir = _get_user_file_path(dir, flags, buf, bufsize);
|
||||
#endif
|
||||
#ifdef HAVE_MULTIDRIVE
|
||||
dir = handle_special_links(dir, flags, buf, bufsize);
|
||||
#endif
|
||||
return dir;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int app_open(const char *name, int o, ...)
|
||||
{
|
||||
char realpath[MAX_PATH];
|
||||
|
|
@ -235,6 +261,7 @@ int app_rename(const char *old, const char *new)
|
|||
* get_dir_info() */
|
||||
struct __dir {
|
||||
DIR *dir;
|
||||
IF_MD(int volumes_returned);
|
||||
char path[];
|
||||
};
|
||||
|
||||
|
|
@ -246,23 +273,31 @@ struct dirinfo dir_get_info(DIR* _parent, struct dirent *dir)
|
|||
struct dirinfo ret;
|
||||
char path[MAX_PATH];
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", parent->path, dir->d_name);
|
||||
memset(&ret, 0, sizeof(ret));
|
||||
|
||||
#ifdef HAVE_MULTIDRIVE
|
||||
char vol_string[VOL_ENUM_POS + 8];
|
||||
sprintf(vol_string, VOL_NAMES, 1);
|
||||
if (!strcmp(vol_string, dir->d_name))
|
||||
{
|
||||
ret.attribute = ATTR_LINK;
|
||||
strcpy(path, MULTIDRIVE_DIR);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
snprintf(path, sizeof(path), "%s/%s", parent->path, dir->d_name);
|
||||
|
||||
if (!stat(path, &s))
|
||||
{
|
||||
if (S_ISDIR(s.st_mode))
|
||||
{
|
||||
ret.attribute = ATTR_DIRECTORY;
|
||||
}
|
||||
ret.attribute |= ATTR_DIRECTORY;
|
||||
|
||||
ret.size = s.st_size;
|
||||
tm = localtime(&(s.st_mtime));
|
||||
}
|
||||
|
||||
if (!lstat(path, &s) && S_ISLNK(s.st_mode))
|
||||
{
|
||||
ret.attribute |= ATTR_LINK;
|
||||
}
|
||||
|
||||
if (tm)
|
||||
{
|
||||
|
|
@ -296,6 +331,7 @@ DIR* app_opendir(const char *_name)
|
|||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
IF_MD(this->volumes_returned = 0);
|
||||
return (DIR*)this;
|
||||
}
|
||||
|
||||
|
|
@ -311,6 +347,18 @@ int app_closedir(DIR *dir)
|
|||
struct dirent* app_readdir(DIR* dir)
|
||||
{
|
||||
struct __dir *d = (struct __dir*)dir;
|
||||
#ifdef HAVE_MULTIDRIVE
|
||||
/* this is not MT-safe but OK according to man readdir */
|
||||
static struct dirent voldir;
|
||||
if (d->volumes_returned < (NUM_VOLUMES-1)
|
||||
&& volume_present(d->volumes_returned+1)
|
||||
&& IS_HOME(d->path))
|
||||
{
|
||||
d->volumes_returned += 1;
|
||||
sprintf(voldir.d_name, VOL_NAMES, d->volumes_returned);
|
||||
return &voldir;
|
||||
}
|
||||
#endif
|
||||
return readdir(d->dir);
|
||||
}
|
||||
|
||||
|
|
@ -329,3 +377,26 @@ int app_rmdir(const char* name)
|
|||
const char *fname = handle_special_dirs(name, NEED_WRITE, realpath, sizeof(realpath));
|
||||
return rmdir(fname);
|
||||
}
|
||||
|
||||
|
||||
/* On MD we create a virtual symlink for the external drive,
|
||||
* for this we need to override readlink(). */
|
||||
ssize_t app_readlink(const char *path, char *buf, size_t bufsiz)
|
||||
{
|
||||
char _buf[MAX_PATH];
|
||||
(void) path; (void) buf; (void) bufsiz;
|
||||
path = handle_special_dirs(path, 0, _buf, sizeof(_buf));
|
||||
#ifdef HAVE_MULTIDRIVE
|
||||
/* if path == _buf then we can be sure handle_special_dir() did something
|
||||
* and path is not an ordinary directory */
|
||||
if (path == _buf && !strncmp(path, MULTIDRIVE_DIR, sizeof(MULTIDRIVE_DIR)-1))
|
||||
{
|
||||
/* copying NUL is not required as per readlink specification */
|
||||
ssize_t len = strlen(path);
|
||||
memcpy(buf, path, len);
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
/* does not append NUL !! */
|
||||
return readlink(path, buf, bufsiz);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,6 +161,10 @@
|
|||
/* This folder resides in the ReadOnly CRAMFS. It is binded to /mnt/media0/.rockbox */
|
||||
#define BOOTDIR "/.rockbox"
|
||||
|
||||
/* No special storage */
|
||||
#define CONFIG_STORAGE STORAGE_HOSTFS
|
||||
/* External SD card can be mounted */
|
||||
#define CONFIG_STORAGE (STORAGE_HOSTFS|STORAGE_SD)
|
||||
#define HAVE_MULTIDRIVE
|
||||
#define NUM_DRIVES 2
|
||||
#define HAVE_HOTSWAP
|
||||
#define HAVE_STORAGE_FLUSH
|
||||
#define MULTIDRIVE_DIR "/mnt/mmc"
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#ifndef __MV_H__
|
||||
#define __MV_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "config.h"
|
||||
|
||||
/* FixMe: These macros are a bit nasty and perhaps misplaced here.
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@
|
|||
#else /* APPLICATION */
|
||||
|
||||
#define HOME_DIR "<HOME>" /* replaced at runtime */
|
||||
#define HOME_DIR_LEN (sizeof(HOME_DIR)-1)
|
||||
|
||||
#define PLUGIN_DIR ROCKBOX_LIBRARY_PATH "/rockbox/rocks"
|
||||
#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
|
||||
|
|
@ -73,10 +72,13 @@ extern void paths_init(void);
|
|||
|
||||
#endif /* !APPLICATION || SAMSUNG_YPR0 */
|
||||
|
||||
#define HOME_DIR_LEN (sizeof(HOME_DIR)-1)
|
||||
|
||||
#ifdef APPLICATION
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int app_open(const char *name, int o, ...);
|
||||
int app_creat(const char* name, mode_t mode);
|
||||
|
|
@ -87,6 +89,7 @@ int app_closedir(DIR *dir);
|
|||
struct dirent* app_readdir(DIR* dir);
|
||||
int app_mkdir(const char* name);
|
||||
int app_rmdir(const char* name);
|
||||
ssize_t app_readlink(const char *path, char *buf, size_t bufsiz);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
# define creat(x,m) app_creat(x, m)
|
||||
# define remove(x) app_remove(x)
|
||||
# define rename(x,y) app_rename(x,y)
|
||||
# define readlink(x,y,z) app_readlink(x,y,z)
|
||||
# if (CONFIG_PLATFORM & (PLATFORM_SDL|PLATFORM_MAEMO|PLATFORM_PANDORA))
|
||||
/* SDL overrides a few more */
|
||||
# define read(x,y,z) sim_read(x,y,z)
|
||||
|
|
@ -59,6 +60,7 @@
|
|||
# define read(x,y,z) sim_read(x,y,z)
|
||||
# define write(x,y,z) sim_write(x,y,z)
|
||||
# define close(x) sim_close(x)
|
||||
/* readlink() not used in the sim yet */
|
||||
extern int sim_open(const char *name, int o, ...);
|
||||
extern int sim_creat(const char *name, mode_t mode);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -19,16 +19,26 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mount.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "kernel.h"
|
||||
#include "thread.h"
|
||||
|
||||
#include "string-extra.h"
|
||||
#include "panic.h"
|
||||
#include "debug.h"
|
||||
#include "hostfs.h"
|
||||
|
||||
#include "storage.h"
|
||||
#include "mv.h"
|
||||
#include "ascodec.h"
|
||||
#include "gpio-ypr.h"
|
||||
#include "ascodec.h"
|
||||
#include "backlight.h"
|
||||
#include "rbunicode.h"
|
||||
#include "logdiskf.h"
|
||||
|
||||
void power_off(void)
|
||||
{
|
||||
|
|
@ -61,15 +71,160 @@ void system_exception_wait(void)
|
|||
system_reboot();
|
||||
}
|
||||
|
||||
/* MicroSD card removal / insertion management */
|
||||
|
||||
bool hostfs_removable(IF_MD_NONVOID(int drive))
|
||||
{
|
||||
#ifdef HAVE_MULTIDRIVE
|
||||
if (drive > 0) /* Active LOW */
|
||||
return true;
|
||||
else
|
||||
#endif
|
||||
return false; /* internal: always present */
|
||||
}
|
||||
|
||||
bool hostfs_present(IF_MD_NONVOID(int drive))
|
||||
{
|
||||
#ifdef HAVE_MULTIDRIVE
|
||||
if (drive > 0) /* Active LOW */
|
||||
return (!gpio_control(DEV_CTRL_GPIO_IS_HIGH, GPIO_SD_SENSE, 0, 0));
|
||||
else
|
||||
#endif
|
||||
return true; /* internal: always present */
|
||||
}
|
||||
|
||||
#ifdef HAVE_HOTSWAP
|
||||
bool volume_removable(int volume)
|
||||
{
|
||||
/* don't support more than one partition yet, so volume == drive */
|
||||
return hostfs_removable(volume);
|
||||
}
|
||||
|
||||
bool volume_present(int volume)
|
||||
{
|
||||
/* don't support more than one partition yet, so volume == drive */
|
||||
return hostfs_present(volume);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int unmount_sd(void)
|
||||
{
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = umount("/mnt/mmc");
|
||||
} while (ret && errno != EBUSY && errno != EINVAL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mount_sd(void)
|
||||
{
|
||||
int ret;
|
||||
/* kludge to make sure we get our wanted mount flags. This is needed
|
||||
* when the sd was already mounted before we booted */
|
||||
unmount_sd();
|
||||
char iocharset[64] = "iocharset=";
|
||||
strlcat(iocharset, get_current_codepage_name_linux(), sizeof(iocharset));
|
||||
ret = mount("/dev/mmcblk0p1", "/mnt/mmc", "vfat",
|
||||
MS_MGC_VAL | MS_SYNCHRONOUS | MS_RELATIME,
|
||||
iocharset);
|
||||
/* failure probably means the kernel does not support the iocharset.
|
||||
* retry without to load the default */
|
||||
if (ret == -1)
|
||||
ret = mount("/dev/mmcblk0p1", "/mnt/mmc", "vfat",
|
||||
MS_MGC_VAL | MS_SYNCHRONOUS | MS_RELATIME, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_HOTSWAP
|
||||
|
||||
static int sd_thread_stack[DEFAULT_STACK_SIZE];
|
||||
|
||||
enum {
|
||||
STATE_POLL,
|
||||
STATE_DEBOUNCE,
|
||||
STATE_MOUNT,
|
||||
};
|
||||
|
||||
static void NORETURN_ATTR sd_thread(void)
|
||||
{
|
||||
int ret, state = STATE_POLL;
|
||||
bool last_present, present;
|
||||
int attempts = 0;
|
||||
|
||||
last_present = present = storage_present(1); /* shut up gcc */
|
||||
|
||||
while (1)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case STATE_POLL:
|
||||
sleep(HZ/3);
|
||||
attempts = 0;
|
||||
present = storage_present(1);
|
||||
if (last_present != present)
|
||||
state = STATE_DEBOUNCE;
|
||||
break;
|
||||
|
||||
case STATE_DEBOUNCE:
|
||||
sleep(HZ/5);
|
||||
present = storage_present(1);
|
||||
if (last_present == present)
|
||||
{
|
||||
if (present)
|
||||
queue_broadcast(SYS_HOTSWAP_INSERTED, 0);
|
||||
else
|
||||
queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0);
|
||||
state = STATE_MOUNT;
|
||||
}
|
||||
else
|
||||
state = STATE_POLL;
|
||||
break;
|
||||
|
||||
case STATE_MOUNT:
|
||||
sleep(HZ/10);
|
||||
if (present)
|
||||
ret = mount_sd();
|
||||
else
|
||||
ret = unmount_sd();
|
||||
if (ret == 0)
|
||||
{
|
||||
NOTEF("Successfully %smounted SD card\n", present ? "":"un");
|
||||
queue_broadcast(SYS_FS_CHANGED, 0);
|
||||
state = STATE_POLL;
|
||||
}
|
||||
else if (++attempts > 20) /* stop retrying after 2s */
|
||||
{
|
||||
ERRORF("Failed to %smount SD card. Giving up.", present ? "":"un");
|
||||
state = STATE_POLL;
|
||||
}
|
||||
/* else: need to retry a few times because the kernel is
|
||||
* busy setting up the SD (=> do not change state) */
|
||||
break;
|
||||
}
|
||||
last_present = present;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void hostfs_init(void)
|
||||
{
|
||||
/* stub */
|
||||
/* Setup GPIO pin for microSD sense, copied from OF */
|
||||
gpio_control(DEV_CTRL_GPIO_SET_MUX, GPIO_SD_SENSE, CONFIG_DEFAULT, 0);
|
||||
gpio_control(DEV_CTRL_GPIO_SET_INPUT, GPIO_SD_SENSE, CONFIG_DEFAULT, 0);
|
||||
if (storage_present(IF_MD(1)))
|
||||
mount_sd();
|
||||
#ifdef HAVE_HOTSWAP
|
||||
create_thread(sd_thread, sd_thread_stack, sizeof(sd_thread_stack), 0,
|
||||
"sd thread" IF_PRIO(, PRIORITY_BACKGROUND) IF_COP(, CPU));
|
||||
#endif
|
||||
}
|
||||
|
||||
int hostfs_flush(void)
|
||||
{
|
||||
sync();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue