Android系统移植方法详解(转)

Android系统移植方法详解
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目录下。

haolele 发表于 2011-11-11 21:03:34

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文件。
 
 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《Android驱动开发与移植实战详解》是一本系统讲解在Android平台上驱动开发与移植的书籍。本书主要内容包括Android系统架构、驱动框架、Linux驱动开发方法Android下驱动开发与移植等方面。本书由易到难、由浅入深,从讲解Android系统架构和驱动框架开始,通过对Linux内核驱动开发方法的讲解来引入读者进入Android下驱动开发与移植的实践。 本书从Android平台的体系结构开始,系统介绍了Android平台的各个组成部分,包括Java层、Native层和Linux内核层。在介绍完整个Android系统架构的同时,本书也详细讲解了Android内核的驱动框架,包括Linux内核驱动框架和Android内核驱动框架,并详细介绍了驱动的编写方法、调试方法和性能优化技巧。 本书还介绍了Android系统下常用硬件的驱动开发方法,包括USB驱动、SPI驱动、I2C驱动、MMC/SD卡驱动、LCD驱动、触摸屏驱动、按键驱动等。而且本书还详细介绍了Android系统的设备树,以及如何进行驱动的移植和调试。 总体来说,本书内容丰富,对Android驱动开发及移植有一定的基础和经验的读者可以通过本书进一步提高自己的技术水平。该书能帮助读者深入理解Android系统的内在机制,掌握Android驱动开发与移植的实际应用技能,是一本实用性强的专业书籍。 ### 回答2: 《Android驱动开发与移植实战详解pdf》是一本关于Android系统驱动开发与移植的专业性教材,主要介绍了如何进行Android系统驱动的开发、调试和移植,帮助读者掌握Android系统底层驱动的知识和技术。 本书首先介绍了Android系统的架构和驱动模型,深入分析了Android设备驱动的实现方式和工作流程。然后详细讲解了如何编写和调试Android驱动程序,包括内核模块、字符设备驱动、块设备驱动等多种类型的驱动开发。 此外,本书还解释了Android驱动程序的移植方法和技巧,包括从其他Linux系统移植Android驱动程序、自定义Android驱动程序以及如何把一个驱动程序移植到不同的设备上等重要内容。这样的话,读者可以在实际项目开发中更加容易地完成Android驱动程序的实现和移植。 总之,《Android驱动开发与移植实战详解pdf》是一本涵盖了Android系统驱动开发和移植等方面内容,对于想进一步了解Android系统底层工作原理的读者有着重要的指导意义。无论是初学者还是有经验的开发人员,在阅读本书后都可以获得很多关于Android驱动开发和移植的实用技巧和工具。 ### 回答3: 《android驱动开发与移植实战详解》是一本介绍Android驱动程序开发和移植的实用指南。本书包含了许多基础概念、应用场景和实例,可以帮助读者快速学习Android驱动程序开发和移植的实际应用。 本书的内容涉及很多主题,例如Android系统的架构和驱动模型、设备驱动程序的编写、驱动程序的调试和测试、不同类型设备的驱动程序移植等。其中,编写设备驱动程序需要掌握C语言的基础知识,而调试和测试则需要熟悉一些工具和技术。 本书的每一章节都配有大量的实例代码和案例分析,可以帮助读者深入理解Android驱动程序的开发和移植流程。同时,作者也提供了一些实用的技巧和建议,例如如何选择最合适的驱动程序类型、如何调试设备驱动程序、如何在移植设备驱动程序时避免常见问题等。 总之,《android驱动开发与移植实战详解》是一本非常实用的书籍,可以帮助Android开发者更加深入地了解驱动程序开发和移植的实际应用。对于那些刚开始从事Android开发的读者来说,这本书也是一个非常不错的入门指南。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值