Email:wei7758@126.com
Blog:http://blog.csdn.net/yinwei520
Author:Yww
Time:2011-9-24
Update:
(轉載請註明出處,謝謝)
這裡引用《Android系統級深入開發——移植與調試》一書中的解釋,關於真正的vibrator程式碼分析,是以我項目中的代碼為基礎。
一: 震動器系統結構和移植內容
震動器負責控制引動電話的震動功能,Android中的震動器系統是一個專供這方面功能的小系統,提供根據時間震動的功能。
震動器系統包含了驅動程式、硬體抽象層、JNI部分、Java架構類等幾個部分,也向Java應用程式層提供了簡單的API作為平台介面。
Android震動器系統的基本階層23-1所示。
圖23-1 Android震動器系統的基本階層
1 震動器部分的結構
Android震動器系統自下而上包含了驅動程式、震動器系統硬體抽象層、震動器系統Java架構類、Java架構中震動器系統使用等幾個部分,其結構23-2所示。
圖23-2 Android震動器系統的結構
自下而上,Android的震動器系統分成了以下部分。
(1)驅動程式:特定硬體平台震動器的驅動程式,通常基於Android的Timed Output驅動架構實現
(2)硬體抽象層
光系統硬體抽象層介面路徑為:hardware/libhardware_legacy/include/hardware_legacy/ vibrator.h
震動器系統的硬體抽象層在Android中已經具有預設實現,代碼路徑:
hardware/libhardware_legacy/vibrator/vibrator.c
震動器的硬體抽象層通常並不需要重新實現,是libhardware_legacy.so的一部分。
(3)JNI部分
代碼路徑:frameworks/base/services/jni/com_android_server_VibratorService.cpp
這個類是震動器的JNI部分,通過調用硬體抽象層向上層提供介面。
(4)Java部分
代碼路徑:
frameworks/base/services/java/com/android/server/VibratorService.java
frameworks/base/core/java/android/os/Vibrator.java
VibratorService.java通過調用,VibratorService JNI來實現com.android.server包中的VibratorService類。這個類不是平台的API,被Android系統Java架構中的一小部分調用。
Vibrator.java檔案實現了android.os包中的Vibrator類,這是向Java層提供的API。
2 移植內容
針對特定的硬體平台,震動器系統的移植有兩種方法。
第一種方法(通常情況):由於已經具有硬體抽象層,震動器系統的移植只需要實現驅動程式即可。這個驅動程式需要基於Android核心中的Timed Output驅動架構。
第二種方法:根據自己實現的驅動程式,重新實現震動器的硬體抽象層定義介面(需要在libhardware_legacy.so庫中),由于振動器硬體抽象層的介面非常簡單,因此這種實現方式也不會很複雜。
二: 移植與調試的要點
1 驅動程式
Vibrator的驅動程式只需要實現震動的介面即可,這是一個輸出裝置,需要接受震動時間作為參數。由於比較簡單,因此Vibrator的驅動程式可以使用多種方式來實現。
在Android中,推薦基於Android核心定義Timed Output驅動程式架構來實現Vibrator的驅動程式。
Timed Output的含義為定時輸出,用於定時發出某個輸出。實際上,這種驅動程式依然是基於sys檔案系統來完成的。
drivers/staging/android/目錄timed_output.h中定義timed_output_dev結構體,其中包含enable和get_time這兩個函數指標,實現結構體後,使用timed_output_dev_register()和timed_output_dev_unregister()函數註冊和登出即可。
Timed Output驅動程式架構將為每個裝置在/sys/class/timed_output/目錄中建立一個子目錄,裝置子目錄中的enable檔案就是裝置的控制檔案。讀enable檔案表示獲得剩餘時間,寫這個檔案表示根據時間震動。
Timed Output驅動的裝置調試,通過sys檔案系統即可。
對於Vibrator裝置,其實現的Timed Output驅動程式的名稱應該為“vibrator”。因此Vibrator裝置在sys檔案系統中的方法如下所示:
# echo "10000" > /sys/class/timed_output/vibrator/enable
# cat /sys/class/timed_output/vibrator/enable
3290
# echo "0" > /sys/class/timed_output/vibrator/enable
對於enable檔案,“寫”表示使能指定的時間,“讀”表示擷取剩餘時間。
2 硬體抽象層的內容
2.1 硬體抽象層的介面
Vibrator硬體抽象層的介面在hardware/libhardware_legacy/include/hardware_legacy/目錄的vibrator.h檔案中定義:
int vibrator_on(int timeout_ms);
// 開始震動
int vibrator_off();
// 關閉震動
vibrator.h檔案中定義兩個介面,分別表示震動和關閉,震動開始以毫秒(ms)作為時間單位。
提示:Timed Output類型驅動本身有獲得剩餘時間的能力(讀enable檔案),但是在Android Vibrator硬體抽象層以上的各層介面都沒有使用這個功能。
2.2 標準硬體抽象層的實現
Vibrator硬體抽象層具有標準的實現,在hardware/libhardware_legacy/vibrator/目錄的vibrator.c中。
其中實現的核心內容為sendit()函數,這個函數的內容如下所示:
#define THE_DEVICE "/sys/class/timed_output/vibrator/enable"static int sendit(int timeout_ms){ int nwr, ret, fd; char value[20];#ifdef QEMU_HARDWARE // 使用QEMU的情況 if (qemu_check()) { return qemu_control_command( "vibrator:%d", timeout_ms ); }#endif fd = open(THE_DEVICE, O_RDWR); // 讀取sys檔案系統中的內容 if(fd < 0) return errno; nwr = sprintf(value, "%d\n", timeout_ms); ret = write(fd, value, nwr); close(fd); return (ret == nwr) ? 0 : -1;}
sendit()函數負責根據時間“震動”:在真實的硬體中,通過sys檔案系統的檔案進行控制;如果是模擬器環境則通過QEMU發送命令。
vibrator_on()調用sendit()以時間作為參數,vibrator_on()調用sendit()以0作為參數。
上層的情況和注意事項
frameworks/base/services/jni/目錄中的com_android_server_VibratorService.cpp檔案是Vibrator硬體抽象層的調用者,它同時也向Java提供JNI支援。
其中,為JNI定義的方法列表如下所示:
static JNINativeMethod method_table[] = { { "vibratorOn", "(J)V", (void*)vibratorOn }, // 震動器開 { "vibratorOff", "()V", (void*)vibratorOff } // 震動器關 }; int register_android_server_VibratorService(JNIEnv *env) { return jniRegisterNativeMethods(env, "com/android/server/VibratorService", method_table, NELEM(method_table)); } //vibratorOn()和vibratorOff()這兩個函數的實現分別如下所示: static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms){ vibrator_on(timeout_ms); } static void vibratorOff(JNIEnv *env, jobject clazz){ vibrator_off(); }
frameworks/base/services/java/com/android/server/目錄中的VibratorService.java通過調用VibratorService JNI來實現com.android.server包中的VibratorService類。
frameworks/base/core/java/android/os/目錄中的Vibrator.java檔案實現了android.os包中的Vibrator類。它通過調用vibrator的Java服務來實現(獲得名稱為vibrator的服務),配合約目錄中的IVibratorService.aidl檔案嚮應用程式層提供Vibrator的相關API。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我具體的驅動程式
#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/device.h>#include <linux/workqueue.h>#include "timed_output.h"#include <linux/hrtimer.h>#include <linux/err.h>#include <linux/platform_device.h>#include <linux/spinlock.h>#include <linux/jiffies.h>#include <linux/timer.h>#include <mach/mt_typedefs.h>#include <mach/mt_pll.h>#include <mach/mt_gpt.h>#define VERSION "v 0.1"#define VIB_DEVICE "mt_vibrator"#define COUNT_DOWN_TIME50#define VIBR_HRTIMER#ifndef VIBR_HRTIMERXGPT_NUM Vibrator_XGPT = XGPT7;#endif/******************************************************************************Error Code No.******************************************************************************/#define RSUCCESS 0/******************************************************************************Debug Message Settings******************************************************************************//* Debug message event */#define DBG_EVT_NONE0x00000000/* No event */#define DBG_EVT_INT0x00000001/* Interrupt related event */#define DBG_EVT_TASKLET0x00000002/* Tasklet related event */#define DBG_EVT_ALL0xffffffff #define DBG_EVT_MASK (DBG_EVT_TASKLET)#if 1#define MSG(evt, fmt, args...) \do {\if ((DBG_EVT_##evt) & DBG_EVT_MASK) { \printk(fmt, ##args); \} \} while(0)#define MSG_FUNC_ENTRY(f)MSG(FUC, "<FUN_ENT>: %s\n", __FUNCTION__)#else#define MSG(evt, fmt, args...) do{}while(0)#define MSG_FUNC_ENTRY(f) do{}while(0)#endif#define VIBR_CON0 ((volatile unsigned long*)(0xF702F7B0))static int vibr_Enable(void){ printk("[vibrator]vibr_Enable \n");hwPowerOn(MT_POWER_LDO_VIBR, VOL_2800 , "VIBR");return 0;}static int vibr_Disable(void){ while((INREG32(VIBR_CON0)&1)) { printk("[vibrator]vibr_Disable \n");hwPowerDown(MT_POWER_LDO_VIBR , "VIBR"); //printk("[vibrator]vibr_Disable:VIBR_CON0=0x%x \r\n", INREG32(VIBR_CON0)); }return 0;}/******************************************************************************Global Definations******************************************************************************///static struct work_struct vibrator_work;static struct hrtimer vibe_timer;static spinlock_t vibe_lock;static int vibrator_get_time(struct timed_output_dev *dev){if (hrtimer_active(&vibe_timer)) {ktime_t r = hrtimer_get_remaining(&vibe_timer);return r.tv.sec * 1000 + r.tv.nsec / 1000000;} elsereturn 0;}static void vibrator_enable(struct timed_output_dev *dev, int value){ unsigned long flags;spin_lock_irqsave(&vibe_lock, flags); #ifdef VIBR_HRTIMERwhile(hrtimer_cancel(&vibe_timer)) { printk("[vibrator]vibrator_enable: try to cancel hrtimer \n"); }#else XGPT_Reset(Vibrator_XGPT); #endifif (value == 0) { printk("[vibrator]vibrator_enable: disable \n"); vibr_Disable(); }else {value = ((value > 15000) ? 15000 : value); printk("[vibrator]vibrator_enable: vibrator start: %d \n", value); #ifdef VIBR_HRTIMER hrtimer_start(&vibe_timer, ktime_set(value / 1000, (value % 1000) * 1000000),HRTIMER_MODE_REL); #else XGPT_CONFIG config;config.num = Vibrator_XGPT; config.clkDiv = 0; config.mode = XGPT_ONE_SHOT; config.bIrqEnable = TRUE; config.u4Compare = value*32768/1000; if(!XGPT_Config(config)) { printk("[vibrator]vibrator_enable: config XGPT: %d fail!\n", value); } XGPT_Start(Vibrator_XGPT); #endif vibr_Enable(); }spin_unlock_irqrestore(&vibe_lock, flags);}#ifdef VIBR_HRTIMERstatic enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer){ printk("[vibrator]vibrator_timer_func: vibrator will disable \n"); vibr_Disable(); return HRTIMER_NORESTART;}#elsevoid vibrator_timer_func(UINT16 temp){ printk("[vibrator]vibrator_timer_func: vibrator will disable \n"); vibr_Disable();}#endifstatic struct timed_output_dev mt_vibrator = {.name = "vibrator",.get_time = vibrator_get_time,.enable = vibrator_enable,};static int vib_probe(struct platform_device *pdev){return 0;}static int vib_remove(struct platform_device *pdev){return 0;}static void vib_shutdown(struct platform_device *pdev){vibr_Disable();}/******************************************************************************Device driver structure*****************************************************************************/static struct platform_driver vibrator_driver = { .probe= vib_probe,.remove = vib_remove, .shutdown = vib_shutdown, .driver = { .name = VIB_DEVICE, },};static ssize_t store_vibr_on(struct device *dev,struct device_attribute *attr, const char *buf, size_t size){if(buf != NULL && size != 0){printk("[vibrator]buf is %s and size is %d \n",buf,size);if(buf[0]== '0'){vibr_Disable();}else{vibr_Enable();}}return size;}static DEVICE_ATTR(vibr_on, 0664, NULL, store_vibr_on);/****************************************************************************** * vib_mod_init * * DESCRIPTION: * Register the vibrator device driver ! * * PARAMETERS: * None * * RETURNS: * None * * NOTES: * RSUCCESS : Success * ******************************************************************************/static s32 __devinit vib_mod_init(void){s32 ret;printk("Mk MT vibrator driver register, version %s\n", VERSION);spin_lock_init(&vibe_lock); #ifdef VIBR_HRTIMERhrtimer_init(&vibe_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);vibe_timer.function = vibrator_timer_func; #else XGPT_Init(Vibrator_XGPT, vibrator_timer_func); #endif timed_output_dev_register(&mt_vibrator); ret = platform_driver_register(&vibrator_driver); if(ret) {printk("[vibrator]Unable to register vibrator driver (%d)\n", ret);return ret; }ret = device_create_file(mt_vibrator.dev,&dev_attr_vibr_on); if(ret) { printk("[vibrator]device_create_file vibr_on fail! \n"); } printk("[vibrator]vib_mod_init Done \n"); return RSUCCESS;}/****************************************************************************** * vib_mod_exit * * DESCRIPTION: * Free the device driver ! * * PARAMETERS: * None * * RETURNS: * None * * NOTES: * None * ******************************************************************************/ static void __exit vib_mod_exit(void){printk("Mk MT vibrator driver unregister, version %s \n", VERSION);printk("[vibrator]vib_mod_exit Done \n");}module_init(vib_mod_init);module_exit(vib_mod_exit);MODULE_AUTHOR("Mk Inc.");MODULE_DESCRIPTION("MT Vibrator Driver (VIB)");MODULE_LICENSE("GPL");