16 2010

android驱动之jogball

cyher

1 简介

JogBall是首款Android手机-HTC Dream上附带的类似轨迹球Trackball的滑轮,通过Jogball用户可以轻松的实现网页的翻页、地图翻

转等操作,这种在手机上增加轨迹球的方式可以取消传统的4维导航键,Jogball并非HTC公司的首例,早在HTC 3300(Dopod P800)就

实现了这项功能,轨迹球操作方式的加入可以实现像电脑上鼠标一样轻松操控。现在jogball基本上算是android手机的标准配置了。

2 框图&架构


2.1 gpio_event子系统

Jogball驱动是由linux代码中的gpio_event子系统实现的。
由以下文件组成:

  • driver/input/misc/gpio_event.c
  • driver/input/misc/gpio_input.c
  • driver/input/misc/gpio_output.c
  • driver/input/misc/gpio_matrix.c
  • driver/input/misc/gpio_axis.c

gpio_event子系统是一个关于gpio的输入设备的通用代码,里面可以包含一般嵌入式设备中需要的键盘阵列和坐标有关的输入等。

2.2 Jogball架构

Jogball是归类于gpio_axis.c中的,是一个相对坐标系,判断电信号的高低来对坐标加或者减一定数值。具体细节在gpio_axis.c中

gpio_axis.c中的结构体初始化是在xxx-borad.c中的,基本架构就是这样,细节在下文叙述。

3 硬件描述


3.1 Jogball机械特性

Jogball是一个基于滚球滚动的输入设备,所以它机械特性也是比较重要,知道他的机械特性,便于我们理解驱动。
Jogball和以前的滚球鼠标比较相似,依靠滚轮的滚动来带动四周的圆柱体旋转。每个圆柱体端头都有一个磁铁,这个磁体铁从横断

面来看就是由N极的扇形和S极的扇形来组成一个圆周。这样当磁铁旋转的时候,N极和S极切换,使霍尔IC产生高低电平。
注意:在滚球旋转时,两个相对方向只有一个方向可以转动,这是为了减化软件编写的一个机械特性。

3.2 Jogball的电气特性

Jogball最重要的电特性就是这个霍尔IC,

霍尔元件的工作原理:所谓霍尔效应,是指磁场作用于载流金属导体、半导体中的载流子时,产生横向电位差的物理现

象。金属的霍尔效应是1879年被美 国物理学家霍尔发现的。当电流通过金属箔片时,若在垂直于电流的方向施加磁场,则金属箔片

两侧面会出现横向电位差。半导体中的霍尔效应比金属箔片中更为明 显,而铁磁金属在居里温度以下将呈现极强的霍尔效应。

所以jogball是旋转磁轴引起磁场的变幻,来产生高低电压的。从而根据机械特性就不难理解jogball的数字输入过程。

3.3 Jogball的原理图

其实jogball只是机械结构,原理图是hall ic的,有兴趣的人在这里下载

4 数据结构

struct hero_axis_info {
        struct gpio_event_axis_info info; /*gpio_event_axis结构的信息*/
        uint16_t in_state;/*记录输入的高低电平信号*/
        uint16_t out_state;/*记录输出的高低电平信号*/
        uint16_t temp_state;/*临时存储高低电平*/
        uint16_t threshold;/*门限值,超过这个值上报给input子系统*/
};
 
struct gpio_event_axis_info {
        /* initialize to gpio_event_axis_func */
        struct gpio_event_info info; /*gpio_event信息*/
        uint8_t  count; /*gpio的数量*/
        uint8_t  type; /* EV_REL or EV_ABS */
        uint16_t code; /*输入键值类型*/
        uint16_t decoded_size; /*gpio 数组的大小*/
        uint16_t (*map)(struct gpio_event_axis_info *info, uint16_t in); /*解析回调函数*/
        uint32_t *gpio; /*gpio端口数组*/
        uint32_t flags; /*调试标值*/
        uint32_t enable_emc_protect_delay; /*保护间隔时间*/
        uint16_t emc_gpio_state; /* 延时中用到gpio_state*/
        atomic_t emc_disable_irqnum;/*延时中用到的屏蔽的中断号*/
};
 
struct gpio_event_info {
        int (*func)(struct input_dev *input_dev,
        struct gpio_event_info *info,
        void **data, int func);
        /*给gpio_event子系统中实现注册到内核中的回调函数*/
        int (*event)(struct input_dev *input_dev,
        struct gpio_event_info *info,
        void **data, unsigned int type,
        unsigned int code, int value); /* out events */
};
 
struct gpio_event_platform_data {
        const char *name;/*名字*/
        struct gpio_event_info **info;/*gpio_event的结构指针*/
        size_t info_count;/*注册到axis中的info 结构体的数量*/
        int (*power)(const struct gpio_event_platform_data *pdata, bool on);/*电源管理回调函数*/
};

5 代码分析

5.1 通用代码

driver/input/misc/gpio_event.c

/*gpio_event基本数据结构*/
struct gpio_event {
        struct input_dev *input_dev;
        const struct gpio_event_platform_data *info;
        struct early_suspend early_suspend;
        void *state[0];
};
 
/*注册给input的回调函数*/
static int gpio_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 
/*调用下层给的回调函数来实现具体的注册*/
static int gpio_event_call_all_func(struct gpio_event *ip, int func)
/*电源管理*/
#ifdef CONFIG_HAS_EARLYSUSPEND
void gpio_event_suspend(struct early_suspend *h)
 
void gpio_event_resume(struct early_suspend *h)
#endif
/*注册*/
static int __init gpio_event_probe(struct platform_device *pdev)
/*注销*/
static int gpio_event_remove(struct platform_device *pdev)
 
static struct platform_driver gpio_event_driver
static int __devinit gpio_event_init(void)
 
static void __exit gpio_event_exit(void)

gpio_event.c:主要是gpio_event子系统的框架

5.2 soc代码

driver/input/misc/gpio_axis.c

struct gpio_axis_state {
struct input_dev *input_dev;/*input设备结构*/
struct gpio_event_axis_info *info; /*坐标系数据结构*/
uint32_t pos; /*位置*/
struct hrtimer emc_hrtimer_delay; /* 延时时间*/
atomic_t atomic_emc_hrtimer_is_run; /*延时的原子变量*/
};
/*上报input数据*/
static void gpio_event_update_axis(struct gpio_axis_state *as, int report)
/*时间处理函数*/
static enum hrtimer_restart emc_progress_hrtimer_handler_func(struct hrtimer *timer)
/*中断处理函数*/
static irqreturn_t gpio_axis_irq_handler(int irq, void *dev_id)
/*给上层的注册回调函数*/
int gpio_event_axis_func(struct input_dev *input_dev, struct gpio_event_info *info, void **data, int func)

5.3 platform代码

例如:/arch/arm/match-msm/board-72×7.c

uint16_t hero_axis_map(struct gpio_event_axis_info *info, uint16_t in)
{
        struct hero_axis_info *ai = container_of(info, struct hero_axis_info, info);
        uint16_t out = ai->out_state;
 
if (nav_just_on) {
        if (jiffies == nav_on_jiffies || jiffies == nav_on_jiffies + 1)
                goto ignore;
        nav_just_on = 0;
}
 
if((ai->in_state ^ in) & 1) /*检测在方向1上有没有数值变化*/
        out--;
if((ai->n_state ^ in) & 2) /*检测在方向1相对方向上有没有数值变化*/
        out++;
ai->;out_state = out;
ignore:
        ai->in_state = in;
if (ai->out_state - ai->temp_state == ai->threshold) {
        ai->temp_state++;
        ai->out_state = ai->temp_state;
} else if (ai->temp_state - ai-out_state == ai->threshold) {
        ai->temp_state--;
        ai->out_state = ai->temp_state;
} else if (abs(ai->out_state - ai->;temp_state) > ai->threshold)
        ai->temp_state = ai->out_state;
 
return ai->temp_state;
}

以上函数,是最终的数据解析函数,也就是把硬件中读出来的数据,转化为实际的位置变化的函数。此函数主要做了差错控制,增加

了程序的鲁棒性和可订制性。

static struct hero_axis_info hero_x_axis = {
        .threshold = 1,
                .info = {
                .info.func = gpio_event_axis_func,
                .count = ARRAY_SIZE(hero_x_axis_gpios),
                .type = EV_REL,
                .code = REL_X,
                .decoded_size = 1U << ARRAY_SIZE(hero_x_axis_gpios),
                .map = hero_axis_map,
                .gpio = hero_x_axis_gpios,
                .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT */,
                .enable_emc_protect_delay = 1 * NSEC_PER_MSEC,
        }
};

X轴上的info结构体的初始化

static struct hero_axis_info hero_y_axis = {
        .threshold = 1,
                .info = {
                .info.func = gpio_event_axis_func,
                .count = ARRAY_SIZE(hero_y_axis_gpios),
                .type = EV_REL,
                .code = REL_Y,
                .decoded_size = 1U << ARRAY_SIZE(hero_y_axis_gpios),
                .map = hero_axis_map,
                .gpio = hero_y_axis_gpios,
                .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT  */,
                .enable_emc_protect_delay = 1 * NSEC_PER_MSEC,
        }
};

Y轴上的info结构体的初始化

6 备注

在android的framework的代码中识别jogball设备是识别成鼠标的特性的,不仅有坐标还是由按键的,但是驱动中并没有axis中并没

有按键,所以在注册input设备的时候要加入按键的键值。如下代码:
在drivers/input/misc/gpio_axis.c中的gpio_event_axis_func函数中

as->input_dev = input_dev;
as->info = ai;
 
input_set_capability(input_dev, ai->type, ai->;code);
if (ai->type == EV_ABS) {
        input_set_abs_params(input_dev, ai->code, 0,
        ai->decoded_size - 1, 0, 0);
}

input_set_capability(input_dev, ai->type, BT_MOUSE);

本文源码是基于hero手机kernel代码
kernel_hero/arch/arm/mach-msm/board-hero.c
下载地址 http://developer.htc.com/

相关日志


24 2009

linux进程可执行文件的绝对路径

cyher

这种情况很少遇到,我们需要一个运行中进程的绝对路径,可惜的是glibc中或者系统调用中我都没有找到类似的函数。但是linux绝对不会不给你这个机会的,那就是proc文件系统了。在proc文件系统中那些数字都是运行中的进程,进入一个文件名为数字的文件夹以后,我们就可以发现以下类似文件目录结构。

[cyher@cyher ~]$ ls /proc/3355/
attr             cpuset   io        mountinfo   pagemap      smaps    task
auxv             cwd      latency   mounts      personality  stack    wchan
cgroup           environ  limits    mountstats  root         stat
clear_refs       exe      loginuid  net         sched        statm
cmdline          fd       maps      oom_adj     schedstat    status
coredump_filter  fdinfo   mem       oom_score   sessionid    syscall

这里就是一个进程所有的信息了大名鼎鼎的ps命令就是读取这里的内容解析出信息的,这里是ps的官方网站 http://procps.sourceforge.net/

那好了,就用这里给的信息来解析出执行文件的绝对路径吧

/*
 * =====================================================================================
 *
 *       Filename:  get_exe_path.c
 *
 *    Description:
 *
 *        Version:  1.0
 *        Created:  2009年09月23日 17时07分17秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  cyher (), cyher.net@gmail.com
 *        Company:  cyher.net
 *
 * =====================================================================================
 */
 
#include
#include
#include
#define BUF 128
 
int main(int agrc, char **argv) {
    char buf[BUF];
    char proc[BUF];
    char *p;
 
    sprintf(proc, "/proc/%d/exe", atoi(argv[1]));
    readlink(proc,buf, BUF); /*proc/pid/exe 是一个链接,用readlink读*/
    p = strchr(buf,'('); /*读出的路径后面有可能会有 (deleted)字样,删去*/
    if (p != NULL) {
        p--;
        *p = '\0';
    }
    puts(buf);
}

这样就能读取出绝对路径了,不过你首先要知道pid啊 呵呵。

相关日志


16 2009

自己曾经作过的小实验

cyher

youku链接:http://v.youku.com/v_show/id_XMTAyODE5MjEy.html

相关日志


9 2009

自己的嵌入式学习经验, 想不到别人给拍成视频了

cyher

见笑了….呵呵. 说的太年轻气盛了….别拍阿,我知错了.现在需要低调…呵呵.

相关日志


26 2009

在macbook上安装各种操作系统

cyher

想在macbook上装操作系统, 但是鉴于macbook于一般pc还不是很相同,所以在发行版的选择上还是有点困难的. 经过我在网上的搜索最后结合我自己的需要,在我的macbook pro上装了ubuntu,opensolaris这两个系统.(别提windows, 他就是用的人多点,其他没有什么可取之处,结论仅限于计算机爱好者).

mac上多系统启动
http://wiki.onmac.net/index.php/Triple_Boot_via_BootCamp_Ubuntu


ubuntu上装mac
https://wiki.ubuntu.com/MactelSupportTeam/CommunityHelpPages

最后还是选择ubuntu, 这个在资深linuxer中口碑不是很好的系统, 为什么口碑不好, 我想是因为ubuntu的成功有点不劳而获的感觉吧.整个系统建立在debian上,而自身对linux内核和软件库的贡献相对他的成功要少.当然这写东西不是我们要讨论的.为什么我选择了ubuntu装在我的macbook上, 因为我需要的是一个稳定,实用,功能完善的系统,主要作桌面应用和编码而不是作系统研究的OS, ubuntu都支持的非常好,在各大linux发行办中支持的最好了.ubuntu有专门的mac支持的团队,看上面的链接,所以很人性化了,其实最重要的是简单了,我现在的情况估计不允许我长时间编译gentoo…..

推荐指数: * * * * *

mac上opensolaris
http://wiki.genunix.org/wiki/index.php/OpenSolaris_Dual_Boot
http://blogs.sun.com/judychen/entry/在macbook_pro上安装solaris
http://www.weiphone.com/viewthread.php?tid=208850
http://developers.sun.com.cn/solaris/opensolaris_2005_mac.html#author
http://wikis.sun.com/display/chosug/OpenSolaris+2009.06+on+a+MacBook+Pro

solaris,哈,同样经典的unix, 现在有opensolaris项目能够跑在x86体系上,看上面的链接就知道sun和apple的关系还是不错的,opensolaris有很好的官方支持macbook.所以希望了解solaris的童鞋不能错过了.我跟人对opensolaris也是一知半解就不多说了,不过感觉不错.

推荐值数: * * * *

mac上debian
http://wiki.debian.org/MacBook
debian,最古老,软件包最多,最自由,最有linux精神的发行版之一,是ubuntu他爹,同样对macbook支持不错,就是配置起来稍微geek点, 喜欢钻研系统的高手们,推荐使用.

推荐指数: * * * *

mac上gentoo
http://www.odi.ch/prog/macbookpro/index.php
gentoo,包管理系统借鉴bsd的port, 全部源码自编译, 高手以及时间充裕的人,我相信一定能做出最适合自己,速度最快的linux. gentoo的意思是一种游的最快的企鹅.

推荐指数: * * *

mac上opensuse
http://en.opensuse.org/Installation_on_MacBook
opensuse, 华丽, 企业级高端应用, top500的超级计算机很多用的都是suse,这是为什么呢?我也不知道…想想华丽的suse配上精致的macbook一定感觉不错,但是文档支持一般, 软件支持也一般了.

推荐值数: * *

mac上arch linux
http://wiki.archlinux.org/index.php/MacBook#Mac_OS_X_with_Arch_Linux
http://wiki.archlinux.org/index.php/MacBook_Aluminum
http://wiki.archlinux.org/index.php/MacBookPro
arch linux, 轻量级linux,可定制性高,对i686有特殊优化. 对mac支持还算不错,对于一般用户来说还是要费点事的.arch可能就是gentoo的折衷方案吧.

推荐指数: * * *

mac上fedora
http://www.cenolan.com/2009/06/installing-fedora-11-on-a-macbook/
fedora, redhat支持的开源发行版,那是相当的有实力,我也一直用.但是装在macbook上可能难度不亚于arch或者gentoo,连个官方文档都难找到.不过上面那个链接介绍的已经很清楚了, 喜欢fedora的童鞋别错过了,毕竟fedora还是一个非常不错的发行版.

推荐指数: * * *

mac上freebsd
http://wiki.freebsd.org/AppleMacbook
freebsd, 和mac os x 同属一系. 优秀的架构,很适合作服务器应用, 让我想不到的是,对mac的支持也是相当的不错的,但是用起来还是需要一些经验和技术的,总之,freebsd装在mac上有些怪怪的,不过freebsd还是相当有内涵的OS大家不妨试试.

推荐指数: * * *

后记: 我们以前在pc上装hackintosh, 现在我们也在mac上装各种开源系统,这里我没有写安装过程,是因为,上面的链接里面已经讲的非常清楚了.写这个目的就是让人们知道,世界上不只有windows和mac os x, 还有许多优秀的系统, 在某些方面甚至更优秀.希望我们中国的开源事业能从OS开始, windows是个毒瘤, 把我们变的越来越傻, 我们越用越难以脱离, 我们就是这样被微软控制的.声明:没有说微软的技术不好, 只是它太封闭, 太独裁. 我们现在的版权意识很差,windows用的都是基本盗版的, 等到盗版不了的时候, 只有乖乖的交钱了. linux不仅免费,还能让我们更了解操作系统, 这样才是安全的.

相关日志