zoukankan      html  css  js  c++  java
  • linux触摸屏驱动程序

    触摸屏驱动程序框架与上一片文章的输入子系统类似,只是底层驱动由按键变成了触摸屏。

    S3C2440的ADC相关寄存器:

    struct s3c_ts_regs {
      unsigned long adccon;
      unsigned long adctsc;
      unsigned long adcdly;
      unsigned long adcdat0;
      unsigned long adcdat1;
      unsigned long adcupdn;
    };

    1.分配input_dev结构体

    struct input_dev *s3c_ts_dev = input_allocate_device();
    2.设置
    2.1设置产生哪类事件
    set_bit(EV_KEY, s3c_ts_dev->evbit);
    set_bit(EV_ABS, s3c_ts_dev->evbit);
    2.2能产生这类事件中的哪些事件
    set_bit(BTN_TOUCH, s3c_ts_dev->keybit);
    //表示支持绝对值x坐标,并设置它在坐标系中的最大值和最小值,以及干扰值和平焊位置等
    input_set_abs_params(s3c_ts_dev, ABS_X,              0, 0x3FF, 0, 0);
    input_set_abs_params(s3c_ts_dev, ABS_Y,              0, 0x3FF, 0, 0);
    input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);
    3.注册
    inpute_register_device(s3c_ts_dev);
    4.硬件相关操作
    4.1使能ADC时钟
    struct clk *clk = clk_get(NULL, "adc");
    clk_enable(clk);
    4.2设置ADC相应寄存器
    s3c_ts_regs = ioremap((0x58000000, sizeof(struct s3c_ts_regs));
    /* converter prescaler enable , ADCCLK=PCLK/(49+1)=50MHz/(49+1)=1MHz */
    s3c_ts_regs->adccon = (1<<14)|(49<<6);
    s3c_ts_regs->adcdly = 0xffff;//为了确保ADC转换的精度,将这个寄存器设置成最大值
    4.3申请中断,ADC转换完成中断和触摸屏按下或抬起中断
    request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);
    request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);
    4.4初始化定时器,用来处理在触摸屏上滑动的情况
    init_timer(&ts_timer);
    ts_timer.function = s3c_ts_timer_function;
    add_timer(&ts_timer);
    4.5让触摸屏进入等待笔尖按下状态
    enter_wait_pen_dowm_mode();
    5.触摸屏模式设置
    void enter_wait_pen_down_mode(void)
    {
         s3c_ts_regs->adctsc = 0xd3;
    }
    void enter_wait_pen_up_mode(void)
    {
         s3c_ts_regs->adctsc = 0x1d3;
    }
    void enter_measure_xy_mode(void)
    {
         s3c_ts_regs->adctsc = (1<<3) | (1<<2);
    }
    void start_adc(void)
    {
         s3c_ts_regs->adccon |= (1<<0);
    }
    6.定时器处理函数,上报事件
    void s3c_ts_timer_function(void)
    {
         if (s3c_ts_regs->adcdat0 & (1<<15))
         {
              /* 松开 */
              input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
              input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
              input_sync(s3c_ts_dev);
              enter_wait_pen_down_mode();
         } else {
              /* 按下 */
              enter_measure_xy_mode();
              start_adc();
         }
    }
    7.中断处理函数
    irqreturn_t pen_down_up_irq(int irq, void *dev_id)
    {
         if (s3c_ts_regs->adcdat0 & (1<<15)) {
              /* 松开 */
              input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
              input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
              input_sync(s3c_ts_dev);
              enter_wait_pen_down_mode();
         } else {
              /* 按下 */
              enter_measure_xy_mode();
              start_adc();
         }
         return IRQ_HANDLED;
    }
    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 & (1<<15)) {
              /* 松开 */
             cnt = 0;
             input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
             input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
              input_sync(s3c_ts_dev);
             enter_wait_pen_down_mode();
         } else {
             x[cnt] = adcdat0 & 0x3FFF;
             y[cnt] = adcdat1 & 0x3FFF;
             ++cnt;
             if (cnt == 4) {
                   if (s3c_filter_ts(x, y)) {
                       input_report_abs(s3c_ts_dev, ABS_X, (x[1]+x[2]+x[3]+x[4])/4);
                       input_report_abs(s3c_ts_dev, ABS_Y, (y[1]+y[2]+y[3]+y[4])/4);
                       input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);
                       input_report_key(s3c_ts_dev, BTN_TOUCH, 1);
                       input_sync(s3c_ts_dev);
                   }
                  cnt = 0;
                  enter_wait_pen_up_mode();
                  mod_timer(&ts_timer, jiffies + HZ / 100);
              } else {
                  enter_measure_xy_mode();
                  start_adc();
              }
         }
        return IRQ_HANDLED;
    }
    8.过滤ADC转化的数据
    static int s3c_filter_ts(int x[], int y[])
    {
    #define ERR_LIMIT 10
    
         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;
    }
     9.移植tslib,测试触摸屏驱动程序
    9.1解压、配置、编译tslib-1.4.tar.gz
      tar xzf tslib-1.4.tar.gz
         cd tslib
         ./autogen.sh
         mkdir tmp
         echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache
         ./configure --host=arm-linux --cache-file=arm-linux.cache --prefix=$(pwd)/tmp
         make
         make install
    9.2装载驱动
      装载s3c_ts.ko驱动和lcd.ko驱动
    9.3修改/etc/ts.conf第1行
      将"# module_raw input"改为"module_raw input",去掉#号和第一个空格
    9.4添加环境变量
      export TSLIB_TSDEVICE=/dev/event0          指定触摸设备
         export TSLIB_CALIBFILE=/etc/pointercal       指定触摸屏校准文件pointercal的存放位置
         export TSLIB_CONFFILE=/etc/ts.conf            指定TSLIB配置文件的位置
         export TSLIB_PLUGINDIR=/lib/ts                  指定触摸屏插件所在目录
         export TSLIB_CONSOLEDEVICE=none           设置控制台设备为none,否则默认为/dev/tty,这样可以避免出现“open consoledevice: No such file or directory KDSETMODE: Bad file descriptor”的错误
         export TSLIB_FBDEVICE=/dev/fb0                 指定帧缓存设备
    一个变量创建时,它不会自动地为在它之后创建的shell进程所知。而命令export可以向后面的shell传递变量的值。当一个shell脚本调用并执行时,它不会自动得到原来脚本(调用者)里定义的变量的访问权,除非这些变量已经被显式地设置为可用。export命令可以用于传递一个或多个变量的值到任何后继脚本。
    9.5触摸屏校准
      执行程序ts_calibrate
    9.6触摸屏测试
      执行程序ts_test
  • 相关阅读:
    Query on The Trees(hdu 4010)
    背单词(bzoj 4567)
    P2819 图的m着色问题
    P1605 迷宫
    P1230 智力大冲浪
    P1082 同余方程
    P3372 【模板】线段树 1
    P2626 斐波那契数列(升级版)
    长生诀
    写给我第一个喜欢的男孩的歌
  • 原文地址:https://www.cnblogs.com/zpehome/p/3819051.html
Copyright © 2011-2022 走看看