Android HAL的被调用流程

在Android系统中,对于硬件的操作,使用HAL Stub的方式来实现。HAL Stub的具体写法请参照Android中HAL如何向上层提供接口总结
在我们写完HAL Stub之后,这个HAL Stub是如何被应用获取,如何被应用程序调用的呢?
显然,由于HAL Stub本质上是一个.so,在调用之后,需要上层应用对其进行加载,然后才能调用。哪么,HAL Stub的加载器是如何实现对不同的Hardware HAL Stub进行通用性调用的呢? 按常规,每个Hareware HAL Stub应该有一个唯一的名字,且有一个通用的规则和一个入口函数。下面看看HAL Stub是如何实现这两个功能的。下面的描述以gralloc为例。

1. 唯一的id

  1. #define GRALLOC_HARDWARE_MODULE_ID "gralloc"
#define GRALLOC_HARDWARE_MODULE_ID "gralloc"


2. hw_module_t实例

每个硬件模块都有一个包含hw_module_t(为第一个成员)数据结构的实例,且实例的名字为:HAL_MODULE_INFO_SYM,它本身是一个宏定义,其定义如下:

hardware.h (通用的东东都在hardware.h和hardware.c中)

  1. /**
  2. * Name of the hal_module_info
  3. */
  4. #define HAL_MODULE_INFO_SYM HMI //.so中将一个符号HMI,获取此符号的地址,就获取到了对应的hw_module_t地址
  5. /**
  6. * Name of the hal_module_info as a string
  7. */
  8. #define HAL_MODULE_INFO_SYM_AS_STR "HMI"
/**
 * Name of the hal_module_info
 */
#define HAL_MODULE_INFO_SYM         HMI //.so中将一个符号HMI,获取此符号的地址,就获取到了对应的hw_module_t地址

/**
 * Name of the hal_module_info as a string
 */
#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"

  1. /**
  2. * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
  3. * and the fields of this data structure must begin with hw_module_t
  4. * followed by module specific information.
  5. */
  6. typedef struct gralloc_module_t {
  7. struct hw_module_t common;
  8. int (*registerBuffer)(struct gralloc_module_t const* module,
  9. buffer_handle_t handle);
  10. int (*unregisterBuffer)(struct gralloc_module_t const* module,
  11. buffer_handle_t handle);
  12. int (*lock)(struct gralloc_module_t const* module,
  13. buffer_handle_t handle, int usage,
  14. int l, int t, int w, int h,
  15. void** vaddr);
  16. int (*unlock)(struct gralloc_module_t const* module,
  17. buffer_handle_t handle);
  18. /* reserved for future use */
  19. int (*perform)(struct gralloc_module_t const* module,
  20. int operation, ... );
  21. /* reserved for future use */
  22. void* reserved_proc[7];
  23. }
/**
 * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
 * and the fields of this data structure must begin with hw_module_t
 * followed by module specific information.
 */
typedef struct gralloc_module_t {
    struct hw_module_t common;
    
    int (*registerBuffer)(struct gralloc_module_t const* module,
            buffer_handle_t handle);

    int (*unregisterBuffer)(struct gralloc_module_t const* module,
            buffer_handle_t handle);
    
    int (*lock)(struct gralloc_module_t const* module,
            buffer_handle_t handle, int usage,
            int l, int t, int w, int h,
            void** vaddr);
    
    int (*unlock)(struct gralloc_module_t const* module,
            buffer_handle_t handle);

    /* reserved for future use */
    int (*perform)(struct gralloc_module_t const* module,
            int operation, ... );
    /* reserved for future use */
    void* reserved_proc[7];
}
  1. struct private_module_t {
  2. gralloc_module_t base;
  3. struct private_handle_t* framebuffer;
  4. uint32_t flags;
  5. uint32_t numBuffers;
  6. uint32_t bufferMask;
  7. pthread_mutex_t lock;
  8. buffer_handle_t currentBuffer;
  9. int pmem_master;
  10. void* pmem_master_base;
  11. unsigned long master_phys;
  12. int gpu;
  13. void* gpu_base;
  14. int fb_map_offset;
  15. struct fb_var_screeninfo info;
  16. struct fb_fix_screeninfo finfo;
  17. float xdpi;
  18. float ydpi;
  19. float fps;
  20. };
struct private_module_t {
    gralloc_module_t base;

    struct private_handle_t* framebuffer;
    uint32_t flags;
    uint32_t numBuffers;
    uint32_t bufferMask;
    pthread_mutex_t lock;
    buffer_handle_t currentBuffer;
    int pmem_master;
    void* pmem_master_base;
    unsigned long master_phys;
    int gpu;
    void* gpu_base;
    int fb_map_offset;

    struct fb_var_screeninfo info;
    struct fb_fix_screeninfo finfo;
    float xdpi;
    float ydpi;
    float fps;
};

其实例为:

  1. static struct hw_module_methods_t gralloc_module_methods = {
  2. open: gralloc_device_open
  3. };
static struct hw_module_methods_t gralloc_module_methods = {
        open: gralloc_device_open
};

  1. struct private_module_t HAL_MODULE_INFO_SYM = {
  2. base: {
  3. common: {
  4. tag: HARDWARE_MODULE_TAG,
  5. version_major: 1,
  6. version_minor: 0,
  7. id: GRALLOC_HARDWARE_MODULE_ID,
  8. name: "Graphics Memory Allocator Module",
  9. author: "The Android Open Source Project",
  10. methods: &gralloc_module_methods
  11. },
  12. registerBuffer: gralloc_register_buffer,
  13. unregisterBuffer: gralloc_unregister_buffer,
  14. lock: gralloc_lock,
  15. unlock: gralloc_unlock,
  16. },
  17. framebuffer: 0,
  18. flags: 0,
  19. numBuffers: 0,
  20. bufferMask: 0,
  21. lock: PTHREAD_MUTEX_INITIALIZER,
  22. currentBuffer: 0,
  23. };
struct private_module_t HAL_MODULE_INFO_SYM = {
    base: {
        common: {
            tag: HARDWARE_MODULE_TAG,
            version_major: 1,
            version_minor: 0,
            id: GRALLOC_HARDWARE_MODULE_ID,
            name: "Graphics Memory Allocator Module",
            author: "The Android Open Source Project",
            methods: &gralloc_module_methods
        },
        registerBuffer: gralloc_register_buffer,
        unregisterBuffer: gralloc_unregister_buffer,
        lock: gralloc_lock,
        unlock: gralloc_unlock,
    },
    framebuffer: 0,
    flags: 0,
    numBuffers: 0,
    bufferMask: 0,
    lock: PTHREAD_MUTEX_INITIALIZER,
    currentBuffer: 0,
};


3. 从HAL Stub(.so)中获取hw_module_t(即private_module_t)

调用函数int hw_get_module(const char *id, const struct hw_module_t **module),其中id为就是1中所讲的GRALLOC_HARDWARE_MODULE_ID,第二个参数为我们要获取的hw_module_t。

下面以在FramebufferNativeWindow::FramebufferNativeWindow中的调用流程为例(FramebufferNativeWindow实现FrameBuffer的管理,它主要被SurfaceFlinger使用,也可以被OpenGL Native程序使用。在本质上,它在Framebuffer之上实现了一个ANativeWindow,目前它只管理两个buffers:front and back buffer.)

  1. FramebufferNativeWindow::FramebufferNativeWindow()
  2. : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
  3. {
  4. hw_module_t const* module;
  5. if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
  6. int stride;
  7. int err;
  8. int i;
  9. err = framebuffer_open(module, &fbDev);
  10. LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
  11. err = gralloc_open(module, &grDev);
  12. LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
  13. // bail out if we can't initialize the modules
  14. if (!fbDev || !grDev)
  15. return;
  16. mUpdateOnDemand = (fbDev->setUpdateRect != 0);
  17. // initialize the buffer FIFO
  18. mNumBuffers = NUM_FRAME_BUFFERS;
  19. mNumFreeBuffers = NUM_FRAME_BUFFERS;
  20. mBufferHead = mNumBuffers-1;
  21. for (i = 0; i < mNumBuffers; i++)
  22. {
  23. buffers[i] = new NativeBuffer(
  24. fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
  25. }
  26. for (i = 0; i < mNumBuffers; i++)
  27. {
  28. err = grDev->alloc(grDev,
  29. fbDev->width, fbDev->height, fbDev->format,
  30. GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);
  31. LOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
  32. i, fbDev->width, fbDev->height, strerror(-err));
  33. if (err)
  34. {
  35. mNumBuffers = i;
  36. mNumFreeBuffers = i;
  37. mBufferHead = mNumBuffers-1;
  38. break;
  39. }
  40. }
  41. const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
  42. const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
  43. const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
  44. const_cast<int&>(ANativeWindow::minSwapInterval) =
  45. fbDev->minSwapInterval;
  46. const_cast<int&>(ANativeWindow::maxSwapInterval) =
  47. fbDev->maxSwapInterval;
  48. }
  49. else
  50. {
  51. LOGE("Couldn't get gralloc module");
  52. }
  53. ANativeWindow::setSwapInterval = setSwapInterval;
  54. ANativeWindow::dequeueBuffer = dequeueBuffer;
  55. ANativeWindow::lockBuffer = lockBuffer;
  56. ANativeWindow::queueBuffer = queueBuffer;
  57. ANativeWindow::query = query;
  58. ANativeWindow::perform = perform;
  59. }
FramebufferNativeWindow::FramebufferNativeWindow() 
    : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
{
    hw_module_t const* module;
    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
        int stride;
        int err;
        int i;
        err = framebuffer_open(module, &fbDev);
        LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
        
        err = gralloc_open(module, &grDev);
        LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));

        // bail out if we can't initialize the modules
        if (!fbDev || !grDev)
            return;
        
        mUpdateOnDemand = (fbDev->setUpdateRect != 0);
        
        // initialize the buffer FIFO
        mNumBuffers = NUM_FRAME_BUFFERS;
        mNumFreeBuffers = NUM_FRAME_BUFFERS;
        mBufferHead = mNumBuffers-1;

        for (i = 0; i < mNumBuffers; i++)
        {
                buffers[i] = new NativeBuffer(
                        fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
        }

        for (i = 0; i < mNumBuffers; i++)
        {
                err = grDev->alloc(grDev,
                        fbDev->width, fbDev->height, fbDev->format,
                        GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);

                LOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
                        i, fbDev->width, fbDev->height, strerror(-err));

                if (err)
                {
                        mNumBuffers = i;
                        mNumFreeBuffers = i;
                        mBufferHead = mNumBuffers-1;
                        break;
                }
        }

        const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags; 
        const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
        const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
        const_cast<int&>(ANativeWindow::minSwapInterval) = 
            fbDev->minSwapInterval;
        const_cast<int&>(ANativeWindow::maxSwapInterval) = 
            fbDev->maxSwapInterval;
    } 
    else 
    {
         LOGE("Couldn't get gralloc module");
    }

    ANativeWindow::setSwapInterval = setSwapInterval;
    ANativeWindow::dequeueBuffer = dequeueBuffer;
    ANativeWindow::lockBuffer = lockBuffer;
    ANativeWindow::queueBuffer = queueBuffer;
    ANativeWindow::query = query;
    ANativeWindow::perform = perform;
}


看看关键的hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module)都做了些什么?它在hardware.c中实现。相关代码如下:

  1. /** Base path of the hal modules */
  2. #define HAL_LIBRARY_PATH1 "/system/lib/hw"
  3. #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
  4. /**
  5. * There are a set of variant filename for modules. The form of the filename
  6. * is "<MODULE_ID>.variant.so" so for the led module the Dream variants
  7. * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
  8. *
  9. * led.trout.so
  10. * led.msm7k.so
  11. * led.ARMV6.so
  12. * led.default.so
  13. */
  14. static const char *variant_keys[] = {
  15. "ro.hardware", /* This goes first so that it can pick up a different
  16. file on the emulator. */
  17. "ro.product.board",
  18. "ro.board.platform",
  19. "ro.arch"
  20. };
  21. static const int HAL_VARIANT_KEYS_COUNT =
  22. (sizeof(variant_keys)/sizeof(variant_keys[0]));
  23. /**
  24. * Load the file defined by the variant and if successful
  25. * return the dlopen handle and the hmi.
  26. * @return 0 = success, !0 = failure.
  27. */
  28. static int load(const char *id,
  29. const char *path,
  30. const struct hw_module_t **pHmi)
  31. {
  32. int status;
  33. void *handle;
  34. struct hw_module_t *hmi;
  35. /*
  36. * load the symbols resolving undefined symbols before
  37. * dlopen returns. Since RTLD_GLOBAL is not or'd in with
  38. * RTLD_NOW the external symbols will not be global
  39. */
  40. handle = dlopen(path, RTLD_NOW);
  41. if (handle == NULL) {
  42. char const *err_str = dlerror();
  43. LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
  44. status = -EINVAL;
  45. goto done;
  46. }
  47. /* Get the address of the struct hal_module_info. */
  48. const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
  49. hmi = (struct hw_module_t *)dlsym(handle, sym);
  50. if (hmi == NULL) {
  51. LOGE("load: couldn't find symbol %s", sym);
  52. status = -EINVAL;
  53. goto done;
  54. }
  55. /* Check that the id matches */
  56. if (strcmp(id, hmi->id) != 0) {
  57. LOGE("load: id=%s != hmi->id=%s", id, hmi->id);
  58. status = -EINVAL;
  59. goto done;
  60. }
  61. hmi->dso = handle;
  62. /* success */
  63. status = 0;
  64. done:
  65. if (status != 0) {
  66. hmi = NULL;
  67. if (handle != NULL) {
  68. dlclose(handle);
  69. handle = NULL;
  70. }
  71. } else {
  72. LOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
  73. id, path, *pHmi, handle);
  74. }
  75. *pHmi = hmi;
  76. return status;
  77. }
  78. int hw_get_module_by_class(const char *class_id, const char *inst,
  79. const struct hw_module_t **module)
  80. {
  81. int status;
  82. int i;
  83. const struct hw_module_t *hmi = NULL;
  84. char prop[PATH_MAX];
  85. char path[PATH_MAX];
  86. char name[PATH_MAX];
  87. if (inst)
  88. snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
  89. else
  90. strlcpy(name, class_id, PATH_MAX);
  91. /*
  92. * Here we rely on the fact that calling dlopen multiple times on
  93. * the same .so will simply increment a refcount (and not load
  94. * a new copy of the library).
  95. * We also assume that dlopen() is thread-safe.
  96. */
  97. /* Loop through the configuration variants looking for a module */
  98. for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
  99. if (i < HAL_VARIANT_KEYS_COUNT) {
  100. if (property_get(variant_keys[i], prop, NULL) == 0) {
  101. continue;
  102. }
  103. snprintf(path, sizeof(path), "%s/%s.%s.so",
  104. HAL_LIBRARY_PATH2, name, prop);
  105. if (access(path, R_OK) == 0) break;
  106. snprintf(path, sizeof(path), "%s/%s.%s.so",
  107. HAL_LIBRARY_PATH1, name, prop);
  108. if (access(path, R_OK) == 0) break;
  109. } else {
  110. snprintf(path, sizeof(path), "%s/%s.default.so",
  111. HAL_LIBRARY_PATH1, name);
  112. if (access(path, R_OK) == 0) break;
  113. }
  114. }
  115. status = -ENOENT;
  116. if (i < HAL_VARIANT_KEYS_COUNT+1) {
  117. /* load the module, if this fails, we're doomed, and we should not try
  118. * to load a different variant. */
  119. status = load(class_id, path, module);
  120. }
  121. return status;
  122. }
  123. int hw_get_module(const char *id, const struct hw_module_t **module)
  124. {
  125. return hw_get_module_by_class(id, NULL, module);
  126. }
/** Base path of the hal modules */
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"

/**
 * There are a set of variant filename for modules. The form of the filename
 * is "<MODULE_ID>.variant.so" so for the led module the Dream variants 
 * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
 *
 * led.trout.so
 * led.msm7k.so
 * led.ARMV6.so
 * led.default.so
 */

static const char *variant_keys[] = {
    "ro.hardware",  /* This goes first so that it can pick up a different
                       file on the emulator. */
    "ro.product.board",
    "ro.board.platform",
    "ro.arch"
};

static const int HAL_VARIANT_KEYS_COUNT =
    (sizeof(variant_keys)/sizeof(variant_keys[0]));

/**
 * Load the file defined by the variant and if successful
 * return the dlopen handle and the hmi.
 * @return 0 = success, !0 = failure.
 */
static int load(const char *id,
        const char *path,
        const struct hw_module_t **pHmi)
{
    int status;
    void *handle;
    struct hw_module_t *hmi;

    /*
     * load the symbols resolving undefined symbols before
     * dlopen returns. Since RTLD_GLOBAL is not or'd in with
     * RTLD_NOW the external symbols will not be global
     */
    handle = dlopen(path, RTLD_NOW);
    if (handle == NULL) {
        char const *err_str = dlerror();
        LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
        status = -EINVAL;
        goto done;
    }

    /* Get the address of the struct hal_module_info. */
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
    hmi = (struct hw_module_t *)dlsym(handle, sym);
    if (hmi == NULL) {
        LOGE("load: couldn't find symbol %s", sym);
        status = -EINVAL;
        goto done;
    }

    /* Check that the id matches */
    if (strcmp(id, hmi->id) != 0) {
        LOGE("load: id=%s != hmi->id=%s", id, hmi->id);
        status = -EINVAL;
        goto done;
    }

    hmi->dso = handle;

    /* success */
    status = 0;

    done:
    if (status != 0) {
        hmi = NULL;
        if (handle != NULL) {
            dlclose(handle);
            handle = NULL;
        }
    } else {
        LOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
                id, path, *pHmi, handle);
    }

    *pHmi = hmi;

    return status;
}

int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    int status;
    int i;
    const struct hw_module_t *hmi = NULL;
    char prop[PATH_MAX];
    char path[PATH_MAX];
    char name[PATH_MAX];

    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
        strlcpy(name, class_id, PATH_MAX);

    /*
     * Here we rely on the fact that calling dlopen multiple times on
     * the same .so will simply increment a refcount (and not load
     * a new copy of the library).
     * We also assume that dlopen() is thread-safe.
     */

    /* Loop through the configuration variants looking for a module */
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
        if (i < HAL_VARIANT_KEYS_COUNT) {
            if (property_get(variant_keys[i], prop, NULL) == 0) {
                continue;
            }
            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH2, name, prop);
            if (access(path, R_OK) == 0) break;

            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH1, name, prop);
            if (access(path, R_OK) == 0) break;
        } else {
            snprintf(path, sizeof(path), "%s/%s.default.so",
                     HAL_LIBRARY_PATH1, name);
            if (access(path, R_OK) == 0) break;
        }
    }

    status = -ENOENT;
    if (i < HAL_VARIANT_KEYS_COUNT+1) {
        /* load the module, if this fails, we're doomed, and we should not try
         * to load a different variant. */
        status = load(class_id, path, module);
    }

    return status;
}

int hw_get_module(const char *id, const struct hw_module_t **module)
{
    return hw_get_module_by_class(id, NULL, module);
}


其关键在于load函数中的下面两行代码:

  1. const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
  2. hmi = (struct hw_module_t *)dlsym(handle, sym);
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
    hmi = (struct hw_module_t *)dlsym(handle, sym);


在打开的.so中查找HMI符号的地址,并保存在hmi中。至此,.so中的hw_module_t已经被成功获取,从而可以根据它获取别的相关接口。

4. 使用实例

代码如下:

  1. GraphicBufferAllocator::GraphicBufferAllocator()
  2. : mAllocDev(0)
  3. {
  4. hw_module_t const* module;
  5. int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
  6. LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
  7. if (err == 0) {
  8. gralloc_open(module, &mAllocDev);
  9. }
  10. }
GraphicBufferAllocator::GraphicBufferAllocator()
    : mAllocDev(0)
{
    hw_module_t const* module;
    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
    LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
    if (err == 0) {
        gralloc_open(module, &mAllocDev);
    }
}


5. 总结

1)HAL通过hw_get_module函数获取hw_module_t

2)HAL通过hw_module_t->methods->open获取hw_device_t指针,并在此open函数中初始化hw_device_t的包装结构中的函数及hw_device_t中的close函数,如gralloc_device_open。
3)三个重要的数据结构:

a) struct hw_device_t: 表示硬件设备,存储了各种硬件设备的公共属性和方法

b)struct hw_module_t: 可用hw_get_module进行加载的module

c)struct hw_module_methods_t: 用于定义操作设备的方法,其中只定义了一个打开设备的方法open.

  1. typedef struct hw_module_t {
  2. /** tag must be initialized to HARDWARE_MODULE_TAG */
  3. uint32_t tag;
  4. /** major version number for the module */
  5. uint16_t version_major;
  6. /** minor version number of the module */
  7. uint16_t version_minor;
  8. /** Identifier of module */
  9. const char *id;
  10. /** Name of this module */
  11. const char *name;
  12. /** Author/owner/implementor of the module */
  13. const char *author;
  14. /** Modules methods */
  15. struct hw_module_methods_t* methods;
  16. /** module's dso */
  17. void* dso;
  18. /** padding to 128 bytes, reserved for future use */
  19. uint32_t reserved[32-7];
  20. } hw_module_t;
  21. typedef struct hw_module_methods_t {
  22. /** Open a specific device */
  23. int (*open)(const struct hw_module_t* module, const char* id,
  24. struct hw_device_t** device);
  25. } hw_module_methods_t;
  26. /**
  27. * Every device data structure must begin with hw_device_t
  28. * followed by module specific public methods and attributes.
  29. */
  30. typedef struct hw_device_t {
  31. /** tag must be initialized to HARDWARE_DEVICE_TAG */
  32. uint32_t tag;
  33. /** version number for hw_device_t */
  34. uint32_t version;
  35. /** reference to the module this device belongs to */
  36. struct hw_module_t* module;
  37. /** padding reserved for future use */
  38. uint32_t reserved[12];
  39. /** Close this device */
  40. int (*close)(struct hw_device_t* device);
  41. } hw_device_t;
typedef struct hw_module_t {
    /** tag must be initialized to HARDWARE_MODULE_TAG */
    uint32_t tag;

    /** major version number for the module */
    uint16_t version_major;

    /** minor version number of the module */
    uint16_t version_minor;

    /** Identifier of module */
    const char *id;

    /** Name of this module */
    const char *name;

    /** Author/owner/implementor of the module */
    const char *author;

    /** Modules methods */
    struct hw_module_methods_t* methods;

    /** module's dso */
    void* dso;

    /** padding to 128 bytes, reserved for future use */
    uint32_t reserved[32-7];

} hw_module_t;

typedef struct hw_module_methods_t {
    /** Open a specific device */
    int (*open)(const struct hw_module_t* module, const char* id,
            struct hw_device_t** device);

} hw_module_methods_t;

/**
 * Every device data structure must begin with hw_device_t
 * followed by module specific public methods and attributes.
 */
typedef struct hw_device_t {
    /** tag must be initialized to HARDWARE_DEVICE_TAG */
    uint32_t tag;

    /** version number for hw_device_t */
    uint32_t version;

    /** reference to the module this device belongs to */
    struct hw_module_t* module;

    /** padding reserved for future use */
    uint32_t reserved[12];

    /** Close this device */
    int (*close)(struct hw_device_t* device);

} hw_device_t;


hw_device_t通过open方法获取。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值