1f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project/* 2f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 3f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * 4f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * you may not use this file except in compliance with the License. 6f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * You may obtain a copy of the License at 7f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * 8f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * 10f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * See the License for the specific language governing permissions and 14f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * limitations under the License. 15f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project */ 16f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 17f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project#include <hardware/hardware.h> 18f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 19f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project#include <cutils/properties.h> 20f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 21f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project#include <dlfcn.h> 22f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project#include <string.h> 23f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project#include <pthread.h> 24f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project#include <errno.h> 25f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project#include <limits.h> 26f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 27f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project#define LOG_TAG "HAL" 28f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project#include <utils/Log.h> 29f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 30f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project/** Base path of the hal modules */ 31e755bd4038cab69f98f7cf17e41f493296ec62abBrian Swetland#define HAL_LIBRARY_PATH1 "/system/lib/hw" 32e755bd4038cab69f98f7cf17e41f493296ec62abBrian Swetland#define HAL_LIBRARY_PATH2 "/vendor/lib/hw" 33f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 34f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project/** 35f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * There are a set of variant filename for modules. The form of the filename 36f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * is "<MODULE_ID>.variant.so" so for the led module the Dream variants 37f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be: 38f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * 39f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * led.trout.so 40f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * led.msm7k.so 41f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * led.ARMV6.so 42f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * led.default.so 43f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project */ 44f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 458232b50d981ce9c584fc1a4af82dae5e70e6ce52The Android Open Source Projectstatic const char *variant_keys[] = { 468232b50d981ce9c584fc1a4af82dae5e70e6ce52The Android Open Source Project "ro.hardware", /* This goes first so that it can pick up a different 478232b50d981ce9c584fc1a4af82dae5e70e6ce52The Android Open Source Project file on the emulator. */ 48f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project "ro.product.board", 49f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project "ro.board.platform", 50cab816fb6d98c23a8958a5df0006d227b14d1146Mathias Agopian "ro.arch" 51f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project}; 523f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian 533f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopianstatic const int HAL_VARIANT_KEYS_COUNT = 543f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian (sizeof(variant_keys)/sizeof(variant_keys[0])); 55f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 56f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project/** 578c4ab1fa14cc13c324bde91c0271f9ab5f4663d3Mathias Agopian * Load the file defined by the variant and if successful 58f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * return the dlopen handle and the hmi. 59f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * @return 0 = success, !0 = failure. 60f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project */ 61f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Projectstatic int load(const char *id, 623f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian const char *path, 633f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian const struct hw_module_t **pHmi) 64f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project{ 65f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project int status; 66f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project void *handle; 67a8a75166a2d3c7639a7432a67075c98796165206Mathias Agopian struct hw_module_t *hmi; 68f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 69f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project /* 70f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * load the symbols resolving undefined symbols before 71f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * dlopen returns. Since RTLD_GLOBAL is not or'd in with 72f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * RTLD_NOW the external symbols will not be global 73f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project */ 74f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project handle = dlopen(path, RTLD_NOW); 75f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project if (handle == NULL) { 76f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project char const *err_str = dlerror(); 773f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown"); 78f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project status = -EINVAL; 79f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project goto done; 80f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project } 81f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 82f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project /* Get the address of the struct hal_module_info. */ 83f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project const char *sym = HAL_MODULE_INFO_SYM_AS_STR; 84a8a75166a2d3c7639a7432a67075c98796165206Mathias Agopian hmi = (struct hw_module_t *)dlsym(handle, sym); 85f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project if (hmi == NULL) { 86f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project LOGE("load: couldn't find symbol %s", sym); 87f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project status = -EINVAL; 88f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project goto done; 89f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project } 90f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 91f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project /* Check that the id matches */ 92f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project if (strcmp(id, hmi->id) != 0) { 93f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project LOGE("load: id=%s != hmi->id=%s", id, hmi->id); 94f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project status = -EINVAL; 95f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project goto done; 96f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project } 973f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian 98a8a75166a2d3c7639a7432a67075c98796165206Mathias Agopian hmi->dso = handle; 99f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 100f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project /* success */ 101f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project status = 0; 102f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 1033f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian done: 104f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project if (status != 0) { 105f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project hmi = NULL; 106f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project if (handle != NULL) { 107f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project dlclose(handle); 108f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project handle = NULL; 109f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project } 1106d125da5d28369df62dc5c186b43fcd40a3d33e8Mathias Agopian } else { 1116d125da5d28369df62dc5c186b43fcd40a3d33e8Mathias Agopian LOGV("loaded HAL id=%s path=%s hmi=%p handle=%p", 1123f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian id, path, *pHmi, handle); 113f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project } 114f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 115f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project *pHmi = hmi; 116f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 117f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project return status; 118f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project} 119f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 120f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Projectint hw_get_module(const char *id, const struct hw_module_t **module) 121f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project{ 122f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project int status; 123f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project int i; 1248232b50d981ce9c584fc1a4af82dae5e70e6ce52The Android Open Source Project const struct hw_module_t *hmi = NULL; 1258232b50d981ce9c584fc1a4af82dae5e70e6ce52The Android Open Source Project char prop[PATH_MAX]; 1263f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian char path[PATH_MAX]; 127f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 128f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project /* 129f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * Here we rely on the fact that calling dlopen multiple times on 130f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * the same .so will simply increment a refcount (and not load 131f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * a new copy of the library). 132f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project * We also assume that dlopen() is thread-safe. 133f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project */ 134f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project 1358232b50d981ce9c584fc1a4af82dae5e70e6ce52The Android Open Source Project /* Loop through the configuration variants looking for a module */ 136cab816fb6d98c23a8958a5df0006d227b14d1146Mathias Agopian for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) { 137cab816fb6d98c23a8958a5df0006d227b14d1146Mathias Agopian if (i < HAL_VARIANT_KEYS_COUNT) { 138cab816fb6d98c23a8958a5df0006d227b14d1146Mathias Agopian if (property_get(variant_keys[i], prop, NULL) == 0) { 139cab816fb6d98c23a8958a5df0006d227b14d1146Mathias Agopian continue; 140cab816fb6d98c23a8958a5df0006d227b14d1146Mathias Agopian } 141cab816fb6d98c23a8958a5df0006d227b14d1146Mathias Agopian snprintf(path, sizeof(path), "%s/%s.%s.so", 142e755bd4038cab69f98f7cf17e41f493296ec62abBrian Swetland HAL_LIBRARY_PATH1, id, prop); 143e755bd4038cab69f98f7cf17e41f493296ec62abBrian Swetland if (access(path, R_OK) == 0) break; 144e755bd4038cab69f98f7cf17e41f493296ec62abBrian Swetland 145e755bd4038cab69f98f7cf17e41f493296ec62abBrian Swetland snprintf(path, sizeof(path), "%s/%s.%s.so", 146e755bd4038cab69f98f7cf17e41f493296ec62abBrian Swetland HAL_LIBRARY_PATH2, id, prop); 147e755bd4038cab69f98f7cf17e41f493296ec62abBrian Swetland if (access(path, R_OK) == 0) break; 148cab816fb6d98c23a8958a5df0006d227b14d1146Mathias Agopian } else { 149cab816fb6d98c23a8958a5df0006d227b14d1146Mathias Agopian snprintf(path, sizeof(path), "%s/%s.default.so", 150e755bd4038cab69f98f7cf17e41f493296ec62abBrian Swetland HAL_LIBRARY_PATH1, id); 151e755bd4038cab69f98f7cf17e41f493296ec62abBrian Swetland if (access(path, R_OK) == 0) break; 1523f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian } 153f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project } 1548232b50d981ce9c584fc1a4af82dae5e70e6ce52The Android Open Source Project 1553f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian status = -ENOENT; 1562b811adcbc821573de53a15f3d4e85a3d5a4ef9bDavid 'Digit' Turner if (i < HAL_VARIANT_KEYS_COUNT+1) { 1573f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian /* load the module, if this fails, we're doomed, and we should not try 1583f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian * to load a different variant. */ 1593f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian status = load(id, path, module); 160f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project } 1613f03e98dbf1b402334c804a3558b6d4f6042048cMathias Agopian 162f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project return status; 163f53ebec38718ff5d6b2aff2fa62b92a75d007ca5The Android Open Source Project} 164