概述
本人才疏浅学,写一篇文档总结自己在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:%sn",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:%sn",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:%sn",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:--------------^_&--------------------n",__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 errorn",__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!n");
35 return ret;
36 }
37
38 printk(KERN_INFO "zbzhuang### val=%dn", 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!n");
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 onn");
59 }
60 else
61 {
62 /*熄灭LED*/
63 // *gpc0dat &= ~((0x1<<3)|(0x1<<4));
64 printk(KERN_ERR "zbzhuang### led offn");
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-------------n",__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-----------------n",__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!n");
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_classn");
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_devicen");
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即可。
觉得不错,就给我点小支持吧
最后
以上就是不安流沙为你收集整理的Android字符设备驱动开发基于高通msm8916【原创 】的全部内容,希望文章能够帮你解决Android字符设备驱动开发基于高通msm8916【原创 】所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复