欢迎大家来到IT世界,在知识的湖畔探索吧!
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");
欢迎大家来到IT世界,在知识的湖畔探索吧!
Makefile
欢迎大家来到IT世界,在知识的湖畔探索吧!#compile regular
KERN_DIR = /work/system/linux-2.6.22.6
all:
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.symvers
obj-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,按下/松开触摸笔
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/48512.html