android APK应用层到kernel层功能接口调用实现总结
客户有个需求需要在上层apk中控制手机上的VMIC、SPK、RAY_LED、OTG、SWITCH、PTT_SWITCH、PTT_PD、BULE_LED、KEYPAD_LED等按键、音频、镭射、OTG、灯的功能切换。其中部分功能是该手机上新增的功能,android原生系统上没有提供相关的接口,因此需要在原生系统框架上增加相关接口,实现APK应用中控制手机上的这些功能。
主要参考原生系统上APK到kernel层接口的调用框架实现,下面以该功能主要代码实现来简述APK应用层到kernel层功能接口调用实现。
1. apk应用主要代码实现
a. 文件packages\K508Control\src\com\android\tmptest\Test.java
package com.android.tmptest;
import android.content.Intent;
importandroid.content.SharedPreferences;
import android.os.Bundle;
importandroid.preference.CheckBoxPreference;
importandroid.preference.EditTextPreference;
importandroid.preference.ListPreference;
importandroid.preference.Preference;
importandroid.preference.PreferenceActivity;
importandroid.preference.PreferenceManager;
importandroid.preference.PreferenceScreen;
importandroid.preference.Preference.OnPreferenceClickListener;
import android.util.Log;
//importcom.android.server.K508ControlService;
import android.os.IK508ControlService;
import android.os.ServiceManager;
public class Test extendsPreferenceActivity implements
Preference.OnPreferenceClickListener,
Preference.OnPreferenceChangeListener{
privatePreference mPreference_VMIC;
privatePreference mPreference_SPK;
privatePreference mPreference_RAY;
privatePreference mPreference_OTG;
privatePreference mPreference_SWITCH;
privatePreference mPreference_PTT_SWITC;
privatePreference mPreference_PTT_PD;
privatePreference mPreference_BULE;
privatePreference mPreference_KEYPAD;
privateIK508ControlService k508Service = null;
@Override
publicvoid onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.d("zhengconglong","onCreate");
addPreferencesFromResource(R.xml.tp_test);
mPreference_VMIC =(Preference)findPreference("K508_IOC_VMIC_EN");
mPreference_SPK =(Preference)findPreference("K508_IOC_SPK_EN");
mPreference_RAY =(Preference)findPreference("K508_IOC_RAY_LED_EN");
mPreference_OTG =(Preference)findPreference("K508_IOC_OTG_EN");
mPreference_SWITCH =(Preference)findPreference("K508_IOC_SWITCH_EN");
mPreference_PTT_SWITC =(Preference)findPreference("K508_IOC_PTT_SWITCH_EN");
mPreference_PTT_PD =(Preference)findPreference("K508_IOC_PTT_PD");
mPreference_BULE =(Preference)findPreference("K508_IOC_BULE_LED_EN");
mPreference_KEYPAD =(Preference)findPreference("K508_IOC_KEYPAD_LED_EN");
mPreference_VMIC.setOnPreferenceClickListener(this);
mPreference_SPK.setOnPreferenceClickListener(this);
mPreference_RAY.setOnPreferenceClickListener(this);
mPreference_OTG.setOnPreferenceClickListener(this);
mPreference_SWITCH.setOnPreferenceClickListener(this);
mPreference_PTT_SWITC.setOnPreferenceClickListener(this);
mPreference_PTT_PD.setOnPreferenceClickListener(this);
mPreference_BULE.setOnPreferenceClickListener(this);
mPreference_KEYPAD.setOnPreferenceClickListener(this);
SharedPreferencesshp = PreferenceManager.getDefaultSharedPreferences(this);
k508Service= IK508ControlService.Stub.asInterface(ServiceManager.getService("K508Control"));
}
@Override
protectedvoid onResume() {
super.onResume();
}
@Override
protectedvoid onPause() {
super.onPause();
}
publicboolean setSummary(Preference pf) {
if(pf.getSummary().equals("false")){
pf.setSummary("true");
return true;
}else{
pf.setSummary("false");
return false;
}
}
@Override
public boolean onPreferenceClick(Preference preference) {
// Log.d("zhengconglong","onPreferenceClick");
if (preference == mPreference_VMIC) {
// Log.d("zhengconglong","111111");
if(setSummary(mPreference_VMIC)){
//mPreference_VMIC on
try {
k508Service.setVal(0,1);
}catch (Throwable e) {
Log.d("k508ServicemPreference_VMIC", "error");
}
Log.d("k508ServicemPreference_VMIC", "on");
} else {
//mPreference_VMIC off
try {
k508Service.setVal(0,0);
}catch (Throwable e) {
Log.d("k508ServicemPreference_VMIC", "error");
}
Log.d("k508ServicemPreference_VMIC", "off");
}
// Log.d("zhengconglong","K508_IOC_VMIC_EN");
}else if(preference.getKey().equals("K508_IOC_SPK_EN")) {
// Log.d("zhengconglong","22222");
if(setSummary(mPreference_SPK)){
try{
k508Service.setVal(1,1);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_SPK_EN", "error");
}
Log.d("k508ServicemPreference_SPK", "on");
} else {
try{
k508Service.setVal(1,0);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_SPK_EN", "error");
}
Log.d("k508Service mPreference_SPK","off");
}
}else if(preference.getKey().equals("K508_IOC_RAY_LED_EN")) {
if(setSummary(mPreference_RAY)){
try{
k508Service.setVal(2,1);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_RAY_LED_EN", "error");
}
Log.d("k508ServiceK508_IOC_RAY_LED_EN", "on");
} else {
try{
k508Service.setVal(2,0);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_RAY_LED_EN", "error");
}
Log.d("k508ServiceK508_IOC_RAY_LED_EN", "off");
}
}else if(preference.getKey().equals("K508_IOC_OTG_EN")) {
if(setSummary(mPreference_OTG)){
try{
k508Service.setVal(3,1);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_OTG_EN", "error");
}
Log.d("k508ServiceK508_IOC_OTG_EN", "on");
} else {
try{
k508Service.setVal(3,0);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_OTG_EN", "error");
}
Log.d("k508ServiceK508_IOC_OTG_EN", "off");
}
}else if(preference.getKey().equals("K508_IOC_SWITCH_EN")) {
if(setSummary(mPreference_SWITCH)){
try{
k508Service.setVal(4,1);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_SWITCH_EN", "error");
}
Log.d("k508ServiceK508_IOC_SWITCH_EN", "on");
} else {
try{
k508Service.setVal(4,0);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_SWITCH_EN", "error");
}
Log.d("k508ServiceK508_IOC_SWITCH_EN", "off");
}
}else if(preference.getKey().equals("K508_IOC_PTT_SWITCH_EN")){
if(setSummary(mPreference_PTT_SWITC)){
try{
k508Service.setVal(5,1);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_PTT_SWITCH_EN", "error");
}
Log.d("k508ServiceK508_IOC_PTT_SWITCH_EN", "on");
} else {
try{
k508Service.setVal(5,0);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_PTT_SWITCH_EN", "error");
}
Log.d("k508ServiceK508_IOC_PTT_SWITCH_EN", "off");
}
}elseif(preference.getKey().equals("K508_IOC_PTT_PD")) {
if(setSummary(mPreference_PTT_PD)){
try{
k508Service.setVal(6,1);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_PTT_PD", "error");
}
Log.d("k508ServiceK508_IOC_PTT_PD", "on");
} else {
try{
k508Service.setVal(6,0);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_PTT_PD", "error");
}
Log.d("k508ServiceK508_IOC_PTT_PD", "off");
}
}else if(preference.getKey().equals("K508_IOC_BULE_LED_EN")) {
if(setSummary(mPreference_BULE)){
try{
k508Service.setVal(7,1);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_BULE_LED_EN", "error");
}
Log.d("k508ServiceK508_IOC_BULE_LED_EN", "on");
} else {
try{
k508Service.setVal(7,0);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_BULE_LED_EN", "error");
}
Log.d("k508ServiceK508_IOC_BULE_LED_EN", "off");
}
}else if(preference.getKey().equals("K508_IOC_KEYPAD_LED_EN")){
if(setSummary(mPreference_KEYPAD)){
try{
k508Service.setVal(8,1);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_KEYPAD_LED_EN", "error");
}
Log.d("k508ServiceK508_IOC_KEYPAD_LED_EN", "on");
} else {
try{
k508Service.setVal(8,0);
}catch (Throwable e) {
Log.d("k508ServiceK508_IOC_KEYPAD_LED_EN", "error");
}
Log.d("k508ServiceK508_IOC_KEYPAD_LED_EN", "off");
}
}
return false;
}
@Override
publicboolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
Log.d("zhengconglong","onPreferenceTreeClick");
returnfalse;
}
@Override
publicboolean onPreferenceChange(Preference preference, Object objValue) {
Log.i("zheng","onPreferenceChange----->"
+String.valueOf(preference.getKey()));
if(preference == mPreference_RAY) {
Log.i("zheng","W " + String.valueOf(objValue));
}else if (preference.getKey().equals("K508_IOC_SPK_EN")) {
Log.i("zheng","internet " + String.valueOf(objValue));
returnfalse;
}else if (preference == mPreference_SWITCH) {
Log.i("zheng"," NewDeptName" + objValue);
}else if (preference.getKey().equals("K508_IOC_PTT_PD")) {
Log.i("zheng","change" + String.valueOf(objValue));
}else if (preference == mPreference_KEYPAD) {
Log.i("zheng","Old Value = " + String.valueOf(objValue));
returnfalse;
}
returntrue;
}
}
2. frameworks 服务层主要代码实现:
a. frameworks/base/Android.mk
红色部分为增加的代码
………
core/java/android/os/IPowerManager.aidl \
core/java/android/os/IRemoteCallback.aidl \
core/java/android/os/IVibratorService.aidl \
core/java/android/os/IK508ControlService.aidl \
core/java/android/service/wallpaper/IWallpaperConnection.aidl \
……….
b. 该文件为新增文件
frameworks/base/core/java/android/os/IK508ControlService.aidl
代码实现如下:
package android.os;
interface IK508ControlService
{
voidsetVal(int cmd,long arg);
}
c. 该文件为新增文件
frameworks/base/services/java/com/android/server/K508ControlService.java
代码实现如下:
package com.android.server;
import android.content.Context;
importandroid.os.IK508ControlService;
import android.util.Slog;
public class K508ControlService extendsIK508ControlService.Stub
{
private static final String TAG = "K508ControlService";
K508ControlService() {
init_native();
}
public void setVal(int cmd,long arg) {
setVal_native(cmd,arg);
}
private static native int init_native();
private static native void setVal_native(int cmd,long arg);
};
d.frameworks/base/services/java/com/android/server/SystemServer.java
红色部分为增加的代码
importcom.android.server.K508ControlService;
public void run() {
…………..
try {
ActivityManagerNative.getDefault().showBootMessage(
context.getResources().getText(
com.android.internal.R.string.android_upgrading_starting_apps),
false);
} catch (RemoteException e) {
}
try {
Slog.e(TAG, "K508Control Service");
ServiceManager.addService("K508Control", newK508ControlService());
} catch (Throwable e) {
Slog.e(TAG, "Failure startingK508Control Service", e);
}
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
try {
Slog.i(TAG, "DevicePolicy");
devicePolicy = newDevicePolicyManagerService(context);
ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy);
} catch (Throwable e) {
reportWtf("startingDevicePolicyService", e);
}
…………….
}
3. frameworks JNI层主要代码实现:
a.frameworks/base/services/jni/Android.mk
红色部分为增加的代码
……………
com_android_server_VibratorService.cpp \
com_android_server_location_GpsLocationProvider.cpp \
com_android_server_connectivity_Vpn.cpp \
com_android_server_K508ControlService.cpp \
onload.cpp
…………….
b. 新增文件
frameworks/base/services/jni/com_android_server_K508ControlService.cpp
代码实现如下:
#define LOG_TAG"K508ControlService"
#include "jni.h"
#include "JNIHelp.h"
#include"android_runtime/AndroidRuntime.h"
#include
#include
#include
#include
#include
namespace android
{
struct k508_device_t* k508_device = NULL;
static void k508_setVal(JNIEnv* env, jobject clazz, jint cmd,jlong arg)
{
intcmd1 = cmd;
longarg1= arg;
LOGI("K508ControlJNI: set cmd = %d ,arg=%d to device.", cmd1,arg1);
if(!k508_device){
LOGI("K508ControlJNI: device is not open.");
return;
}
k508_device->set_val(k508_device,cmd1,arg1);
}
staticinline int k508_device_open(const hw_module_t* module, struct k508_device_t**device)
{
returnmodule->methods->open(module, k508_HARDWARE_MODULE_ID, (structhw_device_t**)device);
}
staticint k508_init(JNIEnv* env, jclass clazz)
{
k508_module_t*module;
LOGI("k508JNI: initializing......");
if(hw_get_module(k508_HARDWARE_MODULE_ID,(const struct hw_module_t**)&module) == 0) {
LOGI("k508JNI: Stub found.");
if(k508_device_open(&(module->common),&k508_device) == 0) {
LOGI("k508JNI: device is open.");
return0;
}
LOGE("k508JNI: failed to open device.");
return-1;
}
LOGE("k508JNI: failed to get stub module.");
return-1;
}
staticconst JNINativeMethod method_table[] = {
{"init_native","()I", (void*)k508_init},
{"setVal_native","(IJ)V", (void*)k508_setVal},
};
intregister_android_server_K508ControlService(JNIEnv *env)
{
returnjniRegisterNativeMethods(env,"com/android/server/K508ControlService", method_table,NELEM(method_table));
}
};
c. frameworks/base/services/jni/onload.cpp
红色部分为增加的代码
namespace android {
………….
intregister_android_server_connectivity_Vpn(JNIEnv* env);
intregister_android_server_K508ControlService(JNIEnv *env);
};
extern "C" jintJNI_OnLoad(JavaVM* vm, void* reserved)
{
…………….
register_android_server_connectivity_Vpn(env);
register_android_server_K508ControlService(env);
return JNI_VERSION_1_4;
}
4. 增加一个节点并修改权限
a. mediatek/config/mt6577/init.rc
红色部分为增加的代码
………….
chmod 0660 /dev/OV8825AF
chmod 0660 /dev/OV8830AF
chmod0666 /dev/K508_CONTROL
………….
chownsystem camera /dev/OV8825AF
chownsystem camera /dev/OV8830AF
chown system system /dev/K508_CONTROL
……………
5. hardware 层主要修改:
a. 新增文件
hardware/libhardware/include/hardware/K508Control.h
代码实现如下:
#ifndef ANDROID_K508_INTERFACE_H
#define ANDROID_K508_INTERFACE_H
#include
__BEGIN_DECLS
#define k508_HARDWARE_MODULE_ID"k508control"
struct k508_module_t {
struct hw_module_t common;
};
struct k508_device_t {
struct hw_device_t common;
int fd;
void (*set_val)(struct k508_device_t* dev, int cmd,long arg);
};
__END_DECLS
#define K508_IOC_MAGIC 'H'
#define K508_IOC_VMIC_EN _IO(K508_IOC_MAGIC, 0) // 音频控制
#define K508_IOC_SPK_EN _IO(K508_IOC_MAGIC, 1) // 音频控制
#define K508_IOC_RAY_LED_EN _IO(K508_IOC_MAGIC, 2) // 对方修改
#define K508_IOC_OTG_EN _IO(K508_IOC_MAGIC, 3) // 不确定
#define K508_IOC_SWITCH_EN _IO(K508_IOC_MAGIC, 4) // 双方控
#define K508_IOC_PTT_SWITCH_EN _IO(K508_IOC_MAGIC, 5) // 双方控
#define K508_IOC_PTT_PD _IO(K508_IOC_MAGIC, 6) // 双方控
#define K508_IOC_BULE_LED_EN _IO(K508_IOC_MAGIC, 7) // 不确定
#define K508_IOC_KEYPAD_LED_EN _IO(K508_IOC_MAGIC, 8) // 光感加接口
#define MAX_K508_IOCTL_CMD_NUM 15
#endif
b. 新增文件
mediatek/source/hardware/K508Control/K508Control.c
代码实现如下:
#define LOG_TAG "k508Stub"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME"/dev/K508_CONTROL"
#define MODULE_NAME"K508_CONTROL"
#define MODULE_AUTHOR"feng.guangyue
const int K508_CMD[]=
{
K508_IOC_VMIC_EN,
K508_IOC_SPK_EN,
K508_IOC_RAY_LED_EN,
K508_IOC_OTG_EN,
K508_IOC_SWITCH_EN,
K508_IOC_PTT_SWITCH_EN,
K508_IOC_PTT_PD,
K508_IOC_BULE_LED_EN,
K508_IOC_KEYPAD_LED_EN
};
static int k508_device_open(const structhw_module_t* module, const char* name, struct hw_device_t** device);
static int k508_device_close(structhw_device_t* device);
static void k508_set_val(structk508_device_t* dev, int cmd,long arg);
static struct hw_module_methods_tk508_module_methods = {
open: k508_device_open
};
struct k508_module_t HAL_MODULE_INFO_SYM= {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: k508_HARDWARE_MODULE_ID,
name: MODULE_NAME,
author: MODULE_AUTHOR,
methods: &k508_module_methods,
}
};
static int k508_device_open(const structhw_module_t* module, const char* name, struct hw_device_t** device)
{
struct k508_device_t* dev;
dev= (struct k508_device_t *)malloc(sizeof(struct k508_device_t));
if(!dev) {
LOGE("k508 Stub: failed to alloc space");
return -EFAULT;
}
memset(dev, 0, sizeof(struct k508_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (hw_module_t*)module;
dev->common.close = k508_device_close;
dev->set_val = k508_set_val;
if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {
LOGE("k508 Stub: failed to open /dev/K508_CONTROL -- %s.",strerror(errno));
free(dev);
return -EFAULT;
}
*device = &(dev->common);
LOGI("k508 Stub: open /dev/K508_CONTROL successfully.");
return 0;
}
static int k508_device_close(structhw_device_t* device)
{
struct k508_device_t* k508_device = (struct k508_device_t*)device;
if(k508_device) {
close(k508_device->fd);
free(k508_device);
}
return 0;
}
static void k508_set_val(structk508_device_t* dev, int cmd,long arg)
{
LOGI("k508 Stub: set value cmd =%d,arg=%d to device.",cmd,arg);
ioctl(dev->fd, K508_CMD[cmd], arg);
}
c. 新增文件
mediatek/source/hardware/K508Control/Android.mk
代码实现如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := K508Control.c
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH :=$(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MODULE := k508control.default
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
6. kernel 层代码实现
a. 新增文件
mediatek/platform/mt6577/kernel/drivers/k508_control/Makefile
代码实现如下
obj-y +=k508_control.o
b. 新增文件
mediatek/platform/mt6577/kernel/drivers/k508_control/k508_control.h
代码实现如下
#ifndef_K508_CONTROL_H_
#define_K508_CONTROL_H_
#include
#include
#defineK508_DEVICE_NAME "K508_CONTROL"
structk508_android_dev
{
int used;
struct mutex sem;
struct cdev dev;
};
static intdebug_enable = 1;
#define K508_CONTROL_DEBUG(format,args...) do{ \
if(debug_enable) \
{\
printk(KERN_ERR format,##args);\
}\
}while(0)
#endif
c. 新增文件
mediatek/platform/mt6577/kernel/drivers/k508_control/k508_control.c
代码实现如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "mach/mt_gpio.h"
#include
#include
#include
#include
#include
#include
#include
#include "k508_control.h"
#define K508_IOC_MAGIC 'H'
#define K508_IOC_VMIC_EN _IO(K508_IOC_MAGIC, 0)
#define K508_IOC_SPK_EN _IO(K508_IOC_MAGIC, 1)
#define K508_IOC_RAY_LED_EN _IO(K508_IOC_MAGIC, 2)
#define K508_IOC_OTG_EN _IO(K508_IOC_MAGIC, 3)
#define K508_IOC_SWITCH_EN _IO(K508_IOC_MAGIC, 4)
#define K508_IOC_PTT_SWITCH_EN _IO(K508_IOC_MAGIC, 5)
#define K508_IOC_PTT_PD _IO(K508_IOC_MAGIC, 6)
#define K508_IOC_BULE_LED_EN _IO(K508_IOC_MAGIC, 7)
#define K508_IOC_KEYPAD_LED_EN _IO(K508_IOC_MAGIC, 8)
#define MAX_K508_IOCTL_CMD_NUM 15
static int k508_major = 0;
static int k508_minor = 0;
static struct class* k508_class =NULL;
static struct k508_android_dev* k508_dev= NULL;
static int k508_open(struct inode*inode, struct file* filp);
static int k508_release(struct inode*inode, struct file* filp);
static long k508_unlocked_ioctl(structfile *file, unsigned int cmd,unsigned long arg);
static struct file_operations k508_fops= {
.owner = THIS_MODULE,
.open = k508_open,
.release = k508_release,
.unlocked_ioctl= k508_unlocked_ioctl,
};
static int k508_setup_dev(structk508_android_dev* dev) ;
static int k508_control_probe(structplatform_device *dev)
{
interr = -1;
dev_ttmp_dev = 0;
structdevice* temp = NULL;
K508_CONTROL_DEBUG("Initializing k508 device./n");
if (k508_major)
{
tmp_dev= MKDEV(k508_major, k508_minor);
err= register_chrdev_region(tmp_dev, 1, K508_DEVICE_NAME);
}
else
{
err= alloc_chrdev_region(&tmp_dev, 0, 1, K508_DEVICE_NAME);
k508_major= MAJOR(tmp_dev);
k508_minor= MINOR(tmp_dev);
}
if(err< 0)
{
K508_CONTROL_DEBUG(KERN_INFO":register_chrdev err=%d\n", err);
return-EIO;
}
k508_dev= kmalloc(sizeof(struct k508_android_dev), GFP_KERNEL);
if(!k508_dev)
{
err= -ENOMEM;
K508_CONTROL_DEBUG("Failedto alloc k508_dev./n");
gotounregister;
}
err= k508_setup_dev(k508_dev);
if(err)
{
K508_CONTROL_DEBUG("Failedto setup dev: %d./n", err);
gotocleanup;
}
k508_class= class_create(THIS_MODULE, K508_DEVICE_NAME);
if(IS_ERR(k508_class))
{
err= PTR_ERR(k508_class);
K508_CONTROL_DEBUG("Failedto create k508 class./n");
gotodestroy_cdev;
}
temp= device_create(k508_class, NULL, tmp_dev, "%s",K508_DEVICE_NAME);
if(IS_ERR(temp))
{
err= PTR_ERR(temp);
K508_CONTROL_DEBUG("Failedto create k508 device.");
gotodestroy_class;
}
dev_set_drvdata(temp,k508_dev);
K508_CONTROL_DEBUG("Succeddedto initialize k508 device./n");
return0;
destroy_device:
device_destroy(k508_class,tmp_dev);
destroy_class:
class_destroy(k508_class);
destroy_cdev:
cdev_del(&(k508_dev->dev));
cleanup:
kfree(k508_dev);
unregister:
unregister_chrdev_region(MKDEV(k508_major,k508_minor), 1);
fail:
returnerr;
}
static int k508_control_suspend(structplatform_device *dev, pm_message_t state) // only one suspend mode
{
return0;
}
static int k508_control_resume(structplatform_device *dev) // wake up
{
return0;
}
static int k508_control_remove(structplatform_device *dev)
{
dev_tdevno = MKDEV(k508_major, k508_minor);
K508_CONTROL_DEBUG("Destroyk508 device./n");
if(k508_class)
{
device_destroy(k508_class,MKDEV(k508_major, k508_minor));
class_destroy(k508_class);
}
if(k508_dev)
{
cdev_del(&k508_dev->dev);
kfree(k508_dev);
}
unregister_chrdev_region(devno,1);
return0;
}
static struct platform_driverk508_control_driver =
{
.probe = k508_control_probe,
.suspend =k508_control_suspend,
.resume = k508_control_resume,
.remove = k508_control_remove,
.driver = {
.name ="k508_control_Driver",
},
};
static struct platform_devicek508_control_device = {
.name ="k508_control_Driver",
.id = -1,
};
static int k508_open(struct inode*inode, struct file* filp)
{
mutex_lock(&k508_dev->sem);
k508_dev->used++;
mutex_unlock(&k508_dev->sem);
K508_CONTROL_DEBUG("k508_opencontuer k508_dev->used = %d\n",k508_dev->used);
// if(k508_dev->used> 1)
// {
// k508_dev->used--;
// return-EBUSY;
// }
return 0;
}
static int k508_release(struct inode*inode, struct file* filp)
{
mutex_lock(&k508_dev->sem);
if(k508_dev->used!= 0)
k508_dev->used--;
mutex_unlock(&k508_dev->sem);
K508_CONTROL_DEBUG("k508_releasecontuer k508_dev->used = %d\n",k508_dev->used);
return 0;
}
extern void set_led_on_off(intchannel,int on);
static long k508_unlocked_ioctl(structfile *file, unsigned int cmd,unsigned long arg)
{
longerr = 0;
inttmp=0;
void__user *ptr;
mutex_lock(&k508_dev->sem);
ptr= (void __user*) arg;
get_user(tmp,(int*)(&ptr));
mutex_unlock(&k508_dev->sem);
K508_CONTROL_DEBUG("k508_unlocked_ioctlcmd=%d,tmp=%d\n",cmd,tmp);
if(_IOC_TYPE(cmd) != K508_IOC_MAGIC ) {
return-ENOTTY;
}
if(_IOC_NR(cmd) > MAX_K508_IOCTL_CMD_NUM ) {
return-ENOTTY;
}
if(_IOC_DIR(cmd) & _IOC_READ) {
err= !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
}else if (_IOC_DIR(cmd) & _IOC_WRITE) {
err= !access_ok(VERIFY_READ, (void *)arg,_IOC_SIZE(cmd));
}
if(err) {
K508_CONTROL_DEBUG("!!argerror!!\n");
return-EFAULT;
}
switch(cmd)
{
caseK508_IOC_VMIC_EN:
mt_set_gpio_mode(GPIO_VMIC_EN,GPIO_VMIC_EN_M_GPIO);
mt_set_gpio_dir(GPIO_VMIC_EN,GPIO_DIR_OUT);
if(tmp== 0)
mt_set_gpio_out(GPIO_VMIC_EN,GPIO_OUT_ZERO);
else
mt_set_gpio_out(GPIO_VMIC_EN,GPIO_OUT_ONE);
break;
caseK508_IOC_SPK_EN:
mt_set_gpio_mode(GPIO_SPK_EN,GPIO_SPK_EN_M_GPIO);
mt_set_gpio_dir(GPIO_SPK_EN,GPIO_DIR_OUT);
if(tmp== 0)
mt_set_gpio_out(GPIO_SPK_EN,GPIO_OUT_ZERO);
else
mt_set_gpio_out(GPIO_SPK_EN,GPIO_OUT_ONE);
break;
caseK508_IOC_RAY_LED_EN:
mt_set_gpio_mode(GPIO_RAY_LED_EN,GPIO_RAY_LED_EN_M_GPIO);
mt_set_gpio_dir(GPIO_RAY_LED_EN,GPIO_DIR_OUT);
if(tmp== 0)
mt_set_gpio_out(GPIO_RAY_LED_EN,GPIO_OUT_ZERO);
else
mt_set_gpio_out(GPIO_RAY_LED_EN,GPIO_OUT_ONE);
break;
caseK508_IOC_OTG_EN:
// mt_set_gpio_mode(GPIO_OTG_EN,GPIO_OTG_EN_M_GPIO);
// mt_set_gpio_dir(GPIO_OTG_EN,GPIO_DIR_OUT);
// if(tmp== 0)
// mt_set_gpio_out(GPIO_OTG_EN,GPIO_OUT_ZERO);
// else
// mt_set_gpio_out(GPIO_OTG_EN,GPIO_OUT_ONE);
break;
caseK508_IOC_SWITCH_EN:
mt_set_gpio_mode(GPIO_SWITCH_EN,GPIO_SWITCH_EN_M_GPIO);
mt_set_gpio_dir(GPIO_SWITCH_EN,GPIO_DIR_OUT);
if(tmp== 0)
mt_set_gpio_out(GPIO_SWITCH_EN,GPIO_OUT_ZERO);
else
mt_set_gpio_out(GPIO_SWITCH_EN,GPIO_OUT_ONE);
break;
caseK508_IOC_PTT_SWITCH_EN:
mt_set_gpio_mode(GPIO_PTT_SWITCH_EN,GPIO_PTT_SWITCH_EN_M_GPIO);
mt_set_gpio_dir(GPIO_PTT_SWITCH_EN,GPIO_DIR_OUT);
if(tmp== 0)
mt_set_gpio_out(GPIO_PTT_SWITCH_EN,GPIO_OUT_ZERO);
else
mt_set_gpio_out(GPIO_PTT_SWITCH_EN,GPIO_OUT_ONE);
break;
caseK508_IOC_PTT_PD:
mt_set_gpio_mode(GPIO_PTT_PD,GPIO_PTT_PD_M_GPIO);
mt_set_gpio_dir(GPIO_PTT_PD,GPIO_DIR_OUT);
if(tmp== 0)
mt_set_gpio_out(GPIO_PTT_PD,GPIO_OUT_ONE);
else
mt_set_gpio_out(GPIO_PTT_PD,GPIO_OUT_ZERO);
break;
caseK508_IOC_BULE_LED_EN:
K508_CONTROL_DEBUG("K508_IOC_BULE_LED_ENtmp=%d\n",tmp);
if(tmp== 0)
set_led_on_off(4,0);
else
set_led_on_off(4,1);
break;
caseK508_IOC_KEYPAD_LED_EN:
if(tmp== 0)
set_led_on_off(5,0);
else
set_led_on_off(5,1);
break;
default:
break;
}
returnerr;
}
static int k508_setup_dev(structk508_android_dev* dev)
{
int err;
dev_t devno = MKDEV(k508_major, k508_minor);
memset(dev, 0, sizeof(struct k508_android_dev));
cdev_init(&(dev->dev), &k508_fops);
dev->dev.owner = THIS_MODULE;
dev->dev.ops = &k508_fops;
err = cdev_add(&(dev->dev),devno, 1);
if(err) {
return err;
}
dev->used= 0;
mutex_init(&dev->sem);
return 0;
}
static int __initk508_control_init(void)
{
intret = 0;
ret = platform_device_register(&k508_control_device);
if(ret != 0)
{
K508_CONTROL_DEBUG("[508_control]platform_device_registererror:(%d)\n", ret);
returnret;
}
ret = platform_driver_register(&k508_control_driver);
if (ret)
{
K508_CONTROL_DEBUG("[508_control]platform_driver_registererror:(%d)\n", ret);
return ret;
}
return0;
}
static void __exitk508_control_exit(void)
{
K508_CONTROL_DEBUG("[508_control]k508_control_exit\n");
platform_driver_unregister(&k508_control_driver);
platform_device_unregister(&k508_control_device);
}
late_initcall(k508_control_init);
module_exit(k508_control_exit);
MODULE_DESCRIPTION("k508control");
MODULE_VERSION("V1.0");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("feng.guangyue
上面apk应用模块到kernel层代码实现,接口调用顺序如下:
1. apk模块实现packages/K508Control
2. frameworks服务层
apk模块与frameworks服务模块通过AIDL(Android Interface Definition Language,android内部进程通信接口)机制进行交互;
实现文件如下:
frameworks/base/Android.mk
新增:frameworks/base/core/java/android/os/IK508ControlService.aidl
新增:frameworks/base/services/java/com/android/server/K508ControlService.java
frameworks/base/services/java/com/android/server/SystemServer.java
3. frameworks JNI层
frameworks服务模块通过JNI机制与hardware层交互;
实现文件如下:
frameworks/base/services/jni/onload.cpp
frameworks/base/services/jni/Android.mk
新增:frameworks/base/services/jni/com_android_server_K508ControlService.cpp
4. 增加一个节点,用于读写参数
mediatek/config/mt6577/init.rc
5. hardware层
实现文件如下:
新增:mediatek/source/hardware/K508Control/Android.mk
新增:mediatek/source/hardware/K508Control/K508Control.c
新增:hardware/libhardware/include/hardware/K508Control.h
6. kernel层
实现文件如下:
新增:mediatek/platform/mt6577/kernel/drivers/k508_control/Makefile
新增:mediatek/platform/mt6577/kernel/drivers/k508_control/k508_control.c
新增:mediatek/platform/mt6577/kernel/drivers/k508_control/k508_control.h