blob: a4c93c5da05c0dc57b53ae72200ce4d349c8dcdd [file] [log] [blame]
The Android Open Source Project8ac3a132009-01-20 14:04:01 -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"
28
29#define DEBUG_BOOTSTRAP 0
30
31static int mmc_bootstrap_controller(char *sysfs_path);
32static int mmc_bootstrap_card(char *sysfs_path);
33static int mmc_bootstrap_block(char *devpath);
34static int mmc_bootstrap_mmcblk(char *devpath);
35static int mmc_bootstrap_mmcblk_partition(char *devpath);
36
37/*
38 * Bootstrap our mmc information.
39 */
40int mmc_bootstrap()
41{
42 DIR *d;
43 struct dirent *de;
44
45 if (!(d = opendir(SYSFS_CLASS_MMC_PATH))) {
46 LOG_ERROR("Unable to open '%s' (%m)\n", SYSFS_CLASS_MMC_PATH);
47 return -errno;
48 }
49
50 while ((de = readdir(d))) {
51 char tmp[255];
52
53 if (de->d_name[0] == '.')
54 continue;
55
56 sprintf(tmp, "%s/%s", SYSFS_CLASS_MMC_PATH, de->d_name);
57 if (mmc_bootstrap_controller(tmp))
58 LOG_ERROR("Error bootstrapping controller '%s' (%m)\n", tmp);
59 }
60
61 closedir(d);
62
63 return 0;
64}
65
66static int mmc_bootstrap_controller(char *sysfs_path)
67{
68 DIR *d;
69 struct dirent *de;
70
71#if DEBUG_BOOTSTRAP
72 LOG_VOL("bootstrap_controller(%s):\n", sysfs_path);
73#endif
74 if (!(d = opendir(sysfs_path))) {
75 LOG_ERROR("Unable to open '%s' (%m)\n", sysfs_path);
76 return -errno;
77 }
78
79 while ((de = readdir(d))) {
80 char tmp[255];
81
82 if (de->d_name[0] == '.')
83 continue;
84
85 if ((!strcmp(de->d_name, "uevent")) ||
86 (!strcmp(de->d_name, "subsystem")) ||
87 (!strcmp(de->d_name, "device")) ||
88 (!strcmp(de->d_name, "power"))) {
89 continue;
90 }
91
92 sprintf(tmp, "%s/%s", sysfs_path, de->d_name);
93
94 if (mmc_bootstrap_card(tmp) < 0)
95 LOG_ERROR("Error bootstrapping card '%s' (%m)\n", tmp);
96 } // while
97
98 closedir(d);
99 return 0;
100}
101
102static int mmc_bootstrap_card(char *sysfs_path)
103{
104 char saved_cwd[255];
105 char new_cwd[255];
106 char *devpath;
107 char *uevent_params[4];
108 char *p;
109 char filename[255];
110 char tmp[255];
111 ssize_t sz;
112
113#if DEBUG_BOOTSTRAP
114 LOG_VOL("bootstrap_card(%s):\n", sysfs_path);
115#endif
116
117 /*
118 * sysfs_path is based on /sys/class, but we want the actual device class
119 */
120 if (!getcwd(saved_cwd, sizeof(saved_cwd))) {
121 LOGE("Buffer too small for working dir path\n");
122 return -errno;
123 }
124
125 if (chdir(sysfs_path) < 0) {
126 LOGE("Unable to chdir to %s (%m)\n", sysfs_path);
127 return -errno;
128 }
129
130 if (!getcwd(new_cwd, sizeof(new_cwd))) {
131 LOGE("Buffer too small for device path\n");
132 return -errno;
133 }
134
135 if (chdir(saved_cwd) < 0) {
136 LOGE("Unable to restore working dir\n");
137 return -errno;
138 }
139
140 devpath = &new_cwd[4]; // Skip over '/sys'
141
142 /*
143 * Collect parameters so we can simulate a UEVENT
144 */
145 sprintf(tmp, "DEVPATH=%s", devpath);
146 uevent_params[0] = (char *) strdup(tmp);
147
148 sprintf(filename, "/sys%s/type", devpath);
149 p = read_file(filename, &sz);
150 p[strlen(p) - 1] = '\0';
151 sprintf(tmp, "MMC_TYPE=%s", p);
152 free(p);
153 uevent_params[1] = (char *) strdup(tmp);
154
155 sprintf(filename, "/sys%s/name", devpath);
156 p = read_file(filename, &sz);
157 p[strlen(p) - 1] = '\0';
158 sprintf(tmp, "MMC_NAME=%s", p);
159 free(p);
160 uevent_params[2] = (char *) strdup(tmp);
161
162 uevent_params[3] = (char *) NULL;
163
164 if (simulate_uevent("mmc", devpath, "add", uevent_params) < 0) {
165 LOGE("Error simulating uevent (%m)\n");
166 return -errno;
167 }
168
169 /*
170 * Check for block drivers
171 */
172 char block_devpath[255];
173 sprintf(tmp, "%s/block", devpath);
174 sprintf(filename, "/sys%s/block", devpath);
175 if (!access(filename, F_OK)) {
176 if (mmc_bootstrap_block(tmp)) {
177 LOGE("Error bootstrapping block @ %s\n", tmp);
178 }
179 }
180
181 return 0;
182}
183
184static int mmc_bootstrap_block(char *devpath)
185{
186 char blockdir_path[255];
187 DIR *d;
188 struct dirent *de;
189
190#if DEBUG_BOOTSTRAP
191 LOG_VOL("mmc_bootstrap_block(%s):\n", devpath);
192#endif
193
194 sprintf(blockdir_path, "/sys%s", devpath);
195
196 if (!(d = opendir(blockdir_path))) {
197 LOGE("Failed to opendir %s\n", devpath);
198 return -errno;
199 }
200
201 while ((de = readdir(d))) {
202 char tmp[255];
203
204 if (de->d_name[0] == '.')
205 continue;
206 sprintf(tmp, "%s/%s", devpath, de->d_name);
207 if (mmc_bootstrap_mmcblk(tmp))
208 LOGE("Error bootstraping mmcblk @ %s\n", tmp);
209 }
210 closedir(d);
211 return 0;
212}
213
214static int mmc_bootstrap_mmcblk(char *devpath)
215{
216 char *mmcblk_devname;
217 int part_no;
218 int rc;
219
220#if DEBUG_BOOTSTRAP
221 LOG_VOL("mmc_bootstrap_mmcblk(%s):\n", devpath);
222#endif
223
224 if ((rc = mmc_bootstrap_mmcblk_partition(devpath))) {
225 LOGE("Error bootstrapping mmcblk partition '%s'\n", devpath);
226 return rc;
227 }
228
229 for (mmcblk_devname = &devpath[strlen(devpath)];
230 *mmcblk_devname != '/'; mmcblk_devname--);
231 mmcblk_devname++;
232
233 for (part_no = 0; part_no < 4; part_no++) {
234 char part_file[255];
235 sprintf(part_file, "/sys%s/%sp%d", devpath, mmcblk_devname, part_no);
236 if (!access(part_file, F_OK)) {
237 char part_devpath[255];
238
239 sprintf(part_devpath, "%s/%sp%d", devpath, mmcblk_devname, part_no);
240 if (mmc_bootstrap_mmcblk_partition(part_devpath))
241 LOGE("Error bootstrapping mmcblk partition '%s'\n", part_devpath);
242 }
243 }
244
245 return 0;
246}
247
248static int mmc_bootstrap_mmcblk_partition(char *devpath)
249{
250 char filename[255];
251 char *uevent_buffer;
252 ssize_t sz;
253 char *uevent_params[4];
254 char tmp[255];
255 FILE *fp;
256 char line[255];
257
258#if DEBUG_BOOTSTRAP
259 LOG_VOL("mmc_bootstrap_mmcblk_partition(%s):\n", devpath);
260#endif
261
262 sprintf(tmp, "DEVPATH=%s", devpath);
263 uevent_params[0] = strdup(tmp);
264
265 sprintf(filename, "/sys%s/uevent", devpath);
266 if (!(fp = fopen(filename, "r"))) {
267 LOGE("Unable to open '%s' (%m)\n", filename);
268 return -errno;
269 }
270
271 while (fgets(line, sizeof(line), fp)) {
272 line[strlen(line)-1] = 0;
273 if (!strncmp(line, "DEVTYPE=", 8))
274 uevent_params[1] = strdup(line);
275 else if (!strncmp(line, "MAJOR=",6))
276 uevent_params[2] = strdup(line);
277 else if (!strncmp(line, "MINOR=",6))
278 uevent_params[3] = strdup(line);
279 }
280 fclose(fp);
281
282 if (!uevent_params[1] || !uevent_params[2] || !uevent_params[3]) {
283 LOGE("mmcblk uevent missing required params\n");
284 return -1;
285 }
286 uevent_params[4] = '\0';
287
288 if (simulate_uevent("block", devpath, "add", uevent_params) < 0) {
289 LOGE("Error simulating uevent (%m)\n");
290 return -errno;
291 }
292 return 0;
293}