一:  振动器系统结构和移植内容

振动器负责控制引动电话的振动功能,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驱动提供上层接口有很多种,这里介绍两种方式:一种是timeout方式,一种是属性节点。

一、timeout方式

         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文件,“写”表示使能指定的时间,“读”表示获取剩余时间。

二 文件属性节点

         这种方法就是直接用kernel sys系统创建文件节点,提供上层接口,直接操作底层gpio口或者PWM等控制器。

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()函数,这个函数的内容如下所示:


[html] view plain copy print ?


1. <PRE class=cpp name="code">#define THE_DEVICE "/sys/class/timed_output/vibrator/enable"  
2.   
3. static int sendit(int timeout_ms)  
4.   
5. {  
6.   
7.     int nwr, ret, fd;  
8.   
9.     char value[20];  
10.   
11. #ifdef QEMU_HARDWARE                // 使用QEMU的情况  
12.   
13.     if (qemu_check()) {  
14.   
15.         return qemu_control_command( "vibrator:%d", timeout_ms );  
16.   
17.     }  
18.   
19. #endif  
20.   
21. fd = open(THE_DEVICE, O_RDWR);               // 读取sys文件系统中的内容  
22.   
23. < 0) return errno;  
24.   
25. nwr = sprintf(value, "%d\n", timeout_ms);  
26.   
27. ret = write(fd, value, nwr);  
28.   
29.     close(fd);  
30.   
31. ret
32.   
33. }  
34.   
35. </PRE><BR>
36. <PRE></PRE>
37. <P> </P>
38. <P>sendit()函数负责根据时间“振动”:在真实的硬件中,通过sys文件系统的文件进行控制;如果是模拟器环境则通过QEMU发送命令。</P>
39. <P>vibrator_on()调用sendit()以时间作为参数,vibrator_on()调用sendit()以0作为参数。</P>
40. <P> </P>
41. <P><STRONG>上层的情况和注意事项</STRONG></P>
42. <P>  frameworks/base/services/jni/目录中的com_android_server_VibratorService.cpp文件是Vibrator硬件抽象层的调用者,它同时也向Java提供JNI支持。</P>
43. <P>  其中,为JNI定义的方法列表如下所示:</P>
44. <P>  </P>
45. <PRE class=cpp name="code">
46.   
47.   { "vibratorOn", "(J)V", (void*)vibratorOn }, // 振动器开  
48.   
49.   { "vibratorOff", "()V", (void*)vibratorOff } // 振动器关  
50.   
51.   };  
52.   
53.   int register_android_server_VibratorService(JNIEnv *env) {  
54.   
55.   return jniRegisterNativeMethods(env, "com/android/server/VibratorService",  
56.   
57.   method_table, NELEM(method_table));  
58.   
59.   }  
60.   //vibratorOn()和vibratorOff()这两个函数的实现分别如下所示:  
61.   
62.      
63.   
64.   static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms){  
65.   
66.   vibrator_on(timeout_ms);  
67.   
68.   }  
69.   
70.   static void vibratorOff(JNIEnv *env, jobject clazz){  
71.   
72.   vibrator_off();  
73.   
74.   }  
75.   
76. </PRE>
77. <P><BR>
78. </P>
79. <P>        frameworks/base/services/java/com/android/server/目录中的VibratorService.java通过调用VibratorService JNI来实现com.android.server包中的VibratorService类。</P>
80. <P>  frameworks/base/core/java/android/os/目录中的Vibrator.java文件实现了android.os包中的Vibrator类。它通过调用vibrator的Java服务来实现(获得名称为vibrator的服务),配合同目录中的IVibratorService.aidl文件向应用程序层提供Vibrator的相关API。</P>
81. <P>-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------</P>
82. <P><STRONG>Timeout方式的驱动程序</STRONG></P>
83. <STRONG></STRONG><PRE class=cpp name="code">#include <linux/init.h>
84. #include <linux/module.h>
85. #include <linux/kernel.h>
86. #include <linux/types.h>
87. #include <linux/device.h>
88. #include <linux/workqueue.h>
89.   
90. #include "timed_output.h"  
91. #include <linux/hrtimer.h>
92. #include <linux/err.h>
93. #include <linux/platform_device.h>
94. #include <linux/spinlock.h>
95.   
96. #include <linux/jiffies.h>
97. #include <linux/timer.h>
98.   
99. #include <mach/mt_typedefs.h>
100. #include <mach/mt_pll.h>
101. #include <mach/mt_gpt.h>
102.   
103. #define VERSION                         "v 0.1"  
104. #define VIB_DEVICE                      "mt_vibrator"  
105.   
106. #define COUNT_DOWN_TIME                 50  
107.   
108. #define VIBR_HRTIMER  
109.   
110. #ifndef VIBR_HRTIMER  
111. XGPT_NUM Vibrator_XGPT = XGPT7;  
112. #endif  
113.   
114. /******************************************************************************  
115. Error Code No.  
116. ******************************************************************************/  
117. #define RSUCCESS        0  
118.   
119. /******************************************************************************  
120. Debug Message Settings  
121. ******************************************************************************/  
122.   
123. /* Debug message event */  
124. #define DBG_EVT_NONE        0x00000000  /* No event */  
125. #define DBG_EVT_INT         0x00000001  /* Interrupt related event */  
126. #define DBG_EVT_TASKLET     0x00000002  /* Tasklet related event */  
127.   
128. #define DBG_EVT_ALL         0xffffffff  
129.    
130. #define DBG_EVT_MASK        (DBG_EVT_TASKLET)  
131.   
132. #if 1  
133. #define MSG(evt, fmt, args...) \  
134. do {    \  
135.     if ((DBG_EVT_##evt) & DBG_EVT_MASK) { \  
136.         printk(fmt, ##args); \  
137.     } \  
138. } while(0)  
139.   
140. #define MSG_FUNC_ENTRY(f)   MSG(FUC, "<FUN_ENT>: %s\n", __FUNCTION__)  
141. #else  
142. #define MSG(evt, fmt, args...) do{}while(0)  
143. #define MSG_FUNC_ENTRY(f)      do{}while(0)  
144. #endif  
145.   
146. #define VIBR_CON0 ((volatile unsigned long*)(0xF702F7B0))  
147.   
148. static int vibr_Enable(void)  
149. {  
150.     printk("[vibrator]vibr_Enable \n");  
151.     hwPowerOn(MT_POWER_LDO_VIBR, VOL_2800 , "VIBR");  
152.     return 0;  
153. }  
154.   
155. static int vibr_Disable(void)  
156. {  
157.     while((INREG32(VIBR_CON0)&1))  
158.     {  
159.         printk("[vibrator]vibr_Disable \n");  
160.     hwPowerDown(MT_POWER_LDO_VIBR , "VIBR");  
161. vibr_Disable:VIBR_CON0=0x%x \r\n", INREG32(VIBR_CON0));  
162.     }  
163.       
164.     return 0;  
165. }  
166.   
167.   
168. /******************************************************************************  
169. Global Definations  
170. ******************************************************************************/  
171. //static struct work_struct vibrator_work;  
172. static struct hrtimer vibe_timer;  
173. static spinlock_t vibe_lock;  
174.   
175.   
176. static int vibrator_get_time(struct timed_output_dev *dev)  
177. {  
178.     if (hrtimer_active(&vibe_timer))   
179.     {  
180. r = hrtimer_get_remaining(&vibe_timer);  
181.         return r.tv.sec * 1000 + r.tv.nsec / 1000000;  
182.     }   
183.     else  
184.         return 0;  
185. }  
186.   
187. static void vibrator_enable(struct timed_output_dev *dev, int value)  
188. {  
189.         unsigned long   flags;  
190.   
191.     spin_lock_irqsave(&vibe_lock, flags);  
192.   
193.         #ifdef VIBR_HRTIMER  
194.     while(hrtimer_cancel(&vibe_timer))  
195.         {  
196.             printk("[vibrator]vibrator_enable: try to cancel hrtimer \n");  
197.         }  
198.     #else  
199.         XGPT_Reset(Vibrator_XGPT);  
200.         #endif  
201.   
202. value
203.         {        
204.             printk("[vibrator]vibrator_enable: disable \n");  
205.             vibr_Disable();  
206.             
207.         }  
208.     else   
209.     {  
210. value = ((value >
211.             printk("[vibrator]vibrator_enable: vibrator start: %d \n", value);   
212.            
213.             #ifdef VIBR_HRTIMER  
214.         hrtimer_start(&vibe_timer,   
215.             ktime_set(value / 1000, (value % 1000) * 1000000),  
216.             HRTIMER_MODE_REL);  
217.   
218.             #else  
219.             XGPT_CONFIG config;  
220. config.num = Vibrator_XGPT;  
221. config.clkDiv = 0;  
222. config.mode = XGPT_ONE_SHOT;  
223. config.bIrqEnable = TRUE;  
224. config.u4Compare = value*32768/1000;  
225.               
226.             if(!XGPT_Config(config))  
227.             {  
228.                 printk("[vibrator]vibrator_enable: config XGPT: %d fail!\n", value);   
229.             }  
230.               
231.             XGPT_Start(Vibrator_XGPT);  
232.             #endif  
233.              
234.             vibr_Enable();  
235.              
236.     }  
237.     spin_unlock_irqrestore(&vibe_lock, flags);  
238.   
239. }  
240.   
241.   
242. #ifdef VIBR_HRTIMER  
243. static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer)  
244. {  
245.      printk("[vibrator]vibrator_timer_func: vibrator will disable \n");  
246.   
247.     vibr_Disable();  
248.               
249.     return HRTIMER_NORESTART;  
250. }  
251.   
252. #else  
253. void vibrator_timer_func(UINT16 temp)  
254. {  
255.     printk("[vibrator]vibrator_timer_func: vibrator will disable \n");  
256.   
257.     vibr_Disable();  
258. }  
259. #endif  
260.   
261.   
262. static struct timed_output_dev mt_vibrator
263. {  
264. .name = "vibrator",  
265. .get_time = vibrator_get_time,  
266. .enable = vibrator_enable,  
267. };  
268.   
269. static int vib_probe(struct platform_device *pdev)  
270. {  
271.     return 0;  
272. }  
273.   
274. static int vib_remove(struct platform_device *pdev)  
275. {  
276.     return 0;  
277. }  
278.   
279. static void vib_shutdown(struct platform_device *pdev)  
280. {  
281.         vibr_Disable();  
282.   
283. }  
284. /******************************************************************************  
285. Device driver structure  
286. *****************************************************************************/  
287. static struct platform_driver vibrator_driver
288. {  
289. .probe      = vib_probe,  
290. .remove     = vib_remove,  
291. .shutdown = vib_shutdown,  
292. .driver
293. .name = VIB_DEVICE,  
294.     },  
295. };  
296.   
297. static ssize_t store_vibr_on(struct device *dev,struct device_attribute *attr, const char *buf, size_t size)  
298. {  
299.     if(buf != NULL && size != 0)  
300.     {  
301.         printk("[vibrator]buf is %s and size is %d \n",buf,size);  
302.         if(buf[0]== '0')  
303.         {  
304.             vibr_Disable();  
305.         }else  
306.         {  
307.             vibr_Enable();  
308.         }  
309.     }  
310.     return size;  
311. }  
312.   
313. static DEVICE_ATTR(vibr_on, 0664, NULL, store_vibr_on);  
314.   
315. /******************************************************************************  
316.  * vib_mod_init  
317.  *   
318.  * DESCRIPTION:  
319.  *   Register the vibrator device driver !   
320.  *   
321.  * PARAMETERS:   
322.  *   None  
323.  *   
324.  * RETURNS:   
325.  *   None  
326.  *   
327.  * NOTES:   
328.  *   RSUCCESS : Success  
329.  *   
330.  ******************************************************************************/  
331.   
332. static s32 __devinit vib_mod_init(void)  
333. {     
334.     s32 ret;  
335.   
336.     printk("Mk MT vibrator driver register, version %s\n", VERSION);  
337.   
338.     spin_lock_init(&vibe_lock);  
339.       
340.         #ifdef VIBR_HRTIMER  
341.     hrtimer_init(&vibe_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);  
342. vibe_timer.function = vibrator_timer_func;  
343.   
344.         #else  
345.         XGPT_Init(Vibrator_XGPT, vibrator_timer_func);  
346.         #endif  
347.       
348.     timed_output_dev_register(&mt_vibrator);  
349.   
350. ret = platform_driver_register(&vibrator_driver);  
351.   
352.         if(ret)   
353.         {  
354.         printk("[vibrator]Unable to register vibrator driver (%d)\n", ret);  
355.         return ret;  
356.         }     
357.   
358. ret = device_create_file(mt_vibrator.dev,&dev_attr_vibr_on);  
359.     if(ret)  
360.     {  
361.         printk("[vibrator]device_create_file vibr_on fail! \n");  
362.     }  
363.       
364.     printk("[vibrator]vib_mod_init Done \n");  
365.    
366.     return RSUCCESS;  
367. }  
368.   
369. /******************************************************************************  
370.  * vib_mod_exit  
371.  *   
372.  * DESCRIPTION:   
373.  *   Free the device driver !   
374.  *   
375.  * PARAMETERS:   
376.  *   None  
377.  *   
378.  * RETURNS:   
379.  *   None  
380.  *   
381.  * NOTES:   
382.  *   None  
383.  *   
384.  ******************************************************************************/  
385.    
386. static void __exit vib_mod_exit(void)  
387. {  
388.     printk("Mk MT vibrator driver unregister, version %s \n", VERSION);  
389.     printk("[vibrator]vib_mod_exit Done \n");  
390. }  
391.   
392. module_init(vib_mod_init);  
393. module_exit(vib_mod_exit);  
394. MODULE_AUTHOR("Mk Inc.");  
395. MODULE_DESCRIPTION("MT Vibrator Driver (VIB)");  
396. MODULE_LICENSE("GPL");</PRE>
397. <P><BR>
398. </P>
399. <P><STRONG></STRONG> </P>
400. <P> </P>
401. <P> </P>
402. <PRE></PRE>
403. <PRE></PRE>

[cpp] 
    
    view plain
    
    copy
    
    print
    
    ?
   
   
  
  
  
  
#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;  
 
  
 
}
#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定义的方法列表如下所示:
[cpp] 
    
    view plain
    
    copy
    
    print
    
    ?
   
   
  
  
  
  
 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();  
 
  
 
  }
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。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


我具体的驱动程序


[cpp] 
    
    view plain
    
    copy
    
    print
    
    ?
   
   
  
  
  
  
#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_TIME                 50   
 
  
 
#define VIBR_HRTIMER   
 
  
 
#ifndef VIBR_HRTIMER   
 
XGPT_NUM Vibrator_XGPT = XGPT7;  
 
#endif   
 
  
 
/****************************************************************************** 
 
Error Code No. 
 
******************************************************************************/  
 
#define RSUCCESS        0   
 
  
 
/****************************************************************************** 
 
Debug Message Settings 
 
******************************************************************************/  
 
  
 
/* Debug message event */  
 
#define DBG_EVT_NONE        0x00000000  /* No event */   
 
#define DBG_EVT_INT         0x00000001  /* Interrupt related event */   
 
#define DBG_EVT_TASKLET     0x00000002  /* Tasklet related event */   
 
  
 
#define DBG_EVT_ALL         0xffffffff   
 
   
 
#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;  
 
    }   
 
    else  
 
        return 0;  
 
}  
 
  
 
static void vibrator_enable(struct timed_output_dev *dev, int value)  
 
{  
 
        unsigned long   flags;  
 
  
 
    spin_lock_irqsave(&vibe_lock, flags);  
 
  
 
        #ifdef VIBR_HRTIMER   
 
    while(hrtimer_cancel(&vibe_timer))  
 
        {  
 
            printk("[vibrator]vibrator_enable: try to cancel hrtimer \n");  
 
        }  
 
    #else   
 
        XGPT_Reset(Vibrator_XGPT);  
 
        #endif   
 
  
 
    if (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_HRTIMER   
 
static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer)  
 
{  
 
     printk("[vibrator]vibrator_timer_func: vibrator will disable \n");  
 
  
 
    vibr_Disable();  
 
              
 
    return HRTIMER_NORESTART;  
 
}  
 
  
 
#else   
 
void vibrator_timer_func(UINT16 temp)  
 
{  
 
    printk("[vibrator]vibrator_timer_func: vibrator will disable \n");  
 
  
 
    vibr_Disable();  
 
}  
 
#endif   
 
  
 
  
 
static 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_HRTIMER   
 
    hrtimer_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");
#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_TIME					50

#define VIBR_HRTIMER

#ifndef VIBR_HRTIMER
XGPT_NUM Vibrator_XGPT = XGPT7;
#endif

/******************************************************************************
Error Code No.
******************************************************************************/
#define RSUCCESS        0

/******************************************************************************
Debug Message Settings
******************************************************************************/

/* Debug message event */
#define DBG_EVT_NONE		0x00000000	/* No event */
#define DBG_EVT_INT			0x00000001	/* Interrupt related event */
#define DBG_EVT_TASKLET		0x00000002	/* Tasklet related event */

#define DBG_EVT_ALL			0xffffffff
 
#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;
	} 
	else
		return 0;
}

static void vibrator_enable(struct timed_output_dev *dev, int value)
{
        unsigned long   flags;

	spin_lock_irqsave(&vibe_lock, flags);

        #ifdef VIBR_HRTIMER
	while(hrtimer_cancel(&vibe_timer))
        {
            printk("[vibrator]vibrator_enable: try to cancel hrtimer \n");
        }
	#else
        XGPT_Reset(Vibrator_XGPT);
        #endif

	if (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_HRTIMER
static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer)
{
     printk("[vibrator]vibrator_timer_func: vibrator will disable \n");

    vibr_Disable();
            
 	return HRTIMER_NORESTART;
}

#else
void vibrator_timer_func(UINT16 temp)
{
    printk("[vibrator]vibrator_timer_func: vibrator will disable \n");

    vibr_Disable();
}
#endif


static 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_HRTIMER
	hrtimer_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");


 


 


<P><STRONG>SYS文件系统方式的驱动程序</STRONG></P>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/lnw_gpio.h>
#include <asm/intel-mid.h>
#define VIBRA_ENABLE_GPIO 91
struct vibra_info {
 int     enabled;
 struct mutex lock;
 struct device *dev;
 const char *name;
 int gpio_en;
};/* Enable's vibra driver */
static void vibra_enable(struct vibra_info *info)
{
 mutex_lock(&info->lock);
 gpio_set_value(info->gpio_en, 1);
 info->enabled = true;
 mutex_unlock(&info->lock);
}static void vibra_disable(struct vibra_info *info)
{
 mutex_lock(&info->lock);
 gpio_set_value(info->gpio_en, 0);
 info->enabled = false;
 mutex_unlock(&info->lock);
}
/******************************************************************************
 * SYSFS                                                                                            *
 ******************************************************************************/static ssize_t vibra_show_vibrator(struct device *dev,
  struct device_attribute *attr, const char *buf, size_t size)
{
 struct vibra_info *info = dev_get_drvdata(dev); return sprintf(buf, "%d\n", info->enabled);}static ssize_t vibra_set_vibrator(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t size)
{
 long vibrator_enable;
 struct vibra_info *info = dev_get_drvdata(dev); if (kstrtol(buf, 10, &vibrator_enable))
  return -EINVAL;
 else if (vibrator_enable == 0)
  vibra_disable(info);
 else if (vibrator_enable == 1)
  vibra_enable(info);
 else
  return -EINVAL;
 return size;
}static DEVICE_ATTR(vibrator, S_IWUSR | S_IRUGO,
     vibra_show_vibrator,vibra_set_vibrator);static struct attribute *gpio_vibra_attrs[] = {
 &dev_attr_vibrator.attr,
 NULL,
};static struct attribute_group gpio_vibra_attr_group = {
 .attrs = gpio_vibra_attrs,
};#if CONFIG_PM
static int vibra_runtime_suspend(struct device *dev)
{
 printk("In %s\n", __func__);
 return 0;
}static int vibra_runtime_resume(struct device *dev)
{
 printk("In %s\n", __func__);
 return 0;
}static const struct dev_pm_ops intel_mid_vibra_pm_ops = {
 .suspend = vibra_runtime_suspend,
 .resume = vibra_runtime_resume,
};#endifstatic int __devinit gpio_vibra_probe(struct platform_device *pdev)
{
 struct vibra_info *info;
 struct mid_vibra_probe *data;
 int ret = 0;
 
 info =  kzalloc(sizeof(*info), GFP_KERNEL);
 if (!info)
  return -ENOMEM; info->gpio_en = VIBRA_ENABLE_GPIO;
 printk("using gpios en: %d", info->gpio_en);
 ret = gpio_request_one(info->gpio_en, GPIOF_DIR_OUT, "VIBRA ENABLE");
 if (ret != 0) {
  pr_err("gpio_request(%d) fails:%d\n", info->gpio_en, ret);
  goto out;
 } info->name = "intel_mid:vibrator";
 mutex_init(&info->lock);
 ret = sysfs_create_group(&pdev->dev.kobj, &gpio_vibra_attr_group);
 if (ret) {
  pr_err("Unable to export keys/switches, error: %d\n",ret);
  goto do_freegpio_vibra_enable;
 } platform_set_drvdata(pdev, info); return ret;
do_freegpio_vibra_enable:
 sysfs_remove_group(&pdev->dev.kobj, &gpio_vibra_attr_group);
 gpio_free(info->gpio_en);
out:
 return ret;
}static void __devexit gpio_vibra_remove(struct platform_device *pdev)
{
 struct vibra_info *info = platform_get_drvdata(pdev);
 gpio_free(info->gpio_en);
 sysfs_remove_group(&pdev->dev.kobj, &gpio_vibra_attr_group);
}static struct of_device_id gpio_vibra_of_match[] = {
 { .compatible = "gpio-vibra", },
 { },
};
MODULE_DEVICE_TABLE(of, gpio_vibra_of_match);
static struct platform_driver gpio_vibra_device_driver = {
 .probe  = gpio_vibra_probe,
 .remove  = __devexit_p(gpio_vibra_remove),
 .driver  = {
  .name = "gpio-vibra",
  .owner = THIS_MODULE,
#ifdef CONFIG_PM_SLEEP
  .pm = &intel_mid_vibra_pm_ops,
#endif
 .of_match_table = gpio_vibra_of_match, }
};
static int __init gpio_vibra_init(void)
{
 int ret = 0; ret = platform_driver_register(&gpio_vibra_device_driver);
 if (ret)
  pr_err("vib driver register failed\n");
 return ret;
}
static void __exit gpio_vibra_exit(void)
{
 platform_driver_unregister(&gpio_vibra_device_driver);
 printk("intel_mid_vibra driver exited\n");
 return;
}static struct platform_device vb_device = {
 .name  = "gpio-vibra",
 .id  = -1,
 .dev  = {
  .platform_data = NULL,//&gpio_keys,
 },
};static int __init vibra_platform_init(void)
{
 return platform_device_register(&vb_device);
}
late_initcall(vibra_platform_init);module_init(gpio_vibra_init);
module_exit(gpio_vibra_exit);MODULE_ALIAS("gpio:intel_mid_vibra");
MODULE_DESCRIPTION("gpio control Vibra driver");
MODULE_LICENSE("GPL v2");