android驱动之jogball

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/

相关日志

月经博文不看也罢

什么叫月经博文? 呵呵,那就看下面吧。

在每个人的个人blog上总会有这样的文章:

好久没来这里了,觉得这一段过的很忙没有时间写blog,以后我会坚持写的 诸如此类。。。

我其实也想写这样的话但是,觉得自己写的也太多了,所以就不无志者长立志了。写本文就是上来冒个泡,别让人觉得我人间蒸发了,或者不在计算机行当工作了。过去的一年让我学会了很多,未来的一年我很期待。我有好多信息想分享到网上,也许是我太懒,但是不能在懒了,再懒下去我就OUT了。

纪念一下,很让人难忘的2009。。

相关日志

北有中关村, 南有华强北!

来深圳一段时间了, 今天有幸去了, 一直听说的华强北. 真是不愧那一句话, 北有中关村, 南有华强北.

这里好多电子市场, 注意是电子市场, 不是一般所说的电脑城, 或者是科技市场. 每座大楼里面1层和2层基本都是电子元件, 想要什么电子元件, 你一定可以找到, 电容论斤称的(开玩笑), 电阻, 二极管, 三极管什么的, 基本上你想找的芯片都能够找到, 我真希望我是个硬件, 自己买回去整个山寨机出来, 可惜了. 说起来深圳了, 一定要去看看水货手机和山寨机, 山寨机的那个强大, 都不用我多说的. 我偶然进了一个专门作电池的店, 里面有个牌子写着, 国产电池, 现场制作, 看完那一个寒阿….一堆一堆的电池,都没有包装, 露着金属皮, 你要什么样就给你贴什么样的, 匆800毫安时到9800都有, 各种各样的形状, 现在可以理解山寨机的强大了. 一个专做iphone配件的, 里面有背壳, 面板, 主板, 电池, 只要你能想到的, 他基本都有, 他要是想,绝对能弄出来个iphone……真是太…呵呵.

长见识了, 有机会的话一定带个深圳特产–山寨机回去…哈哈

相关日志

有人要google wave的邀请么?

突然发现,google wave已经给我发测试邀请了,同时给我了28个邀请,谁要的,留下gmail邮件地址,我邀请他。

谢谢 同志们的光临, 我的邀请已经放完了,不好意思了…..

相关日志

计算机专业人士眼中的女人,cyher续

有的女人就像Windows 虽然很优秀,但是安全隐患太大。
有的女人就像UNIX 她条件很好,然而不是谁都能玩的起。
有的女人就像C# 长的很漂亮,但是家务活不行。
有的女人就像C++,她会默默的为你做很多的事情。
有的女人就像JAVA,只需一点付出她就会为你到处服务。
有的女人就像JAVA script,虽然对她处处小心但最终还是没有结果。
有的女人就像汇编 虽然很麻烦,但是有的时候还得求它。
有的女人就像 SQL,她会为你的发展带来莫大的帮助。
爱情就是死循环,一旦执行就陷进去了。
爱上一个人,就是内存泄露,你永远释放不了。
真正爱上一个人的时候,那就是常量限定,永远不会改变。
女朋友就是私有变量,只有我这个类才能调用。
情人就是指针用的时候一定要注意,要不然就带来巨大的灾难。

这是我今天在网络上看到的,决挺有意思,于是就自己写个我眼中的女人.

  • 我的女人一定不能像windows, 有大众脸不说, 还有一些自己认识不到的怪癖, 身体素质那一个差啊,还容易受那些叫做”virus”小痞子伤害.
  • 我的女人一定不能像java, 谁给她一点好处, 她就能给别人”服务”,而且还不择对象,绝对不能这样!
  • 我的女人一定不能像C++, 满腹经论 ,高学历, 但是我完全控制不了么, 我可不想天天看个电视还要弄个”对象”出来.年老之后略显臃肿.
  • 我的女人一定不能 像IE6, 大众情人?不过已经是人老花黄了.最可怕的是她自己不这样认为.
  • 我的女人可以像C, 简单而睿智,不是谁都能掌控,虽然有时候会莫名其妙的生气,但是绝对是我的错.
  • 我的女人可以像UNIX, 她可以是高官子弟, 她可以是名门之后,她可以是一介草民,但是她们在我眼中都有同样的高素质,对我都是那样和谐,温柔. (POSIX)
  • 我的女人可以像linux, 虽然不是那么容易征服, 但是对我敞开心扉,只要我用心,她一定是我的.
  • 我的女人可以像 Mac os x, 长的好看不说, 还高素质, 我能轻松与之交流, 关键是那些virus只认识照她样子整过容的windows.
  • 我的女人可以像python, 可爱,简单, 我和她在一起很开心.

…….

相关日志