blob: d90845d3a14822d8619245a7ee5ade37ddbabb71 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001
2/*
3 * Copyright (C) 2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <stdlib.h>
19#include <string.h>
20#include <dirent.h>
21#include <errno.h>
22
23#include <sys/types.h>
24
25#include "vold.h"
26#include "mmc.h"
27#include "media.h"
Ben Winslow227c74a2009-08-15 09:52:10 -040028#include "diskmbr.h" /* for NDOSPART */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080029
30#define DEBUG_BOOTSTRAP 0
31
32static int mmc_bootstrap_controller(char *sysfs_path);
33static int mmc_bootstrap_card(char *sysfs_path);
34static int mmc_bootstrap_block(char *devpath);
35static int mmc_bootstrap_mmcblk(char *devpath);
36static int mmc_bootstrap_mmcblk_partition(char *devpath);
37
38/*
39 * Bootstrap our mmc information.
40 */
41int mmc_bootstrap()
42{
43 DIR *d;
44 struct dirent *de;
45
46 if (!(d = opendir(SYSFS_CLASS_MMC_PATH))) {
San Mehat1f278212009-07-16 10:44:15 -070047 LOG_ERROR("Unable to open '%s' (%s)", SYSFS_CLASS_MMC_PATH,
48 strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080049 return -errno;
50 }
51
52 while ((de = readdir(d))) {
53 char tmp[255];
54
55 if (de->d_name[0] == '.')
56 continue;
57
58 sprintf(tmp, "%s/%s", SYSFS_CLASS_MMC_PATH, de->d_name);
San Mehat1f278212009-07-16 10:44:15 -070059 if (mmc_bootstrap_controller(tmp)) {
60 LOG_ERROR("Error bootstrapping controller '%s' (%s)", tmp,
61 strerror(errno));
62 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080063 }
64
65 closedir(d);
66
67 return 0;
68}
69
70static int mmc_bootstrap_controller(char *sysfs_path)
71{
72 DIR *d;
73 struct dirent *de;
74
75#if DEBUG_BOOTSTRAP
76 LOG_VOL("bootstrap_controller(%s):", sysfs_path);
77#endif
78 if (!(d = opendir(sysfs_path))) {
San Mehat1f278212009-07-16 10:44:15 -070079 LOG_ERROR("Unable to open '%s' (%s)", sysfs_path, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080080 return -errno;
81 }
82
83 while ((de = readdir(d))) {
84 char tmp[255];
85
86 if (de->d_name[0] == '.')
87 continue;
88
89 if ((!strcmp(de->d_name, "uevent")) ||
90 (!strcmp(de->d_name, "subsystem")) ||
91 (!strcmp(de->d_name, "device")) ||
92 (!strcmp(de->d_name, "power"))) {
93 continue;
94 }
95
96 sprintf(tmp, "%s/%s", sysfs_path, de->d_name);
97
98 if (mmc_bootstrap_card(tmp) < 0)
San Mehat1f278212009-07-16 10:44:15 -070099 LOG_ERROR("Error bootstrapping card '%s' (%s)", tmp, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800100 } // while
101
102 closedir(d);
103 return 0;
104}
105
106static int mmc_bootstrap_card(char *sysfs_path)
107{
108 char saved_cwd[255];
109 char new_cwd[255];
110 char *devpath;
111 char *uevent_params[4];
112 char *p;
113 char filename[255];
114 char tmp[255];
115 ssize_t sz;
116
117#if DEBUG_BOOTSTRAP
118 LOG_VOL("bootstrap_card(%s):", sysfs_path);
119#endif
120
121 /*
122 * sysfs_path is based on /sys/class, but we want the actual device class
123 */
124 if (!getcwd(saved_cwd, sizeof(saved_cwd))) {
125 LOGE("Error getting working dir path");
126 return -errno;
127 }
128
129 if (chdir(sysfs_path) < 0) {
San Mehat1f278212009-07-16 10:44:15 -0700130 LOGE("Unable to chdir to %s (%s)", sysfs_path, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800131 return -errno;
132 }
133
134 if (!getcwd(new_cwd, sizeof(new_cwd))) {
135 LOGE("Buffer too small for device path");
136 return -errno;
137 }
138
139 if (chdir(saved_cwd) < 0) {
140 LOGE("Unable to restore working dir");
141 return -errno;
142 }
143
144 devpath = &new_cwd[4]; // Skip over '/sys'
145
146 /*
147 * Collect parameters so we can simulate a UEVENT
148 */
149 sprintf(tmp, "DEVPATH=%s", devpath);
150 uevent_params[0] = (char *) strdup(tmp);
151
152 sprintf(filename, "/sys%s/type", devpath);
153 p = read_file(filename, &sz);
154 p[strlen(p) - 1] = '\0';
155 sprintf(tmp, "MMC_TYPE=%s", p);
156 free(p);
157 uevent_params[1] = (char *) strdup(tmp);
158
159 sprintf(filename, "/sys%s/name", devpath);
160 p = read_file(filename, &sz);
Xinyu Chene3530472009-08-16 22:09:18 +0800161 if (!p) {
162 LOGE("Unable to read MMC name: %s", filename);
163 return -errno;
164 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800165 p[strlen(p) - 1] = '\0';
166 sprintf(tmp, "MMC_NAME=%s", p);
167 free(p);
168 uevent_params[2] = (char *) strdup(tmp);
169
170 uevent_params[3] = (char *) NULL;
171
172 if (simulate_uevent("mmc", devpath, "add", uevent_params) < 0) {
San Mehat1f278212009-07-16 10:44:15 -0700173 LOGE("Error simulating uevent (%s)", strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800174 return -errno;
175 }
176
177 /*
178 * Check for block drivers
179 */
180 char block_devpath[255];
181 sprintf(tmp, "%s/block", devpath);
182 sprintf(filename, "/sys%s/block", devpath);
183 if (!access(filename, F_OK)) {
184 if (mmc_bootstrap_block(tmp)) {
185 LOGE("Error bootstrapping block @ %s", tmp);
186 }
187 }
188
189 return 0;
190}
191
192static int mmc_bootstrap_block(char *devpath)
193{
194 char blockdir_path[255];
195 DIR *d;
196 struct dirent *de;
197
198#if DEBUG_BOOTSTRAP
199 LOG_VOL("mmc_bootstrap_block(%s):", devpath);
200#endif
201
202 sprintf(blockdir_path, "/sys%s", devpath);
203
204 if (!(d = opendir(blockdir_path))) {
205 LOGE("Failed to opendir %s", devpath);
206 return -errno;
207 }
208
209 while ((de = readdir(d))) {
210 char tmp[255];
211
212 if (de->d_name[0] == '.')
213 continue;
214 sprintf(tmp, "%s/%s", devpath, de->d_name);
215 if (mmc_bootstrap_mmcblk(tmp))
216 LOGE("Error bootstraping mmcblk @ %s", tmp);
217 }
218 closedir(d);
219 return 0;
220}
221
222static int mmc_bootstrap_mmcblk(char *devpath)
223{
224 char *mmcblk_devname;
225 int part_no;
226 int rc;
227
228#if DEBUG_BOOTSTRAP
229 LOG_VOL("mmc_bootstrap_mmcblk(%s):", devpath);
230#endif
231
232 if ((rc = mmc_bootstrap_mmcblk_partition(devpath))) {
233 LOGE("Error bootstrapping mmcblk partition '%s'", devpath);
234 return rc;
235 }
236
237 for (mmcblk_devname = &devpath[strlen(devpath)];
238 *mmcblk_devname != '/'; mmcblk_devname--);
239 mmcblk_devname++;
240
Ben Winslow227c74a2009-08-15 09:52:10 -0400241 for (part_no = 1; part_no <= NDOSPART; part_no++) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800242 char part_file[255];
243 sprintf(part_file, "/sys%s/%sp%d", devpath, mmcblk_devname, part_no);
244 if (!access(part_file, F_OK)) {
245 char part_devpath[255];
246
247 sprintf(part_devpath, "%s/%sp%d", devpath, mmcblk_devname, part_no);
248 if (mmc_bootstrap_mmcblk_partition(part_devpath))
249 LOGE("Error bootstrapping mmcblk partition '%s'", part_devpath);
250 }
251 }
252
253 return 0;
254}
255
256static int mmc_bootstrap_mmcblk_partition(char *devpath)
257{
258 char filename[255];
259 char *uevent_buffer;
260 ssize_t sz;
Doug Kwane49f9c92009-03-26 14:14:15 -0700261 char *uevent_params[5];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800262 char tmp[255];
263 FILE *fp;
264 char line[255];
265
266#if DEBUG_BOOTSTRAP
267 LOG_VOL("mmc_bootstrap_mmcblk_partition(%s):", devpath);
268#endif
269
270 sprintf(tmp, "DEVPATH=%s", devpath);
271 uevent_params[0] = strdup(tmp);
272
273 sprintf(filename, "/sys%s/uevent", devpath);
274 if (!(fp = fopen(filename, "r"))) {
San Mehat1f278212009-07-16 10:44:15 -0700275 LOGE("Unable to open '%s' (%s)", filename, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800276 return -errno;
277 }
278
279 while (fgets(line, sizeof(line), fp)) {
280 line[strlen(line)-1] = 0;
281 if (!strncmp(line, "DEVTYPE=", 8))
282 uevent_params[1] = strdup(line);
283 else if (!strncmp(line, "MAJOR=",6))
284 uevent_params[2] = strdup(line);
285 else if (!strncmp(line, "MINOR=",6))
286 uevent_params[3] = strdup(line);
287 }
288 fclose(fp);
289
290 if (!uevent_params[1] || !uevent_params[2] || !uevent_params[3]) {
291 LOGE("mmcblk uevent missing required params");
292 return -1;
293 }
294 uevent_params[4] = '\0';
295
296 if (simulate_uevent("block", devpath, "add", uevent_params) < 0) {
San Mehat1f278212009-07-16 10:44:15 -0700297 LOGE("Error simulating uevent (%s)", strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800298 return -errno;
299 }
300 return 0;
301}