1.使G-sensor正常工作需要做的事:
G-sensor driver檔案包括:
driver/i2c/chips/lis331dl.c
driver/i2c/chips/sensorioctl.h
include/linux/lis331dl.h
並在/kernel/arch/arm/mach-s3c6410/mach-ur6410.c檔案中i2c chanel1的結構變數i2c_devs1[] __initdata中需要添加G-sensor的裝置資訊,
以使driver成功載入。
同時在該檔案中添加一個結構變數
//JayLin add for Gsensor
struct lis331dl_platform_data lisGsensor_platform_data={
.name="lis331dl",
.pin_clk=0,
.pin_data=0,
.open_drain=1,
.interrupt=IRQ_EINT(3),
};
該結構變數在i2c_devs1[] __initdata中被引用。
/kernel/arch/arm/mach-s3c6410/mach-ur6410.c 中需要包含lis331dl.h。
在rootfs/system/etc/init.board.sh的最後一行加上mknod /dev/sensorioctl c 51 201&建立節點供ioctl使用。
編譯後的sensor.so放在/rootfs/system/lib/hw下。
sensor.so和driver之間通過ioctl實現對G-sensor的狀態控制。ioctl的命令編號定義在標頭檔sensorioctl.h中,分別放在
kernel/include/linux下
和
androidsourcecode/hardware/libhardware/include/hardware下
供driver和sensor.so使用。
G-sensor driver工作的大致流程:
系統開機後,先載入i2c匯流排驅動,然後載入裝置驅動。
在裝置驅動中的init函數中通過調用i2c_add_driver(&lis331dl_i2c_driver)註冊i2c_driver;此函數將driver註冊到i2c_bus_type的匯流排上,此匯流排的匹配規則是利用i2c_client的名稱和
i2c_driver中id_table中的名稱作匹配。
其中i2c_client是註冊板載資訊是系統自動建立的,註冊板載資訊的過程就是在/kernel/arch/arm/mach-s3c6410 /mach-ur6410.c檔案中i2c chanel1的結構變數i2c_devs1[] __initdata中需要添加G-sensor的裝置資訊。
當匹配成功時,i2c_driver中的probe()函數開始執行。
Probe()函數主要完成以下功能:
1.從i2c_client結構中得到初始化資訊
2.建立G-sensor的工作隊列
2.註冊input_device裝置
3.讀取Chip ID
4.設定寄存器,使能G-sensor
5.設定並啟動中斷
當G-sensor上報資料的時候會觸發中斷,然後在中斷處理函數中提交一個報值的任務到隊列中並禁止中斷。
在工作隊列中讀數G-sensor的資料並上報到input子系統中,最後使能中斷。
2.android上層應用apk到G-sensor driver的大致流程:
Android對於Sensor的API定義在 hardware/libhardware/include/hardware/sensor.h中, 要求在sensor.so提供以下8個API函數
[控制方面]
int (*open_data_source)(struct sensors_control_device_t *dev);
int (*activate)(struct sensors_control_device_t *dev, int handle, int enabled);
int (*set_delay)(struct sensors_control_device_t *dev, int32_t ms);
int (*wake)(struct sensors_control_device_t *dev);
[資料方面]
int (*data_open)(struct sensors_data_device_t *dev, int fd);
int (*data_close)(struct sensors_data_device_t *dev);
int (*poll)(struct sensors_data_device_t *dev, sensors_data_t* data);
[模組方面]
int (*get_sensors_list)(struct sensors_module_t* module, struct sensor_t const** list);
在JAVA層Sensor的狀態控制由SensorService來負責,它的java代碼和JNI代碼分別位於:
frameworks/base/services/java/com/android/server/SensorService.java
frameworks/base/services/jni/com_android_server_SensorService.cpp
在Java層Sensor的資料控制由SensorManager來負責,它的java代碼和JNI代碼分別位於:
frameworks/base/core/java/android/hardware/SensorManager.java
frameworks/base/core/jni/android_hardware_SensorManager.cpp
android framework中與sensor通訊的是sensorService.java和sensorManager.java。
sensorService.java的具體通訊是通過JNI調用sensorService.cpp中的方法實現的。
sensorManager.java的具體通訊是通過JNI調用sensorManager.cpp中的方法實現的。
sensorService.cpp和sensorManger.cpp通過hardware.c與sensor.so通訊。其中sensorService.cpp實現對sensor的狀態控制,sensorManger.cpp實現對sensor的資料控制。
sensor.so通過ioctl控制sensor driver的狀態,通過開啟sensor driver對應的裝置檔案讀取G-sensor採集的資料。
android SDK提供了4個類來於sensor通訊,分別為 sensor,sensorEvent,sensorEventListener,sensorManager.其中 sensorEventListener用來在sensorManager中註冊需要監聽的sensor類型。
sensorManager.java提供registrater(),unregistrater()介面供sensorEventListener使用。
sensorManager.java不斷輪詢從sensor.so中取資料。取到資料後送給負責監聽此類型sensor的 sensorEventListener.java。sensorEventListener.java通過在sensorManager.java中注 冊可以監聽特定類型的sensor傳來的資料。
系統啟動時執行systemProcess,會啟動sensorService.java,在sensorService.java的建構函式中調用JNI方法_sensor_control_init()。
sensorService.cpp中相應的方法android_int()會被執行。該函數會調用hardware.c中的方法hw_get_module()此函數又通過調用load()函數在system/lib/hw下尋找sensor.so
尋找時會根據harware.c中定義好的sensor.*.so的副檔名的順序尋找,找到第一個匹配的時候即停止,並將該sensor.so中定義好的一個全域變數HAL_MODULE_INFO_SYM帶回。該變數包含的一個
重要訊息是它的一個成員結構變數中包含的一個函數指標open,該指標所指函數會對一個device結構變數賦值,從而帶出sensorService.cpp 和sensorManager.cpp與sensor通訊所需要的全部資訊。
device結構變數有兩種變體分別供sensorService.cpp和sensorManaer.cpp使用。其中主要是一些函數指標指向與sensor通訊的函數。
sensorService.cpp和sensorManager.cpp在得到HAL_MODULE_INFO_SYM結構後都會調用 sensors.h的inline函數open()通過HAL_MODULE_INFO_SYM的open函數指標將所需的device資訊取回。
系統在啟動activityManager.java時,它會啟動sensorManager.java,它也會調用hardware.c中的方法hw_get_module()帶回HAL_MODULE_INFO_SYM。
3.關於Rotate的實現:
系統啟動windowManger.java時,它會啟動phoneWindowManager.java,該類有一個內部類myOrientationListener擴充自windowOrientationListener.java。
windowOrientationListener.java是一個輔助類,當device的方向發生變化時,供windowManger.java調用,用來接收資料。
windowOrientationListener.java 內部在sensorManger.java中進行了註冊,它回監聽G-sensor傳來的資料,即x,y,z方向的加速度,收到資料後經過轉換處理,若滿足Roate條件則調用 IwindowManager介面的實作類別windowManagerService.java中的setRotation()方法實現轉屏。
SensorManager通過polling的方式從裝置得到Sensor資料, Sensor資料的結構定義在sensor.h裡,
其中SensorManager只處理了 vector.v, vector.status, time三個域, 分發給登入的對這些訊息的監聽者
比如第一項 vector.v包含x,y,z三個方向的資訊值,就是由 WindowOrientataionLister註冊的,
當 SensorManager擷取到這三個值之後,會傳遞給 WindowOrientataionLister,後者代碼位於:
frameworkd/base/core/java/android/view/WindowOrientationListener.java
WindowOrientataionLister接收到這三個值之後,會計算出裝置對應的orientation,並且執行 onOrientationChanged函數進一步上傳
WindowOrientataionLister是個純虛類,如果在APK裡需要控制方向,可以重載一個執行個體,
而Android的系統執行個體對應在 PhoneWindowManager.java裡,名字為MyOrientationListener
frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java
如果需要旋轉, MyOrientationListener則會調用以下代碼進行視窗旋轉:
mWindowManager.setRotation(rotation, false, mFancyRotationAnimation);
問題總結:
1.將lis302 G-sensor driver從spi匯流排移植到lis331 i2c匯流排時遇到的一些問題:
a).lis331用的中斷管腳與lis302不同,通過硬體原理圖可知lis331用的是GPN3.故需要在driver的probe中設定 writel((readl(S3C64XX_GPNCON) & ~(0xc0)) | (0x80), S3C64XX_GPNCON);
b).通過硬體原理圖可知lis331的時鐘線和資料線用的是i2c chanel1。故需要在/kernel/arch/arm/mach-s3c6410/mach-ur6410.c檔案中i2c chanel1即結構變數i2c_devs1[] __initdata中
添加G-sensor的裝置資訊,以使driver成功載入。
c).lis331 driver是中斷驅動的,每次G-sensor搜集到新資料都會產生中斷,driver要在中斷中通過i2cbus將資料從G-sensor中取回。由 於i2cbus的讀寫操作是可能休眠的,而中斷中不允許調用可能休眠的函數,故通過linux提供的延遲機制work_queue來解決。
問題b)的原理:
i2c驅動包括匯流排驅動和裝置驅動 匯流排驅動只是提供對一條特定匯流排的讀寫機制,本身並不會去做通訊。通過i2c匯流排驅動提供的函數,裝置驅動可以忽略不同匯流排控制器的差異,不考慮其細節的與硬體裝置通訊。
一個匯流排驅動通常需要2個模組:struct i2c_adapter和struct i2c_algorithm 定義在include/linux/i2c.h中
struct i2c_algorithm是為了i2c匯流排驅動和具體的i2c匯流排能夠對話。很多i2c匯流排驅動定義和使用它們自己的algorithm.對於一些i2c匯流排驅動來說,很多algorithm已經寫好了。
drivers/i2c/buses中包含所有的i2c匯流排驅動,drivers/i2c/algos中包含了所有的algorithm.
裝置驅動通過匯流排驅動中的讀寫函數同具體的i2c裝置通訊,一個裝置驅動用兩個模組來描述:struct i2c_driver 和struct i2c_client.
i2c_client代表著位於adapter匯流排上地址為address,使用driver來驅動的一個裝置。它將匯流排驅動,裝置驅動以及裝置地址綁定到了一起。
2.實現sensor.so與driver之間的ioctl時遇到的問題: