8d6dcbd1c8cf5ba04607762a0852164428d93f82
[platform/core/system/libstorage.git] / src / storage-sdcard.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <sys/statvfs.h>
23 #include <vconf.h>
24 #include <tzplatform_config.h>
25
26 #include "common.h"
27 #include "list.h"
28 #include "log.h"
29
30 #define SDCARD_NODE "sdcard"
31
32 #ifndef __USE_FILE_OFFSET64
33 int __WEAK__ storage_get_external_memory_size(struct statvfs *buf);
34 #else
35 int __WEAK__ storage_get_external_memory_size64(struct statvfs *buf);
36 #endif
37
38 static dd_list *cb_list[STORAGE_CALLBACK_MAX];
39
40 static int sdcard_get_state(void)
41 {
42         int val, ret;
43
44         ret = vconf_get_int(VCONFKEY_SYSMAN_MMC_STATUS, &val);
45         if (ret < 0)
46                 return -EPERM;
47
48         switch (val) {
49         case VCONFKEY_SYSMAN_MMC_MOUNTED:
50                 return STORAGE_STATE_MOUNTED;
51         case VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED:
52                 return STORAGE_STATE_UNMOUNTABLE;
53         case VCONFKEY_SYSMAN_MMC_REMOVED:
54         default:
55                 break;
56         }
57
58         return STORAGE_STATE_REMOVED;
59 }
60
61 static int sdcard_get_space(unsigned long long *total, unsigned long long *available)
62 {
63         storage_state_e state;
64         struct statvfs s;
65         int ret;
66         unsigned long long t = 0, a = 0;
67
68         state = sdcard_get_state();
69         if (state >= STORAGE_STATE_MOUNTED) {
70 #ifndef __USE_FILE_OFFSET64
71                 ret = storage_get_external_memory_size(&s);
72 #else
73                 ret = storage_get_external_memory_size64(&s);
74 #endif
75                 if (ret < 0)
76                         return -EPERM;
77
78                 t = (unsigned long long)s.f_frsize*s.f_blocks;
79                 a = (unsigned long long)s.f_bsize*s.f_bavail;
80         }
81
82         if (total)
83                 *total = t;
84         if (available)
85                 *available = a;
86
87         return 0;
88 }
89
90 static const char *sdcard_get_root(void)
91 {
92         return tzplatform_mkpath(TZ_SYS_STORAGE, SDCARD_NODE);
93 }
94
95 static void sdcard_state_cb(keynode_t *key, void *data)
96 {
97         struct storage_cb_info *cb_info;
98         dd_list *elem;
99         storage_state_e state;
100
101         state = sdcard_get_state();
102
103         DD_LIST_FOREACH(cb_list[STORAGE_CALLBACK_STATE], elem, cb_info)
104                 cb_info->state_cb(cb_info->id, state, cb_info->user_data);
105 }
106
107 static int register_request(enum storage_cb_type type)
108 {
109         switch (type) {
110         case STORAGE_CALLBACK_STATE:
111                 return vconf_notify_key_changed(VCONFKEY_SYSMAN_MMC_STATUS,
112                                 sdcard_state_cb, NULL);
113         default:
114                 break;
115         }
116
117         return -EINVAL;
118 }
119
120 static int release_request(enum storage_cb_type type)
121 {
122         switch (type) {
123         case STORAGE_CALLBACK_STATE:
124                 return vconf_ignore_key_changed(VCONFKEY_SYSMAN_MMC_STATUS,
125                                 sdcard_state_cb);
126         default:
127                 break;
128         }
129
130         return -EINVAL;
131 }
132
133 static int sdcard_register_cb(enum storage_cb_type type, struct storage_cb_info *info)
134 {
135         struct storage_cb_info *cb_info;
136         dd_list *elem;
137         int ret, n;
138
139         if (type < 0 || type >= STORAGE_CALLBACK_MAX)
140                 return -EINVAL;
141
142         if (!info)
143                 return -EINVAL;
144
145         /* check if it is the first request */
146         n = DD_LIST_LENGTH(cb_list[type]);
147         if (n == 0) {
148                 ret = register_request(type);
149                 if (ret < 0)
150                         return -EPERM;
151         }
152
153         /* check for the same request */
154         DD_LIST_FOREACH(cb_list[type], elem, cb_info) {
155                 if (cb_info->id == info->id &&
156                     cb_info->state_cb == info->state_cb)
157                         return -EEXIST;
158         }
159
160         /* add device changed callback to list (local) */
161         cb_info = malloc(sizeof(struct storage_cb_info));
162         if (!cb_info)
163                 return -errno;
164
165         memcpy(cb_info, info, sizeof(struct storage_cb_info));
166         DD_LIST_APPEND(cb_list[type], cb_info);
167
168         return 0;
169 }
170
171 static int sdcard_unregister_cb(enum storage_cb_type type, struct storage_cb_info *info)
172 {
173         struct storage_cb_info *cb_info;
174         dd_list *elem;
175         int ret, n;
176
177         if (type < 0 || type >= STORAGE_CALLBACK_MAX)
178                 return -EINVAL;
179
180         if (!info)
181                 return -EINVAL;
182
183         /* search for the same element with callback */
184         DD_LIST_FOREACH(cb_list[type], elem, cb_info) {
185                 if (cb_info->id == info->id &&
186                     cb_info->state_cb == info->state_cb)
187                         break;
188         }
189
190         if (!cb_info)
191                 return -EINVAL;
192
193         /* remove device callback from list (local) */
194         DD_LIST_REMOVE(cb_list[type], cb_info);
195         free(cb_info);
196
197         /* check if this callback is last element */
198         n = DD_LIST_LENGTH(cb_list[type]);
199         if (n == 0) {
200                 ret = release_request(type);
201                 if (ret < 0)
202                         return -EPERM;
203         }
204
205         return 0;
206 }
207
208 const struct storage_ops sdcard = {
209         .type = STORAGE_TYPE_EXTERNAL,
210         .root = sdcard_get_root,
211         .get_state = sdcard_get_state,
212         .get_space = sdcard_get_space,
213         .register_cb = sdcard_register_cb,
214         .unregister_cb = sdcard_unregister_cb,
215 };
216
217 STORAGE_OPS_REGISTER(&sdcard)