HAL 层简介

简介:

HAL层又称硬件抽象层,HAL层在Android体系中有着深远的意义,因为Android究竟是完
全开源还是完全不开源的秘密就在这一层·Google将硬件厂商的驱动程序放在这一层,正是因为
这一层的代码没有开源,所以Android被Linux家族删除.本章将详细介绍HAL层的基本知识,
为本书后面的驱动开发和移植打下坚实的基础
 

1、认识 HAL 层

HAL层(硬件抽象层)是位于操作系统内核与硬件电路之间的接口层,其目的在于将硬件抽象
化。它隐藏了特定平台的硬件接口细节,为操作系统提供虚拟硬件平台,使其具有硬件无关性,这样就可以在多种平台上进行移植。从软、硬件测试的角度来看,软、硬件的测试工作都可分别基于硬件抽象层来完成,从此亻吏软、硬件测试工作的并行进行成为可能。HAL层的位置结构如冬6-1所示。

由图6-1可知,HAL的目的是为了把Android Framework(Android框架)与Linux Kernel(Linux
内核)隔离。让Android不至过度依赖Linux Kemel,从而让Android Framework的开发可在不
考虑驱动程序的前提下进行。HAL层主要包含GPS、Vibrator、Wi-Fi、Copybit、Audio、Camera、Lights、RiI、Overlay等模块。
 

1.1.1 HAL 层的发展

硬件抽象层大概分为一下 6种HAL:

  • 上层软件
  • 虚拟驱动,设置管理模块
  • 内部通信Server
  • 内部以太网
  • 内部通信Client
  • 用户接入口

定义硬件抽象层接口的代码具有一下5个特点:

  • 硬件抽象层具有与硬件的密切相关性
  • 硬件抽象层具有与操作系统无关性
  • 接口定义的功能应该包含硬件或者系统所需硬件支持的所有功能
  • 接口简单明了,太多接口函数会增加软件模拟的复杂性
  • 具有可预测的接口设计有利于系统的软、硬件测试和集成。

在Android 源码中,HAL 主要被保存在下面的目录中:

  • libhardware_legacy :过去的目录,采取链接库模块观念来架构
  • libhardware: 新版的目录,被调整为用HAL stub 观念来架构
  • ril: 是Radio 接口层
  • msm7k : 和QUAL 平台相关的信息

接下来将对目前HAL的现况做一个简单的分析。目前,Android的HAL层仍旧散布在不同
的地方,如分为camera、Wi-Fi等,因此上述的目录并不包含所有的HAL程序代码。成熟前的
HAL架构如图6.2所示,现在的HAL架构如图6.3所示。
 

从现在HAL层的结构可以看出,当前的HAL stub模式是一种代理人(Proxy)的概念,虽然
stub仍以 *.so 档的形式存在,但是HAL己经将 *.so 档隐藏了。Stub向HAL提供了功能强大的操作
函数(Operations),而 runtime 则从 HAL获取特定模块(Stub)的函数,然后再回调这些操作函
数。这种以 lndirect Function CAII 模式的架构,让 HAL stub 变成了一种“包含”关系,也就是说,
在 HAL 中包含了许多 Stub(代理人)。Runtime只要说明moduleID(类型),就可以取得操作函数。
在当前的HAL模式中,Android定义了HAL层结构框架,这样,通过接口访问硬件时就形成了统
一的调用方式。

1.1.2 过去和现在的区别

为了使读者明白过去结构和现在结构的差别,接下来对HALlegacy和HAL做一个对比。

  • HAL_legacy:这是过去HAL的模块,采用共享库形式,在编译时会调用到。由于采用functroncall形式调用,因此可被多个进程使用,但会被mapping到多个进程窄间中,造成浪费,同时需要考虑代码能否安全重入的问题(ThreadSafe)。
  • HAL:这是新式的HAL,采用了HALmodule和HAL stub 结合形式。HALstub不是一个共
    享库,在编译时上层只拥有访问HALstub的函数指针,并不需要HAL stub-在上层通过HAL
    module提供的统一接口获取并操作HAL stub,所以,文件只会被映射到一个进程,而不会存
    在重复映射和重入问题。

2.2 分析HAL 层源码

通过上节的学习,了解了Android中为了给用户提供统一的硬件接口和硬件形态,在Linux
Kemel和用户空间之间提供了一个HAL层,即硬件抽象层。这使得 Android 中的Framework只需要
关心HAL中的内容,而不用关心具体的硬件实现。本节将简单分析HAL层的代码,当然不是具体
驱动的代码,而是HAL层中的各个接口的代码。

2.2.1 分析 HAL moudle 

在 HAL moudle 中主要分为如下3个结构:

  • struct hw_module
  • struct hw_modulemethods_t
  • struct hw_device_t

上述 3 个结构的集成关系 如图 6-4 所示

上述3个抽象概念在文件hardware.c中进行了详细述。HAL模块的源代码保存在harware目
录中,对于不同的 hardware 的HAL,其对应的lib命名规则是id.variant.so,比如gralloc.msm7k.so,
表示其id是gralloc,msm7k是vanant。variant的取值范围是在该文件中的定义的vanant_keys对应
的值。
 

接下来分析 hardware.c 源码。

(1)函数hw_get_module()。此函数根据模块ID寻找硬件模块动态链接库的地址,然后调用load去打开动态链接库并从中获取硬件模块结构体地址。执行后首先得到的是根据固定的符号
HAL_MODULE_INFO_SYM寻找到 hw_module_t 结构体,然后在hw_moule_t中hw_module_methods_t 结构体成员函数提供的open结构打开相应的模块,并进行初始化。因为用户在调用 open() 时通常都会传 入一个指向 hw_device_t 指针的指针。这样,函数 open() 就将对模块的操作函数结构保存到hw_device_t 结构体中,用户通过它可以和模块进行交互。

函数hw_get_module() 的具体实现代码如下:

代码 /hardware/libhardware/hardware.c

int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{``````

   (1) 通过配置变量 循环寻找一个模块

   /* Loop through the configuration variants looking for a module */
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {

·······

(2)数组variant_keys 在上述函数中,需要用到数组variant_keys,因为HAL_VARIANT_KEYS_COUNT就是数组variant_keys的大小。定义此数组的代码如下:

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"
};
 

然后通过此数组,并使用如下代码获取操作权限:

        if (property_get(variant_keys[i], prop, NULL) == 0) {
            continue;
        }
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

在此,variant_keys[il对应有3个值,分别是trout、msm7k和ARMV6,
 

(3) 将路径和文件名保存到 path , 接下来将通过如下代码将路径和文件保存在path 中:

    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH1, name, subname);

通过上述代码,把 HAL_LIBRARY_PATH/id.***.so 保存到 path 中,其中 ****  就是上面 variant_keys 中各个元素的值。

(4) 载入相应的库,并把他们的 HMI 不保存到 module 中,具体代码如下

    /* Nothing found, try the default */
    if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
        goto found;
    }

    return -ENOENT;

found:
    /* load the module, if this fails, we're doomed, and we should not try
     * to load a different variant. */
    return load(class_id, path, module);

(5)打开相应的库并获得 hw_module_t 结构体,具体代码如下:

static int load(const char *id,
        const char *path,
        const struct hw_module_t **pHmi)
{
    int status = -EINVAL;
    void *handle = NULL;
    struct hw_module_t *hmi = NULL;
#ifdef __ANDROID_VNDK__
    const bool try_system = false;
#else
    const bool try_system = true;
#endif

    /*
     * 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
     */
    if (try_system &&
        strncmp(path, HAL_LIBRARY_PATH1, strlen(HAL_LIBRARY_PATH1)) == 0) {
        /* If the library is in system partition, no need to check
         * sphal namespace. Open it with dlopen.
         */
        handle = dlopen(path, RTLD_NOW);
    } else {
#if defined(__ANDROID_RECOVERY__)
        handle = dlopen(path, RTLD_NOW);
#else
        handle = android_load_sphal_library(path, RTLD_NOW);
#endif
    }
    if (handle == NULL) {
        char const *err_str = dlerror();
        ALOGE("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) {
        ALOGE("load: couldn't find symbol %s", sym);
        status = -EINVAL;
        goto done;
    }

    /* Check that the id matches */
    if (strcmp(id, hmi->id) != 0) {
        ALOGE("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 {
        ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
                id, path, hmi, handle);
    }

    *pHmi = hmi;

    return status;
}

2.2.2  分析mokoid 工具

mokoid 工程中提供了一个LedTest示例程序,此示例是我国台湾Jollen的培训教程。了解这个
工程源码,对于理解Android层次结构、HAL编程方法都非常有意义。此工程文件码可以从网络
中获取,在Linux中的下载命令如下;
 

# svn checkout  http://mokoid.googlecode.com/svn/trunk/mokoid-read-only

下载 mokoid 工程之后,目录结构如图6-5所示,

需要通过 JNI 来实现 Android 的HAL, JNI 是Java 程序可以调用C/C++ 写的动态链接库,所以HALkeyi shiyong C/C++语言编写,这样效率更高。在Android 下有以下两种访问HAL 的方式:

  • Android 的app 直接通过 service 调用.so 格式的JNI : 此方法比较简单高效,但是不正规。
  • 经过 Manager 调用 Service : 此方法实现起来比较复杂,但是更符合目前的Android 框架。在此方法中,在进程 LegManager 和 LedService (Java) 中需要通过进程通信的方式实现通信。

在 mokoid 工程中分别实现上述两种方法,下面将详细介绍这两种方法实现原理:

1.直接调用 Service 方法的实现代码

(1)HAL 层的实现代码

文件 hardware/modules/led/led.c 的实现代码如下:

#define LOG_TAG "MokoidLedStub"

#include <hardware/hardware.h>

#include <fcntl.h>
#include <errno.h>

#include <cutils/log.h>
#include <cutils/atomic.h>

#include <mokoid/led.h>

/*****************************************************************************/

int led_device_close(struct hw_device_t* device)
{
    struct led_control_device_t* ctx = (struct led_control_device_t*)device;
    if (ctx) {
        free(ctx);
    }
    return 0;
}

int led_on(struct led_control_device_t *dev, int32_t led)
{
    LOGI("LED Stub: set %d on.", led);

    return 0;
}

int led_off(struct led_control_device_t *dev, int32_t led)
{
    LOGI("LED Stub: set %d off.", led);

    return 0;
}

static int led_device_open(const struct hw_module_t* module, const char* name,
        struct hw_device_t** device) 
{
    struct led_control_device_t *dev;

    dev = (struct led_control_device_t *)malloc(sizeof(*dev));
    memset(dev, 0, sizeof(*dev));

    dev->common.tag =  HARDWARE_DEVICE_TAG;
    dev->common.version = 0;
    dev->common.module = module;
    dev->common.close = led_device_close;

    dev->set_on = led_on;      //  实例化支持的操作
    dev->set_off = led_off;

    *device = &dev->common;      //  将实例化的 led_control_device_t 地址返回给 Jni 层

success:
    return 0;
}

static struct hw_module_methods_t led_module_methods = {
    open: led_device_open
};

const struct led_module_t HAL_MODULE_INFO_SYM = {
    common: {
        tag: HARDWARE_MODULE_TAG,
        version_major: 1,
        version_minor: 0,
        id: LED_HARDWARE_MODULE_ID,
        name: "Sample LED Stub",
        author: "The Mokoid Open Source Project",
        methods: &led_module_methods,
    }
    /* supporting APIs go here */
};
 

(2) JNI 层的实例代码

文件 frameworks/base/service/jni/com_mokoid_server_LedService.cpp 的实现代码如下:

#define LOG_TAG "MokoidPlatform"
#include "utils/Log.h"

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>

#include <jni.h>
#include <mokoid/led.h>

// ----------------------------------------------------------------------------

struct led_control_device_t *sLedDevice = NULL;

static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led) {

    LOGI("LedService JNI: mokoid_setOn() is invoked.");

    if (sLedDevice == NULL) {
        LOGI("LedService JNI: sLedDevice was not fetched correctly.");
        return -1;
    } else {
        return sLedDevice->set_on(sLedDevice, led);  //  调用 HAL 层的注册方法
    }
}

static jboolean mokoid_setOff(JNIEnv* env, jobject thiz, jint led) {

    LOGI("LedService JNI: mokoid_setOff() is invoked.");

    if (sLedDevice == NULL) {
        LOGI("LedService JNI: sLedDevice was not fetched correctly.");
        return -1;
    } else {
        return sLedDevice->set_on(sLedDevice, led);    // 调用 HAL 层的注册方法
    }
}

/** helper APIs */

// JNI 通过 LED_HARDSOFTWARE_MODULE_ID 找到对应的stub 
static inline int led_control_open(const struct hw_module_t* module,
        struct led_control_device_t** device) {
    return module->methods->open(module,
            LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
}

static jboolean
mokoid_init(JNIEnv *env, jclass clazz)
{
    led_module_t* module;

    if (hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) {
        LOGI("LedService JNI: LED Stub found.");
        if (led_control_open(&module->common, &sLedDevice) == 0) {
            LOGI("LedService JNI: Got Stub operations.");
            return 0;
        }
    }

    LOGE("LedService JNI: Get Stub operations failed.");
    return -1;
}

// ----------------------------------------------------------------------------

/*
 * Array of methods.
 *
 * Each entry has three fields: the name of the method, the method
 * signature, and a pointer to the native implementation.

* JNI NativeMethod 是java 层的注册方法
 */
static const JNINativeMethod gMethods[] = {
    {"_init",          "()Z",                 //  Framwork 层调用 _init 时触发 
            (void*)mokoid_init},
    { "_set_on",          "(I)Z",
                        (void*)mokoid_setOn },
    { "_set_off",          "(I)Z",
                        (void*)mokoid_setOff },
};

static int registerMethods(JNIEnv* env) {
    static const char* const kClassName =
        "com/mokoid/server/LedService";
    jclass clazz;

    /* look up the class */
    clazz = env->FindClass(kClassName);
    if (clazz == NULL) {
        LOGE("Can't find class %s\n", kClassName);
        return -1;
    }

    /* register all the methods */
    if (env->RegisterNatives(clazz, gMethods,
            sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)
    {
        LOGE("Failed registering methods for %s\n", kClassName);
        return -1;
    }

    /* fill out the rest of the ID cache */
    return 0;
}

// ----------------------------------------------------------------------------

/*
 * This is called by the VM when the shared library is first loaded.
 */
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("ERROR: GetEnv failed\n");
        goto bail;
    }
    assert(env != NULL);

    if (registerMethods(env) != 0) {
        LOGE("ERROR: PlatformLibrary native registration failed\n");
        goto bail;
    }

    /* success -- return valid version number */
    result = JNI_VERSION_1_4;

bail:
    return result;
}
 

(3) Service 的实现代码

这里的service 属于 Framwork 层,文件 framworks/base/service/java/com/mokoid/server/LedService.java 的实现代码:

package com.mokoid.server;

import android.util.Config;
import android.util.Log;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.IBinder;
import mokoid.hardware.ILedService;

public final class LedService extends ILedService.Stub {    

    static {
        System.load("/system/lib/libmokoid_runtime.so");
    }

    public LedService() {
        Log.i("LedService", "Go to get LED Stub...");
    _init();
    }

    /*
     * Mokoid LED native methods.
     */
    public boolean setOn(int led) {
        Log.i("MokoidPlatform", "LED On");
    return _set_on(led);
    }

    public boolean setOff(int led) {
        Log.i("MokoidPlatform", "LED Off");
    return _set_off(led);
    }

    private static native boolean _init();
    private static native boolean _set_on(int led);
    private static native boolean _set_off(int led);
}
 

(4) App 测试程序的实现代码

这里的测试程序属于 APP 层,文件 apps/LedClient/src/com/mokoid/LedClient/LedClient.java 的实现代码如下:

package com.mokoid.LedClient;
import com.mokoid.server.LedService;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class LedClient extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Call an API on the library.
    LedService ls = new LedService();
    ls.setOn(1);
        
        TextView tv = new TextView(this);
        tv.setText("LED 0 is on.");
        setContentView(tv);
    }
}

2、通过 manager 调用 Service 的实现代码

(1) Manager 的实现代码

APP 通过 此 Manager 和 Service 实现通信功能,文件 framwork/base/core/java/mokoid/hardware/Ledmanager.java

package mokoid.hardware;

import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
import android.util.Log;
import mokoid.hardware.ILedService;

/**
 * Class that lets you access the Mokoid LedService.
 */
public class LedManager
{
    private static final String TAG = "LedManager";
    private ILedService mLedService;

    public LedManager() {
    
        mLedService = ILedService.Stub.asInterface(
                             ServiceManager.getService("led"));

    if (mLedService != null) {
            Log.i(TAG, "The LedManager object is ready.");
    }
    }

    public boolean LedOn(int n) {
        boolean result = false;

        try {
            result = mLedService.setOn(n);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in LedManager.LedOn:", e);
        }
        return result;
    }

    public boolean LedOff(int n) {
        boolean result = false;

        try {
            result = mLedService.setOff(n);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in LedManager.LedOff:", e);
        }
        return result;
    }
}
 

因为 LedService 和 Ledmanager 分别不属于不同的进程,所以在此需要考虑不同进程间的通信问题,此时,在 manager 中可以增加一个aidl 文件来描述通信接口,文件 

framworks/base/core/java/mokoid/hardware/ILedService.aidl 的代码实现如下:

package mokoid.hardware;

interface ILedService
{
    boolean setOn(int led);
    boolean setOff(int led);
}

(2) SystemService 的实现代码

此处的 SystemServer 属于 App 层,文件 apps /LedTest/src/com/mokoid/LedTest/Ledsystem/Server.java 的代码如下:

package com.mokoid.LedTest;

import com.mokoid.server.LedService;

import android.os.IBinder;
import android.os.ServiceManager;
import android.util.Log;
import android.app.Service;
import android.content.Context;
import android.content.Intent;

public class LedSystemServer extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    public void onStart(Intent intent, int startId) {
        Log.i("LedSystemServer", "Start LedService...");

    /* Please also see SystemServer.java for your interests. */
    LedService ls = new LedService();

        try {
            ServiceManager.addService("led", ls);
        } catch (RuntimeException e) {
            Log.e("LedSystemServer", "Start LedService failed.");
        }
    }
}
 

3.App 测试程序

这里的app测试程序属于APP 层,文件 mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedTest.java 的实现代码如下:

package com.mokoid.LedTest;
import mokoid.hardware.LedManager;
import com.mokoid.server.LedService;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Button;
import android.content.Intent;
import android.view.View;

public class LedTest extends Activity implements View.OnClickListener {
    private LedManager mLedManager = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Start LedService in a seperated process.
        startService(new Intent("com.mokoid.systemserver"));

    // Just for testing. !! PLEASE DON't DO THIS !!
    //LedService ls = new LedService();

        Button btn = new Button(this);
        btn.setText("Click to turn LED 1 On");
    btn.setOnClickListener(this);

        setContentView(btn);
    }

    public void onClick(View v) {

        // Get LedManager.
        if (mLedManager == null) {
        Log.i("LedTest", "Creat a new LedManager object.");
        mLedManager = new LedManager();
        }

        if (mLedManager != null) {
        Log.i("LedTest", "Got LedManager object.");
    }

        /** Call methods in LedService via proxy object 
         * which is provided by LedManager. 
         */
        mLedManager.LedOn(1);

        TextView tv = new TextView(this);
        tv.setText("LED 1 is On.");
        setContentView(tv);
    }
}
 

4、使用HAL 的方法 总结

(1)Native code 通过hw_get_module 调用获取 HAL stub.

hw_get_module (LED_HARDWARE_MODULE_ID,(const hw_module_t** )&module)

(2) 通过继承 hw_module_methods_t 的 callback 拉打开设备。

module->methods->open(module,LED_HARDWARE_MODULE_ID,(struct hw_device_t**)device);

(3) 通过继承 hw_device_t 的callback (回访) 来控制设备

sLedDevice -> set_on(sLedDevice,led);

sLedDevice-> set_off(sLedDevice,led);

4.1. 编写 HAL stub 的方法

编写HAL stub 的基本流程入下图所示。

1)自定义 HAL 结构体,编写 头文件 led.h 和 hardware/hardware.h 主要代码如下:

struct ledmodulet {

        struct hw_module_t common;

}

struct led_control_device_t {

        struct hw_device_t common;

        int  fd ;  // 文件描述符 的 LED 装置

        int (*set_on) (struct led_control_device_t *dev, int32_t led);   // 支持控制的 api

        int (*set_off) (struct led_control_device_t *dev,int32_t led);

}

(2) 编写 文件 led.c 实现 HAL stub 注册功能

(3)设置 led_module_methods 继承于 hw_module_methods_t,并实现对 open() 方法的回访,

struct hw_module_methods_t led_module_methods = {

        open : led_device_open

};

(4) 使用 HAL_MODULE_INFO_SYM 实例,led_module_t, 注意 这个名称不可修改,

const struct led_module_t HAL_MODULE_INFO_SYM = {

        common : {

        tag : HARDWARE_MODULE_TAG,

        version_major:1,

        version_minor:0,

        id:LED_HARDWARE_MODULE_ID,

        name:"Sample LED Stub",

        author: "The Mokoid Open Source Project",

        methods: &led_module_methods,

        }

// 支持 api 

};

(5) open() 是一个必须实现的回调 API ,用于负责 申请 结构体空间并填充信息,还可以注册具体操作API 接口, 并打开 Linux 驱动。但是系因为存在多重继承关系,所以只需要对结构体hw_device_t 对象申请空间即可。

static int led_device_open(const struct hw_module_t* module, const char* name,
        struct hw_device_t** device) 
{
    struct led_control_device_t *dev;

    dev = (struct led_control_device_t *)malloc(sizeof(*dev));
    memset(dev, 0, sizeof(*dev));

    dev->common.tag =  HARDWARE_DEVICE_TAG;
    dev->common.version = 0;
    dev->common.module = module;
    dev->common.close = led_device_close;

    dev->set_on = led_on;
    dev->set_off = led_off;

    *device = &dev->common;

        // 初始化硬件接口

      dev->fd = open(LED_DEVICE,o_RDONLY);

       if (dev->fd < 0 ) {

                return -1;        

        }

        led_off(dev,LED_C608);

        led_off(dev,LED_C609);

success:
    return 0;
}

(6) 填充具体 API 操作,具体代码如下:

int led_on (struct led_control_device_t *dev,int32_t led) {

        int fd;

        LOGI("LED Stub: set %d on.",led);

        fd = dev->fd;

        switch(led) {

                case LED_C608:

                        ioctl(fd,1,&led);

                        break;

                case LED_C609:

                          ioctl(fd,1,&led)

                        break;

                default:

                           return -1;

        }

return 0;

}

int led_off (struct led_control_device_t *dev,int32_t led) {

        int fd;

        LOGI("LED Stub : set %d off.",led);

        fd = dev-> fd;

        switch(led) {

                case LED_C608:

                        ioctl(fd,2,&led);

                        break;

                  case LED_C609:

                        ioctl(fd,2,&led);

                        break;

                default:

                        return -1;

        }

        return  0;

}

文章摘自:

《Android 底层接口和驱动开发技术详解》

相关资料下载跳转

版权声明:本文为CSDN博主「放大的EZ」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_27061049/article/details/122481220

生成海报
点赞 0

放大的EZ

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

ESP32S2+ES8388移植过程及问题

电路图如下, 有点小瑕疵ES8388_VMID PIN10/19/20电容没有忘加,查资料应该不影响语言输出,可能噪音大,如果能导致不输出请告诉我一下。 ESP32S2管脚映射 这里主

STM32F4最小系统硬件设计

对于硬件工程师来讲,想要入门STM32相关的开发,我想除了深入阅读一下STM32的数据手册外,最实用且有效的方法就是自己实际做一个STM32的最小系统板了。本文将以一个小的STM32F427VG的电路最