zoukankan      html  css  js  c++  java
  • Android字符设备驱动开发基于高通msm8916【原创 】

    本人才疏浅学,写一篇文档总结自己在msm8916平台上移植自己编写的简单的字符设备驱动开发的整个流程。这个小项目的主要功能是开发一个简单的APP,APP通过JNI去调用位于kernel的字符设备驱动。

    APP的设计,开发平台Android Studio

    主要的文件是下面的三个文件:

    MainActivity.java文件的内容如下:

     1 package com.example.administrator.myled;
     2 
     3 import android.nfc.Tag;
     4 import android.support.v7.app.AppCompatActivity;
     5 import android.os.Bundle;
     6 import android.util.Log;
     7 import android.view.View;
     8 import android.widget.Button;
     9 import android.widget.Toast;
    10 
    11 
    12 import com.zbahuang.led.lowlevel.LedNative;
    13 
    14 public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    15     private final static String TAG = "zbzhuang";
    16     Button btn_led_on;
    17     Button btn_led_off;
    18     LedNative myled;
    19 
    20 
    21     @Override
    22     protected void onCreate(Bundle savedInstanceState) {
    23         super.onCreate(savedInstanceState);
    24         setContentView(R.layout.activity_main);
    25 
    26         initUI();
    27 
    28         myled = new LedNative();
    29         myled.openDev();
    30         Log.d(TAG,"app:open Dev");
    31     }
    32 
    33     private void initUI() {
    34         btn_led_on = (Button) findViewById(R.id.btn_led_on);
    35         btn_led_on.setOnClickListener(this);
    36 
    37         btn_led_off = (Button) findViewById(R.id.btn_led_off);
    38         btn_led_off.setOnClickListener(this);
    39     }
    40 
    41     @Override
    42     public void onClick(View v) {
    43         switch (v.getId()){
    44             case R.id.btn_led_on:
    45                 Toast.makeText(MainActivity.this,"拉灯-->",Toast.LENGTH_SHORT).show();
    46                 Log.d(TAG,"app:LED on");
    47                 myled.devOn();
    48                 break;
    49             case R.id.btn_led_off:
    50                 Toast.makeText(MainActivity.this,"灭灯-->",Toast.LENGTH_SHORT).show();
    51                 Log.d(TAG,"app:LED off");
    52                 myled.devOff();
    53                 break;
    54             default:
    55                 break;
    56         }
    57 
    58     }
    59 
    60     @Override
    61     protected void onDestroy() {
    62         super.onDestroy();
    63         myled.closeDev();
    64         Log.d(TAG,"app:close Dev");
    65     }
    66 }
    LedNative.java文件的内容如下:
    在这个文件中所声明的方法是在jni中实现的啊。使用了特殊的关键字表示该方法是在JNI当中实现的啊。
     1 package com.zbahuang.led.lowlevel;
     2 
     3 /**
     4  * Created by Administrator on 2017/3/29 0029.
     5  */
     6 
     7 public class LedNative {
     8 
     9     static {
    10         System.loadLibrary("led_jni");
    11     }
    12 
    13     public native int openDev();
    14     public native int devOn();
    15     public native int devOff();
    16     public native int closeDev();
    17 }
    18 package com.zbahuang.led.lowlevel;
    19 
    20 /**
    21  * Created by Administrator on 2017/3/29 0029.
    22  */
    23 
    24 public class LedNative {
    25 
    26     static {
    27         System.loadLibrary("led_jni");
    28     }
    29 
    30     public native int openDev();
    31     public native int devOn();
    32     public native int devOff();
    33     public native int closeDev();
    34 }

    activity_main.xml文件的内容如下:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     xmlns:app="http://schemas.android.com/apk/res-auto"
     4     xmlns:tools="http://schemas.android.com/tools"
     5     android:layout_width="match_parent"
     6     android:layout_height="match_parent"
     7     tools:context="com.example.administrator.myled.MainActivity">
     8 
     9 
    10     <RelativeLayout
    11         android:layout_width="394dp"
    12         android:layout_height="520dp"
    13         tools:layout_editor_absoluteX="-5dp"
    14         tools:layout_editor_absoluteY="-10dp">
    15 
    16         <Button
    17             android:id="@+id/btn_led_on"
    18             android:layout_width="wrap_content"
    19             android:layout_height="wrap_content"
    20             android:layout_alignParentStart="true"
    21             android:layout_alignParentTop="true"
    22             android:layout_marginStart="56dp"
    23             android:layout_marginTop="109dp"
    24             android:text="拉灯" />
    25 
    26         <Button
    27             android:id="@+id/btn_led_off"
    28             android:layout_width="wrap_content"
    29             android:layout_height="wrap_content"
    30             android:layout_alignBaseline="@+id/btn_led_on"
    31             android:layout_alignBottom="@+id/btn_led_on"
    32             android:layout_marginStart="81dp"
    33             android:layout_toEndOf="@+id/btn_led_on"
    34             android:text="灭灯" />
    35     </RelativeLayout>
    36 </android.support.constraint.ConstraintLayout>

    JNI的文件:

    led_jni.cpp

      1 #include <sys/types.h>
      2 #include <sys/stat.h>
      3 #include <fcntl.h>
      4 #include <unistd.h>
      5 #include <errno.h>
      6 #include <string.h>
      7 
      8 
      9 #define LOG_TAG "zbzhuang"
     10 #include <utils/Log.h>
     11 
     12 #include "jni.h"
     13 
     14 
     15 
     16 
     17 static jint fd;
     18 
     19 
     20 static jint open_led(JNIEnv *env,jobject thiz)
     21 {
     22     ALOGD("JNI:-----------%s--------------",__FUNCTION__);
     23 
     24     fd = open("/dev/led1",O_RDWR);
     25     if(fd < 0){
     26         ALOGD("JNI:open error:%s
    ",strerror(errno));
     27         return -1;
     28     }
     29 
     30     return 0;
     31 }
     32 
     33 
     34 static jint led_on(JNIEnv *env,jobject thiz)
     35 {
     36     ALOGD("JNI:-----------%s--------------",__FUNCTION__);
     37     jint ret ;
     38     jint on = 1;
     39 
     40     ret = write(fd,&on,4);
     41     if(ret < 0){
     42         ALOGD("JNI:write off error:%s
    ",strerror(errno));
     43         return -1;
     44     }
     45 
     46 
     47     return 0;
     48 }
     49 
     50 
     51 static jint led_off(JNIEnv *env,jobject thiz)
     52 {
     53     ALOGD("JNI:-----------%s--------------",__FUNCTION__);
     54     jint ret;
     55     jint off = 0;
     56 
     57     ret = write(fd,&off,4);
     58     if(ret < 0){
     59         ALOGD("JNI:write off error:%s
    ",strerror(errno));
     60         return -1;
     61     }
     62 
     63     return 0;
     64 }
     65 
     66 
     67 static jint close_led(JNIEnv *env,jobject thiz)
     68 {
     69     ALOGD("JNI:-----------%s--------------",__FUNCTION__);
     70     close(fd);
     71 
     72     return 0;
     73 }
     74 
     75 
     76 
     77 
     78 
     79 const JNINativeMethod  led_jni_methods[] = {
     80     {"openDev","()I",(void *)open_led},
     81     {"devOn","()I",(void *)led_on},
     82     {"devOff","()I",(void *)led_off},
     83     {"closeDev","()I",(void *)close_led},
     84 
     85 
     86 };
     87 
     88 
     89 
     90 
     91 
     92 
     93 
     94 jint JNI_OnLoad(JavaVM * vm,void * reserved)
     95 {
     96     JNIEnv *env = NULL;
     97     jint ret ;
     98 
     99     
    100 
    101     ALOGD("%s[%s:%d]JNI:--------------^_&--------------------
    ",__func__,__FILE__,__LINE__);
    102     ret = vm->GetEnv((void * *)&env,JNI_VERSION_1_4);
    103     if(ret != JNI_OK){
    104         ALOGE("JNI:vm->GetEnv error");
    105         return -1;
    106     }
    107 
    108     jclass clz = env->FindClass("com/zbahuang/led/lowlevel/LedNative");
    109 
    110     if(clz == NULL){
    111         ALOGE("%s[%s:%d]JNI:env->FindClass error",__func__,__FILE__,__LINE__);
    112         return -1;
    113     }
    114 
    115     ret = env->RegisterNatives(clz,
    116                 led_jni_methods,
    117                 sizeof(led_jni_methods)/sizeof(led_jni_methods[0]));
    118 
    119     if(ret < 0){
    120         ALOGE("%s[%s:%d]JNI:env->RegisterNatives error
    ",__func__,__FILE__,__LINE__);
    121         return -1;
    122     }
    123 
    124 
    125 
    126     return JNI_VERSION_1_4;
    127     
    128 
    129 
    130 }

    Android.mk

     1 LOCAL_PATH:= $(call my-dir)
     2 include $(CLEAR_VARS)
     3 
     4 LOCAL_MODULE_TAGS := optional
     5 
     6 LOCAL_MODULE:= libled_jni
     7 
     8 LOCAL_SRC_FILES:= 
     9   led_jni.cpp
    10 
    11 LOCAL_SHARED_LIBRARIES := 
    12     libutils liblog
    13 
    14 LOCAL_C_INCLUDES += 
    15     $(JNI_H_INCLUDE)
    16 
    17 include $(BUILD_SHARED_LIBRARY)

    执行:       mmm mytest/led_jni/   之后会生成动态库放在  out/target/product/msm8916_64/obj/lib/libled_jni.so

    将这个库推送到平板电脑就可以通过这个库去调用驱动。

    内核的驱动文件:kernel/drivers/input/misc/led.c

      1 /*1. 头文件*/
      2 #include<linux/init.h>
      3 #include<linux/module.h>
      4 #include<linux/fs.h>
      5 #include<linux/device.h>
      6 #include<linux/slab.h>
      7 #include<linux/cdev.h>
      8 #include<asm/uaccess.h>
      9 #include<asm/io.h>
     10 
     11 static unsigned int led_major=0;
     12 volatile unsigned long *gpc0con = NULL;
     13 volatile unsigned long *gpc0dat = NULL;
     14 
     15 struct led_device{
     16     struct class *led_class ;    //表示一类设备, 存储某些信息
     17     struct device *led_device ;    //表示一个设备
     18     struct cdev  *led_cdev;
     19     unsigned int val;
     20 
     21 };
     22 
     23 struct led_device *s5pv_led_dev;
     24 
     25 
     26 /*可用于查询LED的状态*/
     27 static ssize_t led_read(struct file *file, char __user *buf, size_t count, loff_t *opps)
     28 {
     29     int ret;
     30 
     31     ret = copy_to_user(buf, &s5pv_led_dev->val, count);
     32     if(ret>0)
     33     {
     34         printk(KERN_ERR "zbzhuang### copy to user failed!
    ");
     35         return ret;
     36     }
     37 
     38     printk(KERN_INFO "zbzhuang### val=%d
    ", s5pv_led_dev->val);
     39     
     40     return ret?0:count;
     41 }
     42 static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *opps)
     43 {
     44     int ret;
     45 
     46     /*拷贝成功,返回0; 拷贝失败, 返回没有被拷贝的字节数*/
     47     ret = copy_from_user(&s5pv_led_dev->val, buf, count);
     48     if(ret>0)
     49     {
     50         printk(KERN_ERR "zbzhuang### copy from user failed!
    ");
     51         return ret;
     52     }
     53 
     54     if(s5pv_led_dev->val)
     55     {
     56         /*点亮LED*/
     57         //*gpc0dat |= ((0x1<<3)|(0x1<<4));
     58         printk(KERN_ERR "zbzhuang### led on
    ");
     59     }
     60     else
     61     {
     62         /*熄灭LED*/
     63 //        *gpc0dat &= ~((0x1<<3)|(0x1<<4));
     64         printk(KERN_ERR "zbzhuang### led off
    ");
     65     }
     66     
     67     return ret?0:count;
     68 }
     69 
     70 
     71 
     72 static int led_open(struct inode *inode, struct file *file)
     73 {
     74 #if 0
     75     /*1. 将物理地址映射为虚拟地址*/
     76     gpc0con = ioremap(0xE0200060, 8);
     77     gpc0dat = gpc0con +1;
     78     
     79     /*2. 初始化GPC0_3,4引脚功能为输出*/
     80     *gpc0con &= ~((0xf<<12)|(0xf<<16));
     81     *gpc0con |=  ((0x1<<12)|(0x1<<16));    
     82 #endif
     83     printk(KERN_ERR "zbzhuang### -----------%s-------------
    ",__FUNCTION__);
     84     
     85     return 0;
     86 }
     87 
     88 static int led_close(struct inode *inode, struct file *file)
     89 {
     90 #if 0
     91 
     92     *gpc0con &= ~((0xf<<12)|(0xf<<16));
     93     iounmap(gpc0con);
     94 #endif
     95     printk(KERN_ERR "zbzhuang### ------------%s-----------------
    ",__FUNCTION__);
     96 
     97     return 0;
     98     
     99 }
    100 
    101 /*硬件操作方法*/
    102 struct file_operations led_fops={
    103     .owner = THIS_MODULE,    //当前模块所用
    104     .open  = led_open,
    105     .write = led_write,
    106     .read  = led_read,
    107     .release = led_close,
    108 
    109 };
    110 
    111 static void setup_led_cdev(void)
    112 {
    113     /*1. 为cdev结构体分配空间*/
    114     s5pv_led_dev->led_cdev = cdev_alloc();
    115 
    116     /*2. 初始化cdev结构体*/
    117     cdev_init(s5pv_led_dev->led_cdev, &led_fops);
    118 
    119     /*3. 注册cdev,加载到内核哈希表中*/
    120     cdev_add(s5pv_led_dev->led_cdev, MKDEV(led_major, 0), 1);
    121 
    122 }
    123 
    124 /*2. 实现模块加载函数*/
    125 static int __init led_init(void)
    126 {
    127     dev_t devno;
    128     int ret;
    129     /*1. 新的申请主设备号的方法*/
    130     if(led_major)
    131     {
    132         /*静态申请*/
    133         devno = MKDEV(led_major, 0);
    134         register_chrdev_region(devno, 1, "led");
    135     }
    136     else
    137     {
    138         /*动态申请*/
    139         alloc_chrdev_region(&devno, 0, 1, "led");
    140         led_major = MAJOR(devno);
    141     }
    142 
    143     /*2. 为本地结构体分配空间*/
    144 
    145         /*
    146         **    param1: 大小
    147         **    param2:    标号: GFP_KERNEL--->表示如果分配不成功,则休眠
    148         */
    149     s5pv_led_dev = kmalloc(sizeof(struct led_device), GFP_KERNEL);
    150     if (!s5pv_led_dev)
    151     {
    152         printk(KERN_ERR "zbzhuang NO memory for malloc!
    ");
    153         ret = -ENOMEM;
    154         goto out_err_1;
    155     }
    156 
    157     /*3. 构建struct cdev结构体*/
    158     setup_led_cdev();
    159             
    160 
    161     /*4. 创建设备文件*/
    162     /*
    163     **    param1:    struct class
    164     **    param2:    父类, 一般为NULL
    165     **    param3:    dev_t ---> 表示一个设备号, 是一个无符号32位整形
    166     **                        其中高12位为主设备号, 低20为次设备号
    167     **            如何操作设备号: MKDEV(major, minor)根据主设备号和次设备号组成一个设备号
    168     */    
    169 
    170     s5pv_led_dev->led_class = class_create(THIS_MODULE, "led_class");
    171     if (IS_ERR(s5pv_led_dev->led_class)) {
    172         printk(KERN_ERR "zbzhuang class_create() failed for led_class
    ");
    173         ret = -EINVAL;
    174         goto out_err_2;
    175     }
    176 
    177     
    178     s5pv_led_dev->led_device = device_create(s5pv_led_dev->led_class, NULL, MKDEV(led_major, 0), NULL, "led1");    // 创建设备文件/dev/led1
    179     if (IS_ERR(s5pv_led_dev->led_device)) {
    180         printk(KERN_ERR "zbzhuang device_create failed for led_device
    ");
    181         ret = -ENODEV;
    182         goto out_err_3;
    183     }
    184 
    185     return 0;
    186 
    187 out_err_3:
    188     class_destroy(s5pv_led_dev->led_class);
    189 
    190 out_err_2:
    191     cdev_del(s5pv_led_dev->led_cdev);
    192     kfree(s5pv_led_dev);
    193 
    194 out_err_1:
    195     unregister_chrdev_region(MKDEV(led_major, 0), 1);
    196     return ret;
    197     
    198 }
    199 
    200 /*3. 实现模块卸载函数*/
    201 static void __exit led_exit(void)
    202 {
    203     unregister_chrdev_region(MKDEV(led_major, 0), 1);
    204     device_destroy(s5pv_led_dev->led_class, MKDEV(led_major, 0));
    205     class_destroy(s5pv_led_dev->led_class);
    206     cdev_del(s5pv_led_dev->led_cdev);
    207     kfree(s5pv_led_dev);
    208 }
    209 
    210 /*4. 模块许可声明*/
    211 module_init(led_init);
    212 module_exit(led_exit);
    213 MODULE_LICENSE("GPL");

    修改kconfig和makefile,在内核当中添加:

    makefile

    kconfig:

    修改这个文件将驱动编译进内核:kernel/arch/arm64/configs/msm_defconfig  与msm-perf_deconfig

     之后使用adb工具将重新编译的boot.imge镜像重新烧录就可以了啊。

    看看log的输出验证一下结果:

    android studio查看log的结果:

    adb查看log的结果:

     

    从app到jni到kernel,整个调用的过程成功。

    如果出现打开设备失败的话在system/core/rootdir/uevent.rc中添加设备节点的权限777即可。

  • 相关阅读:
    Cobbler-自动化部署神器
    ssh,公钥和私钥,远程复制
    VIM文本替换命令
    #!/usr/bin/env bash和#!/usr/bin/bash的比较
    [PXE] Linux(centos6)中PXE 服务器搭建,PXE安装、启动及PXE理论详解
    mount命令中offset参数的意义
    ironic+nova详解
    【ironic】ironic介绍与原理
    在进行商业运算时解决BigDecimal的精度丢失问题
    后台商品搜索功能开发SQL
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/6639753.html
Copyright © 2011-2022 走看看