1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > Android字符设备驱动开发基于高通msm8916【原创 】

Android字符设备驱动开发基于高通msm8916【原创 】

时间:2020-08-03 08:38:39

相关推荐

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 {15private final static String TAG = "zbzhuang";16Button btn_led_on;17Button btn_led_off;18LedNative myled;19 20 21@Override22protected 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 33private 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@Override42public 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@Override61protected 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 /3/29 0029.5 */6 7 public class LedNative {8 9static {10 System.loadLibrary("led_jni");11}12 13public native int openDev();14public native int devOn();15public native int devOff();16public native int closeDev();17 }18 package com.zbahuang.led.lowlevel;19 20 /**21 * Created by Administrator on /3/29 0029.22 */23 24 public class LedNative {25 26static {27 System.loadLibrary("led_jni");28}29 30public native int openDev();31public native int devOn();32public native int devOff();33public native int closeDev();34 }

activity_main.xml文件的内容如下:

1 <?xml version="1.0" encoding="utf-8"?>2 <android.support.constraint.ConstraintLayout xmlns:android="/apk/res/android"3xmlns:app="/apk/res-auto"4xmlns:tools="/tools"5android:layout_width="match_parent"6android:layout_height="match_parent"7tools:context="com.example.administrator.myled.MainActivity">8 9 10<RelativeLayout11 android:layout_width="394dp"12 android:layout_height="520dp"13 tools:layout_editor_absoluteX="-5dp"14 tools:layout_editor_absoluteY="-10dp">15 16 <Button17 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 <Button27 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 {22ALOGD("JNI:-----------%s--------------",__FUNCTION__);23 24fd = open("/dev/led1",O_RDWR);25if(fd < 0){26 ALOGD("JNI:open error:%s\n",strerror(errno));27 return -1;28}29 30return 0;31 }32 33 34 static jint led_on(JNIEnv *env,jobject thiz)35 {36ALOGD("JNI:-----------%s--------------",__FUNCTION__);37jint ret ;38jint on = 1;39 40ret = write(fd,&on,4);41if(ret < 0){42 ALOGD("JNI:write off error:%s\n",strerror(errno));43 return -1;44}45 46 47return 0;48 }49 50 51 static jint led_off(JNIEnv *env,jobject thiz)52 {53ALOGD("JNI:-----------%s--------------",__FUNCTION__);54jint ret;55jint off = 0;56 57ret = write(fd,&off,4);58if(ret < 0){59 ALOGD("JNI:write off error:%s\n",strerror(errno));60 return -1;61}62 63return 0;64 }65 66 67 static jint close_led(JNIEnv *env,jobject thiz)68 {69ALOGD("JNI:-----------%s--------------",__FUNCTION__);70close(fd);71 72return 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 {96JNIEnv *env = NULL;97jint ret ;98 99100 101ALOGD("%s[%s:%d]JNI:--------------^_&--------------------\n",__func__,__FILE__,__LINE__);102ret = vm->GetEnv((void * *)&env,JNI_VERSION_1_4);103if(ret != JNI_OK){104 ALOGE("JNI:vm->GetEnv error");105 return -1;106}107 108jclass clz = env->FindClass("com/zbahuang/led/lowlevel/LedNative");109 110if(clz == NULL){111 ALOGE("%s[%s:%d]JNI:env->FindClass error",__func__,__FILE__,__LINE__);112 return -1;113}114 115ret = env->RegisterNatives(clz,116 led_jni_methods,117 sizeof(led_jni_methods)/sizeof(led_jni_methods[0]));118 119if(ret < 0){120 ALOGE("%s[%s:%d]JNI:env->RegisterNatives error\n",__func__,__FILE__,__LINE__);121 return -1;122}123 124 125 126return JNI_VERSION_1_4;127128 129 130 }

Android.mk

1 LOCAL_PATH:= $(call my-dir)2 include $(CLEAR_VARS)3 4 LOCAL_MODULE_TAGS := optional5 6 LOCAL_MODULE:= libled_jni7 8 LOCAL_SRC_FILES:= \9 led_jni.cpp10 11 LOCAL_SHARED_LIBRARIES := \12libutils liblog13 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{16struct class *led_class ; //表示一类设备, 存储某些信息17struct device *led_device ; //表示一个设备18struct cdev *led_cdev;19unsigned 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 {29int ret;30 31ret = copy_to_user(buf, &s5pv_led_dev->val, count);32if(ret>0)33{34 printk(KERN_ERR "zbzhuang### copy to user failed!\n");35 return ret;36}37 38printk(KERN_INFO "zbzhuang### val=%d\n", s5pv_led_dev->val);3940return ret?0:count;41 }42 static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *opps)43 {44int ret;45 46/*拷贝成功,返回0; 拷贝失败, 返回没有被拷贝的字节数*/47ret = copy_from_user(&s5pv_led_dev->val, buf, count);48if(ret>0)49{50 printk(KERN_ERR "zbzhuang### copy from user failed!\n");51 return ret;52}53 54if(s5pv_led_dev->val)55{56 /*点亮LED*/57 //*gpc0dat |= ((0x1<<3)|(0x1<<4));58 printk(KERN_ERR "zbzhuang### led on\n");59}60else61{62 /*熄灭LED*/63 // *gpc0dat &= ~((0x1<<3)|(0x1<<4));64 printk(KERN_ERR "zbzhuang### led off\n");65}6667return ret?0:count;68 }69 70 71 72 static int led_open(struct inode *inode, struct file *file)73 {74 #if 075/*1. 将物理地址映射为虚拟地址*/76gpc0con = ioremap(0xE0200060, 8);77gpc0dat = gpc0con +1;7879/*2. 初始化GPC0_3,4引脚功能为输出*/80*gpc0con &= ~((0xf<<12)|(0xf<<16));81*gpc0con |= ((0x1<<12)|(0x1<<16)); 82 #endif83printk(KERN_ERR "zbzhuang### -----------%s-------------\n",__FUNCTION__);8485return 0;86 }87 88 static int led_close(struct inode *inode, struct file *file)89 {90 #if 091 92*gpc0con &= ~((0xf<<12)|(0xf<<16));93iounmap(gpc0con);94 #endif95printk(KERN_ERR "zbzhuang### ------------%s-----------------\n",__FUNCTION__);96 97return 0;9899 }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结构体分配空间*/114s5pv_led_dev->led_cdev = cdev_alloc();115 116/*2. 初始化cdev结构体*/117cdev_init(s5pv_led_dev->led_cdev, &led_fops);118 119/*3. 注册cdev,加载到内核哈希表中*/120cdev_add(s5pv_led_dev->led_cdev, MKDEV(led_major, 0), 1);121 122 }123 124 /*2. 实现模块加载函数*/125 static int __init led_init(void)126 {127dev_t devno;128int ret;129/*1. 新的申请主设备号的方法*/130if(led_major)131{132 /*静态申请*/133 devno = MKDEV(led_major, 0);134 register_chrdev_region(devno, 1, "led");135}136else137{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 */149s5pv_led_dev = kmalloc(sizeof(struct led_device), GFP_KERNEL);150if (!s5pv_led_dev)151{152 printk(KERN_ERR "zbzhuang NO memory for malloc!\n");153 ret = -ENOMEM;154 goto out_err_1;155}156 157/*3. 构建struct cdev结构体*/158setup_led_cdev();159 160 161/*4. 创建设备文件*/162/*163** param1: struct class164** param2: 父类, 一般为NULL165** param3: dev_t ---> 表示一个设备号, 是一个无符号32位整形166** 其中高12位为主设备号, 低20为次设备号167** 如何操作设备号: MKDEV(major, minor)根据主设备号和次设备号组成一个设备号168*/ 169 170s5pv_led_dev->led_class = class_create(THIS_MODULE, "led_class");171if (IS_ERR(s5pv_led_dev->led_class)) {172 printk(KERN_ERR "zbzhuang class_create() failed for led_class\n");173 ret = -EINVAL;174 goto out_err_2;175}176 177178s5pv_led_dev->led_device = device_create(s5pv_led_dev->led_class, NULL, MKDEV(led_major, 0), NULL, "led1"); // 创建设备文件/dev/led1179if (IS_ERR(s5pv_led_dev->led_device)) {180 printk(KERN_ERR "zbzhuang device_create failed for led_device\n");181 ret = -ENODEV;182 goto out_err_3;183}184 185return 0;186 187 out_err_3:188class_destroy(s5pv_led_dev->led_class);189 190 out_err_2:191cdev_del(s5pv_led_dev->led_cdev);192kfree(s5pv_led_dev);193 194 out_err_1:195unregister_chrdev_region(MKDEV(led_major, 0), 1);196return ret;197198 }199 200 /*3. 实现模块卸载函数*/201 static void __exit led_exit(void)202 {203unregister_chrdev_region(MKDEV(led_major, 0), 1);204device_destroy(s5pv_led_dev->led_class, MKDEV(led_major, 0));205class_destroy(s5pv_led_dev->led_class);206cdev_del(s5pv_led_dev->led_cdev);207kfree(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即可。

觉得不错,就给我点小支持吧

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。