精华内容
下载资源
问答
  • HelloWorld 程序编写及编入内核驱动, 创建一个 hello驱动,在开机的时候加载,并打印"Hello world",相关简介: 1,增加驱动文件 hello.c 和对应的 Makefile、Kconfig 2,修改上一级的 Makefile 与 Kconfig 3,...
  • Android架构实例分析之编写hello驱动的HAL层代码 摘要: HAL层中文名称又叫硬件抽象层,可以理解我Linux驱动的应用层。本文实现了一个简单的hello HAL的代码,衔接hello驱动和hello JNI: ... Android标准架构实例...

    Android架构实例分析之编写hello驱动的HAL层代码

    摘要:

    HAL层中文名称又叫硬件抽象层,可以理解我Linux驱动的应用层。本文实现了一个简单的hello HAL的代码,衔接hello驱动和hello JNI:

    http://blog.csdn.net/eliot_shao/article/details/51860229

    Android标准架构实例分析之编写最简单的hello驱动

    HAL层的代码会使用open read write等系统调用操作驱动层的文件系统(dev、sysfs、proc),同时它也有自己的数据结构,为上层提供接口,并导出和本体模块相关ID号。上层可以使用hw_get_module获得HAL中写的方法。其实如果不是为了避开Linux的GPL开源协议,HAL层可以不用,直接使用JNI层或者在Java代码中访问操作驱动层的文件系统(dev、sysfs、proc)也是可行的。 
    详细原理可以参考:

    http://blog.csdn.net/eliot_shao/article/details/50461738

    HAL代码编写的基本步骤

    1、编写HAL层头文件

    2、填充相关的结构体

    1、编写HAL层头文件

    首先我们要知道关于HAL的三点要求:

    1、 每一个hardware硬件模块都有一个ID;

    2、 每一个hardware模块必须有一个继承struct hw_module_t common;的结构体;

    3、 每一个hardware模块必须有一个继承struct hw_device_t common;的结构体;

    struct hw_module_t的继承者担负了“联络员”的任务,在/system/lib/hw下面有若干hardware module,本地框架层通过ID找到对应的模块。

    struct hw_device_t的继承者承担了对驱动操作方法的包装的任务。 
    struct hw_module_t和struct hw_device_t的内容定义在:

    hardware\libhardware\include\hardware\hardware.h

    所以我们的hello.h内容如下:

    #ifndef ANDROID_HELLO_INTERFACE_H
    #define ANDROID_HELLO_INTERFACE_H
    #include <hardware/hardware.h>
    
    __BEGIN_DECLS
    #define HELLO_HARDWARE_MODULE_ID "hello"//ID
    struct hello_module_t {
        struct hw_module_t common;
    };//hw_module_t的继承者
    struct hello_device_t {
        struct hw_device_t common;
        int fd;
        int (*set_val)(struct hello_device_t* dev, int val);
        int (*get_val)(struct hello_device_t* dev, int* val);
    };//hw_device_t的继承者
    __END_DECLS
    
    #endif
    

    2、填充相关的结构体

    我们总结一下硬件具体的调用流程,也是hardware层的工作流程:

    1、 通过ID找到硬件模块,struct hw_module_t common的结构体的继承者;

    2、 通过硬件模块找到hw_module_methods_t,打开操作,获得设备的hw_device_t;

    3、 调用hw_device_t中的各种操作硬件的方法;

    4、 调用完成,通过hw_device_t的close关闭设备。

    HAL规定了需要创一个名为HAL_MODULE_INFO_SYM结构体,如下:

    struct hello_module_t HAL_MODULE_INFO_SYM = {
        .common = {
            .tag= HARDWARE_MODULE_TAG,
            //.module_api_version = FINGERPRINT_MODULE_API_VERSION_2_0,
            .hal_api_version= HARDWARE_HAL_API_VERSION,
            .id = HELLO_HARDWARE_MODULE_ID,
            .name   = "Demo shaomingliang hello HAL",
            .author = "The Android Open Source Project",
            .methods= &hello_module_methods,
        },
    };
    

    填充struct hw_module_t common 并对其成员 methods进行赋值:

    .methods= &hello_module_methods,
    

    hello_module_methods的定义如下:

    static struct hw_module_methods_t hello_module_methods = {
        .open = hello_device_open,
    };
    

    在 hello_device_open 对 struct hello_device_t 进行填充。

    下面是抽象层hello.c的详细代码:

    #define LOG_TAG "HelloStub"
    #include <hardware/hardware.h>
    #include <hardware/hello.h>
    
    #include <sys/mman.h>
    
    #include <dlfcn.h>
    
    #include <cutils/ashmem.h>
    #include <cutils/log.h>
    
    #include <fcntl.h>
    #include <errno.h>
    #include <sys/ioctl.h>
    #include <string.h>
    #include <stdlib.h>
    
    #include <cutils/log.h>
    #include <cutils/atomic.h>
    
    #define MODULE_NAME "Hello"
    char const * const device_name = "/dev/hello" ;
    static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);
    static int hello_device_close(struct hw_device_t* device);
    static int hello_set_val(struct hello_device_t* dev, int val);
    static int hello_get_val(struct hello_device_t* dev, int* val);
    
    static struct hw_module_methods_t hello_module_methods = {
        .open = hello_device_open,
    };
    static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device)
    {
        struct hello_device_t* dev;
        char name_[64];
        //pthread_mutex_t lock;
        dev = (struct hello_device_t*)malloc(sizeof(struct hello_device_t));
        if(!dev) {
            ALOGE("Hello Stub: failed to alloc space");
            return -EFAULT;
        }
        ALOGE("Hello Stub: hello_device_open eliot_shao");
        memset(dev, 0, sizeof(struct hello_device_t));
    
        dev->common.tag = HARDWARE_DEVICE_TAG;
        dev->common.version = 0;
        dev->common.module = (hw_module_t*)module;
        dev->common.close = hello_device_close;
        dev->set_val = hello_set_val;
        dev->get_val = hello_get_val;
    
        //pthread_mutex_lock(&lock);
        dev->fd = -1 ;
        snprintf(name_, 64, device_name, 0);
        dev->fd = open(name_, O_RDWR);
        if(dev->fd == -1) {
            ALOGE("Hello Stub:eliot failed to open %s !-- %s.", name_,strerror(errno));
            free(dev);
            return -EFAULT;
        }
        //pthread_mutex_unlock(&lock);
        *device = &(dev->common);
        ALOGI("Hello Stub: open HAL hello successfully.");
        return 0;
    }
    
    static int hello_device_close(struct hw_device_t* device) {
        struct hello_device_t* hello_device = (struct hello_device_t*)device;
        if(hello_device) {
            close(hello_device->fd);
            free(hello_device);
        }
        return 0;
    }
    static int hello_set_val(struct hello_device_t* dev, int val) {
        ALOGI("Hello Stub: set value to device.");
        write(dev->fd, &val, sizeof(val));
        return 0;
    }
    static int hello_get_val(struct hello_device_t* dev, int* val) {
        if(!val) {
            ALOGE("Hello Stub: error val pointer");
            return -EFAULT;
        }
        read(dev->fd, val, sizeof(*val));
        ALOGI("Hello Stub: get value  from device");
        return 0;
    }
    
    struct hello_module_t HAL_MODULE_INFO_SYM = {
        .common = {
            .tag                = HARDWARE_MODULE_TAG,
            //.module_api_version = FINGERPRINT_MODULE_API_VERSION_2_0,
            .hal_api_version    = HARDWARE_HAL_API_VERSION,
            .id                 = HELLO_HARDWARE_MODULE_ID,
            .name               = "Demo shaomingliang hello HAL",
            .author             = "The Android Open Source Project",
            .methods            = &hello_module_methods,
        },
    };

    Android.mk 的详细代码如下:

    
    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := hello.default
    LOCAL_MODULE_RELATIVE_PATH := hw
    LOCAL_SRC_FILES := hello.c
    LOCAL_SHARED_LIBRARIES := liblog
    LOCAL_MODULE_TAGS := optional
    
    include $(BUILD_SHARED_LIBRARY)
    
    

    hello HAL代码的编译

    将hal的代码放到如下位置:

    hardware\libhardware\modules\hello\hello.c 
    hardware\libhardware\modules\hello\Android.mk 
    hardware\libhardware\include\hardware\hello.h

    执行:mmm hardware\libhardware\modules\hello\

    将会在system/lib/hw/下生成一个hello.default.so!

    Android架构实例分析之注册hello HAL的JNI方法表

    摘要:

    Android JNI是一种技术,提供Java调用Android native代码或者native调用Java代码的一种机制,并不提供策略。本文实现了基于前面两篇文章:

    Android标准架构实例分析之编写最简单的hello驱动 
    http://blog.csdn.net/eliot_shao/article/details/51860229

    Android架构实例分析之编写hello驱动的HAL层代码 
    http://blog.csdn.net/eliot_shao/article/details/51861905

    所实现的JNI案例。对HAL层提供的方法进行“翻译”,并转化成android runtime的JNI方法表,当Java代码调用时候可以正确的寻找到native的代码。

    JNI原理分析

    首先上一张Android JNI技术的工作原理图:

    这里写图片描述

    在图中主要描述Java-jni-native的一个调用流程。下面进行按步骤讲解: 
    1、Java代码通过System.loadLibrary(“android_servers”); 加载JNI静态库; 
    2、Android runtime自动调用JNI静态库中的JNI_OnLoad函数; 
    3、JNI_OnLoad调用jniRegisterNativeMethods函数,注册多个或者一个JNINativeMethod到Android runtime的gMthods链表中; 
    4、Java代码声明并调用相关的native代码; 
    5、Android runtime查找gMthods链表找到前面注册的本地函数指针,然后执行。

    注意:JNI和HAL的衔接是通过JNI的代码

    hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) 
    

    实现的。

    本文使用的hello的案例是以system_server进程上建立的,后面会创建一个hello的本地服务。下面是对system_server进程调用JNI过程进行分析。

    1、frameworks\base\services\java\com\android\server\SystemServer.java

        // Initialize native services.
        System.loadLibrary("android_servers");
    

    2、frameworks\base\services\core\jni\onload.cpp

    jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
    register_android_server_HelloService(env);//add by eliot_shao
    

    3、frameworks\base\services\core\jni\com_android_server_HelloService.cpp

    jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));
    static const JNINativeMethod method_table[] = {
            {"init_native", "()Z", (void*)hello_init},
            {"setVal_native", "(I)V", (void*)hello_setVal},
            {"getVal_native", "()I", (void*)hello_getVal},
        };
    

    4、frameworks\base\services\Android.mk

    LOCAL_MODULE:= libandroid_servers
    
    • 1
    • 2

    hello JNI实例

    rameworks\base\services\core\jni\com_android_server_HelloService.cpp

    #define LOG_TAG "HelloService"
    #include "jni.h"
    #include "JNIHelp.h"
    #include "android_runtime/AndroidRuntime.h"
    #include <utils/misc.h>
    #include <utils/Log.h>
    #include <hardware/hardware.h>
    #include <hardware/hello.h>
    #include <stdio.h>
    namespace android
    {
        struct hello_device_t* hello_device = NULL;
        static void hello_setVal(JNIEnv* env, jobject clazz, jint value) {
            int val = value;
            ALOGI("Hello JNI: set value %d to device.", val);
            if(!hello_device) {
                ALOGI("Hello JNI: device is not open.");
                return;
            }
            hello_device->set_val(hello_device, val);
        }
        static jint hello_getVal(JNIEnv* env, jobject clazz) {
            int val = 0;
            if(!hello_device) {
                ALOGI("Hello JNI: device is not open.");
                return val;
            }
            hello_device->get_val(hello_device, &val);
    
            ALOGI("Hello JNI: get value %d from device.", val);
    
            return val;
        }
        static inline int hello_device_open(const hw_module_t* module, struct hello_device_t** device) {
            return module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
    
        }
        static jboolean hello_init(JNIEnv* env, jclass clazz) {
            hello_module_t* module;
    
            ALOGI("Hello JNI: initializing......");
            if(hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {
                ALOGI("Hello JNI: hello Stub found.");
                if(hello_device_open(&(module->common), &hello_device) == 0) {
                    ALOGI("Hello JNI: hello device is open.");
                    return 0;
                }
                ALOGE("Hello JNI: failed to open hello device.");
                return -1;
            }
            ALOGE("Hello JNI: failed to get hello stub module.");
            return -1;      
        }
        static const JNINativeMethod method_table[] = {
            {"init_native", "()Z", (void*)hello_init},
            {"setVal_native", "(I)V", (void*)hello_setVal},
            {"getVal_native", "()I", (void*)hello_getVal},
        };
        int register_android_server_HelloService(JNIEnv *env) {
        return jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));
        }   
    };

    frameworks\base\services\core\jni\onload.cpp

    /*
    * Copyright (C) 2014 MediaTek Inc.
    * Modification based on code covered by the mentioned copyright
    * and/or permission notice(s).
    */
    /*
     * Copyright (C) 2009 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 "JNIHelp.h"
    #include "jni.h"
    #include "utils/Log.h"
    #include "utils/misc.h"
    
    namespace android {
    int register_android_server_AlarmManagerService(JNIEnv* env);
    int register_android_server_AssetAtlasService(JNIEnv* env);
    int register_android_server_BatteryStatsService(JNIEnv* env);
    int register_android_server_ConsumerIrService(JNIEnv *env);
    int register_android_server_InputApplicationHandle(JNIEnv* env);
    int register_android_server_InputWindowHandle(JNIEnv* env);
    int register_android_server_InputManager(JNIEnv* env);
    int register_android_server_LightsService(JNIEnv* env);
    int register_android_server_PowerManagerService(JNIEnv* env);
    int register_android_server_SerialService(JNIEnv* env);
    int register_android_server_SystemServer(JNIEnv* env);
    int register_android_server_UsbDeviceManager(JNIEnv* env);
    int register_android_server_UsbMidiDevice(JNIEnv* env);
    int register_android_server_UsbHostManager(JNIEnv* env);
    int register_android_server_VibratorService(JNIEnv* env);
    int register_android_server_location_GpsLocationProvider(JNIEnv* env);
    int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
    int register_android_server_connectivity_Vpn(JNIEnv* env);
    int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
    int register_android_server_tv_TvInputHal(JNIEnv* env);
    int register_android_server_PersistentDataBlockService(JNIEnv* env);
    int register_android_server_Watchdog(JNIEnv* env);
    int register_com_mediatek_perfservice_PerfServiceManager(JNIEnv* env);
    #if defined (MTK_HDMI_SUPPORT)
    int register_com_mediatek_hdmi_MtkHdmiManagerService(JNIEnv* env);
    #endif
    // Mediatek AAL support
    int register_android_server_display_DisplayPowerController(JNIEnv* env);
    #ifndef MTK_BSP_PACKAGE
    int register_com_android_internal_app_ShutdownManager(JNIEnv *env);
    #endif
    
    int register_android_server_HelloService(JNIEnv *env);//add by eliot_shao
    };
    
    using namespace android;
    
    extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
    {
        JNIEnv* env = NULL;
        jint result = -1;
    
        if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
            ALOGE("GetEnv failed!");
            return result;
        }
        ALOG_ASSERT(env, "Could not retrieve the env!");
    
        register_android_server_PowerManagerService(env);
        register_android_server_SerialService(env);
        register_android_server_InputApplicationHandle(env);
        register_android_server_InputWindowHandle(env);
        register_android_server_InputManager(env);
        register_android_server_LightsService(env);
        register_android_server_AlarmManagerService(env);
        register_android_server_UsbDeviceManager(env);
        register_android_server_UsbMidiDevice(env);
        register_android_server_UsbHostManager(env);
        register_android_server_VibratorService(env);
        register_android_server_SystemServer(env);
        register_android_server_location_GpsLocationProvider(env);
        register_android_server_location_FlpHardwareProvider(env);
        register_android_server_connectivity_Vpn(env);
        register_android_server_AssetAtlasService(env);
        register_android_server_ConsumerIrService(env);
        register_android_server_BatteryStatsService(env);
        register_android_server_hdmi_HdmiCecController(env);
        register_android_server_tv_TvInputHal(env);
        register_android_server_PersistentDataBlockService(env);
        register_android_server_Watchdog(env);
        register_com_mediatek_perfservice_PerfServiceManager(env);
    #if defined (MTK_HDMI_SUPPORT)
        register_com_mediatek_hdmi_MtkHdmiManagerService(env);
    #endif
        // Mediatek AAL support
        register_android_server_display_DisplayPowerController(env);
    #ifndef MTK_BSP_PACKAGE
        register_com_android_internal_app_ShutdownManager(env);
    #endif
        register_android_server_HelloService(env);//add by eliot_shao
        return JNI_VERSION_1_4;
    }
    

    编译:

    android 2.3 和android 6.0版本的JNI位置发生了一点变化。 
    将com_android_server_HelloService.cpp放入frameworks\base\services\core\jni\ 
    修改: LOGI–>ALOGI 
    LOGE–>ALOGE 
    修改onload.cpp 和 Android.mk 
    编译:mmm frameworks/base/services/

    生成system/lib/libandroid_servers.so

     

    摘要:

    在上一文中介绍了hello驱动的JNI方法,最终更新在android runtime中的java-native函数表。本文将介绍java的世界中如何通过调用JNI定义的java函数实现hello系统服务进程,为应用程序提供系统服务。

     

    通信代理AIDL

    java的世界,硬件服务一般是运行在一个独立的进程中为各种应用程序提供服务。因此,调用这些硬件服务的应用程序与这些硬件服务之间的通信需要通过代理来进行。

    AIDL (Android Interface DefinitionLanguage) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。

    如何实现

     

    如上图,在system_server中注册很多系统服务,这些系统服务通过servicemanager进程进行管理,如果应用程序(client)需要使用某个服务就通过servicemanager来申请使用。

    基于这种思路我们需要实现hello系统服务可以这样做:

    1、建立aidl通信接口;

    2、在system_server中注册hello_service到servicemanager;

    3、实现hello_service,对应aidl中的接口函数。

    4、client向servicemanager请求hello_service,成功后,调用aidl接口函数,建立client进程和hello_service进程的通信关系。

    注意:关于android L 版本以后需要添加selinux策略,否则第二步向system_server中注册hello_service到servicemanager不成功,会出现:ServiceManager add_service SELinux Permission Denied !详细解决方案请参考:

    http://blog.csdn.net/eliot_shao/article/details/51770558

     

    下面是具体实现流程和测试过程,主要参考罗升阳的hello代码,感谢!。

     

     

    1、建立aidl通信接口;

    aidl 记得在 frameworks/base/Android.mk 加上 core\java\android\os\IHelloService.aidl

    建立frameworks\base\core\java\android\os\IHelloService.aidl

    内容:

     
    1. package android.os;

    2.  
    3. interface IHelloService {

    4. void setVal(int val);

    5. int getVal();

    6. }

     

    2、在system_server中注册hello_service到servicemanager;

    修改frameworks\base\services\java\com\android\server\SystemServer.java

    添加如下代码:

     
    1. //add by eliot start

    2. try {

    3.  
    4. Slog.i(TAG, "Hello Service");

    5.  
    6. ServiceManager.addService("hello", new HelloService());//

    7.  
    8. } catch (Throwable e) {

    9.  
    10. Slog.e(TAG, "Failure starting Hello Service", e);

    11.  
    12. }

    13.  
    14. //add by eliot end

     

    3、实现hello_service

    创建frameworks\base\services\core\java\com\android\server\HelloService.java

    实现内容:

     
    1. package com.android.server;

    2. import android.content.Context;

    3. import android.os.IHelloService;

    4.  
    5.  
    6. public class HelloService extends IHelloService.Stub {

    7. private static final String TAG = "HelloService";

    8.  
    9. HelloService() {

    10. init_native();

    11. }

    12.  
    13. public void setVal(int val) {

    14. setVal_native(val);

    15. }

    16.  
    17. public int getVal() {

    18. return getVal_native();

    19. }

    20.  
    21. private static native boolean init_native();

    22. private static native void setVal_native(int val);

    23. private static native int getVal_native();

    24. };

     

    4、client使用hello_service

     

    在app中使用hello_service的大致流程如下:

     
    1. import android.os.IHelloService;//导入通信接口

    2. //请求hello_service

    3. private IHelloService helloService = null;

    4. helloService = IHelloService.Stub.asInterface(

    5. ServiceManager.getService("hello"));

    6.  
    7. //使用hello_service并显示

    8. int val = helloService.getVal();

    9. String text = String.valueOf(val);

    10. valueText.setText(text);

    
    

    测试

    <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">在第三步后,就可以进行编译测试。</span>

    mmm frameworks/base

    打包下载到机器,使用service list查看是否有hello service:

    展开全文
  • linux下编写hello驱动

    千次阅读 2018-10-29 22:09:35
    新建一个文件hello.c,编写如下代码: #include &lt;linux/init.h&gt; #include &lt;linux/module.h&gt; #include &lt;linux/moduleparam.h&gt; MODULE_LICENSE("Dual BSD/GPL"...

    新建一个文件hello.c,编写如下代码:

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/moduleparam.h>
    
    MODULE_LICENSE("Dual BSD/GPL");
    
    static int hello_init(void)
    {
    	printk(KERN_ALERT"Hello!\n");
    	return 0;
    }
    
    static void hello_exit(void)
    {
    	printk(KERN_ALERT"Goodbye!\n");
    }
    
    module_init(hello_init);
    module_exit(hello_exit);

    新建一个Makefile文件,编写以下内容:

    KERN_DIR = /lib/modules/$(shell uname -r)/build
    
    all:
    	make -C $(KERN_DIR) M=`pwd` modules
    
    clean:
    	make -C $(KERN_DIR) M=$(shell pwd) modules clean
    	rm -rf modules.order
    
    obj-m := hello.o
    

    然后在终端输入:

    $ make (即可在目录下看到生成的驱动模块hello.ko文件)

    $ sudo insmod hello.ko (将模块加载入内核)

    $ sudo rmmod hello (移除指定的内核模块)

    本驱动在x86 上测试的, printk 打印出来的信息会在日志文件里。

    因此,想查看printk打印的内容,还需要输入:

    $ dmesg

    结果:

    [30664.513378] Goodbye!
    [30666.802957] Hello!
     

    下面是对makefile的一些备注:

    1、操作符“”:=" 和 操作符“=”的解释

    ":="操作符实现简单的变量扩展,当右边是变量时,“:=”操作符左边的变量引用右边变量的当前值,它与"="操作符有点区别,“=”操作符实现递归的变量扩展,当右边是变量时,左边变量引用后面的变量,当后边变量值发生变化时,左边变量的值也跟着改变,如:
    #b = 4
    #a = $(b)
    #b = 100
    #最后a的值为100,而
    #b = 4
    #a := $(b)
    #b = 100
    #最后a的值为4
    #其中 = 和 := 的区别在于, := 只能使用前面定义好的变量, = 可以使用后面定义的变量

    2、KERN_DIR = /lib/modules/$(shell uname -r)/build 的解释

    $(shell uname -r):这个shell应该是make里面的一个函数,shell函数把执行操作系统命令后的输出作为函数返回。函数调用很像变量的使用,也是以“$” 来标识的,其语法:$(<function> <arguments> )或是${<function> <arguments>},<function> 是函数名,<arguments> 是函数的参数,参数间以逗号“,” 分隔,而函数名和参数之间以“ 空格” 分隔。

    3、all: 的解释

    all是一个目标。一般来说,make命令可以指定目标目标(即:$ make 目标名称),例如$make clean 中的clean也是一个目标名称)。make命令在没有指定目标的情况下,会默认执行第一个目标(在这里是all)下的内容。

    4、make -C $(KERN_DIR) M=`pwd` modules 的

    -C 选项的作用是指将当前工作目录转移到指定的位置,-C $(KERN_DIR) 指明跳转到内核源码目录下,读取那里的Makefile。

    M是内核根目录下的Makefile中使用的变量,“M=”的作用是在make命令中对变量M进行赋值。当用户需要以某个内核为基础编译一个外部模块的话,需要在make modules 命令中加入“M=dir”,表示包含dir下的Makefile文件,加入M选项后,程序会自动到你所指定的dir目录中查找模块源码,将其编译,生成KO文件(M=$(PWD) 表明返回到当前目录继续读入、执行当前的Makefile)。

    modules是内核根目录下的Makefile的一个目标,表示编译成模块的意思(大约在Makefile的1253行,内核版本4.13.0-43-generic)。

    5、obj-m := hello.o 的解释

    obj-m表示把编译hello.c生成的文件hello.o编译成内核模块(不会编译到内核,但是会生成一个独立的 "hello.ko" 文件)。ko 文件是内核模块文件,是内核加载的某个模块,一般是驱动程序。
    如果是obj-y,则表示把test.o文件编译进内核
    不太懂得地方,我的猜测:obj-m和obj-y是变量,在内核目录的makefile中会被使用?

     

    (注:本文内容参考自网上的资料和大神们的博客,感谢大家的分享)

    展开全文
  • 4.编写hello_world驱动 驱动文件hello_mod.c示例: # include < linux/init.h> # include < linux/module.h> MODULE_LICENSE( "GPL" ); static int hello_init( void ) { printk(KERN_...

    0.准备条件

    操作系统:VMware虚拟机中运行的Debian 9
    采用的内核:linux4.9

    1.下载linux源代码

    debian或ubuntu下,使用apt工具下载linux源码(或只下载头文件也可以)
    centos使用yum

    su
    apt-get install -y linux-source

    安装完成后应当能够在/usr/src中看到如下3个文件或文件夹:

    dts@debian:~$ ls /usr/src/
    linux-config-4.9 linux-patch-4.9-rt.patch.xz linux-source-4.9.tar.xz

    2.将代码编译源代码

    先解压源码包,并将合适的配置文件复制到源码文件夹下并重命名为.config

    tar -xvf linux-source-4.9.tar.xz
    xz -d linux-config-4.9/config.amd64_none_amd64.xz
    mv linux-config-4.9/config.amd64_none_amd64 linux-source-4.9/.config

    编译一遍源码,以确定没有问题。(至少要编译scripts运行脚本)

    cd linux-source-4.9
    make -j4

    cd linux-source-4.9
    make scripts/

    3.了解Linux驱动相关命令和头文件

    (1) 命令

    #用于安装或删除一个模块 insmod rmmod

    (2)obj-m makefile 符号, 内核建立系统用来决定当前目录下的哪个模块应当被建立

    (3) linux/init.h

    //用于指定模块的初始化和清理函数的宏定义. module_init(init_function); module_exit(cleanup_function);(3)struct task_struct *current

    (4)linux/module.h

    模块相关宏定义的头文件

    (5)关于模块信息的常用宏

    MODULE_AUTHOR(author); MODULE_DESCRIPTION(description); MODULE_VERSION(version_string); MODULE_DEVICE_TABLE(table_info); MODULE_ALIAS(alternate_name);

    (6)int printk(const char * fmt, );//将字符串输出到内核调试信息

    4.编写hello_world驱动

    驱动文件hello_mod.c示例:

    #include&lt;linux/init.h&gt;
     #include&lt;linux/module.h&gt;
    MODULE_LICENSE("GPL");
    
    static int hello_init(void)
    {
        printk(KERN_ALERT "Hello,world\n");
        return 0;
    }
    
    static void hello_exit(void)
    {
        printk(KERN_ALERT "Goodbye,world\n");
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    

    对应的makefile示例:

    obj-m := hello_mod.o
    
    KERNEL_DIR := /usr/src/linux-source-4.9
    PWD := $(shell pwd)
    
    all:
        make -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules
    clean:
        rm *.o *.ko
    
    .PHONY:clean

    5.编译(在makefile和hello.c)

    root@debian:/home/dts/公共# make
    make -C /usr/src/linux-source-4.9 SUBDIRS=/home/dts/公共 modules
    make[1]: Entering directory '/usr/src/linux-source-4.9'
    
      WARNING: Symbol version dump ./Module.symvers
               is missing; modules will have no dependencies and modversions.
    
      CC [M]  /home/dts/公共/hello_mod.o
      Building modules, stage 2.
      MODPOST 1 modules
      LD [M]  /home/dts/公共/hello_mod.ko
    make[1]: Leaving directory '/usr/src/linux-source-4.9'

    6.安装和卸载

    安装模块hello_mod
    insmod hello_mod.ko
    卸载模块
    rmmod hello_mod

    7.在内核调试信息中查看安装和卸载hello_mod时输出的调试信息

    使用dmesg查看内核调试信息,可以发现末尾是hello_mod安装和卸载时的输出信息
    ╰─$ dmesg | tail
    [17961.689403] cfg80211: (5170000 KHz - 5250000 KHz @ 80000 KHz, 160000 KHz AUTO), (N/A, 2300 mBm), (N/A)
    [17961.689406] cfg80211: (5250000 KHz - 5330000 KHz @ 80000 KHz, 160000 KHz AUTO), (N/A, 2300 mBm), (0 s)
    [17961.689408] cfg80211: (5735000 KHz - 5835000 KHz @ 80000 KHz), (N/A, 3000 mBm), (N/A)
    [17961.689411] cfg80211: (57240000 KHz - 59400000 KHz @ 2160000 KHz), (N/A, 2800 mBm), (N/A)
    [17961.689413] cfg80211: (59400000 KHz - 63720000 KHz @ 2160000 KHz), (N/A, 4400 mBm), (N/A)
    [17961.689415] cfg80211: (63720000 KHz - 65880000 KHz @ 2160000 KHz), (N/A, 2800 mBm), (N/A)
    [17961.835073] userif-2: sent link down event.
    [17961.835078] userif-2: sent link up event.
    [18024.538743] Hello,world
    [18030.683052] Goodbye,world

     

    提示:

    1.编译时如果觉得在虚拟机中编译慢,可以多开几个核。开始只给了虚拟机一个核,结果编译的时候死机了…

    2.insmod: ERROR: could not insert module hello_mod.ko: Invalid module format 出现该错误时,请检查当前系统内核和使用的源码是否为一个版本。

    3.Makefile:671: scripts/Makefile.gcc-plugins: 没有那个文件或目录 编译时出现该类错误,请在源码目录下执行make scripts/

    展开全文
  • linux驱动入门-hello设备驱动程序编写

    千次阅读 2016-07-31 11:54:19
    linux驱动入门-hello设备驱动程序编写 创建一个hello.c文件 [luxibao@centos ~]$ mkdir hello [luxibao@centos ~]$ ls dropbear-0.53.1 fl2440 公共的 视频 文档 音乐 dropbear-0.53.1.tar.bz2 hello 模板 图片...

    linux驱动入门-hello设备驱动程序编写

    创建一个hello.c文件

    [luxibao@centos ~]$ mkdir hello

    [luxibao@centos ~]$ ls

    dropbear-0.53.1          fl2440  公共的  视频  文档  音乐

    dropbear-0.53.1.tar.bz2  hello   模板    图片  下载  桌面

    [luxibao@centos ~]$ cd hello/

    [luxibao@centos hello]$ ls

    [luxibao@centos hello]$ vim hello.c

     

     

     

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

     

    }

    MODULE_LICENSE("Dual BSD/GPL");

     *      Copyright: (C) 2016 luxibao<864809344@qq.com>

     *              All rights reserved.

     *

     *      Filename: hello.c

     *      Description: This file

     *

     *      Version: 1.0.0(2016年07月26日)

     *      Author: luxibao <864809344@qq.com>

     *      ChangeLog: 1, Release initial version on "2016年7月26日10时8分00秒"

     *

     *

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

     

    #include <linux/init.h>

    #include <linux/module.h>

    MODULE_LICENSE("Dual BSD/GPL");

     

     

    static int hello_init(void)

    {

            printk(KERN_ALERT "Hello, luxibao\n");

            return 0;

    }

     

     

     

    static void hello_exit(void)

    {

            printk(KERN_ALERT "Goodbye, luxibao\n");

    }

     

     

    module_init(hello_init);

    module_exit(hello_exit);

     

    这个模块定义了两个函数,其中一个在模块被装载打到内核是调用(hello——init),而另一个则是在模块被移除时调用(hello_exit)。

    特殊宏(MODULE_LICENSE)用来告诉内核,该模块采取自由许可证,如果没有这样的声明,内核在装载该模块时会产生抱怨。

    [luxibao@centos hello]$ ls

    hello.c

    Hello 驱动的Makefile编写:

    适用于Linux操作系统:

    hello.c同一级目录下创建makefile

    [luxibao@centos hello]$ vim makefile

     

    obj-m=hello.o

    modules:

            make -C /lib/modules/`uname -r`/build/ M=`pwd` modules

            make clean

     

    clean:

            rm -f *.o *.mod.c *.order *.symvers

     

    [luxibao@centos hello]$ ls

    hello.c  makefile

    [luxibao@centos hello]$ make

    [luxibao@centos hello]$ make

    make -C /lib/modules/`uname -r`/build/ M=`pwd` modules

    make[1]: Entering directory `/usr/src/kernels/2.6.32-573.el6.x86_64'

      CC [M]  /home/luxibao/hello/hello.o

      Building modules, stage 2.

      MODPOST 1 modules

      CC      /home/luxibao/hello/hello.mod.o

      LD [M]  /home/luxibao/hello/hello.ko.unsigned

      NO SIGN [M] /home/luxibao/hello/hello.ko

    make[1]: Leaving directory `/usr/src/kernels/2.6.32-573.el6.x86_64'

    make clean

    make[1]: Entering directory `/home/luxibao/hello'

    rm -f *.o *.mod.c *.order *.symvers

    make[1]: Leaving directory `/home/luxibao/hello'

     

    [luxibao@centos hello]$ ls

    hello.c  hello.ko  hello.ko.unsigned  Makefile

    [luxibao@centos hello]$ sudo insmod ./hello.ko

    [luxibao@centos hello]$ dmesg

    .....................................

    SELinux: initialized (dev mqueue, type mqueue), uses transition SIDs

    lo: Disabled Privacy Extensions

    SELinux: initialized (dev proc, type proc), uses genfs_contexts

    fuse init (API version 7.14)

    psmouse.c: Wheel Mouse at isa0060/serio1/input0 lost synchronization, throwing 2 bytes away.

    psmouse.c: resync failed, issuing reconnect request

    Hello, luxibao

     

    [luxibao@centos hello]$ sudo rmmod ./hello.ko

    [luxibao@centos hello]$ dmesg

    ........................................

    SELinux: initialized (dev proc, type proc), uses genfs_contexts

    fuse init (API version 7.14)

    psmouse.c: Wheel Mouse at isa0060/serio1/input0 lost synchronization, throwing 2 bytes away.

    psmouse.c: resync failed, issuing reconnect request

    Hello, luxibao

    Goodbye, luxibao

     

    [luxibao@centos hello]$ lsmod

     

    [luxibao@centos hello]$ dmesg

    SELinux: initialized (dev mqueue, type mqueue), uses transition SIDs

    SELinux: initialized (dev proc, type proc), uses genfs_contexts

    SELinux: initialized (dev mqueue, type mqueue), uses transition SIDs

    lo: Disabled Privacy Extensions

    SELinux: initialized (dev proc, type proc), uses genfs_contexts

    fuse init (API version 7.14)

    psmouse.c: Wheel Mouse at isa0060/serio1/input0 lost synchronization, throwing 2 bytes away.

    psmouse.c: resync failed, issuing reconnect request

    Hello, luxibao

    Goodbye, luxibao

    适用于fl2440开发板:

    [luxibao@centos ~]$ mkdir hello.1

    [luxibao@centos hello]$ ls

    hello.c  hello.ko  hello.ko.unsigned  Makefile

    [luxibao@centos hello]$ sz hello.c

    rz

    Starting zmodem transfer.  Press Ctrl+C to cancel.

    Transferring hello.c...

      100%     748 bytes  748 bytes/s 00:00:01       0 Errors

     

    [luxibao@centos hello]$

    [luxibao@centos hello]$ ls

    hello.c  hello.ko  hello.ko.unsigned  Makefile

    [luxibao@centos hello]$ cd ../

    [luxibao@centos ~]$ cd hello.1

    [luxibao@centos hello.1]$ ls

    Makefile

    [luxibao@centos hello.1]$ rz

    rz waiting to receive.

    Starting zmodem transfer.  Press Ctrl+C to cancel.

    Transferring hello.c...

      100%     748 bytes  748 bytes/s 00:00:01       0 Errors

     

     

    [luxibao@centos hello.1]$ vim Makefile

     

    C=/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gcc

    KDIR?=/home/luxibao/fl2440/kernel/linux-3.0

    obj-m:=hello.o

     

    default:

            $(MAKE) -C $(KDIR) M=`pwd` modules

            make clean

     

    clean:

            rm -f *.o *mod.c *.order *.symvers

     

    [luxibao@centos hello.1]$ ls

    hello.c  Makefile

    [luxibao@centos hello.1]$ make

    make -C /home/luxibao/fl2440/kernel/linux-3.0 M=`pwd` modules

    make[1]: Entering directory `/home/luxibao/fl2440/kernel/linux-3.0'

      CC [M]  /home/luxibao/hello.1/hello.o

      Building modules, stage 2.

      MODPOST 1 modules

      CC      /home/luxibao/hello.1/hello.mod.o

      LD [M]  /home/luxibao/hello.1/hello.ko

    make[1]: Leaving directory `/home/luxibao/fl2440/kernel/linux-3.0'

    make clean

    make[1]: Entering directory `/home/luxibao/hello.1'

    rm -f *.o *mod.c *.order *.symvers

    make[1]: Leaving directory `/home/luxibao/hello.1'

    [luxibao@centos hello.1]$ ls

    hello.c  hello.ko  Makefile

    在开发板上操作:

    >: ifconfig

    eth0      Link encap:Ethernet  HWaddr D6:86:38:B9:4D:CF  

              inet addr:192.168.1.111  Bcast:192.168.1.255  Mask:255.255.255.0

              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

              RX packets:54 errors:0 dropped:0 overruns:0 frame:0

              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

              collisions:0 txqueuelen:1000

              RX bytes:7236 (7.0 KiB)  TX bytes:0 (0.0 B)

              Interrupt:51 Base address:0x2300

    >: tftp -gr hello.ko 192.168.1.2

    hello.ko             100% |*******************************|  2134   0:00:00 ETA

    >: insmod hello.ko

    Hello, luxibao

    >: ls /lib/

    ld-uClibc-0.9.33.2.so       libnsl-0.9.33.2.so

    ld-uClibc.so.0              libnsl.so.0

    libc.so.0                   libpthread-0.9.33.2.so

    libcrypt-0.9.33.2.so        libpthread.so.0

    libcrypt.so.0               libresolv-0.9.33.2.so

    libdl-0.9.33.2.so           libresolv.so.0

    libdl.so.0                  librt-0.9.33.2.so

    libgcc_s.so                 librt.so.0

    libgcc_s.so.1               libstdc++.so

    libm-0.9.33.2.so            libstdc++.so.6

    libm.so.0                   libstdc++.so.6.0.14

    libmudflap.so               libstdc++.so.6.0.14-gdb.py

    libmudflap.so.0             libuClibc-0.9.33.2.so

    libmudflap.so.0.0.0         libutil-0.9.33.2.so

    libmudflapth.so             libutil.so.0

    libmudflapth.so.0           modules

    libmudflapth.so.0.0.0

    >: dmesg

    Linux version 3.0.0 (luxibao@centos.6localdomain) (gcc version 4.5.4 (Buildroot 2012.08) ) #16 Sat Jul 30 10:18:27 CST 2016

    CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177

    CPU: VIVT data cache, VIVT instruction cache

    Machine: SMDK2440

    .................

    usb 1-1: new full speed USB device number 2 using s3c2410-ohci

    hub 1-1:1.0: USB hub found

    hub 1-1:1.0: 4 ports detected

    dm9000 dm9000: eth0: link down

    dm9000 dm9000: eth0: link up, 100Mbps, full-duplex, lpa 0xCDE1

    Hello, luxibao

    >: lsmod

    hello 628 0 - Live 0xbf000000

    >: rmmod hello

    Goodbye, luxibao

    >: dmesg 

    ............................

    Freeing init memory: 132K

    usb 1-1: new full speed USB device number 2 using s3c2410-ohci

    hub 1-1:1.0: USB hub found

    hub 1-1:1.0: 4 ports detected

    dm9000 dm9000: eth0: link down

    dm9000 dm9000: eth0: link up, 100Mbps, full-duplex, lpa 0xCDE1

    Hello, luxibao

    Goodbye, luxibao

     

    遇到的问题和解决方法:

     

    1.编写的Makefile程序make 报错:



    解决:出去多余的?号,Tab键代替空格,检查命令是否出错,单词是否拼写错误。

     

    2.忘记在hello.1下创建hello.c文件


    解决:创建hello.c文件或者从hello文件夹下直接copy   hello.c过来

     

     

    展开全文
  • linux驱动入门-hello设备驱动程序编写及内核的更新(网卡的添加)
  • ARM Linux 下 Hello 驱动程序

    千次阅读 2012-12-08 22:21:21
    今天终于在我的TQ2440 ARM板子上运行了一个简单的驱动程序,惭愧!!!  简单的 Hello 驱动 . ...编写程序驱动程序:  新建一个名为 yikai_hello.c .  内容如下: /********************
  • 文章目录最简单的hello word驱动程序1 前言2 hello word 驱动3 驱动程序的makefile4 测试程序的编写5 驱动程序的测试 1 前言 ​ 在前面的文章中已经叙述过开发板中如何运行hello word。接下来本文将讲解如果写一个...
  • 现在,你已经创建了空的 Hello World 项目并添加了 Driver.c 源文件,你将通过实现两个基本事件回调函数来编写驱动程序运行所需的最基本的代码。 在 Driver.c 中,首先包括以下标头: C++ #include #...
  • 在上一文中介绍了hello驱动的JNI方法,最终更新在android runtime中的java-native函数表。本文将介绍java的世界中如何通过调用JNI定义的java函数实现hello系统服务进程,为应用程序提供系统服务。 通信代理AIDL ...
  • 编写第一个HelloWorld驱动程序

    千次阅读 2016-02-16 11:26:56
    开发应用程序需要用到SDK,内核编程需要使用WDK(Windows Driver Kit),WDK已经自带所需要的头文件,库,C/C++语言及汇编语言的编译器与链接器,所有完全可以不用安装Visual Studio。 1.首先我们下载安装WinDDK,安装...
  • 编写一个helloworld的驱动程序到内核

    千次阅读 2016-07-26 18:54:09
    编写一个最简单的驱动程序到内核,有两种方式: 1.直接修改Makefile 2.修改Kconfig,提供可选菜单 /*有如下的helloworld.c的驱动程序*/ #include #include static int helloworld_init(void) {  printk...
  • 1.首先编写一个hello.c文件,如图所示这就是驱动程序的标准模式。 2.在低版本的linux中驱动程序是一个.o文件,而且在低版本的内核需要手动添加kernel和module模块,所以需要在命令终端输入gcc -c -kernel -module...
  • android基于Linux内核,故该驱动与Linux驱动没有任何不同,为了保证流程的完整性,故这里写一个Hello驱动,供后面的android学习使用,对于已经熟悉linux驱动的朋友,可以跳过此部分的学习,复制驱动编译即可;...
  • 编写 Hello world 模块驱动

    千次阅读 2010-05-18 00:10:00
    编写 Hello world 模块驱动华清远见-嵌入式领域著名讲师 O(∩_∩)O 牛牛猛点击链接加我好友!http://student.csdn.net/invite.php?u=111047&c=758a60d66d3a92d1欢迎大家去我CSDN博客上踩踩我的个人主页 晚上没事...
  • Android系统编写Linux内核驱动程序

    千次阅读 2016-09-29 16:52:30
    想起我们第一次学习程序语言时,都喜欢用“Hello, World”作为例子,这里,我们就把这个虚拟的设备命名为“hello”,而这个内核驱动程序也命名为hello驱动程序。其实,Android内核驱动程序和一般Li
  • 嵌入式:内核驱动模块hello程序 )。 系统版本信息: gyz@debian:~$ uname -a Linux debian 4.19.0-0.bpo.2-amd64 #1 SMP Debian 4.19.16-1~bpo9+1 (2019-02-07) x86_64 GNU/Linux gyz@debian:~$ lsb_...
  • Tiny210驱动开发之Hello world驱动模块编写与测试构建交叉编译环境获取Linux内核源码编译Linux内核编写helloworld驱动模块编写helloworld驱动模块的Makefile文件可能遇到的问题 最近手边有一个Tiny210开发板,重温...
  • 恩,可能是我比较愚钝,一个内核编译搞了一天,各种问题,各种bug,几度无奈,也是因为我突发奇想,并没有按照原来的那种操作,我直接把helloworld程序放到内核模块中编译成了一个驱动程序,虽然其中遇到了不知道...
  • 字符驱动程序框架与应用测试程序编写-源码,详细见笔者文章:《字符驱动程序框架与应用测试程序编写》。
  • 一、如何写驱动程序 在学习C语言的时候有一个著名的hello world程序。在学习驱动程序的时候我们也可以写一个类似的小程序,它的源码如下: //file name module_ts.c #include #include static int __init m
  • 嵌入式驱动编写-LCD驱动程序

    千次阅读 2016-11-08 22:14:23
    如何来写LCD的驱动程序,首先 看芯片开发手册和原理图 根据原理图,找到s3c2440的GPIO控制管脚,gpb gpc gpd gpg管脚控制 需要设置寄存器 以及...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 50,048
精华内容 20,019
关键字:

编写hello驱动程序