android物理按键samsungexynos4210平台 samsung exynos 7420


关键词:android按键矩阵按键 AD按键

平台信息:

内核:linux2.6/linux3.0

系统:android/android4.0

平台:S5PV310(samsungexynos4210)

一、硬件部分:

1、矩阵按键、IO按键、AD按键

这个知识相对来说比较简单,不过上次真有一个网友不太清楚这个。所以这个基础部分我们在这里也说一下。

(1)、矩阵按键


记得上大学时学单片机时,这个矩阵按键还是个重点呢,上面的图还是AT89S52的片子,工作原理比较简单,通过行、列来确定是那个按键按下,比如说上图标号为1的键按下,IO(P1.7,P1.3)有电平变化,程序可以通过这里来判断是那一个键按下的,同理标号为2的按键按下IO(P1.4,P1.0)有电平变化。

这样做程序上要从两个IO来判断是那个键按下,多了一个步骤,但是在硬件上有一个优势,就是如果按键比较多的时候比较节省IO口,比如说上面4x4= 16,8个IO可以做16个按键,8x8=64,16个IO可以做64个按键。

优点:可以用少的IO来做多个按键,判断按键比较准确;

缺点:程序上相对IO按键来说多了一步。

(2)、IO按键

这个就比较简单了,用一个IO口的高低电平来判断按键是否按下。

优点:程序、硬件电路都比较简单,判断按键比较准确;

缺点:IO有限、按键多时不太合适。比如矩阵按键16个IO可以表示64个按键,IO的话只有16个。

(3)、AD按键

这个在之前在做电视的时候用的比较多一点。

AD按键就是通过一个ADC接口,如下图所示,给一个VCC电压,比如说S1接地时AD接口得到的模拟电压值为ADC=0;当S2按下时,ADC= VCC/(R1+R2)*R2;这样就可以得到不同的ADC值,程序中在这里判断是那个按键按下。

优点:程序、硬件电路都比较简单,一个IO可以做多个按键;

缺点:AD按键有时候判断不准确,所以在程序中要多加检测AD值的次数。

2、S5PV310的矩阵按键

硬件原理图如下:


硬件接口说明:vol+,vol-,back,home,menu为1*5的矩阵键盘,芯片接口信息如下:

XGNSS_GPIO_3/KP_COL3

XGNSS_GPIO_4/KP_COL4

XGNSS_GPIO_5/KP_COL5

XGNSS_GPIO_6/KP_COL6

XGNSS_GPIO_7/KP_COL7

XEINT17/KP_ROW1

我们这里1*5=5也没有节省多少IO呀?情况是这样的,我们的原理图是从三星开发板上参考过来的,开发板上按键本来多一点,可是我们用不了那么多,人家那样做比较合理。可是我们“偷懒”,硬件上不用改,软件上也不用改,从这一点也可以看出我们国内做技术这个行业的有点……不太深入呀,整天老板在催,可是我们在细节上做不太好呀。三星在IO矩阵也有专用接口,所以就“奢侈”一次,用1*5的矩阵来实现5个按键。

3、S5PV310的矩阵按键接口

看一下芯片上的专用接口,如下图,全用的话有点多。



关于专用接口的寄存器,这些寄存器我们后面要用得到的,按键的行、列信息会在这里面暂存的。


以S5PV310为例,驱动代码:samsung-keypad.c

软件部分:

总体流程图如下,这个是在触摸屏基础上改过来的,感觉流程都是这个样子的。中断触发,中断处理。


一、矩阵键行、列设定,和上报键值设定

在android-kernel-samsung-dev/arch/arm/mach-exynos/mach-smdkv310.c中

[cpp]viewplaincopy
  1. staticuint32_tsmdkv310_keymap[]__initdata={
  2. KEY(0,3,KEY_1),KEY(0,4,KEY_2),KEY(0,5,KEY_3),
  3. KEY(0,6,KEY_4),KEY(0,7,KEY_5),
  4. KEY(1,3,KEY_A),KEY(1,4,KEY_C),KEY(1,5,KEY_E),
  5. KEY(1,6,KEY_B),KEY(1,7,KEY_D)//(1)、键值初始化;
  6. };
  7. staticstructmatrix_keymap_datasmdkv310_keymap_data__initdata={
  8. .keymap=smdkv310_keymap,
  9. .keymap_size=ARRAY_SIZE(smdkv310_keymap),
  10. };
  11. staticstructsamsung_keypad_platdatasmdkv310_keypad_data__initdata={
  12. .keymap_data=&smdkv310_keymap_data,
  13. .rows=2,//(2)、行、列设定,8行、2列,其实我们只用了5行、1列;
  14. .cols=8,
  15. };
  16. staticvoid__initsmdkv310_machine_init(void)
  17. {
  18. samsung_keypad_set_platdata(&smdkv310_keypad_data);//(3)、平台设备初始化;
  19. }

(1)、KEY(row, col,keycode)

KEY这个宏在android-kernel-samsung-dev/include/linux/input/Matrix_keypad.h中实现:

[cpp]viewplaincopy
  1. #defineMATRIX_MAX_ROWS32
  2. #defineMATRIX_MAX_COLS32
  3. #defineKEY(row,col,val)((((row)&(MATRIX_MAX_ROWS-1))<<24)|
  4. (((col)&(MATRIX_MAX_COLS-1))<<16)|
  5. ((val)&0xffff))

keycode的值在android-kernel-samsung-dev/include/linux/input.h中有定义,如下:

[cpp]viewplaincopy
  1. #defineKEY_RESERVED0
  2. #defineKEY_ESC1
  3. #defineKEY_12
  4. #defineKEY_23
  5. #defineKEY_34
  6. #defineKEY_45
  7. #defineKEY_56
  8. #defineKEY_67
  9. #defineKEY_78
  10. #defineKEY_89
  11. #defineKEY_910
  12. #defineKEY_011
  13. #defineKEY_MINUS12
  14. #defineKEY_EQUAL13
  15. #defineKEY_BACKSPACE14
  16. #defineKEY_TAB15
  17. #defineKEY_Q16
  18. #defineKEY_W17
  19. #defineKEY_E18
  20. #defineKEY_R19
  21. #defineKEY_T20
  22. #defineKEY_Y21
  23. #defineKEY_U22

(2)、行列设定;

[cpp]viewplaincopy
  1. .rows=2,
  2. .cols=8,

(3)、平台设备初始化;

[cpp]viewplaincopy
  1. samsung_keypad_set_platdata(&smdkv310_keypad_data)。

二、上面设定的keycode键值和上层相对应

4.0.3_r1/device/samsung/smdkv310/samsung-keypad.kl中

[cpp]viewplaincopy
  1. key2DPAD_UPWAKE_DROPPED
  2. key3DPAD_CENTERWAKE_DROPPED
  3. key4DPAD_DOWNWAKE_DROPPED
  4. key5DPAD_RIGHTWAKE_DROPPED
  5. key6DPAD_LEFTWAKE_DROPPED
  6. key18VOLUME_DOWNWAKE
  7. key30HOMEWAKE_DROPPED
  8. key32MENUWAKE_DROPPED
  9. key46VOLUME_UPWAKE
  10. key48BACKWAKE_DROPPED
  11. key10POWERWAKE

总体对应图:

以KEY_A为例,KEY_A30最终和上层的keypad.kl中的30 HOME相对应




三、矩阵键盘驱动程序分析

android-kernel-samsung-dev/drivers/input/keyboard/samsung-keypad.c

1、probe函数分析:

[cpp]viewplaincopy
  1. staticint__devinitsamsung_keypad_probe(structplatform_device*pdev)
  2. {
  3. conststructsamsung_keypad_platdata*pdata;
  4. conststructmatrix_keymap_data*keymap_data;
  5. structsamsung_keypad*keypad;
  6. structresource*res;
  7. structinput_dev*input_dev;
  8. unsignedintrow_shift;
  9. unsignedintkeymap_size;
  10. interror;
  11. ………………
  12. keymap_size=(pdata->rows<<row_shift)*sizeof(keypad->keycodes[0]);
  13. keypad=kzalloc(sizeof(*keypad)+keymap_size,GFP_KERNEL);
  14. input_dev=input_allocate_device();
  15. if(!keypad||!input_dev){
  16. error=-ENOMEM;
  17. gotoerr_free_mem;
  18. }
  19. res=platform_get_resource(pdev,IORESOURCE_MEM,0);
  20. if(!res){
  21. error=-ENODEV;
  22. gotoerr_free_mem;
  23. }
  24. keypad->base=ioremap(res->start,resource_size(res));
  25. if(!keypad->base){
  26. error=-EBUSY;
  27. gotoerr_free_mem;
  28. }
  29. …………
  30. //(1)、input参数初始化;
  31. keypad->input_dev=input_dev;
  32. keypad->row_shift=row_shift;
  33. keypad->rows=pdata->rows;
  34. keypad->cols=pdata->cols;
  35. init_waitqueue_head(&keypad->wait);
  36. input_dev->name=pdev->name;
  37. input_dev->id.bustype=BUS_HOST;
  38. input_dev->dev.parent=&pdev->dev;
  39. input_set_drvdata(input_dev,keypad);
  40. //(2)、打开、关闭函数;
  41. input_dev->open=samsung_keypad_open;
  42. input_dev->close=samsung_keypad_close;
  43. input_dev->evbit[0]=BIT_MASK(EV_KEY);
  44. if(!pdata->no_autorepeat)
  45. input_dev->evbit[0]|=BIT_MASK(EV_REP);
  46. input_set_capability(input_dev,EV_MSC,MSC_SCAN);
  47. input_dev->keycode=keypad->keycodes;
  48. input_dev->keycodesize=sizeof(keypad->keycodes[0]);
  49. input_dev->keycodemax=pdata->rows<<row_shift;
  50. matrix_keypad_build_keymap(keymap_data,row_shift,
  51. input_dev->keycode,input_dev->keybit);
  52. keypad->irq=platform_get_irq(pdev,0);
  53. if(keypad->irq<0){
  54. error=keypad->irq;
  55. gotoerr_put_clk;
  56. }
  57. //(3)、中断函数注册;
  58. error=request_threaded_irq(keypad->irq,NULL,samsung_keypad_irq,
  59. IRQF_ONESHOT,dev_name(&pdev->dev),keypad);
  60. if(error){
  61. dev_err(&pdev->dev,"failedtoregisterkeypadinterruptn");
  62. gotoerr_put_clk;
  63. }
  64. //(4)、input驱动注册。
  65. error=input_register_device(keypad->input_dev);
  66. if(error)
  67. gotoerr_free_irq;
  68. device_init_wakeup(&pdev->dev,pdata->wakeup);
  69. platform_set_drvdata(pdev,keypad);
  70. return0;
  71. ………………
  72. }

(1)、input参数初始化;

(2)、打开、关闭函数;

[cpp]viewplaincopy
  1. input_dev->open=samsung_keypad_open;
  2. staticintsamsung_keypad_open(structinput_dev*input_dev)
  3. {
  4. structsamsung_keypad*keypad=input_get_drvdata(input_dev);
  5. samsung_keypad_start(keypad);
  6. return0;
  7. }
  8. 其实open函数调用samsung_keypad_start()函数,对按键的寄存器一些操作,如下面寄存器列表中的。
  9. staticvoidsamsung_keypad_start(structsamsung_keypad*keypad)
  10. {
  11. unsignedintval;
  12. keypad->stopped=false;
  13. clk_enable(keypad->clk);
  14. val=readl(keypad->base+SAMSUNG_KEYIFCON);
  15. val|=SAMSUNG_KEYIFCON_INT_F_EN|SAMSUNG_KEYIFCON_INT_R_EN;
  16. writel(val,keypad->base+SAMSUNG_KEYIFCON);
  17. writel(0,keypad->base+SAMSUNG_KEYIFCOL);
  18. }

(3)、中断函数注册;

[cpp]viewplaincopy
  1. error=request_threaded_irq(keypad->irq,NULL,samsung_keypad_irq,IRQF_ONESHOT,dev_name(&pdev->dev),keypad);

request_threaded_irq这个函数也许我们比较陌生,可是看下下面一个函数也许就不难理解了:

[cpp]viewplaincopy
  1. staticinlineint__must_check
  2. request_irq(unsignedintirq,irq_handler_thandler,unsignedlongflags,
  3. constchar*name,void*dev)
  4. {
  5. returnrequest_threaded_irq(irq,handler,NULL,flags,name,dev);
  6. }
这个函数跟中断的作用是一样的,keypad->irq= platform_get_irq(pdev,0);于中段号,当有按键按下时,会跳到中断函数,samsung_keypad_irq中;

(4)、input驱动注册,input驱动比较重要,触摸屏、按键、gsensor、battery等都是通过input子系统上报的。

2、中断函数:samsung_keypad_irq分析,当有按键按下时,调用这个函数

[cpp]viewplaincopy
  1. staticirqreturn_tsamsung_keypad_irq(intirq,void*dev_id)
  2. {
  3. structsamsung_keypad*keypad=dev_id;
  4. unsignedintrow_state[SAMSUNG_MAX_COLS];
  5. unsignedintval;
  6. boolkey_down;
  7. do{
  8. val=readl(keypad->base+SAMSUNG_KEYIFSTSCLR);
  9. //(1)、清除中断;
  10. writel(~0x0,keypad->base+SAMSUNG_KEYIFSTSCLR);
  11. //(2)、扫描行列值,写入寄存器;
  12. samsung_keypad_scan(keypad,row_state);
  13. //(3)、键值上报,这是函数的主要部分了;
  14. key_down=samsung_keypad_report(keypad,row_state);
  15. //(4)、延时去抖动;
  16. if(key_down)
  17. wait_event_timeout(keypad->wait,keypad->stopped,
  18. msecs_to_jiffies(50));
  19. }while(key_down&&!keypad->stopped);
  20. returnIRQ_HANDLED;
  21. }

(1)、清除中断;

(2)、扫描行列值,写入寄存器(后面分析);

(3)、键值上报,这是函数的主要部分了(后面分析);

(4)、延时去抖动,如果有按键按下,有一个段时间的延时,看是否真正有按键,这就是所说的去抖动;

3、当按键按下时,行列值的扫描函数samsung_keypad_scan执行,写入相应行列寄存器

上图我们知道,对于矩阵键盘,主控有专门的接口,也有相应的寄存器,

[cpp]viewplaincopy
  1. staticvoidsamsung_keypad_scan(structsamsung_keypad*keypad,
  2. unsignedint*row_state)
  3. {
  4. structdevice*dev=keypad->input_dev->dev.parent;
  5. unsignedintcol;
  6. unsignedintval;
  7. for(col=0;col<keypad->cols;col++){
  8. if(samsung_keypad_is_s5pv210(dev)){
  9. val=S5PV210_KEYIFCOLEN_MASK;
  10. val&=~(1<<col)<<8;
  11. }else{
  12. val=SAMSUNG_KEYIFCOL_MASK;
  13. val&=~(1<<col);
  14. }
  15. writel(val,keypad->base+SAMSUNG_KEYIFCOL);
  16. mdelay(1);
  17. val=readl(keypad->base+SAMSUNG_KEYIFROW);
  18. row_state[col]=~val&((1<<keypad->rows)-1);
  19. }
  20. writel(0,keypad->base+SAMSUNG_KEYIFCOL);
  21. }

4、通过扫描键值写入相应寄存器,然后通过

[cpp]viewplaincopy
  1. staticboolsamsung_keypad_report(structsamsung_keypad*keypad,
  2. unsignedint*row_state)
  3. {
  4. structinput_dev*input_dev=keypad->input_dev;
  5. unsignedintchanged;
  6. unsignedintpressed;
  7. unsignedintkey_down=0;
  8. unsignedintval;
  9. unsignedintcol,row;
  10. for(col=0;col<keypad->cols;col++){
  11. changed=row_state[col]^keypad->row_state[col];
  12. key_down|=row_state[col];
  13. if(!changed)
  14. continue;
  15. for(row=0;row<keypad->rows;row++){
  16. if(!(changed&(1<<row)))
  17. continue;
  18. pressed=row_state[col]&(1<<row);
  19. dev_dbg(&keypad->input_dev->dev,
  20. "key%s,row:%d,col:%dn",
  21. pressed?"pressed":"released",row,col);
  22. //(1)、得到按键在矩阵中的位置;
  23. val=MATRIX_SCAN_CODE(row,col,keypad->row_shift);
  24. printk("key%s,row:%d,col:%dn",pressed?"pressed":"released",row,col);
  25. printk("testbyxu_binforval=%d,key=%dn",val,keypad->keycodes[val]);
  26. input_event(input_dev,EV_MSC,MSC_SCAN,val);
  27. //(2)、上报键值keypad->keycodes[val];
  28. input_report_key(input_dev,
  29. keypad->keycodes[val],pressed);
  30. }
  31. //(3)、input上报后同步;
  32. input_sync(keypad->input_dev);
  33. }
  34. memcpy(keypad->row_state,row_state,sizeof(keypad->row_state));
  35. returnkey_down;
  36. }

(1)、#defineMATRIX_SCAN_CODE(row, col, row_shift) (((row)<<(row_shift)) + (col))

row_shift = 3

如:row = 1; col = 6; row_shift= 3

val = MATRIX_SCAN_CODE(row,col,keypad->row_shift) = ((1)<<(3)+(6)) = 14;

就相当于:(1,6)这个数组里面的值:48

printk("key %s, row: %d,col:%dn",pressed ? "pressed" : "released", row, col);

printk("test by xu_bin forval =%d,key = %dn",val,keypad->keycodes[val]);


(2)、上报键值keypad->keycodes[val],这个值是对于我们这个驱动来说的最终值;

(3)、input上报后同步,这个和input子系统相关。

这样就完成了驱动部分的上报。

android物理按键(samsungexynos4210平台) samsung exynos 7420



  

爱华网本文地址 » http://www.413yy.cn/a/25101017/339477.html

更多阅读

《极限方程式赛车》玩法 方程式赛车手

《极限方程式赛车》玩法——简介智能手机硬件性能的提升让越来越多的大型游戏能够在手机上顺畅的运行,尤其是赛车类游戏尤其能够考验手机的硬件配置。极限方程式赛车Android中文版以及iOS平台上的一款经典赛车游戏,玩家给它的评价甚至

如何在eclipse中添加android ADT 精 eclipse中androidadt

如何在eclipse中添加android ADT 精——简介对于程序开发的学者来说,eclipse并不陌生,它为我们提供了一个非常广阔的平台来开发程序。同样我们也可以用它来开发android程序。但是在eclipse中并不能直接开发android程序,需要我们安装一

安卓手机开发平台搭建 mac 安卓开发环境搭建

android手机开发平台搭建www.111cn.net2012-02-09 编辑:jimmy本文章来给想做android手机开的朋友介绍一下android手机开发平台环境配置教程,有需要的同学可以参考一下本教程。初学Android,以便记录学习过程,增强学习效果。1.下载搭建a

android全格式多媒体播放器一:ffmpeg移植

为了能在android平台上播放全格式的多媒体文件,我们需要自己做一个多媒体播放器。android自带的opencore系统解码格式较少,只支持mp4和ogg,并且结构不是很好理解。如果要加其他的解码方式实在太费劲。经过考虑,基于ffmpeg实现全功能的播

Android-APILevels androidapi中文版

[转自]http://www.cnblogs.com/over140/archive/2011/04/29/2032433.htmlAPI级别是什么当你开发你的Android应用程序时,了解该平台API变更管理的基本方法和概念是很有帮助的。同样的,知道API级别标识以及该标识如何保障你的应用与实

声明:《android物理按键samsungexynos4210平台 samsung exynos 7420》为网友没伱也一样分享!如侵犯到您的合法权益请联系我们删除