美文网首页android驱动开发
Android 字符驱动#0#开发硬件驱动程序和c测试程序

Android 字符驱动#0#开发硬件驱动程序和c测试程序

作者: 古风子 | 来源:发表于2019-05-06 09:31 被阅读0次

    开发Android硬件驱动程序程序和C验证程序

    开发坏境

    本地在在6.x的环境上调试

    Android版本号:mtk_6737_6.x
    Linux内核 版本号:Linux version 3.18.19+ ,arm64 //cat /proc/version
    

    开发Androd硬件驱动

    实现内核驱动程序模块

    驱动文件包括三个文件:
    Kconfig,Makefile,hello.c

    • hello.c
    
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include <linux/kernel.h>
    #include <linux/slab.h>
    #include <asm/uaccess.h>
    #include <linux/proc_fs.h>
    #include <linux/device.h>
    struct hello_cdev{
        char val;
        struct cdev cv;
    };
    dev_t devNo1;
    struct hello_cdev *hello_c;
    
    int hello_open (struct inode *node, struct file *filp){
        //获取到当前自定义结构体变量,保存至file中,以便其他函数方便访问
        struct hello_cdev *n_cdev = container_of(node->i_cdev,struct hello_cdev,cv);
        filp->private_data = n_cdev;
        return 0;
    }
    
    int hello_release (struct inode *node, struct file *filp){
        filp->private_data = NULL;
        return 0;
    }
    
    ssize_t hello_read (struct file *filp, char __user *buf, size_t len, loff_t *pos){
        struct hello_cdev *n_cdev = (struct hello_cdev *)filp->private_data;
        int err;
        printk("hello read %c  count : %d",n_cdev->val, sizeof(n_cdev->val));
        if(copy_to_user(buf,&n_cdev->val, sizeof(n_cdev->val))){
            err = -EFAULT;
            return err;
        }
        return sizeof(n_cdev->val);
    
    }
    
    ssize_t hello_write (struct file *filp, const char __user *buf, size_t len, loff_t *pos){
        struct hello_cdev *n_cdev = (struct hello_cdev *)filp->private_data;
        int err;
        printk("hello write %s  count : %d",(buf),len);
        if(copy_from_user(&n_cdev->val,buf,len)){
            err = -EFAULT;
            return err;
        }
        return sizeof(n_cdev->val);
    }
    
    struct file_operations hello_op = {
        .owner = THIS_MODULE,
        .open  = hello_open,
        .release = hello_release,
        .write = hello_write,
        .read = hello_read
    };
    
    
    
    
    static int hello_init(void){
        //申请设备号,自动分配 fs.h
        int err = alloc_chrdev_region(&devNo1,0,1,"hello");
        if(err){
            printk("获取设备号失败~ %d",err);
            return err;
        }
        //申请自定义结构体内存 slab.h
        hello_c = kmalloc(sizeof(struct hello_cdev),GFP_KERNEL);
        //初始化 字符设备
        cdev_init(&hello_c->cv,&hello_op);
        //添加字符设备
        err = cdev_add(&hello_c->cv,devNo1,1);
        if(err){
            printk("添加设备失败~ %d",err);
            return err;
        }
    
        hello_c->val = '1';
        //在/dev中创建节点
        struct class * cls = class_create(THIS_MODULE,"hello");
        device_create(cls,NULL,devNo1,NULL,"hello");
    
        return 0;
    }
    
    static void hello_exit(void){
        //释放设备号
        unregister_chrdev_region(devNo1,1);
        //释放自定义结构体的内存
        kfree(hello_c);
        //移除字符设备
        cdev_del(&hello_c->cv);
    }
    
    
    module_init(hello_init);
    module_exit(hello_exit);
    
    
    
    
    
    • Kconfig
    config HELLO
        tristate 'HELLO Driver'
        default n
    
    • Makefile
    obj-y  += hello.o
    

    把以上三个文件,放到源码的kernel的驱动目录

    //kernel目录选择当前源码中最新版本目录
    android\xxx\kernel-3.18\drivers\hello
    

    修改内核drivers目录的Kconfig和Makefile文件

    关联我们创建的模块
    Kconfig

    diff --git a/kernel-4.9/drivers/Kconfig b/kernel-3.18/drivers/Kconfig
    index c38428c..5626ff9 100755
    --- a/kernel-3.18/drivers/Kconfig
    +++ b/kernel-3.18/drivers/Kconfig
    @@ -1,5 +1,9 @@
     menu "Device Drivers"
     
    +source "drivers/hello/Kconfig"
    
     source "drivers/amba/Kconfig"
     
     source "drivers/base/Kconfig"
    
    

    Makefile

    diff --git a/kernel-3.18/drivers/Makefile b/kernel-3.18/drivers/Makefile
    index 6750823..588796a 100755
    --- a/kernel-4.9/drivers/Makefile
    +++ b/kernel-4.9/drivers/Makefile
    @@ -179,3 +179,5 @@ obj-$(CONFIG_NVMEM)         += nvmem/
     obj-$(CONFIG_FPGA)             += fpga/
     obj-$(CONFIG_TEE)              += tee/
     obj-$(CONFIG_TRUSTY)   += trusty/
    +obj-y        += hello/
    
    

    必须使用obj-y ,这样才会把生成的hello.o文件编译进内核,如果你使用obj-$(CONFIG_HELLO),则还需要参考配置默认打开驱动模块去配置CONFIG_HELLO变量

    CONFIG_HELLO属性默认为not set,也就是“n”

    关联之后,我们的模块已经添加到kernel驱动中去了,但此时模块是默认关闭的,因此我们还需要在源码中默认打开改功能

    配置默认打开驱动模块

    此步骤,只有在drivers/Makefile 中配置obj-$(CONFIG_HELLO) +=hello而非obj-y方式下,才需要配置属性,如果你使用的是obj-y ,此章节略过

    确认需要修改的defconfig文件

    驱动模块默认是关闭的,需要修改kernel-3.18/arch/arm64/configs的deconfig文件,默认打开改功能
    该目录下有多个defconfig文件,怎么确认需要修改哪个文件呢?

    lunch工程后,查看对应的TARGET_PRODUCT

    #source build/envsetup.sh 
    
    #full_yk658_37m_lwtg_35g-userdebug
    PLATFORM_VERSION_CODENAME=REL
    PLATFORM_VERSION=6.0
    TARGET_PRODUCT=full_yk658_37m_lwtg_35g
    TARGET_BUILD_VARIANT=userdebug
    TARGET_BUILD_TYPE=release
    TARGET_BUILD_APPS=
    TARGET_ARCH=arm
    TARGET_ARCH_VARIANT=armv7-a-neon
    TARGET_CPU_VARIANT=cortex-a53
    TARGET_2ND_ARCH=
    TARGET_2ND_ARCH_VARIANT=
    TARGET_2ND_CPU_VARIANT=cortex-a53
    HOST_ARCH=x86_64
    HOST_OS=linux
    HOST_OS_EXTRA=Linux-3.19.0-25-generic-x86_64-with-Ubuntu-14.04-trusty
    HOST_BUILD_TYPE=release
    BUILD_ID=MRA58K
    OUT_DIR=out
    

    可以看到TARGET_PRODUCT=full_yk658_37m_lwtg_35g,然后去TARGET_PRODUCT=full_yk658_37m_lwtg_35g目录搜索KERNEL_DEFCONFIG
    对应的是哪个文件

    jdf@ubuntu:~/mtk_6737_6.x_wtwd_8_qiku_LE_PLUS/android/qiku/device/lentek/yk658_37m_lwtg_35g$ grep -nr KERNEL_DEFCONFIG 
    lentek/yk658_37m_lwtg_35g/full_yk658_37m_lwtg_35g.mk:41:KERNEL_DEFCONFIG ?= yk658_37m_lwtg_35g_debug_defconfig
    lentek/yk658_37m_lwtg_35g/full_yk658_37m_lwtg_35g.mk:43:KERNEL_DEFCONFIG ?= yk658_37m_lwtg_35g_defconfig
    

    由此可以确认,需要修改kernel-3.18/arch/arm64/configs的以下文件,去默认打开驱动模块

    yk658_37m_lwtg_35g_debug_defconfig
    yk658_37m_lwtg_35g_defconfig
    

    本地只修改改目录下defconfig文件,也可以生效,修改内容如下;如果修改后不生效,可以修改具体项目对应的配置文件

    diff --git a/kernel-3.18/arch/arm64/configs/defconfig b/kernel-3.18/arch/arm64/configs/defconfig
    old mode 100644
    new mode 100755
    index 9ce3d4b..5d72b88
    --- a/kernel-4.9/arch/arm64/configs/defconfig
    +++ b/kernel-4.9/arch/arm64/configs/defconfig
    @@ -453,3 +453,5 @@ CONFIG_CRYPTO_GHASH_ARM64_CE=y
     CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
     CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
     CONFIG_CRYPTO_CRC32_ARM64=y
    +CONFIG_HELLO=y
    

    刷机验证

    //查看驱动是否已经注册
    root@yk658_37m_lwtg_35g:/ # cat /proc/devices  | grep hello
    232 hello
    //查看dev是否有hello驱动
    root@yk658_37m_lwtg_35g:/ # ls -l /dev/hello
    crw-rw-rw- root     root     232,   0 2015-01-01 00:45 hello
    

    开发C可执行程序验证硬件驱动

    创建验证程序

    在源码\external\hello下面增加可执行文件
    hello文件夹中包含两个文件

    Android.mk
    hello.c
    

    Android.mk

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE_TAGS := optional
    LOCAL_SRC_FILES := hello.c
    LOCAL_MODULE := hello
    include $(BUILD_EXECUTABLE)
    

    hello.c文件

    #include <fcntl.h>
    #include <stdio.h>
    int main(void){
        char val = '1';
        int fd = open("/dev/hello",O_RDWR);
        read(fd,&val,1);
        printf("hello read fromc c:  %c\n",val);
        val = val+1;
        write(fd,&val,1);
        printf("hello write from c: %c\n",val);
        return 0;
    }
    
    
    

    添加模块到编译文件

    为了在在整个系统编译的时候(比如make -j16)能够生成可执行文件,还需要修改/device/mediatek/common/device.mk文件,
    添加PRODUCT_PACKAGES += PRODUCT_PACKAGES += hello

    diff --git a/mediatek/common/device.mk b/mediatek/common/device.mk
    index c4b078d..ca36221 100755
    --- a/mediatek/common/device.mk
    +++ b/mediatek/common/device.mk
    @@ -47,6 +47,9 @@ endif
     
     #MTB
     PRODUCT_PACKAGES += mtk_setprop
    +PRODUCT_PACKAGES += hello
    +
     
     #MMS
     ifeq ($(strip $(MTK_BASIC_PACKAGE)), yes)
    

    刷机验证

    配置成功后,全编工程,刷入手机,在/system/bin目录就可以看到hello测试程序,运行查看效果

    也可以只编译system.img文件(命令::make snob,需要运行source build/envsetup.sh)

    root@yk658_37m_lwtg_35g:/system/bin # hello
    hello read fromc c:  1
    hello write from c: 2
    root@yk658_37m_lwtg_35g:/system/bin # hello
    hello read fromc c:  2
    hello write from c: 3
    root@yk658_37m_lwtg_35g:/system/bin # hello
    hello read fromc c:  3
    hello write from c: 4
    root@yk658_37m_lwtg_35g:/system/bin # hello
    hello read fromc c:  4
    hello write from c: 5
    root@yk658_37m_lwtg_35g:/system/bin # hello
    hello read fromc c:  5
    hello write from c: 6
    
    

    以上就是使用C语言编写的可执行程序来访问我们的Linux内核驱动程序;
    接下来我们介绍,为改驱动程序增加HAL层代码,因为,最终,我们的驱动程序还是提供给Application层应用使用的

    相关文章

      网友评论

        本文标题:Android 字符驱动#0#开发硬件驱动程序和c测试程序

        本文链接:https://www.haomeiwen.com/subject/oeiloqtx.html