版权声明:本文为博主原创文章,未经博主允许转载。 https://blog.csdn.net/jklinux/article/details/79853414
设备驱动代码:
/* myled.c */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <mach/gpio.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#define LED_IO GPIOA(15)
long myioctl(struct file *fl, unsigned int cmd, unsigned long arg)
{
if (cmd) // led on
gpio_set_value(LED_IO, 1);
else // led off
gpio_set_value(LED_IO, 0);
return 0;
}
struct file_operations fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = myioctl,
};
struct miscdevice mdev = {
.minor = MISC_DYNAMIC_MINOR,
.fops = &fops,
.name = "myled",
};
static int __init test_init(void)
{
gpio_request(LED_IO, "mydev"); //请求gpio口
gpio_direction_output(LED_IO, 0); //配置gpio口为输出,先输出低电平
return misc_register(&mdev);
}
static void __exit test_exit(void)
{
misc_deregister(&mdev);
gpio_free(LED_IO); //释放gpio
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
/* Makefile */
obj-m += myled.o
KSRC := /home/jk/Downloads/h3_android/lichee/linux-3.4
export ARCH := arm
export CROSS_COMPILE := arm-linux-gnueabi-
all:
make -C $(KSRC) modules M=`pwd`
.PHONY : clean
clean:
make -C $(KSRC) modules clean M=`pwd`
编译完成后,可通过”adb push myled.ko /” 推送到板子上,然后在板上”insmod myled.ko”加载驱动模块. 加载后, 会在产生一个”/dev/myled”设备文件.
注意,加载驱动模块前须确认”gpio_sunxi”模块是否已加载,因此模块也会占用gpio口,所以可能需要卸载gpio_sunxi模块后才可以加载myled模块
通过应用程序来测试驱动的工作:
/* myapp.c */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd = open("/dev/myled", O_RDWR);
if (fd < 0)
return 1;
ioctl(fd, atoi(argv[1]));
close(fd);
return 0;
}
可以把通过静态编译产生的程序推送到板子上执行。
也可以编译出使用Android系统动态库的程序,需要编写Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := myapp.c
LOCAL_MODULE := myapp
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
然后,进入Android系统源码目录下:
. ./build/envsetup.sh
lunch dolphin_fvd_p1-eng
mmm myapp.c所在的目录路径
编译完成后, 生成的程序在out/target/product/dolphin-fvd-p1/system/bin/myapp
Android App上的调用:
/* MyJni.java */
package com.jk;
public class MyJni {
static {
System.loadLibrary("myjni");
}
public native int ledOn();
public native int ledOff();
}
生成的JNI文件:
/* com_jk_MyJni.h */
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_jk_MyJni */
#ifndef _Included_com_jk_MyJni
#define _Included_com_jk_MyJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_jk_MyJni
* Method: ledOn
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_jk_MyJni_ledOn
(JNIEnv *, jobject);
/*
* Class: com_jk_MyJni
* Method: ledOff
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_jk_MyJni_ledOff
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
/* com_jk_MyJni.cpp */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "com_jk_MyJni.h"
JNIEXPORT jint JNICALL Java_com_jk_MyJni_ledOn
(JNIEnv *env, jobject obj)
{
int fd = open("/dev/myled", O_RDWR);
if (fd < 0)
return -1;
ioctl(fd, 1);
close(fd);
return 0;
}
JNIEXPORT jint JNICALL Java_com_jk_MyJni_ledOff
(JNIEnv *env, jobject obj)
{
int fd = open("/dev/myled", O_RDWR);
if (fd < 0)
return -1;
ioctl(fd, 0);
close(fd);
return 0;
}
/* MainActivity.java */
package com.example.helloworld;
import com.jk.MyJni;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
private Button btn1, btn2;
private MyJni myjni = new MyJni();
private byte [] data = new byte[1024];
private OnClickListener lt = new OnClickListener() {
public void onClick(View arg0) {
if (btn1 == arg0) {
// led on
myjni.ledOn();
}
if (btn2 == arg0) {
myjni.ledOff();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button)findViewById(R.id.btn_ledon);
btn2 = (Button)findViewById(R.id.btn_ledoff);
btn1.setOnClickListener(lt);
btn2.setOnClickListener(lt);
}
}
同时需要注意,设备驱动产生的/dev/myled设备文件默认Android app是无权限访问的,可以通过”chmod 0666 /dev/myled”设置权限,以便访问调用.