歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Android jogball 驅動分析

Android jogball 驅動分析

日期:2017/2/28 16:21:49   编辑:Linux教程

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/

Copyright © Linux教程網 All Rights Reserved