msg2133觸控螢幕(TP原始碼學習)

來源:互聯網
上載者:User

msg2133觸控螢幕(TP原始碼學習)

強調:下面的裝置指觸控螢幕

ABS:絕對值

 

 

1.input子系統簡介

Linux輸入裝置總類繁雜,常見的包括有按鍵、鍵盤、觸控螢幕、滑鼠、搖杆等等,他們本身就是字元裝置,而linux核心將這些裝置的共同性抽象出來,簡化驅動開發建立了一個input子系統。子系統共分為三層,1所示。

圖1


驅動層和硬體相關,直接捕捉和擷取硬體裝置的資料資訊等(包括觸控螢幕被按下、按下位置、滑鼠移動、鍵盤按下等等),然後將資料資訊報告到核心層。核心層負責串連驅動層和事件處理層,裝置驅動(device driver)和處理常式(handler)的註冊需要通過核心層來完成,核心層接收來自驅動層的資料資訊,並將資料資訊選擇對應的handler去處理,最終handler將資料複製到使用者空間。

所有的inputdevice在註冊後會加入一個input_dev_list(輸入裝置鏈表),所有的eventhandler在註冊後會加入一個input_handler_list(輸入處理常式鏈表),這裡的list_head主要的作用是作為input_dev_list和input_handler_list的一個節點來儲存地址。Input_dev_list和input_handler_list之間的對應關係由input_handle結構體橋接

 

input_handle是用來關聯input_dev和input_handler。為什麼用input_handle來關聯input_dev和input_handler而不將input_dev和input_handler直接對應呢?因為一個device可以對應多個handler,而一個handler也可處理多個device。就如一個觸控螢幕裝置可以對應event handler也可以對應tseve handler。

input_dev、input_handler、input_handle的關係如2所示。

圖2


2.觸控螢幕驅動簡介

流程

在Linux中,Input裝置用input_dev結構體描述,定義在input.h中。裝置的驅動只需按照如下步驟就可實現了。

1).在驅動模組載入函數中設定Input裝置支援input子系統的哪些事件;

2).將Input裝置註冊到input子系統中;

3).在Input裝置發生輸入操作時(如:鍵盤被按下/抬起、觸控螢幕被觸摸/抬起/移動、滑鼠被移動/單擊/抬起時等),提交所發生的事件及對應的索引值/座標等狀態。

 

2.1 input device的註冊

Inputdevice的註冊實際上僅僅只有幾行代碼,因為在input.c中已經將大量的代碼封裝好了,主需要調用幾個關鍵的函數就能完成對input device的註冊。

在xxx_ts.c中預先定義全域變數structinput_devtsdev;然後進入到初始化函數

一個完整input裝置系統不僅要有裝置,還需要有處理常式input_handler

 

2.2 input handler的註冊

Input_handler是要和使用者層打交道的,在evdev.c中直接定義了一個input_handler結構體並初始化了一些內部成員變數。

 

2.3 資料傳遞過程

從硬體裝置(觸控螢幕)中獲得的資料需要經過input.c選擇相應的handler進行處理,最後上報到使用者空間。如何從硬體裝置(觸控螢幕)中獲得資料,那就得看xxx_ts.c中的代碼了,在xxx_ts.c中的原始碼是直接和硬體裝置相關的。在xxx_ts.c中我們一方面要完成觸控螢幕裝置相關的寄存器配置,另一方面要完成將獲得的資料上報。

至於裝置初始化配置方面,根據每個人使用的ARM晶片的Datasheet去初始化配置寄存器,這裡也不需要多說了。不管是通過查詢法還是中斷法(我沒見過用查詢的),當觸控螢幕按下時候我們會得到觸控螢幕被按下的相關資料(主要是被按下的X和Y座標值),然後需要將資料資訊上報,在觸控螢幕被按下的時候需要上報:

input_report_key(tsdev, BTN_TOUCH, 1); //報告按鍵被按下事件

input_report_abs(tsdev, ABS_X, x); //報告觸控螢幕被按下的x座標值

input_report_abs(tsdev, ABS_Y, y); //報告觸控螢幕被按下的y座標值

input_report_abs(tsdev, ABS_PRESSURE, 1);//報告觸控螢幕被按下的壓力值(0或者1)

input_sync(tsdev); //報告同步事件,表示一次事件結束

當觸筆從觸控螢幕上抬起時需要上報:

input_report_key(tsdev, BTN_TOUCH, 0); //報告按鍵被鬆開事件

input_report_abs(tsdev, ABS_PRESSURE, 0);//報告觸控螢幕被按下的壓力值(0或者1)

input_sync(tsdev); //報告同步事件,表示一次事件結束

 

2.4 資料讀取過程

讀取就變得很簡單了,做過linux編程的都能知道,只要在應用中定義了個input_event結構體,通過open開啟裝置,然後進行read即可。

 

2.5

3.Msg2133A驅動代碼學習

3.1 touch_driver_probe()

所涉及的檔案及一些主要函數關係如下:

 

圖3

 

(1)mstar_drv_platform_porting_layer.c:DrvPlatformLyrInputDeviceInitialize()

 

//為一個新的輸入裝置分配內容,返回一個預先準備好的結構體input_dev,並讓//g_InputDevice指向它。 /* allocate an input device */   g_InputDevice = input_allocate_device();   if (g_InputDevice == NULL)    {       DBG("*** input device allocation failed ***\n");       return -ENOMEM;    } //phys:系統階層中觸控螢幕裝置的實體路徑,這裡的觸控螢幕裝置是掛載在//I2C匯流排上的;id:裝置的id,對應結構體input_id,裝置採用的匯流排是I2C。g_InputDevice->name= pClient->name;   g_InputDevice->phys = "I2C";g_InputDevice->dev.parent= &pClient->dev;g_InputDevice->id.bustype= BUS_I2C;   //設定裝置支援的事件類型,evbit表示裝置支援的事件類型,這裡支援EV_ABS:絕對座標事件,用於搖杆EV_SYN:同步事件EV_KEY:鍵盤事件Keybit表示裝置支援的按鍵類型,BTN_TOUCH表示觸摸按鍵;propbit表示裝置屬性和相容(quirks),INPUT_PROP_DIRECT表示直接的輸入裝置   /* set the supported event type for input device */   set_bit(EV_ABS, g_InputDevice->evbit);   set_bit(EV_SYN, g_InputDevice->evbit);   set_bit(EV_KEY, g_InputDevice->evbit);   set_bit(BTN_TOUCH, g_InputDevice->keybit);   set_bit(INPUT_PROP_DIRECT, g_InputDevice->propbit); // when touch panel support virtual key(EX.Menu, Home, Back, Search)定義此宏,input_set_capability()作用是標記裝置有能力處理按鍵事件(EV_KEY),可處理的事件code由g_TpVirtualKey[i]指定,這裡支援menu、home、back和search。#ifdef CONFIG_TP_HAVE_KEY   // Method 1.    {       u32 i;       for (i = 0; i < MAX_KEY_NUM; i ++)       {           input_set_capability(g_InputDevice, EV_KEY, g_TpVirtualKey[i]);       }    }#endif

 

// ABS_MT_TOUCH_MAJOR表示描述了主接觸面的長軸

ABS_MT_WIDTH_MAJOR表示了接觸工具的長軸,比如

ABS_MT_TOUCH_MAJOR/ABS_MT_WIDTH_MAJOR,永遠小於1,並且和壓力有關,壓力越大,越接近1。

ABS_MT_POSITION_X接觸位置的中心點X座標

ABS_MT_POSITION_Y接觸位置的中心點Y座標

 

input_set_abs_params(g_InputDevice,ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);input_set_abs_params(g_InputDevice,ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0);//對於X軸範圍是TOUCH_SCREEN_X_MIN到TOUCH_SCREEN_X_MIN,資料誤差是-0到+0,中心平滑位置是0。input_set_abs_params(g_InputDevice,ABS_MT_POSITION_X, TOUCH_SCREEN_X_MIN, TOUCH_SCREEN_X_MAX, 0, 0);input_set_abs_params(g_InputDevice,ABS_MT_POSITION_Y, TOUCH_SCREEN_Y_MIN, TOUCH_SCREEN_Y_MAX, 0, 0); //向input子系統註冊輸入裝置   /* register the input device to input sub-system */   nRetVal = input_register_device(g_InputDevice);   if (nRetVal < 0)    {       DBG("*** Unable to register touch input device ***\n");    }

 

(2)mstar_drv_platform_porting_layer.c:DrvPlatformLyrTouchDeviceRequestGPIO()

此函數就是申請複位和中斷引腳的GPIO。

 

#define MS_TS_MSG_IC_GPIO_RST   12#define MS_TS_MSG_IC_GPIO_INT   13#define MSM_TS_MSG_IC_GPIO_RST  (MS_TS_MSG_IC_GPIO_RST+911)#define MSM_TS_MSG_IC_GPIO_INT  (MS_TS_MSG_IC_GPIO_INT+911)//向申請MSM_TS_MSG_IC_GPIO_RST這個GPIO,其名字為為C_TP_RSTnRetVal =gpio_request(MSM_TS_MSG_IC_GPIO_RST, "C_TP_RST");       if (nRetVal < 0)    {       DBG("*** Failed to request GPIO %d, error %d ***\n",MSM_TS_MSG_IC_GPIO_RST, nRetVal);    }    nRetVal = gpio_request(MSM_TS_MSG_IC_GPIO_INT,"C_TP_INT");      if (nRetVal < 0)    {       DBG("*** Failed to request GPIO %d, error %d ***\n",MSM_TS_MSG_IC_GPIO_INT, nRetVal);    }


 

(3)mstar_drv_platform_porting_layer.c:DrvPlatformLyrTouchDevicePowerOn()

// 複位觸控螢幕IC,gpio_direction_output()在某個GPIO口寫上某個值之後,還會把這個連接埠設定為輸出模式。

 

gpio_direction_output(MSM_TS_MSG_IC_GPIO_RST,1);udelay(100);gpio_set_value(MSM_TS_MSG_IC_GPIO_RST, 0);udelay(100);gpio_set_value(MSM_TS_MSG_IC_GPIO_RST, 1);mdelay(25);

 

(4)mstar_drv_main.c :DrvMainTouchDeviceInitialize()

主要是建立procfs檔案系統目錄入口和建立/kernel/kset_example/kobject_example目錄

 

圖4

 

(5)mstar_drv_ic_fw_porting_layer.c:DrvIcFwLyrGetChipType()

通過調用mstar_drv_self_fw_control.c:DrvFwCtrlGetChipType()擷取觸控螢幕IC類型,msg2133A對應的為2

 

(6)mstar_drv_self_fw_control.c:DrvFwCtrlGetChipType()

擷取觸控螢幕IC晶片類型,比如#defineCHIP_TYPE_MSG21XXA (0x02)

 

(7)mstar_drv_platform_porting_layer.c:DrvPlatformLyrTouchDeviceResetHw()

通過控制複位引腳複位hw,和DrvPlatformLyrTouchDevicePowerOn()實現一樣。

 

(8)mstar_drv_platform_porting_layer.c:DrvPlatformLyrTouchDeviceRegisterFingerTouchInterruptHandler()

 

//初始化手指觸摸工作隊列,並將此工作隊列和處理函數_DrvPlatformLyrFingerTouchDoWork()綁定。/* initialize the finger touch work queue*/INIT_WORK(&_gFingerTouchWork,_DrvPlatformLyrFingerTouchDoWork); //返回中斷標號給_gIrq。_gIrq =gpio_to_irq(MSM_TS_MSG_IC_GPIO_INT); //申請一個IRQ和註冊對應的ISR,當IRQ發生的時候,會調用ISR(這裡為_DrvPlatformLyrFingerTouchInterruptHandler()) /*request an irq and register the isr */nRetVal =request_threaded_irq(_gIrq/*MS_TS_MSG_IC_GPIO_INT*/, NULL,_DrvPlatformLyrFingerTouchInterruptHandler,IRQF_TRIGGER_RISING | IRQF_ONESHOT/*| IRQF_NO_SUSPEND *//* IRQF_TRIGGER_FALLING */,                      "msg2xxx",NULL);_gInterruptFlag = 1;

 

(9)mstar_drv_platform_porting_layer.c:DrvPlatformLyrTouchDeviceRegisterEarlySuspend()

//註冊通知器,什麼時候調用呢?

 

_gFbNotifier.notifier_call = MsDrvInterfaceTouchDeviceFbNotifierCallback;fb_register_client(&_gFbNotifier);

 

(10)

3.2 手指觸摸觸控螢幕的處理過程

從上面可知當觸摸TP時,對應的中斷會產生,然後調用_DrvPlatformLyrFingerTouchInterruptHandler()。

 

圖5

 

(1)_DrvPlatformLyrFingerTouchInterruptHandler()

 

spin_lock_irqsave(&_gIrqLock,nIrqFlag);     if(_gInterruptFlag == 1){      //disable_irq_nosync()關閉中斷,不等待中斷處理完成       disable_irq_nosync(_gIrq);       _gInterruptFlag = 0;       schedule_work(&_gFingerTouchWork);    } spin_unlock_irqrestore(&_gIrqLock,nIrqFlag);

 

初始化後_gInterruptFlag就是1,schedule_work(&_gFingerTouchWork);這裡會調用_DrvPlatformLyrFingerTouchDoWork()

 

(2)_DrvPlatformLyrFingerTouchDoWork()

主要通過調用DrvIcFwLyrHandleFingerTouch來處理觸摸動作。

 

DrvIcFwLyrHandleFingerTouch(NULL, 0);spin_lock_irqsave(&_gIrqLock,nIrqFlag);if (_gInterruptFlag == 0){      //使能一個IRQ的處理,便於響應下個觸摸動作。       enable_irq(_gIrq);       _gInterruptFlag = 1;}spin_unlock_irqrestore(&_gIrqLock,nIrqFlag);   nReportPacketLength =DEMO_MODE_PACKET_LENGTH;pPacket = g_DemoModePacket; rc = IicReadData(SLAVE_I2C_ID_DWI2C,&pPacket[0], nReportPacketLength);   if (rc < 0)    {       DBG("I2C read packet data failed, rc = %d\n", rc);       goto TouchHandleEnd;              }

 

(3)DrvIcFwLyrHandleFingerTouch()

調用DrvFwCtrlHandleFingerTouch()來處理

 

(4)DrvFwCtrlHandleFingerTouch()

DrvFwCtrlHandleFingerTouch

通過調用_DrvFwCtrlParsePacket()來解析資料,然後上報資料。

 

(5)_DrvFwCtrlParsePacket()

通過I2C讀取到msg2133a發送回來的8個位元組資料包,這8個位元組資料的意義

/*

pPacket[0]:id, pPacket[1]~pPacket[3]:thefirst point abs, pPacket[4]~pPacket[6]:the relative distance between the firstpoint abs and the second point abs

when pPacket[1]~pPacket[4], pPacket[6] is0xFF, keyevent, pPacket[5] to judge which key press.

pPacket[1]~pPacket[6] all are 0xFF, releasetouch

*/

對應msg2133A來說,pPacket[0]=0x52,pPacket[1]~pPacket[3]是ADC採樣值,需要轉換為x和y座標值,轉換的公式為x=(x對應的AD採樣值*480)/2048,y的類似。

 

(6)DrvPlatformLyrFingerTouchPressed()

上報事件

 

input_report_key(g_InputDevice, BTN_TOUCH,1);input_report_abs(g_InputDevice, ABS_MT_TOUCH_MAJOR,1);input_report_abs(g_InputDevice,ABS_MT_WIDTH_MAJOR, 1);input_report_abs(g_InputDevice,ABS_MT_POSITION_X, nX);input_report_abs(g_InputDevice,ABS_MT_POSITION_Y, nY);input_mt_sync(g_InputDevice);

 

(7)

3.3 虛擬按鍵實現

when pPacket[1]~pPacket[4], pPacket[6] is0xFF, keyevent, pPacket[5] to judge which key press.根據我們觸控螢幕絲印按鍵有menu、home、back和search,按下這幾個位置pPacket[5]的值分別為4、8、1、2,然後在DrvFwCtrlHandleFingerTouch函數中做對應的處理即可:

 

const int g_TpVirtualKey[] = {TOUCH_KEY_MENU,TOUCH_KEY_HOME, TOUCH_KEY_BACK, TOUCH_KEY_SEARCH};if (tInfo.nTouchKeyCode != 0)           {#ifdef CONFIG_TP_HAVE_KEY                if (tInfo.nTouchKeyCode == 4)// TOUCH_KEY_MENU                {                    nTouchKeyCode=g_TpVirtualKey[0];                 }                else if (tInfo.nTouchKeyCode ==1) // TOUCH_KEY_BACK                {                    nTouchKeyCode =g_TpVirtualKey[2];                }                          else if (tInfo.nTouchKeyCode ==2) //TOUCH_KEY_SEARCH                {                    nTouchKeyCode =g_TpVirtualKey[3];                }                          else if (tInfo.nTouchKeyCode ==8) //TOUCH_KEY_HOME                {                     nTouchKeyCode =g_TpVirtualKey[1];                      }                 if (nLastKeyCode !=nTouchKeyCode)               {                    DBG("key touchpressed\n");                    DBG("nTouchKeyCode =%d, nLastKeyCode = %d\n", nTouchKeyCode, nLastKeyCode);                                       nLastKeyCode =nTouchKeyCode;                     input_report_key(g_InputDevice,BTN_TOUCH, 1);                   input_report_key(g_InputDevice, nTouchKeyCode, 1);                     input_sync(g_InputDevice);                }#endif //CONFIG_TP_HAVE_KEY 

 

3.4

4.調試方法

4.1 調試串口

4.2 Adb

(1)getevent,按鍵觸控螢幕

 

圖6

 

(2)busybox hexdump /dev/input/event2

圖7

對應下面的代碼

 

struct timeval {       __kernel_time_t        tv_sec;          /*seconds */       __kernel_suseconds_t       tv_usec; /*microseconds */};/* *The event structure itself */ struct input_event {       structtimeval time;       __u16type;       __u16code;       __s32value;};

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.