summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2014-02-07 18:30:50 +0100
committerThomas Martitz <kugel@rockbox.org>2014-02-23 20:23:52 +0100
commitf6c26d33a4e15d966597bc9d66c1f33328a750af (patch)
tree5e0e4d0189c856010a78ce0b79cdc3c3cb5c1354
parent46137ebd4d59d7a91d0b8d98d846a3fd2ec70f5c (diff)
downloadrockbox-f6c26d33a4e15d966597bc9d66c1f33328a750af.tar.gz
rockbox-f6c26d33a4e15d966597bc9d66c1f33328a750af.zip
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
-rw-r--r--firmware/common/rbpaths.c117
-rw-r--r--firmware/export/config/samsungypr0.h8
-rw-r--r--firmware/export/mv.h1
-rw-r--r--firmware/export/rbpaths.h5
-rw-r--r--firmware/include/file.h2
-rw-r--r--firmware/target/hosted/samsungypr/ypr0/system-ypr0.c165
6 files changed, 267 insertions, 31 deletions
diff --git a/firmware/common/rbpaths.c b/firmware/common/rbpaths.c
index 8efb6dd238..dba39476fc 100644
--- a/firmware/common/rbpaths.c
+++ b/firmware/common/rbpaths.c
@@ -48,6 +48,7 @@
48#undef rmdir 48#undef rmdir
49#undef dirent 49#undef dirent
50#undef DIR 50#undef DIR
51#undef readlink
51 52
52#if (CONFIG_PLATFORM & PLATFORM_ANDROID) 53#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
53static const char rbhome[] = "/sdcard"; 54static const char rbhome[] = "/sdcard";
@@ -61,6 +62,9 @@ const char *rbhome;
61 * over the ones where Rockbox is installed to. Classic example would be 62 * over the ones where Rockbox is installed to. Classic example would be
62 * $HOME/.config/rockbox.org vs /usr/share/rockbox */ 63 * $HOME/.config/rockbox.org vs /usr/share/rockbox */
63#define HAVE_SPECIAL_DIRS 64#define HAVE_SPECIAL_DIRS
65#define IS_HOME(p) (!strcmp(p, rbhome))
66#else
67#define IS_HOME(p) (!strcmp(p, HOME_DIR))
64#endif 68#endif
65 69
66/* flags for get_user_file_path() */ 70/* flags for get_user_file_path() */
@@ -70,6 +74,35 @@ const char *rbhome;
70/* file or directory? */ 74/* file or directory? */
71#define IS_FILE (1<<1) 75#define IS_FILE (1<<1)
72 76
77#ifdef HAVE_MULTIDRIVE
78/* A special link is created under e.g. HOME_DIR/<microSD1>, e.g. to access
79 * external storage in a convinient location, much similar to the mount
80 * point on our native targets. Here they are treated as symlink (one which
81 * doesn't actually exist in the filesystem and therefore we have to override
82 * readlink() */
83static const char *handle_special_links(const char* link, unsigned flags,
84 char *buf, const size_t bufsize)
85{
86 (void) flags;
87 char vol_string[VOL_ENUM_POS + 8];
88 int len = sprintf(vol_string, VOL_NAMES, 1);
89
90 /* link might be passed with or without HOME_DIR expanded. To handle
91 * both perform substring matching (VOL_NAMES is unique enough) */
92 const char *begin = strstr(link, vol_string);
93 if (begin)
94 {
95 /* begin now points to the start of vol_string within link,
96 * we want to copy the remainder of the paths, prefixed by
97 * the actual mount point (the remainder might be "") */
98 snprintf(buf, bufsize, MULTIDRIVE_DIR"%s", begin + len);
99 return buf;
100 }
101
102 return link;
103}
104#endif
105
73#ifdef HAVE_SPECIAL_DIRS 106#ifdef HAVE_SPECIAL_DIRS
74void paths_init(void) 107void paths_init(void)
75{ 108{
@@ -156,38 +189,31 @@ static const char* _get_user_file_path(const char *path,
156 return ret; 189 return ret;
157} 190}
158 191
192#elif !defined(paths_init)
193void paths_init(void) { }
194#endif
159 195
160static const char* handle_special_dirs(const char* dir, unsigned flags, 196static const char* handle_special_dirs(const char* dir, unsigned flags,
161 char *buf, const size_t bufsize) 197 char *buf, const size_t bufsize)
162{ 198{
199 (void) flags; (void) buf; (void) bufsize;
200#ifdef HAVE_SPECIAL_DIRS
163 if (!strncmp(HOME_DIR, dir, HOME_DIR_LEN)) 201 if (!strncmp(HOME_DIR, dir, HOME_DIR_LEN))
164 { 202 {
165 const char *p = dir + HOME_DIR_LEN; 203 const char *p = dir + HOME_DIR_LEN;
166 while (*p == '/') p++; 204 while (*p == '/') p++;
167 snprintf(buf, bufsize, "%s/%s", rbhome, p); 205 snprintf(buf, bufsize, "%s/%s", rbhome, p);
168 return buf; 206 dir = buf;
169 } 207 }
170 else if (!strncmp(ROCKBOX_DIR, dir, ROCKBOX_DIR_LEN)) 208 else if (!strncmp(ROCKBOX_DIR, dir, ROCKBOX_DIR_LEN))
171 return _get_user_file_path(dir, flags, buf, bufsize); 209 dir = _get_user_file_path(dir, flags, buf, bufsize);
172 210#endif
173 return dir; 211#ifdef HAVE_MULTIDRIVE
174} 212 dir = handle_special_links(dir, flags, buf, bufsize);
175
176#else /* !HAVE_SPECIAL_DIRS */
177
178#ifndef paths_init
179void paths_init(void) { }
180#endif 213#endif
181
182static const char* handle_special_dirs(const char* dir, unsigned flags,
183 char *buf, const size_t bufsize)
184{
185 (void) flags; (void) buf; (void) bufsize;
186 return dir; 214 return dir;
187} 215}
188 216
189#endif
190
191int app_open(const char *name, int o, ...) 217int app_open(const char *name, int o, ...)
192{ 218{
193 char realpath[MAX_PATH]; 219 char realpath[MAX_PATH];
@@ -235,6 +261,7 @@ int app_rename(const char *old, const char *new)
235 * get_dir_info() */ 261 * get_dir_info() */
236struct __dir { 262struct __dir {
237 DIR *dir; 263 DIR *dir;
264 IF_MD(int volumes_returned);
238 char path[]; 265 char path[];
239}; 266};
240 267
@@ -246,23 +273,31 @@ struct dirinfo dir_get_info(DIR* _parent, struct dirent *dir)
246 struct dirinfo ret; 273 struct dirinfo ret;
247 char path[MAX_PATH]; 274 char path[MAX_PATH];
248 275
249 snprintf(path, sizeof(path), "%s/%s", parent->path, dir->d_name);
250 memset(&ret, 0, sizeof(ret)); 276 memset(&ret, 0, sizeof(ret));
251 277
278#ifdef HAVE_MULTIDRIVE
279 char vol_string[VOL_ENUM_POS + 8];
280 sprintf(vol_string, VOL_NAMES, 1);
281 if (!strcmp(vol_string, dir->d_name))
282 {
283 ret.attribute = ATTR_LINK;
284 strcpy(path, MULTIDRIVE_DIR);
285 }
286 else
287#endif
288 snprintf(path, sizeof(path), "%s/%s", parent->path, dir->d_name);
289
252 if (!stat(path, &s)) 290 if (!stat(path, &s))
253 { 291 {
254 if (S_ISDIR(s.st_mode)) 292 if (S_ISDIR(s.st_mode))
255 { 293 ret.attribute |= ATTR_DIRECTORY;
256 ret.attribute = ATTR_DIRECTORY; 294
257 }
258 ret.size = s.st_size; 295 ret.size = s.st_size;
259 tm = localtime(&(s.st_mtime)); 296 tm = localtime(&(s.st_mtime));
260 } 297 }
261 298
262 if (!lstat(path, &s) && S_ISLNK(s.st_mode)) 299 if (!lstat(path, &s) && S_ISLNK(s.st_mode))
263 {
264 ret.attribute |= ATTR_LINK; 300 ret.attribute |= ATTR_LINK;
265 }
266 301
267 if (tm) 302 if (tm)
268 { 303 {
@@ -296,6 +331,7 @@ DIR* app_opendir(const char *_name)
296 free(buf); 331 free(buf);
297 return NULL; 332 return NULL;
298 } 333 }
334 IF_MD(this->volumes_returned = 0);
299 return (DIR*)this; 335 return (DIR*)this;
300} 336}
301 337
@@ -311,6 +347,18 @@ int app_closedir(DIR *dir)
311struct dirent* app_readdir(DIR* dir) 347struct dirent* app_readdir(DIR* dir)
312{ 348{
313 struct __dir *d = (struct __dir*)dir; 349 struct __dir *d = (struct __dir*)dir;
350#ifdef HAVE_MULTIDRIVE
351 /* this is not MT-safe but OK according to man readdir */
352 static struct dirent voldir;
353 if (d->volumes_returned < (NUM_VOLUMES-1)
354 && volume_present(d->volumes_returned+1)
355 && IS_HOME(d->path))
356 {
357 d->volumes_returned += 1;
358 sprintf(voldir.d_name, VOL_NAMES, d->volumes_returned);
359 return &voldir;
360 }
361#endif
314 return readdir(d->dir); 362 return readdir(d->dir);
315} 363}
316 364
@@ -329,3 +377,26 @@ int app_rmdir(const char* name)
329 const char *fname = handle_special_dirs(name, NEED_WRITE, realpath, sizeof(realpath)); 377 const char *fname = handle_special_dirs(name, NEED_WRITE, realpath, sizeof(realpath));
330 return rmdir(fname); 378 return rmdir(fname);
331} 379}
380
381
382/* On MD we create a virtual symlink for the external drive,
383 * for this we need to override readlink(). */
384ssize_t app_readlink(const char *path, char *buf, size_t bufsiz)
385{
386 char _buf[MAX_PATH];
387 (void) path; (void) buf; (void) bufsiz;
388 path = handle_special_dirs(path, 0, _buf, sizeof(_buf));
389#ifdef HAVE_MULTIDRIVE
390 /* if path == _buf then we can be sure handle_special_dir() did something
391 * and path is not an ordinary directory */
392 if (path == _buf && !strncmp(path, MULTIDRIVE_DIR, sizeof(MULTIDRIVE_DIR)-1))
393 {
394 /* copying NUL is not required as per readlink specification */
395 ssize_t len = strlen(path);
396 memcpy(buf, path, len);
397 return len;
398 }
399#endif
400 /* does not append NUL !! */
401 return readlink(path, buf, bufsiz);
402}
diff --git a/firmware/export/config/samsungypr0.h b/firmware/export/config/samsungypr0.h
index 361c9697c5..bed5a2f977 100644
--- a/firmware/export/config/samsungypr0.h
+++ b/firmware/export/config/samsungypr0.h
@@ -161,6 +161,10 @@
161/* This folder resides in the ReadOnly CRAMFS. It is binded to /mnt/media0/.rockbox */ 161/* This folder resides in the ReadOnly CRAMFS. It is binded to /mnt/media0/.rockbox */
162#define BOOTDIR "/.rockbox" 162#define BOOTDIR "/.rockbox"
163 163
164/* No special storage */ 164/* External SD card can be mounted */
165#define CONFIG_STORAGE STORAGE_HOSTFS 165#define CONFIG_STORAGE (STORAGE_HOSTFS|STORAGE_SD)
166#define HAVE_MULTIDRIVE
167#define NUM_DRIVES 2
168#define HAVE_HOTSWAP
166#define HAVE_STORAGE_FLUSH 169#define HAVE_STORAGE_FLUSH
170#define MULTIDRIVE_DIR "/mnt/mmc"
diff --git a/firmware/export/mv.h b/firmware/export/mv.h
index 05c9c6349f..1d0a536663 100644
--- a/firmware/export/mv.h
+++ b/firmware/export/mv.h
@@ -22,6 +22,7 @@
22#ifndef __MV_H__ 22#ifndef __MV_H__
23#define __MV_H__ 23#define __MV_H__
24 24
25#include <stdbool.h>
25#include "config.h" 26#include "config.h"
26 27
27/* FixMe: These macros are a bit nasty and perhaps misplaced here. 28/* FixMe: These macros are a bit nasty and perhaps misplaced here.
diff --git a/firmware/export/rbpaths.h b/firmware/export/rbpaths.h
index 0a5b36c5ab..1f7e1a2643 100644
--- a/firmware/export/rbpaths.h
+++ b/firmware/export/rbpaths.h
@@ -60,7 +60,6 @@
60#else /* APPLICATION */ 60#else /* APPLICATION */
61 61
62#define HOME_DIR "<HOME>" /* replaced at runtime */ 62#define HOME_DIR "<HOME>" /* replaced at runtime */
63#define HOME_DIR_LEN (sizeof(HOME_DIR)-1)
64 63
65#define PLUGIN_DIR ROCKBOX_LIBRARY_PATH "/rockbox/rocks" 64#define PLUGIN_DIR ROCKBOX_LIBRARY_PATH "/rockbox/rocks"
66#if (CONFIG_PLATFORM & PLATFORM_ANDROID) 65#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
@@ -73,10 +72,13 @@ extern void paths_init(void);
73 72
74#endif /* !APPLICATION || SAMSUNG_YPR0 */ 73#endif /* !APPLICATION || SAMSUNG_YPR0 */
75 74
75#define HOME_DIR_LEN (sizeof(HOME_DIR)-1)
76
76#ifdef APPLICATION 77#ifdef APPLICATION
77 78
78#include <dirent.h> 79#include <dirent.h>
79#include <fcntl.h> 80#include <fcntl.h>
81#include <unistd.h>
80 82
81int app_open(const char *name, int o, ...); 83int app_open(const char *name, int o, ...);
82int app_creat(const char* name, mode_t mode); 84int app_creat(const char* name, mode_t mode);
@@ -87,6 +89,7 @@ int app_closedir(DIR *dir);
87struct dirent* app_readdir(DIR* dir); 89struct dirent* app_readdir(DIR* dir);
88int app_mkdir(const char* name); 90int app_mkdir(const char* name);
89int app_rmdir(const char* name); 91int app_rmdir(const char* name);
92ssize_t app_readlink(const char *path, char *buf, size_t bufsiz);
90 93
91#endif 94#endif
92 95
diff --git a/firmware/include/file.h b/firmware/include/file.h
index 9b7f123999..77930864c7 100644
--- a/firmware/include/file.h
+++ b/firmware/include/file.h
@@ -43,6 +43,7 @@
43# define creat(x,m) app_creat(x, m) 43# define creat(x,m) app_creat(x, m)
44# define remove(x) app_remove(x) 44# define remove(x) app_remove(x)
45# define rename(x,y) app_rename(x,y) 45# define rename(x,y) app_rename(x,y)
46# define readlink(x,y,z) app_readlink(x,y,z)
46# if (CONFIG_PLATFORM & (PLATFORM_SDL|PLATFORM_MAEMO|PLATFORM_PANDORA)) 47# if (CONFIG_PLATFORM & (PLATFORM_SDL|PLATFORM_MAEMO|PLATFORM_PANDORA))
47/* SDL overrides a few more */ 48/* SDL overrides a few more */
48# define read(x,y,z) sim_read(x,y,z) 49# define read(x,y,z) sim_read(x,y,z)
@@ -59,6 +60,7 @@
59# define read(x,y,z) sim_read(x,y,z) 60# define read(x,y,z) sim_read(x,y,z)
60# define write(x,y,z) sim_write(x,y,z) 61# define write(x,y,z) sim_write(x,y,z)
61# define close(x) sim_close(x) 62# define close(x) sim_close(x)
63/* readlink() not used in the sim yet */
62extern int sim_open(const char *name, int o, ...); 64extern int sim_open(const char *name, int o, ...);
63extern int sim_creat(const char *name, mode_t mode); 65extern int sim_creat(const char *name, mode_t mode);
64#endif 66#endif
diff --git a/firmware/target/hosted/samsungypr/ypr0/system-ypr0.c b/firmware/target/hosted/samsungypr/ypr0/system-ypr0.c
index 477b71c6a2..893c710861 100644
--- a/firmware/target/hosted/samsungypr/ypr0/system-ypr0.c
+++ b/firmware/target/hosted/samsungypr/ypr0/system-ypr0.c
@@ -19,16 +19,26 @@
19 ****************************************************************************/ 19 ****************************************************************************/
20 20
21#include <stdlib.h> 21#include <stdlib.h>
22#include <string.h>
23#include <inttypes.h> 22#include <inttypes.h>
24#include <unistd.h> 23#include <unistd.h>
24#include <sys/mount.h>
25#include <errno.h>
26
25#include "system.h" 27#include "system.h"
28#include "kernel.h"
29#include "thread.h"
30
31#include "string-extra.h"
26#include "panic.h" 32#include "panic.h"
27#include "debug.h" 33#include "debug.h"
28#include "hostfs.h" 34#include "storage.h"
29 35#include "mv.h"
30#include "ascodec.h" 36#include "ascodec.h"
31#include "gpio-ypr.h" 37#include "gpio-ypr.h"
38#include "ascodec.h"
39#include "backlight.h"
40#include "rbunicode.h"
41#include "logdiskf.h"
32 42
33void power_off(void) 43void power_off(void)
34{ 44{
@@ -61,15 +71,160 @@ void system_exception_wait(void)
61 system_reboot(); 71 system_reboot();
62} 72}
63 73
74/* MicroSD card removal / insertion management */
75
76bool hostfs_removable(IF_MD_NONVOID(int drive))
77{
78#ifdef HAVE_MULTIDRIVE
79 if (drive > 0) /* Active LOW */
80 return true;
81 else
82#endif
83 return false; /* internal: always present */
84}
85
86bool hostfs_present(IF_MD_NONVOID(int drive))
87{
88#ifdef HAVE_MULTIDRIVE
89 if (drive > 0) /* Active LOW */
90 return (!gpio_control(DEV_CTRL_GPIO_IS_HIGH, GPIO_SD_SENSE, 0, 0));
91 else
92#endif
93 return true; /* internal: always present */
94}
95
96#ifdef HAVE_HOTSWAP
97bool volume_removable(int volume)
98{
99 /* don't support more than one partition yet, so volume == drive */
100 return hostfs_removable(volume);
101}
102
103bool volume_present(int volume)
104{
105 /* don't support more than one partition yet, so volume == drive */
106 return hostfs_present(volume);
107}
108#endif
109
110static int unmount_sd(void)
111{
112 int ret;
113 do
114 {
115 ret = umount("/mnt/mmc");
116 } while (ret && errno != EBUSY && errno != EINVAL);
117
118 return ret;
119}
120
121static int mount_sd(void)
122{
123 int ret;
124 /* kludge to make sure we get our wanted mount flags. This is needed
125 * when the sd was already mounted before we booted */
126 unmount_sd();
127 char iocharset[64] = "iocharset=";
128 strlcat(iocharset, get_current_codepage_name_linux(), sizeof(iocharset));
129 ret = mount("/dev/mmcblk0p1", "/mnt/mmc", "vfat",
130 MS_MGC_VAL | MS_SYNCHRONOUS | MS_RELATIME,
131 iocharset);
132 /* failure probably means the kernel does not support the iocharset.
133 * retry without to load the default */
134 if (ret == -1)
135 ret = mount("/dev/mmcblk0p1", "/mnt/mmc", "vfat",
136 MS_MGC_VAL | MS_SYNCHRONOUS | MS_RELATIME, NULL);
137 return ret;
138}
139
140#ifdef HAVE_HOTSWAP
141
142static int sd_thread_stack[DEFAULT_STACK_SIZE];
143
144enum {
145 STATE_POLL,
146 STATE_DEBOUNCE,
147 STATE_MOUNT,
148};
149
150static void NORETURN_ATTR sd_thread(void)
151{
152 int ret, state = STATE_POLL;
153 bool last_present, present;
154 int attempts = 0;
155
156 last_present = present = storage_present(1); /* shut up gcc */
157
158 while (1)
159 {
160 switch (state)
161 {
162 case STATE_POLL:
163 sleep(HZ/3);
164 attempts = 0;
165 present = storage_present(1);
166 if (last_present != present)
167 state = STATE_DEBOUNCE;
168 break;
169
170 case STATE_DEBOUNCE:
171 sleep(HZ/5);
172 present = storage_present(1);
173 if (last_present == present)
174 {
175 if (present)
176 queue_broadcast(SYS_HOTSWAP_INSERTED, 0);
177 else
178 queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0);
179 state = STATE_MOUNT;
180 }
181 else
182 state = STATE_POLL;
183 break;
184
185 case STATE_MOUNT:
186 sleep(HZ/10);
187 if (present)
188 ret = mount_sd();
189 else
190 ret = unmount_sd();
191 if (ret == 0)
192 {
193 NOTEF("Successfully %smounted SD card\n", present ? "":"un");
194 queue_broadcast(SYS_FS_CHANGED, 0);
195 state = STATE_POLL;
196 }
197 else if (++attempts > 20) /* stop retrying after 2s */
198 {
199 ERRORF("Failed to %smount SD card. Giving up.", present ? "":"un");
200 state = STATE_POLL;
201 }
202 /* else: need to retry a few times because the kernel is
203 * busy setting up the SD (=> do not change state) */
204 break;
205 }
206 last_present = present;
207 }
208}
209
210#endif
211
64void hostfs_init(void) 212void hostfs_init(void)
65{ 213{
66 /* stub */ 214 /* Setup GPIO pin for microSD sense, copied from OF */
215 gpio_control(DEV_CTRL_GPIO_SET_MUX, GPIO_SD_SENSE, CONFIG_DEFAULT, 0);
216 gpio_control(DEV_CTRL_GPIO_SET_INPUT, GPIO_SD_SENSE, CONFIG_DEFAULT, 0);
217 if (storage_present(IF_MD(1)))
218 mount_sd();
219#ifdef HAVE_HOTSWAP
220 create_thread(sd_thread, sd_thread_stack, sizeof(sd_thread_stack), 0,
221 "sd thread" IF_PRIO(, PRIORITY_BACKGROUND) IF_COP(, CPU));
222#endif
67} 223}
68 224
69int hostfs_flush(void) 225int hostfs_flush(void)
70{ 226{
71 sync(); 227 sync();
72
73 return 0; 228 return 0;
74} 229}
75 230