欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
android 物理按鍵

關(guān)鍵詞:android   按鍵  矩陣按鍵 AD按鍵 

平臺信息:

內核:linux2.6/linux3.0

系統:android/android4.0

平臺:S5PV310(samsung exynos4210)

作者:xubin341719(歡迎轉載,請注明作者)

一、硬件部分:

1、矩陣按鍵、IO按鍵、AD按鍵

    這個(gè)知識相對來(lái)說(shuō)比較簡(jiǎn)單,不過(guò)上次真有一個(gè)網(wǎng)友不太清楚這個(gè)。所以這個(gè)基礎部分我們在這里也說(shuō)一下。

(1)、矩陣按鍵


記得上大學(xué)時(shí)學(xué)單片機時(shí),這個(gè)矩陣按鍵還是個(gè)重點(diǎn)呢,上面的圖還是AT89S52的片子,工作原理比較簡(jiǎn)單,通過(guò)行、列來(lái)確定是那個(gè)按鍵按下,比如說(shuō)上圖標號為1的鍵按下,IO(P1.7,P1.3)有電平變化,程序可以通過(guò)這里來(lái)判斷是那一個(gè)鍵按下的,同理標號為2的按鍵按下IO(P1.4,P1.0)有電平變化。

    這樣做程序上要從兩個(gè)IO來(lái)判斷是那個(gè)鍵按下,多了一個(gè)步驟,但是在硬件上有一個(gè)優(yōu)勢,就是如果按鍵比較多的時(shí)候比較節省IO口,比如說(shuō)上面4x4 = 16,8個(gè)IO可以做16個(gè)按鍵,8x8=64,16個(gè)IO可以做64個(gè)按鍵。

優(yōu)點(diǎn):可以用少的IO來(lái)做多個(gè)按鍵,判斷按鍵比較準確;

缺點(diǎn):程序上相對IO按鍵來(lái)說(shuō)多了一步。

(2)、IO按鍵

        這個(gè)就比較簡(jiǎn)單了,用一個(gè)IO口的高低電平來(lái)判斷按鍵是否按下。

優(yōu)點(diǎn):程序、硬件電路都比較簡(jiǎn)單,判斷按鍵比較準確;

缺點(diǎn):IO有限、按鍵多時(shí)不太合適。比如矩陣按鍵16個(gè)IO可以表示64個(gè)按鍵,IO的話(huà)只有16個(gè)。

(3)、AD按鍵

        這個(gè)在之前在做電視的時(shí)候用的比較多一點(diǎn)。

        AD按鍵就是通過(guò)一個(gè)ADC接口,如下圖所示,給一個(gè)VCC電壓,比如說(shuō)S1接地時(shí)AD接口得到的模擬電壓值為ADC=0;當S2按下時(shí),ADC= VCC/(R1+R2)*R2;這樣就可以得到不同的ADC值,程序中在這里判斷是那個(gè)按鍵按下。

優(yōu)點(diǎn):程序、硬件電路都比較簡(jiǎn)單,一個(gè)IO可以做多個(gè)按鍵;

缺點(diǎn):AD按鍵有時(shí)候判斷不準確,所以在程序中要多加檢測AD值的次數。


2、S5PV310的矩陣按鍵

硬件原理圖如下:


硬件接口說(shuō)明:vol+,vol-,back,home,menu為1*5的矩陣鍵盤(pán),芯片接口信息如下:

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也沒(méi)有節省多少I(mǎi)O呀?情況是這樣的,我們的原理圖是從三星開(kāi)發(fā)板上參考過(guò)來(lái)的,開(kāi)發(fā)板上按鍵本來(lái)多一點(diǎn),可是我們用不了那么多,人家那樣做比較合理??墒俏覀儭巴祽小?,硬件上不用改,軟件上也不用改,從這一點(diǎn)也可以看出我們國內做技術(shù)這個(gè)行業(yè)的有點(diǎn)……不太深入呀,整天老板在催,可是我們在細節上做不太好呀。三星在IO矩陣也有專(zhuān)用接口,所以就“奢侈”一次,用1*5的矩陣來(lái)實(shí)現5個(gè)按鍵。

3、S5PV310的矩陣按鍵接口

看一下芯片上的專(zhuān)用接口,如下圖,全用的話(huà)有點(diǎn)多。



關(guān)于專(zhuān)用接口的寄存器,這些寄存器我們后面要用得到的,按鍵的行、列信息會(huì )在這里面暫存的。


以S5PV310為例,驅動(dòng)代碼:samsung-keypad.c

軟件部分:

總體流程圖如下,這個(gè)是在觸摸屏基礎上改過(guò)來(lái)的,感覺(jué)流程都是這個(gè)樣子的。中斷觸發(fā),中斷處理。


一、矩陣鍵行、列設定,和上報鍵值設定

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

  1. static uint32_t smdkv310_keymap[] __initdata = {  
  2.     /* KEY(row, col, keycode) */  
  3.     KEY(0, 3, KEY_1), KEY(0, 4, KEY_2), KEY(0, 5, KEY_3),  
  4.     KEY(0, 6, KEY_4), KEY(0, 7, KEY_5),  
  5.     KEY(1, 3, KEY_A), KEY(1, 4, KEY_C), KEY(1, 5, KEY_E),  
  6.     KEY(1, 6, KEY_B), KEY(1, 7, KEY_D)//(1)、鍵值初始化;  
  7. };  
  8.   
  9. static struct matrix_keymap_data smdkv310_keymap_data __initdata = {  
  10.     .keymap     = smdkv310_keymap,  
  11.     .keymap_size    = ARRAY_SIZE(smdkv310_keymap),  
  12. };  
  13. static struct samsung_keypad_platdata smdkv310_keypad_data __initdata = {  
  14.     .keymap_data    = &smdkv310_keymap_data,  
  15.     .rows       = 2,         //(2)、行、列設定,8行、2列,其實(shí)我們只用了5行、1列;  
  16.     .cols       = 8,  
  17. };  
  18. static void __init smdkv310_machine_init(void)  
  19. {  
  20.     samsung_keypad_set_platdata(&smdkv310_keypad_data); //(3)、平臺設備初始化;  
  21. }  

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

KEY這個(gè)宏在android-kernel-samsung-dev/include/linux/input/Matrix_keypad.h中實(shí)現:

  1. #define MATRIX_MAX_ROWS     32  
  2. #define MATRIX_MAX_COLS         32  
  3. #define KEY(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中有定義,如下:

  1. #define KEY_RESERVED        0  
  2. #define KEY_ESC         1  
  3. #define KEY_1           2  
  4. #define KEY_2           3  
  5. #define KEY_3           4  
  6. #define KEY_4           5  
  7. #define KEY_5           6  
  8. #define KEY_6           7  
  9. #define KEY_7           8  
  10. #define KEY_8           9  
  11. #define KEY_9           10  
  12. #define KEY_0           11  
  13. #define KEY_MINUS       12  
  14. #define KEY_EQUAL       13  
  15. #define KEY_BACKSPACE       14  
  16. #define KEY_TAB         15  
  17. #define KEY_Q           16  
  18. #define KEY_W           17  
  19. #define KEY_E           18  
  20. #define KEY_R           19  
  21. #define KEY_T           20  
  22. #define KEY_Y           21  
  23. #define KEY_U           22  

(2)、行列設定;

  1. .rows       = 2,         
  2. .cols       = 8,  

(3)、平臺設備初始化;

  1. samsung_keypad_set_platdata(&smdkv310_keypad_data)。  

二、上面設定的keycode鍵值和上層相對應

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

  1. key 2     DPAD_UP               WAKE_DROPPED  
  2. key 3     DPAD_CENTER           WAKE_DROPPED  
  3. key 4     DPAD_DOWN             WAKE_DROPPED  
  4. key 5     DPAD_RIGHT            WAKE_DROPPED  
  5. key 6     DPAD_LEFT             WAKE_DROPPED  
  6. key 18    VOLUME_DOWN       WAKE  
  7. key 30    HOME                      WAKE_DROPPED  
  8. key 32    MENU                      WAKE_DROPPED  
  9. key 46    VOLUME_UP             WAKE  
  10. key 48    BACK                      WAKE_DROPPED  
  11. key 10    POWER                     WAKE  

總體對應圖:

以KEY_A為例,KEY_A 30最終和上層的keypad.kl中的30 HOME相對應




三、矩陣鍵盤(pán)驅動(dòng)程序分析

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

1、probe函數分析:

  1. static int __devinit samsung_keypad_probe(struct platform_device *pdev)  
  2. {  
  3.     const struct samsung_keypad_platdata *pdata;  
  4.     const struct matrix_keymap_data *keymap_data;  
  5.     struct samsung_keypad *keypad;  
  6.     struct resource *res;  
  7.     struct input_dev *input_dev;  
  8.     unsigned int row_shift;  
  9.     unsigned int keymap_size;  
  10.     int error;  
  11.     ………………  
  12.     keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]);  
  13.   
  14.     keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL);  
  15.     input_dev = input_allocate_device();  
  16.     if (!keypad || !input_dev) {  
  17.         error = -ENOMEM;  
  18.         goto err_free_mem;  
  19.     }  
  20.   
  21.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  22.     if (!res) {  
  23.         error = -ENODEV;  
  24.         goto err_free_mem;  
  25.     }  
  26.   
  27.     keypad->base = ioremap(res->start, resource_size(res));  
  28.     if (!keypad->base) {  
  29.         error = -EBUSY;  
  30.         goto err_free_mem;  
  31.     }  
  32.     …………  
  33. //(1)、input參數初始化;  
  34.     keypad->input_dev = input_dev;  
  35.     keypad->row_shift = row_shift;  
  36.     keypad->rows = pdata->rows;  
  37.     keypad->cols = pdata->cols;  
  38.     init_waitqueue_head(&keypad->wait);  
  39.   
  40.     input_dev->name = pdev->name;  
  41.     input_dev->id.bustype = BUS_HOST;  
  42.     input_dev->dev.parent = &pdev->dev;  
  43.     input_set_drvdata(input_dev, keypad);  
  44. //(2)、打開(kāi)、關(guān)閉函數;  
  45.     input_dev->open = samsung_keypad_open;  
  46.     input_dev->close = samsung_keypad_close;  
  47.   
  48.     input_dev->evbit[0] = BIT_MASK(EV_KEY);  
  49.     if (!pdata->no_autorepeat)  
  50.         input_dev->evbit[0] |= BIT_MASK(EV_REP);  
  51.   
  52.     input_set_capability(input_dev, EV_MSC, MSC_SCAN);  
  53.   
  54.     input_dev->keycode = keypad->keycodes;  
  55.     input_dev->keycodesize = sizeof(keypad->keycodes[0]);  
  56.     input_dev->keycodemax = pdata->rows << row_shift;  
  57.   
  58.     matrix_keypad_build_keymap(keymap_data, row_shift,  
  59.             input_dev->keycode, input_dev->keybit);  
  60.   
  61.     keypad->irq = platform_get_irq(pdev, 0);  
  62.     if (keypad->irq < 0) {  
  63.         error = keypad->irq;  
  64.         goto err_put_clk;  
  65.     }  
  66. //(3)、中斷函數注冊;   
  67.     error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq,  
  68.             IRQF_ONESHOT, dev_name(&pdev->dev), keypad);  
  69.     if (error) {  
  70.         dev_err(&pdev->dev, "failed to register keypad interrupt\n");  
  71.         goto err_put_clk;  
  72.     }  
  73. //(4)、input驅動(dòng)注冊。  
  74.     error = input_register_device(keypad->input_dev);  
  75.     if (error)  
  76.         goto err_free_irq;  
  77.   
  78.     device_init_wakeup(&pdev->dev, pdata->wakeup);  
  79.     platform_set_drvdata(pdev, keypad);  
  80.     return 0;  
  81.   
  82. ………………  
  83. }  

(1)、input參數初始化;

(2)、打開(kāi)、關(guān)閉函數;

  1. input_dev->open = samsung_keypad_open;  
  2. static int samsung_keypad_open(struct input_dev *input_dev)  
  3. {  
  4.     struct samsung_keypad *keypad = input_get_drvdata(input_dev);  
  5.     samsung_keypad_start(keypad);  
  6.     return 0;  
  7. }  
  8. 其實(shí)open函數調用samsung_keypad_start()函數,對按鍵的寄存器一些操作,如下面寄存器列表中的。  
  9. static void samsung_keypad_start(struct samsung_keypad *keypad)  
  10. {  
  11.     unsigned int val;  
  12.     /* Tell IRQ thread that it may poll the device. */  
  13.     keypad->stopped = false;  
  14.     clk_enable(keypad->clk);  
  15.     /* Enable interrupt bits. */  
  16.     val = readl(keypad->base + SAMSUNG_KEYIFCON);  
  17.     val |= SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN;  
  18.     writel(val, keypad->base + SAMSUNG_KEYIFCON);  
  19.     /* KEYIFCOL reg clear. */  
  20.     writel(0, keypad->base + SAMSUNG_KEYIFCOL);  
  21. }  

(3)、中斷函數注冊;

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

request_threaded_irq這個(gè)函數也許我們比較陌生,可是看下下面一個(gè)函數也許就不難理解了:

  1. static inline int __must_check  
  2. request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,  
  3.         const char *name, void *dev)  
  4. {  
  5.     return request_threaded_irq(irq, handler, NULL, flags, name, dev);  
  6. }  
這個(gè)函數跟中斷的作用是一樣的,keypad->irq= platform_get_irq(pdev, 0);于中段號,當有按鍵按下時(shí),會(huì )跳到中斷函數,samsung_keypad_irq中;

 (4)、input驅動(dòng)注冊,input驅動(dòng)比較重要,觸摸屏、按鍵、gsensor、battery等都是通過(guò)input子系統上報的。

 2、中斷函數: samsung_keypad_irq分析,當有按鍵按下時(shí),調用這個(gè)函數

  1. static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)  
  2. {  
  3.     struct samsung_keypad *keypad = dev_id;  
  4.   
  5.     unsigned int row_state[SAMSUNG_MAX_COLS];  
  6.     unsigned int val;  
  7.     bool key_down;  
  8.     do {  
  9.         val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);  
  10.         /* Clear interrupt. */  
  11. //(1)、清除中斷;  
  12.         writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);   
  13. //(2)、掃描行列值,寫(xiě)入寄存器;  
  14.     samsung_keypad_scan(keypad, row_state);  
  15. //(3)、鍵值上報,這是函數的主要部分了;  
  16.         key_down = samsung_keypad_report(keypad, row_state);  
  17. //(4)、延時(shí)去抖動(dòng);   
  18.         if (key_down)  
  19.             wait_event_timeout(keypad->wait, keypad->stopped,  
  20.                        msecs_to_jiffies(50));  
  21.     } while (key_down && !keypad->stopped);  
  22.     return IRQ_HANDLED;  
  23. }  

(1)、清除中斷;

(2)、掃描行列值,寫(xiě)入寄存器(后面分析);

(3)、鍵值上報,這是函數的主要部分了(后面分析);

(4)、延時(shí)去抖動(dòng),如果有按鍵按下,有一個(gè)段時(shí)間的延時(shí),看是否真正有按鍵,這就是所說(shuō)的去抖動(dòng);

3、當按鍵按下時(shí),行列值的掃描函數samsung_keypad_scan執行,寫(xiě)入相應行列寄存器

上圖我們知道,對于矩陣鍵盤(pán),主控有專(zhuān)門(mén)的接口,也有相應的寄存器,

  1. static void samsung_keypad_scan(struct samsung_keypad *keypad,  
  2.                 unsigned int *row_state)  
  3. {  
  4.     struct device *dev = keypad->input_dev->dev.parent;  
  5.     unsigned int col;  
  6.     unsigned int val;  
  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.     /* KEYIFCOL reg clear */  
  21.     writel(0, keypad->base + SAMSUNG_KEYIFCOL);  
  22. }  

4、通過(guò)掃描鍵值寫(xiě)入相應寄存器,然后通過(guò)

  1. static bool samsung_keypad_report(struct samsung_keypad *keypad,  
  2.                   unsigned int *row_state)  
  3. {  
  4.     struct input_dev *input_dev = keypad->input_dev;  
  5.     unsigned int changed;  
  6.     unsigned int pressed;  
  7.     unsigned int key_down = 0;  
  8.     unsigned int val;  
  9.     unsigned int col, row;  
  10.   
  11.     for (col = 0; col < keypad->cols; col++) {  
  12.         changed = row_state[col] ^ keypad->row_state[col];  
  13.         key_down |= row_state[col];  
  14.         if (!changed)  
  15.             continue;  
  16.         for (row = 0; row < keypad->rows; row++) {  
  17.             if (!(changed & (1 << row)))  
  18.                 continue;  
  19.             pressed = row_state[col] & (1 << row);  
  20.             dev_dbg(&keypad->input_dev->dev,  
  21.                 "key %s, row: %d, col: %d\n",  
  22.                 pressed ? "pressed" : "released", row, col);  
  23. //(1)、得到按鍵在矩陣中的位置;  
  24.             val = MATRIX_SCAN_CODE(row, col, keypad->row_shift);  
  25. printk("key %s, row: %d, col: %d\n",pressed ? "pressed" : "released", row, col);  
  26. printk("test by xu_bin for val = %d,key = %d\n",val,keypad->keycodes[val]);  
  27.             input_event(input_dev, EV_MSC, MSC_SCAN, val);  
  28. //(2)、上報鍵值keypad->keycodes[val];  
  29.             input_report_key(input_dev,  
  30.                     keypad->keycodes[val], pressed);  
  31.         }  
  32. //(3)、input上報后同步;   
  33.         input_sync(keypad->input_dev);  
  34.     }  
  35.     memcpy(keypad->row_state, row_state, sizeof(keypad->row_state));  
  36.     return key_down;  
  37. }  

(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)這個(gè)數組里面的值:48

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

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


(2)、上報鍵值keypad->keycodes[val],這個(gè)值是對于我們這個(gè)驅動(dòng)來(lái)說(shuō)的最終值;

(3)、input上報后同步,這個(gè)和input子系統相關(guān)。 

這樣就完成了驅動(dòng)部分的上報。





本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
keypad driver
222 f0701
淺析linux下鍵盤(pán)設備工作和注冊流程 -tty串口﹑hid鼠標鍵盤(pán)和usb盤(pán)相關(guān) - ...
usb鍵鼠標驅動(dòng)分析
linux 2.6 輸入子系統 鍵盤(pán)驅動(dòng)的實(shí)現
S3C6410開(kāi)發(fā)全紀錄(二)《如何計算內存大小,并在UBOOT中調整內存大小》
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久