zoukankan      html  css  js  c++  java
  • 输入子系统框架

    以触摸屏驱动为例

    框架入口源文件: touch_screen.c  input.c  evdev.c

    (可根据入口源文件,再按着框架到内核走一遍)

    内核版本:linux_2.6.22.6 硬件平台:JZ2440

     以下是驱动框架:

    以下是驱动代码 touch_screen.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>
    
    //定义一个 input_dev 结构体
    static struct input_dev *s3c_ts_dev; 
    
    //定义 ts 结构体
     struct ts_con
    {
      unsigned long ADCCON;
      unsigned long ADCTSC;
      unsigned long ADCDLY;
      unsigned long ADCDAT0;
      unsigned long ADCDAT1;
      unsigned long ADCUPDN;
    };
    
    static volatile struct ts_con *ts_con;
    
    //定义定时器链表结构体
    static struct timer_list ts_timer;
    
    static void pen_up_mode(void)
    {
        ts_con->ADCTSC = 0x1d3;     //检测笔尖抬起中断信号
    }
    
    static void pen_down_mode(void)
    {
        ts_con->ADCTSC = 0xd3;      //检测笔尖落下中断信号
    }
    
    //进去xy轴自由转换模式
    static void enter_xy_measure_mode(void)
    {
       ts_con->ADCTSC |= (1<<2)|(1<<3);
    }
    
    //进入 adc_sc 中断模式
    static void start_adc_sc(void)
    {
       ts_con->ADCCON |= (1<<0);
    }
    
    //过滤函数
    static int filter(int *x,int *y)
    {
       int  count=0;
       for(count=0;count<2;count++)
       {
         if(((x[count] >x[count+1] ? x[count] - x[count+1] : x[count+1] - x[count])<10) && ((y[count] >y[count+1] ? y[count] - y[count+1] : y[count+1] - y[count])<10) )
          return 1; 
         else 
             return 0;
       }
    }
    
    //定时器函数
    void ts_timer_function(unsigned long data)
    {
          if((1<<15) & ts_con->ADCDAT0)  //已经抬起了
              {
              pen_down_mode();
             }
          else
              {
               enter_xy_measure_mode();
               start_adc_sc();    
            }
       
    }
    
    //ts_sc_con 中断处理函数
    static irqreturn_t adcstcon_irq(int irq, void *dev_id)
    {
        static int cnt=0;
        static int x[4],y[4];
    
        //优化2 如果已经抬起 则丢包
        unsigned long x_val = ts_con->ADCDAT0 & 0x3ff;
        unsigned long y_val = ts_con->ADCDAT1 & 0x3ff;
    
        if((1<<15) & ts_con->ADCDAT0)  //已经抬起了
        {
            pen_down_mode();
            cnt = 0;
        }
        else
        {
            //优化3    多次读取取其平均值
            x[cnt] = x_val;
            y[cnt] = y_val;
            cnt++;
            if(cnt == 4)
                {
                 //优化4     软件过滤
                 if(filter(x,y))
                     {
                      printk(" x= %d ,y= %d
    ",(x[0]+x[1]+x[2]+x[3])/4,(y[0]+y[1]+y[2]+y[3])/4);
                     }
                  cnt=0;
                  pen_up_mode();
    
                  mod_timer(&ts_timer,jiffies + HZ/100);
                }
            else
                {
                 enter_xy_measure_mode();
                 start_adc_sc();            
                }    
        }    
        return IRQ_HANDLED; 
    }
    
    
    // ts_up_down 中断处理函数
    static irqreturn_t pen_up_down_irq(int irq, void *dev_id)
    {
      if( (1<<15) & ts_con->ADCDAT0)
          {
           printk(" pen is up
    ");      // 1 笔尖抬起态
           pen_down_mode();
        }
      else
        {
          //   printk("pen is down
    ");   // 0 笔尖落下态
         //   enter_xy_measure_mode();        
             enter_xy_measure_mode();
             start_adc_sc();
        }
      return IRQ_HANDLED;
    }
    
    static int ts_init(void)
    {
       struct clk* clk;
    //申请 input_dev 
       s3c_ts_dev = input_allocate_device();
    
    //初始化 input_dev
       //事件类型
        set_bit(EV_KEY,s3c_ts_dev->evbit);
        set_bit(EV_ABS,s3c_ts_dev->evbit);
       //哪些事件
        set_bit(BTN_TOUCH,s3c_ts_dev->keybit);
        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);
    
    //注册 input_dev 结构体
       input_register_device(s3c_ts_dev);
    
    //硬件初始化
       //时钟初始化    
           clk = clk_get(NULL, "adc");
        clk_enable(clk);
    
       //映射寄存器
       ts_con = ioremap(0x58000000,sizeof(struct ts_con));
    
       /* ADCCON
       *  bit[14]    : 1
       *  bin[13:6]  : 49
       *  bit[0]     : 0
       */
       ts_con->ADCCON = (49<<6)|(1<<14);
    
       request_irq(IRQ_TC,pen_up_down_irq,IRQF_SAMPLE_RANDOM,"ts_up",NULL);
       request_irq(IRQ_ADC,adcstcon_irq,IRQF_SAMPLE_RANDOM,"adcstcon_irq",NULL);
    
       // 优化1 延时启动定时器
       ts_con->ADCDLY = 0xffff;
    
       //优化5    滑动和长按
       init_timer(&ts_timer);
       ts_timer.function = ts_timer_function;
       add_timer(&ts_timer);
       
       pen_down_mode();
    
       return 0;
    }
    
    
    static void ts_exit(void)
    {
        input_free_device(s3c_ts_dev);
        input_unregister_device(s3c_ts_dev);
        iounmap(ts_con);
        free_irq(IRQ_TC,NULL);
        free_irq(IRQ_ADC,NULL);
        del_timer(&ts_timer);
    }
    
    
    module_init(ts_init);
    module_exit(ts_exit);
    
    MODULE_LICENSE("GPL");

    以下是驱动代码 touch_screen_input.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>
    
    //定义一个 input_dev 结构体
    static struct input_dev *s3c_ts_dev; 
    
    //定义 ts 结构体
     struct ts_con
    {
      unsigned long ADCCON;
      unsigned long ADCTSC;
      unsigned long ADCDLY;
      unsigned long ADCDAT0;
      unsigned long ADCDAT1;
      unsigned long ADCUPDN;
    };
    
    static volatile struct ts_con *ts_con;
    
    //定义定时器链表结构体
    static struct timer_list ts_timer;
    
    static void pen_up_mode(void)
    {
        ts_con->ADCTSC = 0x1d3;     //检测笔尖抬起中断信号
    }
    
    static void pen_down_mode(void)
    {
        ts_con->ADCTSC = 0xd3;      //检测笔尖落下中断信号
    }
    
    //进去xy轴自由转换模式
    static void enter_xy_measure_mode(void)
    {
       ts_con->ADCTSC |= (1<<2)|(1<<3);
    }
    
    //进入 adc_sc 中断模式
    static void start_adc_sc(void)
    {
       ts_con->ADCCON |= (1<<0);
    }
    
    //过滤函数
    static int filter(int *x,int *y)
    {
       int  count=0;
       for(count=0;count<2;count++)
       {
         if(((x[count] >x[count+1] ? x[count] - x[count+1] : x[count+1] - x[count])<10) && ((y[count] >y[count+1] ? y[count] - y[count+1] : y[count+1] - y[count])<10) )
          return 1; 
         else 
             return 0;
       }
    }
    
    //定时器函数
    void ts_timer_function(unsigned long data)
    {
          if((1<<15) & ts_con->ADCDAT0)  //已经抬起了
              {
              pen_down_mode();
             }
          else
              {
               enter_xy_measure_mode();
               start_adc_sc();    
            }
       
    }
    
    //ts_sc_con 中断处理函数
    static irqreturn_t adcstcon_irq(int irq, void *dev_id)
    {
        static int cnt=0;
        static int x[4],y[4];
    
        //优化2 如果已经抬起 则丢包
        unsigned long x_val = ts_con->ADCDAT0 & 0x3ff;
        unsigned long y_val = ts_con->ADCDAT1 & 0x3ff;
    
        if((1<<15) & ts_con->ADCDAT0)  //已经抬起了
        {
            pen_down_mode();
            input_report_abs(s3c_ts_dev,ABS_PRESSURE,0);
            input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
            input_sync(s3c_ts_dev);         
            cnt = 0;
        }
        else
        {
            //优化3    多次读取取其平均值
            x[cnt] = x_val;
            y[cnt] = y_val;
            cnt++;
            if(cnt == 4)
                {
                 //优化4     软件过滤
                 if(filter(x,y))
                     {
                     // printk(" x= %d ,y= %d
    ",(x[0]+x[1]+x[2]+x[3])/4,(y[0]+y[1]+y[2]+y[3])/4);
                      input_report_abs(s3c_ts_dev,ABS_X,(x[0]+x[1]+x[2]+x[3])/4);
                      input_report_abs(s3c_ts_dev,ABS_Y,(y[0]+y[1]+y[2]+y[3])/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;
                  pen_up_mode();
    
                  mod_timer(&ts_timer,jiffies + HZ/100);
                }
            else
                {
                 enter_xy_measure_mode();
                 start_adc_sc();            
                }    
        }    
        return IRQ_HANDLED; 
    }
    
    
    // ts_up_down 中断处理函数
    static irqreturn_t pen_up_down_irq(int irq, void *dev_id)
    {
      if( (1<<15) & ts_con->ADCDAT0)
          {
           printk(" pen is up
    ");      // 1 笔尖抬起态
           pen_down_mode();
        }
      else
        {
          //   printk("pen is down
    ");   // 0 笔尖落下态
         //   enter_xy_measure_mode();        
             enter_xy_measure_mode();
             start_adc_sc();
        }
      return IRQ_HANDLED;
    }
    
    static int ts_init(void)
    {
       struct clk* clk;
    //申请 input_dev 
       s3c_ts_dev = input_allocate_device();
    
    //初始化 input_dev
       //事件类型
        set_bit(EV_KEY,s3c_ts_dev->evbit);
        set_bit(EV_ABS,s3c_ts_dev->evbit);
       //哪些事件
        set_bit(BTN_TOUCH,s3c_ts_dev->keybit);
        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);
    
    //注册 input_dev 结构体
       input_register_device(s3c_ts_dev);
    
    //硬件初始化
       //时钟初始化    
           clk = clk_get(NULL, "adc");
        clk_enable(clk);
    
       //映射寄存器
       ts_con = ioremap(0x58000000,sizeof(struct ts_con));
    
       /* ADCCON
       *  bit[14]    : 1
       *  bin[13:6]  : 49
       *  bit[0]     : 0
       */
       ts_con->ADCCON = (49<<6)|(1<<14);
    
       request_irq(IRQ_TC,pen_up_down_irq,IRQF_SAMPLE_RANDOM,"ts_up",NULL);
       request_irq(IRQ_ADC,adcstcon_irq,IRQF_SAMPLE_RANDOM,"adcstcon_irq",NULL);
    
       // 优化1 延时启动定时器
       ts_con->ADCDLY = 0xffff;
    
       //优化5    滑动和长按
       init_timer(&ts_timer);
       ts_timer.function = ts_timer_function;
       add_timer(&ts_timer);
       
       pen_down_mode();
    
       return 0;
    }
    
    
    static void ts_exit(void)
    {
        input_free_device(s3c_ts_dev);
        input_unregister_device(s3c_ts_dev);
        iounmap(ts_con);
        free_irq(IRQ_TC,NULL);
        free_irq(IRQ_ADC,NULL);
        del_timer(&ts_timer);
    }
    
    
    module_init(ts_init);
    module_exit(ts_exit);
    
    MODULE_LICENSE("GPL");

    以下是编译驱动的Makefile:

    KERN_DIR = /work/systems/kernel/linux-2/linux-2.6.22.6
    
    all:
        make -C $(KERN_DIR) M=`pwd` modules 
    
    clean:
        make -C $(KERN_DIR) M=`pwd` modules clean
        rm -rf modules.order
    
    obj-m    += touch_screen.o
    obj-m   += touch_screen_input.o
  • 相关阅读:
    Android学习笔记04-Activity及Activity生命周期
    Android学习笔记03-学习过程中碰到的一些问题及解决方法
    Android学习笔记--生命周期
    Android学习笔记01
    Android学习笔记--项目框架介绍
    Android学习笔记- Animation动画
    Android学习笔记02-AndroidManifest.xml文件解析
    cx_Oracle.DatabaseError: DPI-1047: 64-bit Oracle Client library cannot be loaded 解决方法
    jvm 03-java堆内存模型
    jvm 02-java对象访问模式
  • 原文地址:https://www.cnblogs.com/zsy12138/p/10392663.html
Copyright © 2011-2022 走看看