2.0 alpha
[platform/core/system/devman.git] / devices / mmc.c
1 /*
2  *  devman
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: DongGi Jang <dg0402.jang@samsung.com>
7  * 
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20 */ 
21
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/ioctl.h>
28 #include <sys/mount.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <limits.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <errno.h>
35 #include <heynoti.h>
36 #include <vconf.h>
37
38 #include "device_engine.h"
39
40 #define MMC_DEV         "/dev/mmcblk"
41 #define MMC_MOUNT_PATH  "/opt/storage/sdcard"
42
43 static int exec_process(char *name, const char *arg1)
44 {
45         int ret, pid;
46         int i;
47
48         if (name[0] == '\0')
49                 return 0;
50
51         pid = fork();
52         switch (pid) {
53         case -1:
54                 ERR("Fork error");
55                 ret = -1;
56                 break;
57         case 0:
58                 for (i = 0; i < _NSIG; i++)
59                         signal(i, SIG_DFL);
60                 execl(name, name, arg1, NULL);
61                 ERR("execlp() error : %s\n", strerror(errno));
62                 exit(-1);
63                 break;
64         default:
65                 ret = pid;
66                 break;
67         }
68         return ret;
69 }
70
71 static int get_mmcblk_num()
72 {
73         int i;
74         char buf[255];
75
76         /* mmcblk0 and mmcblk1 is reserved for movinand */
77         for (i = 9; i > 0; i--) {
78                 snprintf(buf, 255, "%s%d", MMC_DEV, i);
79                 if (access(buf, R_OK) == 0)
80                         return i;
81         }
82         ERR("Failed to find mmc block number\n");
83         return -1;
84 }
85
86 int format_mmc(int blknum)
87 {
88         int fd;
89         struct stat parent_stat, mount_stat;
90
91         /* check MMC_MOUNT_FULL_PATH length */
92         char parent_path[PATH_MAX], mount_path[PATH_MAX];
93         int ret_f = 0, ret_s = 0;
94         char buf[512];
95         char dev_mmcblk[NAME_MAX];
96         int mkfs_pid = 0;
97
98         if (blknum < 0) {
99                 vconf_set_int(VCONFKEY_SYSMAN_MMC_FORMAT,
100                               VCONFKEY_SYSMAN_MMC_FORMAT_FAILED);
101                 return -1;
102         } else
103                 snprintf(dev_mmcblk, NAME_MAX, "%s%d", MMC_DEV, blknum);
104
105         snprintf(parent_path, sizeof(parent_path), "%s/%s", MMC_MOUNT_PATH, "..");
106         snprintf(mount_path, sizeof(mount_path), "%s", MMC_MOUNT_PATH);
107
108         if (stat(mount_path, &mount_stat) != 0) {
109                 ERR("get stat error : %s\n", mount_path);
110                 ret_f = -1;
111         } else if (stat(parent_path, &parent_stat) != 0) {
112                 ERR("get stat error : %s\n", parent_path);
113                 ret_f = -1;
114         }
115
116         else if (mount_stat.st_dev == parent_stat.st_dev) {
117                 ERR("Does not mounted, same st_dev\n");
118                 ret_f = -2;
119         } else {
120                 ERR("MMC mounted, diff st_dev\n");
121         }
122
123         if (ret_f == 0) {
124                 if (umount2(MMC_MOUNT_PATH, MNT_FORCE) == -1) {
125                         ERR("devman mmc_format umount fail\n");
126                         if (umount2(MMC_MOUNT_PATH, MNT_FORCE) == -1) {
127                                 vconf_set_int(VCONFKEY_SYSMAN_MMC_FORMAT,
128                                               VCONFKEY_SYSMAN_MMC_FORMAT_FAILED);
129                                 ERR("devman mmc_format umount retry fail\n");
130                                 return -1;
131                         }
132                 }
133         }
134
135         fd = open(dev_mmcblk, O_RDWR);
136         if (fd < 0) {
137                 ERR("%s open fail", dev_mmcblk);
138                 ret_s = -1;
139         } else {
140
141                 memset(buf, 0, sizeof(buf));
142                 if (write(fd, buf, sizeof(buf)) < 0) {
143                         ERR("%s write fail to erase partition\n", dev_mmcblk);
144                         close(fd);
145                         ret_s = -2;
146                 } else {
147                         sync();
148                         usleep(200000);
149
150                         if (ioctl(fd, BLKRRPART, NULL) < 0) {
151                                 ERR("%s ioctl fail\n", dev_mmcblk);
152                                 close(fd);
153                                 ret_s = -3;
154                         } else {
155                                 close(fd);
156                                 sync();
157
158                                 mkfs_pid =
159                                     exec_process("/sbin/mkfs.vfat", dev_mmcblk);
160                                 if (mkfs_pid == -1) {
161                                         ERR("devman mmc_format mkfs.vfat fail\n");
162                                         ret_s = -4;
163                                 }
164                         }
165                 }
166         }
167         int i = 0;
168         snprintf(buf, sizeof(buf), "%s%d", "/proc/", mkfs_pid);
169         while (1) {
170                 sleep(1);
171                 if (access(buf, R_OK) != 0)
172                         break;
173         }
174         sync();
175
176         if (ret_f == 0 && ret_s == 0) {
177                 if (mount
178                     (dev_mmcblk, MMC_MOUNT_PATH, "vfat", 0,
179                      "uid=0,gid=0,dmask=0000,fmask=0111,iocharset=iso8859-1,utf8,shortname=mixed")
180                     != 0) {
181                         ERR("Failed to mount mmc card, %s,%s\n", dev_mmcblk,
182                             MMC_MOUNT_PATH);
183                         vconf_set_int(VCONFKEY_SYSMAN_MMC_FORMAT,
184                                       VCONFKEY_SYSMAN_MMC_FORMAT_FAILED);
185                         heynoti_publish("mmcblk_remove");
186                         return -1;
187                 } else
188                     if (heynoti_publish("mmcblk_add") == -1
189                         && ret_s == 0)
190                         ERR("notification failed for new MMC\n");
191         } else {
192                 vconf_set_int(VCONFKEY_SYSMAN_MMC_FORMAT,
193                               VCONFKEY_SYSMAN_MMC_FORMAT_FAILED);
194                 ERR("result format process fail\n");
195                 heynoti_publish("mmcblk_remove");
196                 return -1;
197         }
198
199         vconf_set_int(VCONFKEY_SYSMAN_MMC_FORMAT,
200                       VCONFKEY_SYSMAN_MMC_FORMAT_COMPLETED);
201         return 0;
202 }
203
204 static int set_mmc_int(int prop, int val)
205 {
206         int ret = -1;
207         switch (prop) {
208         case MMC_PROP_FORMAT:
209                 ret = format_mmc(get_mmcblk_num());
210                 return ret;
211         }
212
213         return -1;
214
215 }
216
217 static struct device mmc = {
218         .devname = "mmc",
219         .set_int = set_mmc_int,
220         .devtype = DEVTYPE_MMC,
221 };
222
223 static void __attribute__ ((constructor)) module_init()
224 {
225         add_dev(&mmc);
226 }