菜鳥與月薪10萬大神的差距都在這 : Android、嵌入式Linux開發者必讀 !

CSDN學院發表於2020-04-04

文章來源:xgbing    (文末有彩蛋)

嵌入式linux和嵌入式android系統有什麼區別和聯絡?

這個問題很多人問,尤其是初入嵌入式的菜鳥。其實大家都認為android是java,已經不是linux,殊不知android就是靠著linux 才發展起來的,現在來說說有啥區別吧。
嵌入式android原始碼架構:uboot+linux kernel+android(包含檔案系統,虛擬機器,UI)
嵌入式linux:這是大部分人認識的linux uboot+linux kernel+檔案系統+QT(UI),
當然兩者的linux 核心因為上層UI的不同會稍有差別,不過還是非常接近的,做過linux的人可以無縫切換到android底層開發,所以大家說的學習android系統,其實最重要的就是學習linux驅動,再加一下android下的專門的HAL,JNI,java等等,不過大公司android相關部分也是專門的人做的了。

甚至連QT都不用了,因為linux很多裝置都是沒有UI的,所以要來幹啥?直接無介面,照樣是嵌入式linux。

現在大家說的什麼嵌入式debian,ubuntu,其實也是站在linux巨人的肩膀上,其實都不算是linux的分支,只算是linux的延伸,小變化而已。看到這裡大家知道嵌入式linux的強大了吧,反正是比wince 強大N倍啊。

O(∩_∩)O~,所以啊,學習嵌入式android,其實底下就是學習uboot,linux核心啊,不會搞這些就像搞應用一樣,所以大家以為android就是java,是非常片面的。

以前老的,說了一下區別,可以參考一下

也為大家推薦了技術教程:

課程名稱 課程連結 技術分類
Linux視訊教程 https://edu.csdn.net/course/detail/9128?utm_source=blog11xk 系統/網路/運維 > Linux
zabbix企業實戰應用 https://edu.csdn.net/course/detail/9124?utm_source=blog11xk 系統/網路/運維 > Linux
Linux 實用講解+實操+面試題 https://edu.csdn.net/course/detail/9116?utm_source=blog11xk 系統/網路/運維 > Linux

ARCH --  這是Android修改了arch/arm下面的一些檔案:
arch/arm:
Chg: arch/arm/kernel/entry-armv.S
Chg: arch/arm/kernel/module.c
Chg: arch/arm/kernel/process.c
Chg: arch/arm/kernel/ptrace.c
Chg: arch/arm/kernel/setup.c
Chg: arch/arm/kernel/signal.c
Chg: arch/arm/kernel/traps.c
Chg: arch/arm/mm/cache-v6.S
Chg: arch/arm/vfp/entry.S
Chg: arch/arm/vfp/vfp.h
Chg: arch/arm/vfp/vfphw.S
Chg: arch/arm/vfp/vfpmodule.c
Goldfish --  這是Android為了模擬器所開發的一個虛擬硬體平臺。Goldfish執行arm926T指令(在2.6.29中,goldfish也支援ATMv7指令),但是在實際的裝置中,該虛擬平臺的檔案不會被編譯。
arch/arm/mach-goldfish:
New: arch/arm/mach-goldfish/audio.c
New: arch/arm/mach-goldfish/board-goldfish.c
New: arch/arm/mach-goldfish/pdev_bus.c
New: arch/arm/mach-goldfish/pm.c
New: arch/arm/mach-goldfish/switch.c
New: arch/arm/mach-goldfish/timer.c
YAFFS2 --  和PC把檔案儲存在硬碟上不一樣, 移動裝置一般把Flash作為儲存裝置。尤其是NAND flash應用非常廣泛(絕大多數手機用的都是NAND flash,三星的一些手機使用的是OneNAND)。NAND flash具有低成本和高密度的優點。
YAFFS2 是“Yet Another Flash File System, 2nd edition" 的簡稱。 它提供在Linux核心和NAND flash裝置 之前高效率的介面。 YAFFS2並沒有包含在標準的Linux核心中, Google把它新增到了Android的kernel
fs/yaffs2:
New: fs/yaffs2/devextras.h
New: fs/yaffs2/Kconfig
New: fs/yaffs2/Makefile
New: fs/yaffs2/moduleconfig.h
New: fs/yaffs2/yaffs_checkptrw.c
New: fs/yaffs2/yaffs_checkptrw.h
New: fs/yaffs2/yaffs_ecc.c
New: fs/yaffs2/yaffs_ecc.h
New: fs/yaffs2/yaffs_fs.c
New: fs/yaffs2/yaffs_getblockinfo.h
New: fs/yaffs2/yaffs_guts.c
New: fs/yaffs2/yaffs_guts.h
New: fs/yaffs2/yaffsinterface.h
New: fs/yaffs2/yaffs_mtdif1.c
New: fs/yaffs2/yaffs_mtdif1.h
New: fs/yaffs2/yaffs_mtdif2.c
New: fs/yaffs2/yaffs_mtdif2.h
New: fs/yaffs2/yaffs_mtdif.c
New: fs/yaffs2/yaffs_mtdif.h
New: fs/yaffs2/yaffs_nand.c
New: fs/yaffs2/yaffs_nandemul2k.h
New: fs/yaffs2/yaffs_nand.h
New: fs/yaffs2/yaffs_packedtags1.c
New: fs/yaffs2/yaffs_packedtags1.h
New: fs/yaffs2/yaffs_packedtags2.c
New: fs/yaffs2/yaffs_packedtags2.h
New: fs/yaffs2/yaffs_qsort.c
New: fs/yaffs2/yaffs_qsort.h
New: fs/yaffs2/yaffs_tagscompat.c
New: fs/yaffs2/yaffs_tagscompat.h
New: fs/yaffs2/yaffs_tagsvalidity.c
New: fs/yaffs2/yaffs_tagsvalidity.h
New: fs/yaffs2/yportenv.h
Bluetooth --  Google為Bluetooth打上了patch,fix了一些Bluetooth的bug
drivers/bluetooth:
Chg: drivers/bluetooth/bfusb.c
Chg: drivers/bluetooth/bt3c_cs.c
Chg: drivers/bluetooth/btusb.c
Chg: drivers/bluetooth/hci_h4.c
Chg: drivers/bluetooth/hci_ll.c
Scheduler --  對於Scheduler的改變非常小,我對它並沒有去研究。
Chg: kernel/sched.c
New Android Functionality --  除了fix一些bug以及其他一些小的更改,Android增加了一些新的功能,介紹如下:
IPC Binder -- The IPC Binder is an Inter-Process Communication (IPC) mechanism. It allows processes to provide services to other processes via a set of higher-level APIs than are available in standard Linux. An Internet search indicated that the Binder concept originated at Be, Inc., and then made its way into Palm's software, before Google wrote a new Binder for Android.
New: drivers/staging/android/binder.c
Low Memory Killer -- Android adds a low-memory killer that, each time it's called, scans the list of running Linux processes, and kills one. It was not clear in our cursory examination why Android adds a low-memory killer on top of the already existing one in the standard Linux kernel.
New: drivers/staging/android/lowmemorykiller.c
Ashmem -- Ashmem is an Anonymous SHared MEMory system that adds interfaces so processes can share named blocks of memory. As an example, the system could use Ashmem to store icons, which multiple processes could then access when drawing their UI. The advantage of Ashmem over traditional Linux shared memory is that it provides a means for the kernel to reclaim these shared memory blocks if they are not currently in use. If a process then tries to access a shared memory block the kernel has freed, it will receive an error, and will then need to reallocate the block and reload the data.
New: mm/ashmem.c
RAM Console and Log Device -- To aid in debugging, Android adds the ability to store kernel log messages to a RAM buffer. Additionally, Android adds a separate logging module so that user processes can read and write user log messages.
New: drivers/staging/android/ram_console.c
Android Debug Bridge -- Debugging embedded devices can best be described as challenging. To make debugging easier, Google created the Android Debug Bridge (ADB), which is a protocol that runs over a USB link between a hardware device running Android and a developer writing applications on a desktop PC. 
drivers/usb/gadget:
New: drivers/usb/gadget/android.c
Chg: drivers/usb/gadget/composite.c
Chg: drivers/usb/gadget/f_acm.c
New: drivers/usb/gadget/f_acm.h
New: drivers/usb/gadget/f_adb.c
New: drivers/usb/gadget/f_adb.h
New: drivers/usb/gadget/f_mass_storage.c
New: drivers/usb/gadget/f_mass_storage.h

Android also adds a new real-time clock, switch support, and timed GPIO support. We list the impacted files for these new modules at the end of this document.

Power Management --  Power management is one of the most difficult pieces to get right in mobile devices, so we split it out into a group separate from the other pieces. It's interesting to note that Google added a new power management system to Linux, rather than reuse what already existed. We list the impacted files at the end of this document.
kernel/power:
New: kernel/power/consoleearlysuspend.c
New: kernel/power/earlysuspend.c
New: kernel/power/fbearlysuspend.c
Chg: kernel/power/main.c
Chg: kernel/power/power.h
Chg: kernel/power/process.c
New: kernel/power/userwakelock.c
New: kernel/power/wakelock.c
Miscellaneous Changes --  In addition to the above, we found a number of changes that could best be described as, 'Miscellaneous.' Among other things, these changes include additional debugging support, keypad light controls, and management of TCP networking
http://www.linuxfordevices.com/c ... id-to-a-new-device/
http://hi.baidu.com/smallbigwang/item/95c99ebcb0e9544cba0e1281

也給大家推薦幾門教程:

深入探究Linux/VxWorks的裝置樹

探究Linux的匯流排、裝置、驅動模型

Android視訊編碼和直播推流

Android高手進階


haolele 發表於 2011-11-11 21:03:34Android系統移植方法詳解
http://www.anzhuoba.com/archiver/?tid-8419.html
[本文WORD文件下載:]
通過Android系統移植,讓它在目標系統上執行起來。Android系統由於用的是linux核心,因此核心移植和嵌入式linux核心移植差異不大,過程如下:

(1)移植boot-loader和linux2.6核心到目標平臺上,讓linux核心可以啟動起來,基本的驅動允許正常。
此過程完全是嵌入式linux的開發,這裡直接跳過。需要注意的是,由於android已經被linux官方開除,因此從
網站上(如http://www.kernel.org/)下載的最新linux核心原始碼已經不包含android的專有驅動,因此建議
從google網上下下載Linux核心,android原始碼瀏覽網站如下:
http://android.git.kernel.org/
從該網站上發現核心相關的包如下:
kernel/common.git 通用android核心專案
kernel/experimental.git 實驗性核心專案
kernel/linux-2.6.git 這個是標準的Linux核心,沒有android的驅動
kernel/lk.git 微核心專案
kernel/msm.git 這個是高通msm7xxx系列晶片所用核心
kernel/omap.git
kernel/tegra.git NVIDIA Tegra系列晶片所用核心
下載核心程式碼的方法如下:
git clone git://android.git.kernel.org/kernel/common.git
下載完後用git branch -a檢視所有git分支,結果如下:
  android-2.6.27
  origin/HEAD
  origin/android-2.6.25
  origin/android-2.6.27
  origin/android-2.6.29
  origin/android-2.6.32
  origin/android-2.6.35
  origin/android-2.6.36
  origin/android-goldfish-2.6.27
  origin/android-goldfish-2.6.29
然後切換到最新分支git checkout origin/android-2.6.36

(2)修改核心配置檔案,開啟Android必須的驅動(日誌和BINDER)如下:
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_ANDROID_LOGGER=y
此部分的程式碼在核心drivers/staging/android目錄下。

(3)為了提高啟動速度,採用ramdisk,將android檔案系統的部分內容壓縮到核心中。
首先開啟核心驅動:
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE="root"
CONFIG_INITRAMFS_ROOT_UID=0
CONFIG_INITRAMFS_ROOT_GID=0
然後在android原始碼編譯出來的out/target/product/merlin/root目錄複製到核心目錄下。

(4)根據android檔案系統的要求對nand flash進行重新分割槽,舉例如下:
將nand flash分割槽以下8個分割槽
NTIM
OBM
U-boot
Kernel
System
UserData
Mass Storage
BBT

(5)根據分割槽表修改核心啟動引數如下:
CONFIG_CMDLINE="ubi.mtd=4 ubi.mtd=5 ubi.mtd=6 root=ubi0_0 rootfstype=ubifs console=ttyS1,115200 uart_dma init=/init"
引數的意思是:載入的檔案系統部分有3個分割槽,分別為nand flash的第4,5,6分割槽(從0編號),檔案系統採用ubifs格式,控制檯裝置為ttyS1,波特率為115200
啟動的第一個應用程式是/init

(6)確保控制檯的設定和硬體保持一致,如:硬體上串列埠用的是UART1,則核心啟動引數中設定有console=ttyS1,而且android的啟動過程中設要設定正確,修改
部分位於android原始碼system/core/init/init.c檔案中,將
static char *console_name = "/dev/console";
修改成
static char *console_name = "/dev/ttyS1";

(7)修改android原始碼system/core/rootdir目錄下的init.rc檔案,作如下修改(android預設yaffs2檔案系統):
首先將android檔案系統修改成可讀寫,將
    mount rootfs rootfs / ro remount
修改成
    mount rootfs rootfs / rw remount
然後修改掛載system和userdata部分的程式碼,將
    # Mount /system rw first to give the filesystem a chance to save a checkpoint
    mount yaffs2 mtd@system /system
    mount yaffs2 mtd@system /system ro remount

    # We chown/chmod /data again so because mount is run as root + defaults
    mount yaffs2 mtd@userdata /data nosuid nodev
    chown system system /data
    chmod 0771 /data
改成
    # Mount /system rw first to give the filesystem a chance to save a checkpoint
    mount ubifs ubi0_0 /system ro

    # We chown/chmod /data again so because mount is run as root + defaults
    mount ubifs ubi1_0 /data nosuid nodev
    chown system system /data
    chmod 0771 /data

(8)完成後編譯核心,可以啟動檔案系統,控制檯可用,但是沒有顯示啟動log,而且不停的重啟。

(9)系統不停的重啟,因此控制檯已經可用了,自然而然的想到看到logcat日誌,一看,發現logcat裝置居然沒起來,配置檔案裡面都定義了
居然沒起來,檢視了下核心drivers/staging/android目錄,沒有.o檔案,證明是沒編譯到,在看核心目錄下的.config檔案,發現居然沒有了
logcat和binder的巨集定義,配置檔案裡面有定義而.config檔案中無定義,肯定是相關Kconfig檔案的問題,通過分析drivers/staging目錄下的
Kconfig檔案發現是因為STAGING_EXCLUDE_BUILD巨集預設是y,在配置檔案中否定此巨集即可,在配置檔案中CONFIG_STAGING定義後加上即可,如下:
CONFIG_STAGING=y
# CONFIG_STAGING_EXCLUDE_BUILD is not set
修改後重新編譯發現系統完成正常啟動,啟動過程中啟動log也顯示正常。
至此,android初步移植工作已經完成,當然,系統還有很多問題,需要下一步繼續修改。
總結:android的移植按如下流程:
(1)android linux核心的普通驅動移植,讓核心可以在目標平臺上執行起來。
(2)正確掛載檔案系統,確保核心啟動引數和android原始碼system/core/rootdir目錄下的init.rc中的檔案系統掛載正確。
(3)除錯控制檯,讓核心啟動引數中的console引數以及android原始碼system/core/init/init.c中的console_name設定和硬體保持一致
(4)開啟android相關的驅動(logger,binder等),串列埠輸入logcat看logger驅動起來,沒有的話除錯logger驅動。
說明:ARM的核心配置檔案定義在核心arch/arm/configs目錄下。

Android系統移植之按鍵移植本帖最後由 haolele 於 2011-11-11 21:04 編輯 

Android系統移植之按鍵移植這一部分主要是移植android的鍵盤和按鍵
(1)Android使用標準的linux輸入事件裝置(/dev/input目錄下)和驅動,按鍵定義在核心include/linux/input.h檔案中,
按鍵定義形式如下:
#define KEY_ESC            1
#define KEY_1            2
#define KEY_2            3

(2)核心中(我的平臺是arch/arm/mach-mmp/merlin.c檔案)中按鍵的定義如下形式:
static struct gpio_keys_button btn_button_table[] = {
    = {
        .code            =    KEY_F1,
        .gpio            =    MFP_PIN_GPIO2,
        .active_low        =    1,        /* 0 for down 0, up 1; 1 for down 1, up 0 */
        .desc            =    "H_BTN button",
        .type            =    EV_KEY,
        /* .wakeup            = */
        .debounce_interval    =    10,        /* 10 msec jitter elimination */
    },
    = {
        .code            =    KEY_F2,
        .gpio            =    MFP_PIN_GPIO3,
        .active_low        =    1,        /* 0 for down 0, up 1; 1 for down 1, up 0 */
        .desc            =    "O_BTN button",
        .type            =    EV_KEY,
        /* .wakeup            = */
        .debounce_interval    =    10,        /* 10 msec jitter elimination */
    },
    = {
        .code            =    KEY_F4,
        .gpio            =    MFP_PIN_GPIO1,
        .active_low        =    1,        /* 0 for down 0, up 1; 1 for down 1, up 0 */
        .desc            =    "S_BTN button",
        .type            =    EV_KEY,
        /* .wakeup            = */
        .debounce_interval    =    10,        /* 10 msec jitter elimination */
    },
};
static struct gpio_keys_platform_data gpio_keys_data = {
    .buttons  = btn_button_table,
    .nbuttons = ARRAY_SIZE(btn_button_table),
};

static struct platform_device gpio_keys = {
    .name = "gpio-keys",
    .dev  = {
        .platform_data = &gpio_keys_data,
    },
    .id   = -1,
};
上面定義是將MFP_PIN_GPIO2這個GPIO口的按鍵對映到Linux的KEY_F1按鍵,MPF_PIN_GPIO3對映到KEY_F2,MFP_PIN_GPIO1對映到KEY_F4

(3)上面(2)步實現了從硬體GPIO口到核心標準按鍵的對映,但是android並沒有直接使用對映後的鍵值,而且對其再進行了一次對映,從核心標準鍵值
到android所用鍵值的對映表定義在android檔案系統的/system/usr/keylayout目錄下。標準的對映檔案為qwerty.kl,定義如下:
key 399   GRAVE
key 2     1
key 3     2
key 4     3
key 5     4
key 6     5
key 7     6
key 8     7
key 9     8
key 10    9
key 11    0
key 158   BACK              WAKE_DROPPED
key 230   SOFT_RIGHT        WAKE
key 60    SOFT_RIGHT        WAKE
key 107   ENDCALL           WAKE_DROPPED
key 62    ENDCALL           WAKE_DROPPED
key 229   MENU              WAKE_DROPPED
key 139   MENU              WAKE_DROPPED
key 59    MENU              WAKE_DROPPED
key 127   SEARCH            WAKE_DROPPED
key 217   SEARCH            WAKE_DROPPED
key 228   POUND
key 227   STAR
key 231   CALL              WAKE_DROPPED
key 61    CALL              WAKE_DROPPED
key 232   DPAD_CENTER       WAKE_DROPPED
key 108   DPAD_DOWN         WAKE_DROPPED
key 103   DPAD_UP           WAKE_DROPPED
key 102   HOME              WAKE
key 105   DPAD_LEFT         WAKE_DROPPED
key 106   DPAD_RIGHT        WAKE_DROPPED
key 115   VOLUME_UP
key 114   VOLUME_DOWN
key 116   POWER             WAKE
key 212   CAMERA

key 16    Q
key 17    W
key 18    E
key 19    R
key 20    T
key 21    Y
key 22    U
key 23    I
key 24    O
key 25    P
key 26    LEFT_BRACKET
key 27    RIGHT_BRACKET
key 43    BACKSLASH

key 30    A
key 31    S
key 32    D
key 33    F
key 34    G
key 35    H
key 36    J
key 37    K
key 38    L
key 39    SEMICOLON
key 40    APOSTROPHE
key 14    DEL
        
key 44    Z
key 45    X
key 46    C
key 47    V
key 48    B
key 49    N
key 50    M
key 51    COMMA
key 52    PERIOD
key 53    SLASH
key 28    ENTER
        
key 56    ALT_LEFT
key 100   ALT_RIGHT
key 42    SHIFT_LEFT
key 54    SHIFT_RIGHT
key 15    TAB
key 57    SPACE
key 150   EXPLORER
key 155   ENVELOPE        

key 12    MINUS
key 13    EQUALS
key 215   AT

(4)android對底層按鍵的處理方法
android按鍵的處理是Window Manager負責,主要的對映轉換實現在android原始碼frameworks/base/libs/ui/EventHub.cpp
此檔案處理來自底層的所有輸入事件,並根據來源對事件進行分類處理,對於按鍵事件,處理過程如下:
(a)記錄驅動名稱為
(b)獲取環境變數ANDROID_ROOT為系統路徑(預設是/system,定義在android原始碼/system/core/rootdir/init.rc檔案中)
(c)查詢路徑為"系統路徑/usr/keylayout/驅動名稱.kl"的按鍵對映檔案,如果不存在則預設用路徑為"系統路徑/usr/keylayout/qwerty.kl"
這個預設的按鍵對映檔案,對映完成後再把經對映得到的android按鍵碼值發給上層應用程式。
所以我們可以在核心中定義多個按鍵裝置,然後為每個裝置設定不同的按鍵對映檔案,不定義則會預設用qwerty.kl

(5)舉例
上面(2)步我們在核心中宣告瞭一個名為"gpio-keys"的按鍵裝置,此裝置定義在核心drivers/input/keyboard/gpio_keys.c檔案中
然後我們在核心啟動過程中註冊此裝置:  platform_device_register(&gpio_keys);
然後我們可以自己定義一個名為gpio-keys.kl的android按鍵對映檔案,此檔案的定義可以參考querty.kl的內容,比如說我們想將MPF_PIN_GPIO3
對應的按鍵作android中的MENU鍵用,首先我們在核心中將MPF_PIN_GPIO3對映到KEY_F2,在核心include/linux/input.h中查詢KEY_F2發現
#define KEY_F2            60
參照KEY_F2的值我們在gpio-keys.kl中加入如下對映即可
key 60    MENU              WAKE
其它按鍵也照此新增,完成後將按鍵表放置到/system/usr/keylayout目錄下即可。
補充:
(1)android按鍵裝置的對映關係可以在logcat開機日誌中找的到(查詢EventHub即可)
(2)android按鍵裝置由Window Manager負責,Window Manager從按鍵驅動讀取核心按鍵碼,然後將核心按鍵碼轉換成android按鍵碼,轉換完成
後Window Manager會將核心按鍵碼和android按鍵碼一起發給應用程式來使用,這一點一定要注意。Android系統開發小知識-在android產品開 發中新增新的編譯模組 Android開發中使用者內容定義在vendor目錄下,而使用者產品的內容都定義在vendor/<company_name> /<board_name>目錄下
如果需要新增新的內容,可以在該目錄下新建子目錄,同時修改AndroidBoard.mk檔案即可。比如說要新增一個按鍵對映檔案:
(1)在vendor/<company_name>/<board_name>目錄下建立一個keymaps子目錄
(2)將我們需要的按鍵對映檔案gpio-keys.kl和power-button.kl複製到keymaps目錄下
(3)在keymaps目錄下新建一個Mdroid.mk檔案,內容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

file := $(TARGET_OUT_KEYLAYOUT)/gpio-keys.kl
ALL_PREBUILT += $(file)
$(file): $(LOCAL_PATH)/gpio-keys.kl | $(ACP)
    $(transform-prebuilt-to-target)

file := $(TARGET_OUT_KEYLAYOUT)/power-button.kl
ALL_PREBUILT += $(file)
$(file): $(LOCAL_PATH)/power-button.kl | $(ACP)
    $(transform-prebuilt-to-target)
(4)在vendor/<company_name>/<board_name>目錄下的AndroidBoard.mk新增如下內容:
include $(LOCAL_PATH)/keymaps/Mdroid.mk

haolele 發表於 2011-11-11 21:04:44

Android系統移植之按鍵字元表本帖最後由 haolele 於 2011-11-11 21:05 編輯 

Android系統移植之按鍵字元表

上節講android的Window Manager將核心按鍵碼通過按鍵對映錶轉換成android按鍵碼,
這節講的是android按鍵碼向android字元的轉換,轉換也是通過Window Manager來完成的
(1)原始按鍵字元表,我們知道一個按鍵是可以顯示多個字元的,決定顯示字元的是CAPS(大小寫),FN,NUNMBER等按鍵
舉例如下:
                                           
                                                        
# keycode       display number  base    caps    fn      caps_fn
                                                        
A               'A'     '2'     'a'     'A'     '#'     0x00
B               'B'     '2'     'b'     'B'     '<'     0x00
C               'C'     '2'     'c'     'C'     '9'     0x00E7
D               'D'     '3'     'd'     'D'     '5'     0x00
E               'E'     '3'     'e'     'E'     '2'     0x0301
F               'F'     '3'     'f'     'F'     '6'     0x00A5
G               'G'     '4'     'g'     'G'     '-'     '_'
H               'H'     '4'     'h'     'H'     '['     '{'
I               'I'     '4'     'i'     'I'     '$'     0x0302
J               'J'     '5'     'j'     'J'     ']'     '}'
K               'K'     '5'     'k'     'K'     '"'     '~'
L               'L'     '5'     'l'     'L'     '''     '`'
M               'M'     '6'     'm'     'M'     '!'     0x00
N               'N'     '6'     'n'     'N'     '>'     0x0303
O               'O'     '6'     'o'     'O'     '('     0x00
P               'P'     '7'     'p'     'P'     ')'     0x00
Q               'Q'     '7'     'q'     'Q'     '*'     0x0300
R               'R'     '7'     'r'     'R'     '3'     0x20AC
S               'S'     '7'     's'     'S'     '4'     0x00DF
T               'T'     '8'     't'     'T'     '+'     0x00A3
U               'U'     '8'     'u'     'U'     '&'     0x0308
V               'V'     '8'     'v'     'V'     '='     '^'
W               'W'     '9'     'w'     'W'     '1'     0x00
X               'X'     '9'     'x'     'X'     '8'     0xEF00
Y               'Y'     '9'     'y'     'Y'     '%'     0x00A1
Z               'Z'     '9'     'z'     'Z'     '7'     0x00
                                                        
# on pc keyboards
COMMA           ','     ','     ','     ';'     ';'     '|'
PERIOD          '.'     '.'     '.'     ':'     ':'     0x2026
AT              '@'     '0'     '@'     '0'     '0'     0x2022
SLASH           '/'     '/'     '/'     '?'     '?'     '\'
                                                        
SPACE           0x20    0x20    0x20    0x20    0xEF01  0xEF01
ENTER         0xa     0xa     0xa     0xa     0xa     0xa
                                                        
TAB             0x9     0x9     0x9     0x9     0x9     0x9
0               '0'     '0'     '0'     ')'     ')'     ')'
1               '1'     '1'     '1'     '!'     '!'     '!'
2               '2'     '2'     '2'     '@'     '@'     '@'
3               '3'     '3'     '3'     '#'     '#'     '#'
4               '4'     '4'     '4'     '$'     '$'     '$'
5               '5'     '5'     '5'     '%'     '%'     '%'
6               '6'     '6'     '6'     '^'     '^'     '^'
7               '7'     '7'     '7'     '&'     '&'     '&'
8               '8'     '8'     '8'     '*'     '*'     '*'
9               '9'     '9'     '9'     '('     '('     '('
                                                        
GRAVE           '`'     '`'     '`'     '~'     '`'     '~'
MINUS           '-'     '-'     '-'     '_'     '-'     '_'
EQUALS          '='     '='     '='     '+'     '='     '+'
LEFT_BRACKET    '['     '['     '['     '{'     '['     '{'
RIGHT_BRACKET   ']'     ']'     ']'     '}'     ']'     '}'
BACKSLASH       '\'     '\'     '\'     '|'     '\'     '|'
SEMICOLON       ';'     ';'     ';'     ':'     ';'     ':'
APOSTROPHE      '''     '''     '''     '"'     '''     '"'
STAR            '*'     '*'     '*'     '*'     '*'     '*'
POUND           '#'     '#'     '#'     '#'     '#'     '#'
PLUS            '+'     '+'     '+'     '+'     '+'     '+'

(2)android為了減少載入時間,並沒有使用原始按鍵表檔案,而是將其轉換成二進位制檔案
轉換的工具原始碼在android原始碼build/tools/kcm目錄下,android在編譯過程中會
首先編譯轉換工具,然後利用轉換工具將android原始碼sdk/emulator/keymaps目錄下
的qwerty.kcm和qwerty2.kcm檔案分別轉換成qwerty.kcm.bin和qwerty2.kcm.bin
轉換後的二進位制檔案複製到out/target/product/<board_name>/system/usr/keychars
目錄下,也就是目標平臺的/system/usr/keychars目錄中。

(3)Window Manager對按鍵的處理在android原始碼frameworks/base/libs/ui/EventHub.cpp檔案中
Window Manager從核心接收到一個按鍵輸入事件後會首先呼叫按鍵對映表將核心按鍵碼對映成android按鍵碼(這部分上節已講),然後會
將android按鍵碼轉換成字元,具體過程如下:
(a)設定系統系統屬性hw.keyboards.裝置號.devname的值為裝置名
以上節的gpio-keys裝置為例,會設定系統屬性hw.keyboards.65539.devname的值為gpio-keys
(b)載入按鍵字元表,首先載入/system/usr/keychars目錄下的裝置名.kcm.bin檔案(此例即gpio-keys.kcm.bin檔案),如果載入失敗
則載入該目錄下的querty.kcm.bin.
(c)利用載入的按鍵字元表將android按鍵轉換成按鍵字元發給上層應用程式。

(4)一般情況下一個控制按鍵是不需要作按鍵字元表的,系統會呼叫預設的去處理,但是如果要開發一個全功能鍵盤(包含了字母和數字),那可能就需要
自己作一個專用的按鍵字元表了。android系統開發小問題-啟動過程中android字元沒有顯示出來 android目標平臺可以正常啟動,但是啟動過程中的android字元沒有顯示出來,這個是linux核心配置的問題
開啟核心framebuffer控制檯即可。
(1)make menuconifg後選擇Device Drivers->Graphics support->Console display driver support->Framebuffer Console support
然後開啟相關的幾個配置選項即可。
(2)直接修改核心配置檔案,如下:
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FONTS=y
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
CONFIG_FONT_6x11=y
# CONFIG_FONT_7x14 is not set
# CONFIG_FONT_PEARL_8x8 is not set
# CONFIG_FONT_ACORN_8x8 is not set
# CONFIG_FONT_MINI_4x6 is not set
# CONFIG_FONT_SUN8x16 is not set
# CONFIG_FONT_SUN12x22 is not set
# CONFIG_FONT_10x18 is not set
(3)android啟動過程中的android字元顯示在原始碼的system/core/init.c中,如下:
    if( load_565rle_image(INIT_IMAGE_FILE) ) {
    fd = open("/dev/tty0", O_WRONLY);
    if (fd >= 0) {
        const char *msg;
            msg = "\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "\n"  // console is 40 cols x 30 lines
        "\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "             A N D R O I D ";
        write(fd, msg, strlen(msg));
        close(fd);
    }
    } 

haolele 發表於 2011-11-11 21:06:22

Android系統開發之觸控式螢幕tslib移植(核心)和原理分析本帖最後由 haolele 於 2011-11-11 21:07 編輯

Android系統開發之觸控式螢幕tslib移植(核心)和原理分析

首先了解一下tslib的執行原理,tslib的執行分成兩部分
(1)校驗
在LCD固定座標位置依次顯示出5個座標讓使用者觸控,把LCD座標和使用者觸控時驅動屏驅動底層的座標總共5組值儲存起來
執行tslib庫的演算法對其進行運算,得出校準用7個值

(2)校準
每次觸控式螢幕驅動讀取到硬體座標時應用校準用的7個值對該座標進行一次運算,然後將運算後的座標作為正常座標即可。
按照上面的原理,
(1)我們先修改核心部分,我的平臺用的觸控螢幕驅動是tsc2007,驅動檔案為核心/drivers/input/touchscreen
目錄下的tsc2007.c和ts_linear.c
其中,ts_linear.c中定義的是校準模組,該模組在proc檔案系統中建立了7個檔案,用來存放校準用的7個點,7的點的預設值
為1,0,0,0,1,0,1,對應的目標平臺檔案系統的位置為/proc/sys/dev/ts_device目錄下a0,a1,a2,a3,a4,a5,a6等7個檔案
此模組中還定義了一個校準函式ts_linear_scale,此函式的主要內容是讀取a0,a1,a2,a3,a4,a5,a6等7個檔案中的值作為7個
校準值與傳入的觸控平座標值進行運算,返回運算結果。
ts_linear_scale函式定義如下:
int ts_linear_scale(int *x, int *y, int swap_xy)
{
    int xtemp, ytemp;

    xtemp = *x;
    ytemp = *y;

    if (cal.a == 0)
        return -EINVAL;

    *x = (cal.a + cal.a * xtemp + cal.a * ytemp) / cal.a;
    *y = (cal.a + cal.a * xtemp + cal.a * ytemp) / cal.a;

    if (swap_xy) {
        int tmp = *x;
        *x = *y;
        *y = tmp;
    }
    return 0;
}ts2007.c為觸控式螢幕驅,與其他驅動不同的地方是在取得硬體座標值傳送之前先呼叫了ts_linear_scale函式對座標值進行了校準
            if (x > 0 && y > 0)
            {
                ts_linear_scale(&x, &y, invert);
                input_report_abs(input, ABS_X, x);
                input_report_abs(input, ABS_Y, y);
                input_report_abs(input, ABS_PRESSURE, 255);
                input_report_abs(input, ABS_TOOL_WIDTH, 1);
                input_report_key(input, BTN_TOUCH, 1);
                input_sync(input);
            }

(2)在android原始碼/system/core/rootdir/init.rc檔案中新增tslib相關的巨集定義如下:
# touchscreen parameters
    export TSLIB_FBDEVICE /dev/graphics/fb0
    export TSLIB_CALIBFILE /data/etc/pointercal
    export TSLIB_CONFFILE  /system/etc/ts.conf
    export TSLIB_TRIGGERDEV /dev/input/event0
    export TSLIB_TSDEVICE /dev/input/event1

(2)移植tslib庫到android系統,比較麻煩,看下一節的內容。

(3)校驗程式完成後會將生成的7個校準值寫入到環境變數TSLIB_CALIBFILE對應的路徑/data/etc/pointercal檔案中

(4)校驗完後將pointercal檔案中的7個值分別寫入到/proc/sys/dev/ts_device目錄下a0,a1,a2,a3,a4,a5,a6檔案即可。

(5)開機啟動的時候我們編寫一個應用程式,首先判斷環境變數TSLIB_CALIBFILE對應的路徑/data/etc/pointercal檔案是否存在,如果
檔案存在而且非空,則將該檔案中的7個值取出來分別寫入到/proc/sys/dev/ts_device目錄下a0,a1,a2,a3,a4,a5,a6檔案

(6)為了確保未校驗前觸控式螢幕可用,我們將一次校驗後得出的7個座標值作為初始值,修改到核心ts_linear.c檔案中。下面是原始碼:
ts_linear.c檔案
/*
*  Touchscreen Linear Scale Adaptor
*
*  Copyright (C) 2009 Marvell Corporation

*  Author: Mark F. Brown <markb@marvell.com>
*  Based on tslib 1.0 plugin linear.c by Russel King
*
* This library is licensed under GPL.
*
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include <asm/system.h>

/*
* sysctl-tuning infrastructure.
*/
static struct ts_calibration {
/* Linear scaling and offset parameters for x,y (can include rotation) */
    int a;
} cal;

static ctl_table ts_proc_calibration_table[] = {
    {
     .ctl_name = CTL_UNNUMBERED,
     .procname = "a0",
     .data = &cal.a,
     .maxlen = sizeof(int),
     .mode = 0666,
     .proc_handler = &proc_dointvec,
     },
    {
     .ctl_name = CTL_UNNUMBERED,
     .procname = "a1",
     .data = &cal.a,
     .maxlen = sizeof(int),
     .mode = 0666,
     .proc_handler = &proc_dointvec,
     },
    {
     .ctl_name = CTL_UNNUMBERED,
     .procname = "a2",
     .data = &cal.a,
     .maxlen = sizeof(int),
     .mode = 0666,
     .proc_handler = &proc_dointvec,
     },
    {
     .ctl_name = CTL_UNNUMBERED,
     .procname = "a3",
     .data = &cal.a,
     .maxlen = sizeof(int),
     .mode = 0666,
     .proc_handler = &proc_dointvec,
     },
    {
     .ctl_name = CTL_UNNUMBERED,
     .procname = "a4",
     .data = &cal.a,
     .maxlen = sizeof(int),
     .mode = 0666,
     .proc_handler = &proc_dointvec,
     },
    {
     .ctl_name = CTL_UNNUMBERED,
     .procname = "a5",
     .data = &cal.a,
     .maxlen = sizeof(int),
     .mode = 0666,
     .proc_handler = &proc_dointvec,
     },
    {
     .ctl_name = CTL_UNNUMBERED,
     .procname = "a6",
     .data = &cal.a,
     .maxlen = sizeof(int),
     .mode = 0666,
     .proc_handler = &proc_dointvec,
     },

    {.ctl_name = 0}
};

static ctl_table ts_proc_root[] = {
    {
     .ctl_name = CTL_UNNUMBERED,
     .procname = "ts_device",
     .mode = 0555,
     .child = ts_proc_calibration_table,
     },
    {.ctl_name = 0}
};

static ctl_table ts_dev_root[] = {
    {
     .ctl_name = CTL_DEV,
     .procname = "dev",
     .mode = 0555,
     .child = ts_proc_root,
     },
    {.ctl_name = 0}
};

static struct ctl_table_header *ts_sysctl_header;

int ts_linear_scale(int *x, int *y, int swap_xy)
{
    int xtemp, ytemp;

    xtemp = *x;
    ytemp = *y;

    if (cal.a == 0)
        return -EINVAL;

    *x = (cal.a + cal.a * xtemp + cal.a * ytemp) / cal.a;
    *y = (cal.a + cal.a * xtemp + cal.a * ytemp) / cal.a;

    if (swap_xy) {
        int tmp = *x;
        *x = *y;
        *y = tmp;
    }
    return 0;
}

EXPORT_SYMBOL(ts_linear_scale);

static int __init ts_linear_init(void)
{
    ts_sysctl_header = register_sysctl_table(ts_dev_root);
    /* Use default values that leave ts numbers unchanged after transform */
    cal.a = 1;
    cal.a = 0;
    cal.a = 0;
    cal.a = 0;
    cal.a = 1;
    cal.a = 0;
    cal.a = 1;
    return 0;
}

static void __exit ts_linear_cleanup(void)
{
    unregister_sysctl_table(ts_sysctl_header);
}

module_init(ts_linear_init);
module_exit(ts_linear_cleanup);

MODULE_DESCRIPTION("touch screen linear scaling driver");
MODULE_LICENSE("GPL");



ts2007.c檔案
/*
*  linux/drivers/input/touchscreen/tsc2007.c
*
*  touch screen driver for tsc2007
*
*  Copyright (C) 2006, Marvell Corporation
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License version 2 as
*  published by the Free Software Foundation.
*/


#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/freezer.h>
#include <linux/proc_fs.h>
#include <linux/clk.h>
#include <linux/i2c.h>
#include <mach/gpio.h>

#include <linux/sysctl.h>
#include <asm/system.h>

extern int ts_linear_scale(int *x, int *y, int swap_xy);

/* Use MAV filter */
#define TSC_CMD_SETUP 0xb0

/* Use 12-bit */
#define TSC_CMD_X 0xc0
#define TSC_CMD_PLATEX 0x80
#define TSC_CMD_Y 0xd0
#define TSC_CMD_PLATEY 0x90

#define TSC_X_MAX 4096
#define TSC_Y_MAX 4096
#define TSC_X_MIN 0
#define TSC_Y_MIN 0

/* delay time for compute x, y, computed as us */

#define DEBUG
#ifdef DEBUG
#define TS_DEBUG(fmt,args...) printk(KERN_DEBUG fmt, ##args )
#else
#define TS_DEBUG(fmt,args...)
#endif
static int x_min=TSC_X_MIN;
static int y_min=TSC_Y_MIN;
static int x_max=TSC_X_MAX;
static int y_max=TSC_Y_MAX;
static int invert = 0;
static int debounce_time  = 150;
static int init_debounce = true;
static int delay_time = 1;

enum tsc2007_status {
    PEN_UP,
    PEN_DOWN,
};

struct _tsc2007 {
    struct input_dev *dev;
    int x;        /* X sample values */
    int y;        /* Y sample values */

    int status;
    struct work_struct irq_work;
    struct i2c_client *client;
    unsigned long last_touch;
};
struct _tsc2007 *g_tsc2007;

/* update abs params when min and max coordinate values are set */
int tsc2007_proc_minmax(struct ctl_table *table, int write, struct file *filp,
                     void __user *buffer, size_t *lenp, loff_t *ppos)
{
    struct _tsc2007 *tsc2007= g_tsc2007;
    struct input_dev *input = tsc2007->dev;

    /* update value */
    int ret = proc_dointvec(table, write, filp, buffer, lenp, ppos);

    /* updated abs params */
    if (input) {
        TS_DEBUG(KERN_DEBUG "update x_min %d x_max %d"
            " y_min %d y_max %d\n", x_min, x_max,
            y_min, y_max); 
        input_set_abs_params(input, ABS_X, x_min, x_max, 0, 0);
        input_set_abs_params(input, ABS_Y, y_min, y_max, 0, 0);
    }
    return ret;
}

static ctl_table tsc2007_proc_table[] = {
    {
        .ctl_name    = CTL_UNNUMBERED,
        .procname    = "x-max",
        .data        = &x_max,
        .maxlen        = sizeof(int),
        .mode        = 0666,
        .proc_handler    = &tsc2007_proc_minmax,
    },
    {
        .ctl_name    = CTL_UNNUMBERED,
        .procname    = "y-max",
        .data        = &y_max,
        .maxlen        = sizeof(int),
        .mode        = 0666,
        .proc_handler    = &tsc2007_proc_minmax,
    },
    {
        .ctl_name    = CTL_UNNUMBERED,
        .procname    = "x-min",
        .data        = &x_min,
        .maxlen        = sizeof(int),
        .mode        = 0666,
        .proc_handler    = &tsc2007_proc_minmax,
    },
    {
        .ctl_name    = CTL_UNNUMBERED,
        .procname    = "y-min",
        .data        = &y_min,
        .maxlen        = sizeof(int),
        .mode        = 0666,
        .proc_handler    = &tsc2007_proc_minmax,
    },
    {
        .ctl_name    = CTL_UNNUMBERED,
        .procname    = "invert_xy",
        .data        = &invert,
        .maxlen        = sizeof(int),
        .mode        = 0666,
        .proc_handler    = &proc_dointvec,
    },
    {
        .ctl_name    = CTL_UNNUMBERED,
        .procname    = "debounce_time",
        .data        = &debounce_time,
        .maxlen        = sizeof(int),
        .mode        = 0666,
        .proc_handler    = &proc_dointvec,
    },
    {
        .ctl_name    = CTL_UNNUMBERED,
        .procname    = "delay_time",
        .data        = &delay_time,
        .maxlen        = sizeof(int),
        .mode        = 0666,
        .proc_handler    = &proc_dointvec,
    },
    { .ctl_name = 0 }
};

static ctl_table tsc2007_proc_root[] = {
    {
        .ctl_name    = CTL_UNNUMBERED,
        .procname    = "ts_device",
        .mode        = 0555,
        .child        = tsc2007_proc_table,
    },
    { .ctl_name = 0 }
};

static ctl_table tsc2007_proc_dev_root[] = {
    {
        .ctl_name    = CTL_DEV,
        .procname    = "dev",
        .mode        = 0555,
        .child        = tsc2007_proc_root,
    },
    { .ctl_name = 0 }
};

static struct ctl_table_header *sysctl_header;

static int __init init_sysctl(void)
{
    sysctl_header = register_sysctl_table(tsc2007_proc_dev_root);
    return 0;
}

static void __exit cleanup_sysctl(void)
{
    unregister_sysctl_table(sysctl_header);
}

static int tsc2007_measure(struct i2c_client *client, int *x, int * y)
{
    u8 x_buf = {0, 0};
    u8 y_buf = {0, 0};

    i2c_smbus_write_byte(client, TSC_CMD_PLATEX);
    msleep_interruptible(delay_time);

    i2c_smbus_write_byte(client, TSC_CMD_X);
    i2c_master_recv(client, x_buf, 2);
    *x = (x_buf<<4) | (x_buf >>4);

    i2c_smbus_write_byte(client, TSC_CMD_PLATEY);
    msleep_interruptible(delay_time);

    i2c_smbus_write_byte(client, TSC_CMD_Y);
    i2c_master_recv(client, y_buf, 2);
    *y = (y_buf<<4) | (y_buf >>4);
    *y = 4096 - *y; //added by allen
    printk("\ntouchscreen x = 0x%x, y = 0x%x\n",*x,*y);
    return 0;
}

static void tsc2007_irq_work(struct work_struct *work)
{
    struct _tsc2007 *tsc2007= g_tsc2007;
    struct i2c_client *client = tsc2007-> client;
    struct input_dev *input = tsc2007->dev;

    int x = -1, y = -1, is_valid = 0;
    int tmp_x = 0, tmp_y = 0;

    int gpio = irq_to_gpio(client->irq);


    /* Ignore if PEN_DOWN */
    if(PEN_UP == tsc2007->status){

        if (gpio_request(gpio, "tsc2007 touch detect")) {
            printk(KERN_ERR "Request GPIO failed, gpio: %X\n", gpio);
            return;
        }
        gpio_direction_input(gpio);    
        
        while(0 == gpio_get_value(gpio)){

                        if ((jiffies_to_msecs(
                                ((long)jiffies - (long)tsc2007->last_touch)) <
                 debounce_time &&
                tsc2007->status == PEN_DOWN) ||
                init_debounce)
                        {
                init_debounce = false;
                                tsc2007_measure(client, &tmp_x, &tmp_y);
                                TS_DEBUG(KERN_DEBUG
                "dropping pen touch %lu %lu (%u)\n",
                                jiffies, tsc2007->last_touch,
                                jiffies_to_msecs(
                (long)jiffies - (long)tsc2007->last_touch));
                                schedule();
                continue;
                        }


            /* continue report x, y */
            if (x > 0 && y > 0)
            {
                ts_linear_scale(&x, &y, invert);
                input_report_abs(input, ABS_X, x);
                input_report_abs(input, ABS_Y, y);
                input_report_abs(input, ABS_PRESSURE, 255);
                input_report_abs(input, ABS_TOOL_WIDTH, 1);
                input_report_key(input, BTN_TOUCH, 1);
                input_sync(input);
            }

            tsc2007->status = PEN_DOWN;
            tsc2007_measure(client, &x, &y);
            TS_DEBUG(KERN_DEBUG "pen down x=%d y=%d!\n", x, y);
            is_valid = 1;
            schedule();
        }

        if (is_valid)
        {
            /*consider PEN_UP */
            tsc2007->status = PEN_UP;
            input_report_abs(input, ABS_PRESSURE, 0);
            input_report_abs(input, ABS_TOOL_WIDTH, 1);
            input_report_key(input, BTN_TOUCH, 0);
            input_sync(input);
            tsc2007->last_touch = jiffies;
            TS_DEBUG(KERN_DEBUG "pen up!\n"); 
        }

        gpio_free(gpio);    
    }
}

static irqreturn_t tsc2007_interrupt(int irq, void *dev_id)
{    
    schedule_work(&g_tsc2007->irq_work);
    
    return IRQ_HANDLED;
}

static int __devinit tsc2007_probe(struct i2c_client *client, 
                const struct i2c_device_id *id)
{
    struct _tsc2007 *tsc2007;
    struct input_dev *input_dev;
    int ret;

    tsc2007 = kzalloc(sizeof(struct _tsc2007), GFP_KERNEL);
    input_dev = input_allocate_device();

    g_tsc2007 = tsc2007;

    if (!tsc2007 || !input_dev) {
        ret = -ENOMEM;
        goto fail1;
    }

    i2c_set_clientdata(client, tsc2007);

    tsc2007->dev = input_dev;

    input_dev->name = "tsc2007";
    input_dev->phys = "tsc2007/input0";

    //input_dev->id.bustype = BUS_HOST;
    input_dev->dev.parent = &client->dev;

    __set_bit(EV_KEY, input_dev->evbit);
    __set_bit(BTN_TOUCH, input_dev->keybit);

    __set_bit(EV_ABS, input_dev->evbit);
    __set_bit(ABS_PRESSURE, input_dev->evbit);
    __set_bit(ABS_X, input_dev->evbit);
    __set_bit(ABS_Y, input_dev->evbit);

    input_set_abs_params(input_dev, ABS_X, x_min, x_max, 0, 0);
    input_set_abs_params(input_dev, ABS_Y, y_min, y_max, 0, 0);
    input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);

    ret = request_irq(client->irq, tsc2007_interrupt, 
        IRQF_DISABLED | IRQF_TRIGGER_FALLING,
         "tsc2007 irq", NULL);
    if (ret){
        printk(KERN_ERR "tsc2007 request irq failed\n");
        goto fail2;
    }

    ret = input_register_device(tsc2007->dev);
    if (ret){
        printk(KERN_ERR "tsc2007 register device fail\n");
        goto fail2;
    }

    /*init */
    tsc2007->status = PEN_UP;
    tsc2007->client = client;
    tsc2007->last_touch = jiffies;

    INIT_WORK(&tsc2007->irq_work, tsc2007_irq_work);

    /* init tsc2007 */
    i2c_smbus_write_byte(client, TSC_CMD_SETUP);

    return 0;

fail2:
    free_irq(client->irq, client);
fail1:
    i2c_set_clientdata(client, NULL);
    input_free_device(input_dev);
    kfree(tsc2007);
    return ret;
}

static int __devexit tsc2007_remove(struct i2c_client *client)
{
    struct _tsc2007 *tsc2007 = i2c_get_clientdata(client);

    if(client->irq)
        free_irq(client->irq, client);
    
    i2c_set_clientdata(client, NULL);
    input_unregister_device(tsc2007->dev);
    kfree(tsc2007);

    return 0;
}

static struct i2c_device_id tsc2007_idtable[] = { 
    { "tsc2007", 0 }, 
    { } 
}; 

MODULE_DEVICE_TABLE(i2c, tsc2007_idtable);

static struct i2c_driver tsc2007_driver = {
    .driver = {
        .name     = "tsc2007",
    },
    .id_table       = tsc2007_idtable,
    .probe        = tsc2007_probe,
    .remove        = __devexit_p(tsc2007_remove),
};

static int __init tsc2007_ts_init(void)
{
    init_sysctl();
    return i2c_add_driver(&tsc2007_driver);     
}

static void __exit tsc2007_ts_exit(void)
{
    cleanup_sysctl();
    i2c_del_driver(&tsc2007_driver);
}

module_init(tsc2007_ts_init);
module_exit(tsc2007_ts_exit);

MODULE_DESCRIPTION("tsc2007 touch screen driver");
MODULE_LICENSE("GPL");

haolele 發表於 2011-11-11 21:07:48

Android系統開發之tslib移植本帖最後由 haolele 於 2011-11-11 21:08 編輯 

Android系統開發之tslib移植

(1)切換至tslib目錄然後執行如下命令(以marvell平臺為例)
./autogen.sh
echo "ac_cv_func_malloc_0_nonnull=yes" > arm-marvell-linux.cache
./configure --host=arm-marvell-linux-gnueabi --prefix=/work/svn/ts_build --cache-file=arm-marvell-linux.cache
上面三步僅僅是為了取得tslib目錄下的config.h檔案

(2)將tslib複製到android原始碼vendor/<company_name>/<board_name>目錄下

(3)修改vendor/<company_name>/<board_name>目錄下的AndroidBoard.mk檔案,加入如下內容
include $(LOCAL_PATH)/tslib/Mdroid.mk
一定要主義LOCAL_PATH這個巨集的時效性

(4)在tslib目錄下建立Mdroid.mk,內容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

TS_PATH := $(LOCAL_PATH)

include $(TS_PATH)/src/Mdroid.mk
include $(TS_PATH)/plugins/Mdroid.mk
include $(TS_PATH)/tests/Mdroid.mk

include $(CLEAR_VARS)
file := $(TARGET_OUT_ETC)/ts.conf
$(file) : $(TS_PATH)/etc/ts.conf | $(ACP)
    $(transform-prebuilt-to-target)
ALL_PREBUILT += $(file)


(5)在tslib/src目錄下建立Mdroid.mk,內容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= ts_attach.c ts_close.c ts_config.c \
    ts_error.c ts_fd.c ts_load_module.c ts_open.c ts_parse_vars.c \
    ts_read.c ts_read_raw.c ts_option.c

LOCAL_C_INCLUDES += \
        $(LOCAL_PATH)/../

LOCAL_SHARED_LIBRARIES += libutils libcutils

LOCAL_SHARED_LIBRARIES += libdl
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := libts

include $(BUILD_SHARED_LIBRARY)


(6)在tslib/plugins目錄下建立Mdroid.mk,內容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= input-raw.c

LOCAL_C_INCLUDES += \
        $(LOCAL_PATH)/../ \
        $(LOCAL_PATH)/../src

LOCAL_SHARED_LIBRARIES := libts
LOCAL_MODULE := input
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_SRC_FILES:= pthres.c

LOCAL_C_INCLUDES += \
        $(LOCAL_PATH)/../ \
        $(LOCAL_PATH)/../src

LOCAL_SHARED_LIBRARIES := libts
LOCAL_MODULE := pthres
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_SRC_FILES:= variance.c

LOCAL_C_INCLUDES += \
        $(LOCAL_PATH)/../ \
        $(LOCAL_PATH)/../src

LOCAL_SHARED_LIBRARIES := libts
LOCAL_MODULE := variance
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_SRC_FILES:= dejitter.c

LOCAL_C_INCLUDES += \
        $(LOCAL_PATH)/../ \
        $(LOCAL_PATH)/../src

LOCAL_SHARED_LIBRARIES := libts
LOCAL_MODULE := dejitter
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_SRC_FILES:= linear.c

LOCAL_C_INCLUDES += \
        $(LOCAL_PATH)/../ \
        $(LOCAL_PATH)/../src

LOCAL_SHARED_LIBRARIES := libts
LOCAL_MODULE := linear
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)


(7)在tslib/tests目錄下建立Mdroid.mk,內容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= ts_calibrate.c fbutils.c testutils.c font_8x8.c font_8x16.c

LOCAL_C_INCLUDES += \
        $(LOCAL_PATH)/../ \
        $(LOCAL_PATH)/../src

LOCAL_SHARED_LIBRARIES := libts

LOCAL_SHARED_LIBRARIES += libutils libcutils

LOCAL_MODULE := tscalibrate

include $(BUILD_EXECUTABLE)


(8)在tslib/config.h檔案中加入如下定義:
#define TS_CONF  "/system/etc/ts.conf"
#define PLUGIN_DIR "/system/lib"
#define TS_POINTERCAL "/data/etc/pointercal"


(9)將下面路徑檔案
tslib/src/ts_open.c
tslib/tests/ts_calibrate.c
tslib/tests/fbutils.c
中的
#include <sys/fcntl.h>
修改成
#include <fcntl.h>

(10)將tslib/tests/ts_calibrate.c檔案中
static int clearbuf(struct tsdev *ts)
修改為
static void clearbuf(struct tsdev *ts)

(11)修改tslib/etc/ts.conf內容如下:
module_raw input
module pthres pmin=1
module variance delta=30
module dejitter delta=100
module linear

(12)在android原始碼init.rc中宣告tslib相關的巨集如下:
# touchscreen parameters
    export TSLIB_FBDEVICE /dev/graphics/fb0
    export TSLIB_CALIBFILE /data/etc/pointercal
    export TSLIB_CONFFILE  /system/etc/ts.conf
    export TSLIB_TRIGGERDEV /dev/input/event0
    export TSLIB_TSDEVICE /dev/input/event1

(13)重新編譯後即可呼叫tscalibrate命令來校驗觸控式螢幕,校驗後產生一個/data/etc/pointercal檔案。

 

文末彩蛋:

1.CSDN學院助學會員:僅需百元- 1300門課+600次下載特權,一次購買,全年無憂!點選檢視。

2.CSDN學院知識週刊:每週更新學院優惠課程活動及精品上新內容,點選檢視!

3.本期推薦linux課程:

課程名稱 課程連結 技術分類
Linux視訊教程 https://edu.csdn.net/course/detail/9128?utm_source=blog11xk 系統/網路/運維 > Linux
zabbix企業實戰應用 https://edu.csdn.net/course/detail/9124?utm_source=blog11xk 系統/網路/運維 > Linux
Linux 實用講解+實操+面試題 https://edu.csdn.net/course/detail/9116?utm_source=blog11xk 系統/網路/運維 > Linux

相關文章