Android平台中震動器系統詳解

來源:互聯網
上載者:User

       

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");

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.