diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-01-20 14:04:01 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-01-20 14:04:01 -0800 |
| commit | 8ac3a138168f79b47356fb5aea2f6d95fc3147c6 (patch) | |
| tree | 97e97f6ce4dbd0461e52b50192420b4a70b1b988 /vold/mmc.c | |
| parent | 2eef60297a0ca1433d0824d6d662efd402709cfd (diff) | |
| download | system_core-8ac3a138168f79b47356fb5aea2f6d95fc3147c6.tar.gz system_core-8ac3a138168f79b47356fb5aea2f6d95fc3147c6.tar.bz2 system_core-8ac3a138168f79b47356fb5aea2f6d95fc3147c6.zip | |
auto import from //branches/cupcake/...@127101
Diffstat (limited to 'vold/mmc.c')
| -rw-r--r-- | vold/mmc.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/vold/mmc.c b/vold/mmc.c new file mode 100644 index 00000000..a4c93c5d --- /dev/null +++ b/vold/mmc.c @@ -0,0 +1,293 @@ + +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <string.h> +#include <dirent.h> +#include <errno.h> + +#include <sys/types.h> + +#include "vold.h" +#include "mmc.h" +#include "media.h" + +#define DEBUG_BOOTSTRAP 0 + +static int mmc_bootstrap_controller(char *sysfs_path); +static int mmc_bootstrap_card(char *sysfs_path); +static int mmc_bootstrap_block(char *devpath); +static int mmc_bootstrap_mmcblk(char *devpath); +static int mmc_bootstrap_mmcblk_partition(char *devpath); + +/* + * Bootstrap our mmc information. + */ +int mmc_bootstrap() +{ + DIR *d; + struct dirent *de; + + if (!(d = opendir(SYSFS_CLASS_MMC_PATH))) { + LOG_ERROR("Unable to open '%s' (%m)\n", SYSFS_CLASS_MMC_PATH); + return -errno; + } + + while ((de = readdir(d))) { + char tmp[255]; + + if (de->d_name[0] == '.') + continue; + + sprintf(tmp, "%s/%s", SYSFS_CLASS_MMC_PATH, de->d_name); + if (mmc_bootstrap_controller(tmp)) + LOG_ERROR("Error bootstrapping controller '%s' (%m)\n", tmp); + } + + closedir(d); + + return 0; +} + +static int mmc_bootstrap_controller(char *sysfs_path) +{ + DIR *d; + struct dirent *de; + +#if DEBUG_BOOTSTRAP + LOG_VOL("bootstrap_controller(%s):\n", sysfs_path); +#endif + if (!(d = opendir(sysfs_path))) { + LOG_ERROR("Unable to open '%s' (%m)\n", sysfs_path); + return -errno; + } + + while ((de = readdir(d))) { + char tmp[255]; + + if (de->d_name[0] == '.') + continue; + + if ((!strcmp(de->d_name, "uevent")) || + (!strcmp(de->d_name, "subsystem")) || + (!strcmp(de->d_name, "device")) || + (!strcmp(de->d_name, "power"))) { + continue; + } + + sprintf(tmp, "%s/%s", sysfs_path, de->d_name); + + if (mmc_bootstrap_card(tmp) < 0) + LOG_ERROR("Error bootstrapping card '%s' (%m)\n", tmp); + } // while + + closedir(d); + return 0; +} + +static int mmc_bootstrap_card(char *sysfs_path) +{ + char saved_cwd[255]; + char new_cwd[255]; + char *devpath; + char *uevent_params[4]; + char *p; + char filename[255]; + char tmp[255]; + ssize_t sz; + +#if DEBUG_BOOTSTRAP + LOG_VOL("bootstrap_card(%s):\n", sysfs_path); +#endif + + /* + * sysfs_path is based on /sys/class, but we want the actual device class + */ + if (!getcwd(saved_cwd, sizeof(saved_cwd))) { + LOGE("Buffer too small for working dir path\n"); + return -errno; + } + + if (chdir(sysfs_path) < 0) { + LOGE("Unable to chdir to %s (%m)\n", sysfs_path); + return -errno; + } + + if (!getcwd(new_cwd, sizeof(new_cwd))) { + LOGE("Buffer too small for device path\n"); + return -errno; + } + + if (chdir(saved_cwd) < 0) { + LOGE("Unable to restore working dir\n"); + return -errno; + } + + devpath = &new_cwd[4]; // Skip over '/sys' + + /* + * Collect parameters so we can simulate a UEVENT + */ + sprintf(tmp, "DEVPATH=%s", devpath); + uevent_params[0] = (char *) strdup(tmp); + + sprintf(filename, "/sys%s/type", devpath); + p = read_file(filename, &sz); + p[strlen(p) - 1] = '\0'; + sprintf(tmp, "MMC_TYPE=%s", p); + free(p); + uevent_params[1] = (char *) strdup(tmp); + + sprintf(filename, "/sys%s/name", devpath); + p = read_file(filename, &sz); + p[strlen(p) - 1] = '\0'; + sprintf(tmp, "MMC_NAME=%s", p); + free(p); + uevent_params[2] = (char *) strdup(tmp); + + uevent_params[3] = (char *) NULL; + + if (simulate_uevent("mmc", devpath, "add", uevent_params) < 0) { + LOGE("Error simulating uevent (%m)\n"); + return -errno; + } + + /* + * Check for block drivers + */ + char block_devpath[255]; + sprintf(tmp, "%s/block", devpath); + sprintf(filename, "/sys%s/block", devpath); + if (!access(filename, F_OK)) { + if (mmc_bootstrap_block(tmp)) { + LOGE("Error bootstrapping block @ %s\n", tmp); + } + } + + return 0; +} + +static int mmc_bootstrap_block(char *devpath) +{ + char blockdir_path[255]; + DIR *d; + struct dirent *de; + +#if DEBUG_BOOTSTRAP + LOG_VOL("mmc_bootstrap_block(%s):\n", devpath); +#endif + + sprintf(blockdir_path, "/sys%s", devpath); + + if (!(d = opendir(blockdir_path))) { + LOGE("Failed to opendir %s\n", devpath); + return -errno; + } + + while ((de = readdir(d))) { + char tmp[255]; + + if (de->d_name[0] == '.') + continue; + sprintf(tmp, "%s/%s", devpath, de->d_name); + if (mmc_bootstrap_mmcblk(tmp)) + LOGE("Error bootstraping mmcblk @ %s\n", tmp); + } + closedir(d); + return 0; +} + +static int mmc_bootstrap_mmcblk(char *devpath) +{ + char *mmcblk_devname; + int part_no; + int rc; + +#if DEBUG_BOOTSTRAP + LOG_VOL("mmc_bootstrap_mmcblk(%s):\n", devpath); +#endif + + if ((rc = mmc_bootstrap_mmcblk_partition(devpath))) { + LOGE("Error bootstrapping mmcblk partition '%s'\n", devpath); + return rc; + } + + for (mmcblk_devname = &devpath[strlen(devpath)]; + *mmcblk_devname != '/'; mmcblk_devname--); + mmcblk_devname++; + + for (part_no = 0; part_no < 4; part_no++) { + char part_file[255]; + sprintf(part_file, "/sys%s/%sp%d", devpath, mmcblk_devname, part_no); + if (!access(part_file, F_OK)) { + char part_devpath[255]; + + sprintf(part_devpath, "%s/%sp%d", devpath, mmcblk_devname, part_no); + if (mmc_bootstrap_mmcblk_partition(part_devpath)) + LOGE("Error bootstrapping mmcblk partition '%s'\n", part_devpath); + } + } + + return 0; +} + +static int mmc_bootstrap_mmcblk_partition(char *devpath) +{ + char filename[255]; + char *uevent_buffer; + ssize_t sz; + char *uevent_params[4]; + char tmp[255]; + FILE *fp; + char line[255]; + +#if DEBUG_BOOTSTRAP + LOG_VOL("mmc_bootstrap_mmcblk_partition(%s):\n", devpath); +#endif + + sprintf(tmp, "DEVPATH=%s", devpath); + uevent_params[0] = strdup(tmp); + + sprintf(filename, "/sys%s/uevent", devpath); + if (!(fp = fopen(filename, "r"))) { + LOGE("Unable to open '%s' (%m)\n", filename); + return -errno; + } + + while (fgets(line, sizeof(line), fp)) { + line[strlen(line)-1] = 0; + if (!strncmp(line, "DEVTYPE=", 8)) + uevent_params[1] = strdup(line); + else if (!strncmp(line, "MAJOR=",6)) + uevent_params[2] = strdup(line); + else if (!strncmp(line, "MINOR=",6)) + uevent_params[3] = strdup(line); + } + fclose(fp); + + if (!uevent_params[1] || !uevent_params[2] || !uevent_params[3]) { + LOGE("mmcblk uevent missing required params\n"); + return -1; + } + uevent_params[4] = '\0'; + + if (simulate_uevent("block", devpath, "add", uevent_params) < 0) { + LOGE("Error simulating uevent (%m)\n"); + return -errno; + } + return 0; +} |
