首頁>技術>

linux輸入子系統(linux input subsystem)從上到下由三層實現,分別為:輸入子系統事件處理層(EventHandler)、輸入子系統核心層(InputCore)和輸入子系統裝置驅動層

linux輸入子系統的事件處理機制

Linux輸入子系統支援的資料型別:

EV_SYN 0x00 同步事件

EV_KEY 0x01 按鍵事件

EV_REL 0x02 相對座標(如:滑鼠移動,報告相對最後一次位置的偏移)

EV_ABS 0x03 絕對座標(如:觸控式螢幕或操作杆,報告絕對的座標位置)

EV_MSC 0x04 其它

EV_SW 0x05 開關

EV_LED 0x11 按鍵/裝置燈

EV_SND 0x12 聲音/警報

EV_REP 0x14 重複

EV_FF 0x15 力反饋

EV_PWR 0x16 電源

EV_FF_STATUS 0x17 力反饋狀態

EV_MAX 0x1f 事件型別最大個數和提供位掩碼支援

注:參考核心:/include/linux/input.h

程式設計思路總體程式設計思路驅動程式
//touch.c#include <linux/errno.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/input.h>#include <linux/init.h>#include <linux/serio.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/clk.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/plat-s3c24xx/ts.h>#include <asm/arch/regs-adc.h>#include <asm/arch/regs-gpio.h>#define Stylus_up_state      (1<<15)#define Start_up_adc           (1<<0)  #define Wait_down_mode   0xd3#define Wait_up_mode        0x1d3struct s3c_ts_regs {	unsigned long adccon;	unsigned long adctsc;	unsigned long adcdly;	unsigned long adcdat0;	unsigned long adcdat1;	unsigned long adcupdn;};//static struct input_dev  * mytouch_dev;static struct input_handle   mytouch_handle;static struct timer_list  ts_timer;static volatile struct s3c_ts_regs *s3c_ts_regs;//函式宣告static void s3c_ts_timer_function(unsigned long data);static void enter_wait_down_mode(void);static void enter_wait_up_mode(void);static void configurate_event(void);static void configurate_hardware(void);static int s3c_filter_ts(int *x, int *y);static void enter_measure_xy_mode(void){	s3c_ts_regs->adctsc = 0x0c;}static void start_adc(void){	s3c_ts_regs->adccon |= Start_up_adc;}static irqreturn_t pen_down_up_irq(int irq, void *dev_id){	if(s3c_ts_regs->adcdat0 &  Stylus_up_state )//up	{		printk("touch up");		enter_wait_down_mode();	}	else//down	{		printk("touch down");		enter_measure_xy_mode();		start_adc();	}		return IRQ_HANDLED;}static irqreturn_t adc_irq(int irq, void *dev_id){		static int cnt = 0;	static int x[4], y[4];	int adcdat0, adcdat1;		adcdat0 = s3c_ts_regs->adcdat0;	adcdat1 = s3c_ts_regs->adcdat1;	if (s3c_ts_regs->adcdat0 & Stylus_up_state)	{		cnt = 0;		input_report_abs(mytouch_handle.dev, ABS_PRESSURE, 0);		input_report_key(mytouch_handle.dev, BTN_TOUCH, 0);		input_sync(mytouch_handle.dev);		enter_wait_down_mode();	}	else	{		x[cnt] = adcdat0 & 0x3ff;		y[cnt] = adcdat1 & 0x3ff;		++cnt;		if (cnt == 4)		{			if (s3c_filter_ts(x, y))			{							printk("x = %d, y = %d\n", (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4);				input_report_abs(mytouch_handle.dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4);				input_report_abs(mytouch_handle.dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);				input_report_abs(mytouch_handle.dev, ABS_PRESSURE, 1);				input_report_key(mytouch_handle.dev, BTN_TOUCH, 1);				input_sync(mytouch_handle.dev);			}			cnt = 0;			enter_wait_up_mode();			mod_timer(&ts_timer, jiffies + HZ/100);		}		else		{			enter_measure_xy_mode();			start_adc();		}			}		return IRQ_HANDLED;}static int s3c_filter_ts(int x[], int y[])//filter{#define ERR_LIMIT 5	int avr_x, avr_y;	int det_x, det_y;	avr_x = (x[0] + x[1])/2;	avr_y = (y[0] + y[1])/2;	det_x = (x[2] > avr_x) ? (x[2] - avr_x) : (avr_x - x[2]);	det_y = (y[2] > avr_y) ? (y[2] - avr_y) : (avr_y - y[2]);	if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))		return 0;	avr_x = (x[1] + x[2])/2;	avr_y = (y[1] + y[2])/2;	det_x = (x[3] > avr_x) ? (x[3] - avr_x) : (avr_x - x[3]);	det_y = (y[3] > avr_y) ? (y[3] - avr_y) : (avr_y - y[3]);	if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))		return 0;		return 1;}static int mytouch_init(void){	mytouch_handle.dev = input_allocate_device();		configurate_event();	input_register_device(mytouch_handle.dev);		configurate_hardware();	return 0;}static void mytouch_exit(void){	free_irq(IRQ_TC, NULL);	free_irq(IRQ_ADC, NULL);	iounmap(s3c_ts_regs);	input_free_device(mytouch_handle.dev);	input_unregister_device(mytouch_handle.dev);	del_timer(&ts_timer);}static void configurate_event(void){	set_bit(EV_KEY,mytouch_handle.dev->evbit);	set_bit(EV_ABS,mytouch_handle.dev->evbit);	set_bit(BTN_TOUCH,mytouch_handle.dev->keybit);	input_set_abs_params(mytouch_handle.dev, ABS_X, 0, 0X3FF,0,0);	input_set_abs_params(mytouch_handle.dev, ABS_Y, 0, 0X3FF,0,0);	input_set_abs_params(mytouch_handle.dev, ABS_PRESSURE, 0, 1,0,0);}static void configurate_hardware(void){	struct clk *adc_clk;	//開啟時鐘	adc_clk = clk_get(NULL, "adc_clk");	clk_enable(adc_clk);	//io重對映	s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));	//ADC配置	//ADCCLK=PCLK/(49+1)=50MHz/(49+1)=1MHz	s3c_ts_regs->adccon = (1<<14)|(49<<6);		s3c_ts_regs->adcdly = 0xffff;	//註冊中斷	request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);	request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc_clk", NULL);	//註冊定時器	init_timer(&ts_timer);	ts_timer.function = s3c_ts_timer_function;	add_timer(&ts_timer);	//進入等待按下模式	enter_wait_down_mode();	}static void s3c_ts_timer_function(unsigned long data){	if (s3c_ts_regs->adcdat0 & Stylus_up_state)	{		input_report_abs(mytouch_handle.dev, ABS_PRESSURE, 0);		input_report_key(mytouch_handle.dev, BTN_TOUCH, 0);		input_sync(mytouch_handle.dev);		enter_wait_down_mode();	}	else	{		enter_measure_xy_mode();		start_adc();	}}static void enter_wait_down_mode(void){	s3c_ts_regs->adctsc = Wait_down_mode;}static void enter_wait_up_mode(void){	s3c_ts_regs->adctsc = Wait_up_mode;	}module_init(mytouch_init);module_exit(mytouch_exit);MODULE_LICENSE("GPL");

Makefile

#compile regularKERN_DIR = /work/system/linux-2.6.22.6all:	make -C $(KERN_DIR) M=`pwd` modules	rm -rf modules.order Module.symvers .PHONY:clean:	make -C $(KERN_DIR) M=`pwd` modules clean	rm -rf modules.order Module.symversobj-m   += touch.o
測試方法:

1. make menuconfig 去掉原來的觸控式螢幕驅動程式

-> Device Drivers -> Input device support -> Generic input layer -> Touchscreens <> S3C2410/S3C2440 touchscreens

2,make uImage 使用新核心啟動

3. insmod touch.ko

4,按下/鬆開觸控筆

10
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 手把手教你用Pycharm連線遠端Python環境