3. 打开摄像头设备

任务说明

本案例实现 Camera HAL 层设备打开的核心逻辑:编写 open 函数,完成 camera_device_t 实例的创建、硬件接口初始化,并返回设备指针供上层调用。该函数对应 HAL 模块中 hw_module_methods_t::open 的回调实现,是上层通过 hw_get_module 获取摄像头设备后的第一个调用入口。

核心代码实现

// camera_hal_device.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hardware/hardware.h>
#include <hardware/camera_common.h>
#include <cutils/log.h>

// 硬件接口操作集(本案例仅实现 open/close 的最小闭环)
static int camera_device_close(struct hw_device_t* device) {
    if (device == NULL) return -EINVAL;

    camera_device_t* cam_dev = (camera_device_t*)device;
    camera_device_ops_t* ops = cam_dev->ops;

    // 释放内部资源(此处为最小实现,仅做空指针保护)
    if (ops != NULL) {
        free(ops);
        cam_dev->ops = NULL;
    }
    free(cam_dev);
    ALOGI("camera device closed and freed");
    return 0;
}

// 设备打开入口:创建实例、绑定 ops、初始化硬件接口
static int camera_device_open(const hw_module_t* module, const char* id,
                              hw_device_t** device) {
    if (module == NULL || id == NULL || device == NULL) {
        ALOGE("invalid argument: module=%p id=%p device=%p", module, id, device);
        return -EINVAL;
    }

    // 1. 分配 camera_device_t 实例
    camera_device_t* cam_dev = (camera_device_t*)calloc(1, sizeof(camera_device_t));
    if (cam_dev == NULL) {
        ALOGE("failed to alloc camera_device_t");
        return -ENOMEM;
    }

    // 2. 分配并填充 ops 操作集(当前仅注册 close,其余按业务扩展)
    camera_device_ops_t* ops = (camera_device_ops_t*)calloc(1, sizeof(camera_device_ops_t));
    if (ops == NULL) {
        ALOGE("failed to alloc camera_device_ops_t");
        free(cam_dev);
        return -ENOMEM;
    }
    ops->close = camera_device_close;

    // 3. 初始化公共 hw_device_t 字段
    cam_dev->common.tag = HARDWARE_DEVICE_TAG;
    cam_dev->common.version = CAMERA_DEVICE_API_VERSION_1_0;
    cam_dev->common.module = (hw_module_t*)module;
    cam_dev->common.close = camera_device_close;
    cam_dev->ops = ops;

    // 4. 初始化硬件接口(此处以模拟寄存器基址为例,实际项目替换为真实硬件访问)
    //    真实场景:映射寄存器地址、配置 I2C/CSI 引脚、上电时序等
    cam_dev->priv = NULL;  // 私有数据指针,可存放硬件上下文
    ALOGI("camera device opened, id=%s", id);

    *device = &cam_dev->common;
    return 0;
}

// HAL 模块方法表(导出符号)
static hw_module_methods_t camera_module_methods = {
    .open = camera_device_open,
};

// 模块实例(实际项目中由 hw_get_module 按名称加载)
struct camera_module HAL_MODULE_INFO_SYM = {
    .common = {
        .tag           = HARDWARE_MODULE_TAG,
        .module_api_version = CAMERA_MODULE_API_VERSION_1_0,
        .hal_api_version   = HARDWARE_HAL_API_VERSION,
        .id            = CAMERA_HARDWARE_MODULE_ID,
        .name          = "Camera HAL Module",
        .author        = "CodeCase",
        .methods       = &camera_module_methods,
    },
};

关键实现说明

上述代码完成了 open 回调的完整链路:camera_device_open 接收上层传入的 module、设备 id 和输出参数 device。函数内部依次完成三件事:分配 camera_device_t 结构体内存;分配并填充 camera_device_ops_t 操作集(当前注册 close 回调);初始化公共 hw_device_t 字段(tag、version、module 指针、close 函数指针)。最后将 cam_dev->common 的地址写入 *device 返回给调用者。

硬件接口初始化在代码中以 priv 字段预留位置,并注释标明真实场景需要完成的寄存器映射、引脚配置等操作。这是刻意的最小化设计——本案例聚焦于 HAL 设备对象的创建与返回路径,不展开具体传感器驱动细节。

编译与验证

# 编译(假设 Android 源码环境已就绪)
mmm hardware/libhardware/modules/camera/

# 或直接编译当前目录
mm -j8

验证方法:在 Android 系统启动后,通过 adb shell 执行以下命令触发 HAL 模块加载与设备打开:

# 查看 HAL 模块是否被系统识别
adb shell ls /system/lib/hw/camera.*.so

# 使用 v4l2 或 CameraService 日志确认 open 被调用
adb logcat -s CameraHAL

判定标准:logcat 中出现 camera device opened 日志,且无 invalid argument 或 failed to alloc 报错,说明 open 函数成功创建了设备实例并返回了有效的 camera_device_t 指针。若上层继续调用 close,应看到 camera device closed and freed 日志,表明资源释放路径正常。