精华内容
下载资源
问答
  • 2019-09-29 15:39:34

    专题5-触摸屏驱动程序设计

    第1课-输入子系统模型解析

     

    1. 为什么需要输入子系统
    2. 输入子系统模型介绍

     

    输入子系统由设备驱动层(input device driver),核心层(input core)和事件驱动层(event driver)三部份组成。任何一次输入事件,如鼠标移动,按

    键按下,都需要通过InputDeviceDriver->InputCore->EventDrive才能到达用户空间的应用程序。

    l  设备驱动层:

    将底层的硬件输入转化为统一事件型式,向输入核心(InputCore)汇报。

    l  v输入核心层:

    为设备驱动层提供输入设备注册与操作接口,如:input_register_device;通知事件处理层对事件进行处理;

    l  事件驱动层:

    主要作用是和用户空间交互,如提供read,open等设备方法,创建设备文件等。

    1. 输入子系统案例分析

    输入型设备驱动;输入型按键驱动

     

    附录

    事件类型:

    EV_RST         Reset                        EV_KEY 按键

    EV_REL         相对坐标                     EV_ABS 绝对坐标

    EV_MSC        其它                         EV_LED LED

    EV_SND        声音

    EV_REP         Repeat

    EV_FF          力反馈

    当事件类型为EV_KEY时,还需指明按键类型:

    BTN_ LEFT:鼠标左键                      BTN_0:数字0键

    BTN_RIGHT:鼠标右键                     BTN_1:数字1键

     

    第2课-输入子系统原理分析

    1. 子系统核心架构

     

     

    1. 输入设备注册

    输入型设备注册

    1. 事件上报

    第3课-触摸屏驱动分析

    第4课-触摸屏驱动编程

    转载于:https://www.cnblogs.com/free-1122/p/11452274.html

    更多相关内容
  • 嵌入式触摸屏设备驱动程序-课程设计
  • 本文以触摸屏控制器ADS7843为例,介绍了其内部结构、工作原理,并详细阐述了在Linux操作系统的设备文件系统机制中编写设备驱动程序的过程与方法,同时给出基于PXA255微外理器的触摸屏控制器ADS7843中断方式的驱动程序。...
  • 一般来说,WinCE触摸屏驱动设计和实现有以下几个步骤:  (1)配置和初始化触摸屏  触摸屏驱动在初始化过程会调用TouchPanelEnable函数,该函数调用的DDSI函数为DdsiTouchPanelEnable和 DdsiTouchPanelDisable...
  • 本文介绍了基于三星S3C2410X微处理器,采用SPI接口与ADS7843触摸屏控制器芯片完成触摸屏模块的设计。具体包括在嵌入式Linux操作...设计完成的触摸屏驱动程序在博创公司教学实验设备UP-NETARM2410-S平台上运行效果良好。
  • 论文在介绍了嵌入式Linux下设备驱动层次结构、运行机制、编译平台方法以及字符设备驱动程序使用流程的基础上,针对Unity805plus此新型平台下键盘、触摸屏、LCD这三种人机交互设备提出了实际的驱动设计方案。...
  • Linux设备驱动程序设计 实验目的 学习Linux下进行驱动程序设计的原理 掌握Linux设备驱动程序开发的基本过程和设计方法 实验内容 内核驱动设计入门模块方式驱动程序5.1 内核驱动设计实验触摸屏驱动5.2 写一个简单的...
  • CE系统与其它操作系统一样,也提供了设备驱动程序。以驱动内部或者外围硬件设备。驱动程序将操作系统和设备链接起来,使得操作系统能够识别设备,并为应用程序提供相应的服务。要想真正了解驱动程序必须结合一些驱动...
  • 尽管触摸屏正在迅速普及开来,但大多数开发...本文将介绍如何编写软件驱动程序,从而能够使用这些微处理器配置、校准触摸屏以及对触摸屏输入持续响应。最终将提供可免费下载和使用的工作代码,作为读者进一步设计的基础
  • CE系统与其它操作系统一样,也提供了设备驱动程序。以驱动内部或者外围硬件设备。驱动程序将操作系统和设备链接起来,使得操作系统能够识别设备,并为应用程序提供相应的服务。要想真正了解驱动程序必须结合一些驱动...
  • 设计分享的是多功能Arduino / Seeeduino / Arduino Mega兼容电阻式触摸屏驱动板V2.0设计,见附件下载其原理图/PCB/库文件等。该TFT电阻式触摸屏驱动板可以用作显示设备或草图板,与原来的V1.0版本对比,该电阻式...
  •  本书是linux设备驱动程序开发领域的权威著作。全书基于2.6内核,不仅透彻讲解了基本概念和技术,更深入探讨了其他书没有涵盖或浅尝辄止的许多重要主题和关键难点,如pcmcia、i2c和usb等外部总线以及视频、音频、...
  • 实验步骤-触摸屏驱动 测试驱动程序 驱动程序位于内核源代码目录下面的drivers/char/下面, 名称:s3c2410-ts-ads7843.o 装载驱动程序和建立设备文件节点 在将触摸屏驱动加载到内核中时,可以看到系统为触摸屏设备分配的...
  • 深入分析Windows CE.Net设备驱动程序的框架结构,详细介绍了分层驱动程序和流接口驱动程序的开发方法。通过研究Windows CE.Net内核及部分驱动程序的源代码,设计了操作系统的键盘驱动程序、触摸屏、LCD驱动、电源...
  • x260使用Windows 2000光盘安装操作系统后会出现视频控制...操作系统安装完成后,依次安装Windows 2000的最新Service Pack补丁和设备驱动。操作系统安装前准备和安装步骤请参阅IBM xSeries 服务器安心服务有关文档内容。
  •  嵌入式计算机的输入设备一般有鼠标、键盘、触摸屏、按钮、旋钮等,而光电编码器(俗称“单键飞梭”)作为一种输入设备,由于其具有输入灵活,简单可靠等特点,因此特别适合应用在嵌入式仪器和手持式设备上,整个...
  • 触摸屏设备驱动程序

    2015-03-16 18:43:44
    触摸屏设备驱动程序 由于触摸屏设备简单、价格低廉,到处应用 在消费电子商品、工业控制系统、甚至航空领域都有应用   触摸屏作为一种最新的电脑输入设备,是目前最简单、方便、自然的的一种人机交互方式,具有...

    触摸屏设备驱动程序

    由于触摸屏设备简单、价格低廉,到处应用

    在消费电子商品、工业控制系统、甚至航空领域都有应用

     

    触摸屏作为一种最新的电脑输入设备,是目前最简单、方便、自然的的一种人机交互方式,具有坚固耐用、反应速度快、节省空间、易于交流等许多优点。

    事实上,触摸屏是一个使多媒体信息系统改头换面的设备,它赋予多媒体系统以崭新的面貌,是极富有吸引力的全新多媒体交互设备

     

    从技术原理来区别触摸屏,可分为5类:

    1,矢量压力传感技术触摸屏

    2,电阻式触摸屏

    3,电容式触摸屏

    4,红外线技术触摸屏

    5,表面声波技术触摸屏

     

    矢量压力传感技术触摸屏已经退出历史舞台

    红外线技术触摸屏价格低廉,但其外框易碎,容易产生光干扰,曲面情况下失真

    电容技术触摸屏设计构思合理,但其图像失真问题很难得到解决

    电阻技术触摸屏的定位准确,但其价格颇高,且怕刮易损

    表面声波触摸屏解决了以往触摸屏的各种缺陷,清晰且不容易被破坏,适用于各种场合,缺点是:屏幕表面如果有水滴和尘土会使触摸屏变得迟钝

     

    电阻式触摸屏的屏体部分是一块与显示器表面相匹配的多层复合薄膜,由一层玻璃或有机玻璃作为底层,表面涂有一层透明的导电层,上面再盖有一层外表面硬化处理、光滑防刮的塑料层,它的内表面也涂有一层透明导电层,在两层导电层之间有很多细小(小于千分之一英寸)的透明隔离点把它们隔开绝缘。

    四线触摸屏包含两个阻性层。其中一层在屏幕的左右边缘各有一条垂直总线,另一层在屏幕的底部和顶部各有一条水平总线,见图4。为了在X轴方向进行测量,将左侧总线偏置为0V,右侧总线偏置为VREF。将顶部或底部总线连接到ADC,当顶层和底层相接触时即可作一次测量。   为了在Y轴方向进行测量,将顶部总线偏置为VREF,底部总线偏置为0V。将ADC输入端接左 侧总线或右侧总线,当顶层与底层相接触时即可对电压进行测量。图5显示了四线触摸屏在两层相接触时的简化模型。对于四线触摸屏,最理想的连接方法是将偏置 为VREF的总线接ADC的正参考输入端,并将设置为0V的总线接ADC的负参考输入端。

     

    s3c2440芯片支持触摸屏接口。这个触摸屏接口包括一个外部晶体管控制逻辑和一个模数转换器ADC,s3c2440芯片具有一个8通道的10位CMOS模数转换器(ADC)。2.5MHz下A/D转换器可达500KSPS,A/D支持片上采样和保持功能,并支持掉电模式

    s3c2440触摸屏特点:

    1,分辨率,10位

    2,微分线性误差:1.0LSB

    3,积分线性误差:2.0LSB

    4,最大转换速率:500KSPS

    5,低功耗

    6,供电电压:3.3V

    7,输入模拟电压范围:0~3.3V

    8,片上采样保持功能

    9,普通转换模式

    10,分离X/Y轴坐标转换模式

    11,自动(连续)X/Y轴坐标转换模式

    12,等待中断模式

     

    S3C2440触摸屏4种工作模式:

    1,正常转换模式

               在不使用触摸屏设备时,可以单独使用触摸屏接口中共用的模数转换器ADC。这这种模式下,可以通过设置ADCCON寄存器启动普通的A/D转韩,当转换结束时,结果被写到ADCCDAT0寄存器中

    2,等待中断模式

                当设置触摸屏接口控制器的ADCTSC寄存器为0XD3时,触摸屏就处于等待中断模式。这时触摸屏等待触摸信号的到来。当触摸信号到来时,触摸屏接口控制器将通过INT_TC线产生中断信号,表示有触摸动作发生。当中断发生,触摸屏可以转换为其他两种状态来读取触摸点的位置(x,y)。这两种模式是独立的X/Y位置转换模式和自动X/Y位置转换模式

    3,独立X/Y位置转换模式

                独立的X/Y位置转换模式由两个子模式组成,分别是X位置模式和Y位置模式。X位置模式将转换后的X坐标写到ADCDAT0寄存器的XPDATA位。转换后,触摸屏接口控制器会通过INT_ADC中断线产生中断信号,由中断处理函数来处理。Y位置模式将转换后的Y坐标写到ADCDAT1寄存器的YPDATA位。同样转换后,触摸屏接口控制器会通过INT_ADC中断线产生中断信号,由中断处理函数来处理

    4,自动X/Y位置转化模式

                 这种模式触摸屏控制器自动转换X位置和Y位置。当位置转换后,模式触摸屏接口控制器自动写转换后的X坐标写到ADCDAT0寄存器的XPDATA位;写转换后的Y坐标到ADCDAT1寄存器的YPDATA位。当转换完后,触摸屏接口控制器会通过INT_AC中断行产生中断信号

     

    寄存器:

    ADCCON:模数转换控制寄存器,用于控制AD转换、是否使用分频、设置分频系数、读取AD转换器的状态

    ADCDLY:ADC延时寄存器,用于正常模式下和等待中断模式下的延时操作

    ADCDAT0:ADC转换数据寄存器0,用于存储触摸屏的点击状态、工作模式、X坐标等

    ADCDAT1:ADC转换数据寄存器1,用于存储触摸屏的点击状态、工作模式、Y坐标等

    注意:ADCDAT0和ADCDAT1的第15位,表示X和Y方向上检测到的触摸屏是否被按下。只有当ADCDAT0和ADCDAT1寄存器的第15位,即两个寄存器的15位都等于0时,才表示触摸屏被按下,或者有触笔点击触摸屏。

    ADCTSC:ADC触摸屏控制寄存器,用于控制触摸屏的YMON,nYPON,nXPON和XMON等状态

     

     

    触摸屏设备驱动程序

    struct s3c2410ts {
        struct input_dev dev;
        long xp;
        long yp;
        int count;
        int shift;
        char phys[32];
    };

    触摸屏设备驱动程序的初始化函数、退出函数、和中断处理函数关系如图:

    1,当模块加载时,会调用初始化函数s3c2410ts_init()。在该函数中会调用probe()函数,该函数中会进一步调用request_irq()函数注册两个中断。这两个中断的处理函数分别是stylus_updown()和stylus_action()。request_irq()函数会操作内核中的一个中断描述符数组结构irq_dest。该数组结构比较复杂,主要功能就是记录中断号对应的中断处理函数

    2,当中断到来时,会到中断描述符数组中询问中断号对应的处理函数,然后执行该函数。在本例中,这两个中断的处理函数分别是stylus_updown()和stylus_action()。

    3,卸载模块时,会调用退出函数s3c2410ts_exit()。在该函数中,会调用free_irq()来释放设备所使用的中断号。free_irq()函数也会操作中断描述符数组结构irq_desc,将该设备对应的中断处理函数删除

    4,中断处理函数stylus_updown()中会调用touch_timer_fire()。这个函数也被定时器触发,触发的条件是,缓冲区中的数据不为0,也就是有触摸时间产生

     

    加载和卸载函数:

    int __init s3c2410ts_init(void)                    //加载函数
    {
        return driver_register(&s3c2410ts_driver);           //注册一个触摸屏设备驱动程序,之后内核会以s3c2410ts_driver中的name成员为依据,在系统查找已经注册的相同name的设备。如果 找到相应的设备,就调用s3c2410ts_driver中定义的探测函数probe()。driver_register()函数是Linux设备驱动 模型中最常用的函数
    }

    void __exit s3c2410ts_exit(void)                  //卸载函数
    {
        driver_unregister(&s3c2410ts_driver);           //卸载触摸屏设备驱动程序
    }

     

    下面来看看导火线:s3c2410ts_driver:

    static struct device_driver s3c2410ts_driver = {
        .name           = "s3c2410-ts",                   //名字
        .bus            = &platform_bus_type,        //总线
        .probe          = s3c2410ts_probe,             //探测函数,该函数在模块加载函数完成且设备匹配成功后执行
        .remove         = s3c2410ts_remove,          //移除函数
    };

     

    probe()对应的s3c2410ts_probe()。这个函数在触摸屏设备的初始化过程中,检查设备是否准备就绪、映射物理地址到虚拟地址、配置GPIO引脚、注册相应的中断和注册输入设备等,大多数Linux设备驱动程序中,当执行完模块加载后,就执行probe():

    static int __init s3c2410ts_probe(struct device *dev)
    {
        struct s3c2410_ts_mach_info *info;                                                    //定义了触摸屏接口相关硬件的配置信息结构体指针
        
        info = ( struct s3c2410_ts_mach_info *)dev->platform_data;               //从device的平台数据dev->platform_data中获得指向struct s3c2410_ts_match_info结构体的指针
        
        if (!info)                           //说明没有平台数据
        {
            printk(KERN_ERR "Hm... too bad : no platform data for ts\n");
            return -EINVAL;
        }
        
    #ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG             //如果内核配置了调试信息选项,则打印调试信息
        printk(DEBUG_LVL "Entering s3c2410ts_init\n");
    #endif
        
        adc_clock = clk_get(NULL, "adc");                                  //获得ADC的时钟源,并赋值给adc_clock指针
        if (!adc_clock) {                       //如果没有正确的获得ADC时钟源,错误退出
            printk(KERN_ERR "failed to get adc clock source\n");
            return -ENOENT;
        }
        clk_use(adc_clock);                                                     //增加时钟源的使用计数
        clk_enable(adc_clock);                                                //启动ADC时钟源
        
    #ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG                     //配置调试信息选项的话打印调试信息
        printk(DEBUG_LVL "got and enabled clock\n");
    #endif
        
        base_addr=ioremap(S3C2410_PA_ADC,0x20);                             //把一个ADC控制寄存器的物理地址内存映射到一个虚拟地址。这段被映射的长度是0x20。

                                                                                                           #define S3C2410_PA_ADC       (0x58000000)   //这是触摸屏一组寄存器的首地址

        if (base_addr == NULL) {                        //映射失败退出
            printk(KERN_ERR "Failed to remap register block\n");
            return -ENOMEM;
        }
        
        
        /* Configure GPIOs */
        s3c2410_ts_connect();                                  //配置处理器的GPIO。这个函数配置端口G的12,13,14,15引脚为XMON,nXPON,YMON,nPON。
        /* Set the prscvl*/
        if ((info->presc&0xff) > 0)                                   //设置AD转换的分频系数。如果info->presc的低8位的值大于0,那么配置ADCCON寄存器

                                                                                                位14:是否使用AD转换器的预分频功能,位6-13位共8位表示AD转换的预分频器的数值

            writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(info->presc&0xFF),\
                     base_addr+S3C2410_ADCCON);
        else
            writel(0,base_addr+S3C2410_ADCCON);                               //不使用预分频功能,将ADCCON寄存器各位都设置为0
        
        
        /* Initialise the adcdly registers */
        if ((info->delay&0xffff) > 0)                           //如果需要延时。写延时时间到ADCDLY寄存器
            writel(info->delay & 0xffff,  base_addr+S3C2410_ADCDLY);                    
        
        writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);                                 //写ADC触摸屏设备的ADCTSC寄存器,使触摸屏设备 处于等待中断模式                   
        
        /* Initialise input stuff */
        memset(&ts, 0, sizeof(struct s3c2410ts));                        //清零全局变量
        init_input_dev(&ts.dev);                                                //申请并初始化一个输入设备。通过这个输入设备,驱动程序才能和用户交互
        ts.dev.evbit[0] = ts.dev.evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);                             //下面是初始化ts变量
        ts.dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
        input_set_abs_params(&ts.dev, ABS_X, 0, 0x3FF, 0, 0);
        input_set_abs_params(&ts.dev, ABS_Y, 0, 0x3FF, 0, 0);
        input_set_abs_params(&ts.dev, ABS_PRESSURE, 0, 1, 0, 0);
        
        sprintf(ts.phys, "ts0");
        
        ts.dev.private = &ts;
        ts.dev.name = s3c2410ts_name;
        ts.dev.phys = ts.phys;
        ts.dev.id.bustype = BUS_RS232;
        ts.dev.id.vendor = 0xDEAD;
        ts.dev.id.product = 0xBEEF;
        ts.dev.id.version = S3C2410TSVERSION;
        
        ts.shift = info->oversampling_shift;
        
        /* Get irqs */
        if (request_irq(IRQ_ADC, stylus_action, SA_SAMPLE_RANDOM,
            "s3c2410_action", &ts.dev)) {                                  //申请ADC中断,并设置中断处理函数为stylus_action
            printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n");
            iounmap(base_addr);
            return -EIO;
        }
        if (request_irq(IRQ_TC, stylus_updown, SA_SAMPLE_RANDOM,
            "s3c2410_action", &ts.dev)) {                                  //申请触摸屏中断,并设置中断处理函数为stylus_updown
            printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n");
            iounmap(base_addr);
            return -EIO;
        }
        
        printk(KERN_INFO "%s successfully loaded\n", s3c2410ts_name);
        
        /* All went ok, so register to the input system */
        input_register_device(&ts.dev);                            //将触摸屏设备注册到输入子系统中
        
        return 0;
    }

     

    s3c2410_ts_mach_info是s3c2410触摸屏接口相关硬件的配置信息

    struct  s3c2410_ts_mach_info

    {

                int delay;                          //延时时间

                int  presc;                        //预分频值

                int  oversampling_shift;    //输入数据的缓冲区大小

    };

     

    下面介绍触摸屏设备配置,具体的硬件知识,请参考相关资料:

    s3c2410_ts_connect()用来处理GPG端口12,13,14,15引脚,设置为与触摸屏相关的状态。这里分别设为XMON,nXPON,YMON,和nYOPN状态:

    static inline void s3c2410_ts_connect(void)
    {
        s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);          //GPG的端口12引脚设置为读写触摸屏设备XM引脚的值,EINT【20】连接到触摸屏XM引脚上
        s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);         //GPG的端口13引脚设置为读写触摸屏设备nXPON引脚的值,EINT[21]连接到触摸屏的nXPON上
        s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON);          //GPG的端口13引脚设置为读写触摸屏设备YMON引脚的值,EINT[22]连接到触摸屏的YMON上
        s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);         //GPG的端口14引脚设置为读写触摸屏设备nYPON引脚的值,EINT[23]连接到触摸屏的nYPON上
    }

    触摸屏设备中断处理函数

    当触摸屏设备驱动的探测函数执行完之后,驱动程序处于等待状态。在等待状态中,驱动程序可以接受两个中断信号,并触发中断处理函数。这两个中断是触摸屏中断(IRQ_TC)和ADC中断(IRQ_ADC)。

    stylus_updown():

    当触摸屏被按下时,会产生触摸中断信号IRQ_TC,该函数会激发stylus_updown()函数的调用:

    static irqreturn_t stylus_updown(int irq, void *dev_id, struct pt_regs *regs)
    {
        unsigned long data0;
        unsigned long data1;
        int updown;              //用来表示触摸屏是否被按下。按下是1,否则是0
        /********************************debug************************************/
        printk(KERN_INFO "You touch the screen\n");
        /*************************************************************************/
        data0 = readl(base_addr+S3C2410_ADCDAT0);               //读取ADCDATA0寄存器的值
        data1 = readl(base_addr+S3C2410_ADCDAT1);               //读取ADCDATA1寄存器的值
        
        updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT1_UPDOWN));  //判断触摸笔是否被按下
        
        /* TODO we should never get an interrupt with updown set while
        * the timer is running, but maybe we ought to verify that the
        * timer isn't running anyways. */
        
        if (updown)                      //如果被按下,执行touch_timer_fire()
            touch_timer_fire(0);
        
        return IRQ_HANDLED;
    }

    touch_timer_fire()函数:继续处理触摸中断:

    static void touch_timer_fire(unsigned long data)
    {
        unsigned long data0;
        unsigned long data1;
        int updown;
        
        data0 = readl(base_addr+S3C2410_ADCDAT0);
        data1 = readl(base_addr+S3C2410_ADCDAT1);
        
        updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT1_UPDOWN));      //上面的和stylus_updown()函数中前面的一样
        
        if (updown) {
            if (ts.count != 0) {                                         //用来向输入子系统报告当前触摸笔的位置
                ts.xp >>= ts.shift;
                ts.yp >>= ts.shift;
                
    #ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
                {
                    struct timeval tv;
                    do_gettimeofday(&tv);
                    printk(DEBUG_LVL "T: %06d, X: %03ld, Y: %03ld\n", (int)tv.tv_usec, ts.xp, ts.yp);
                    printk(KERN_INFO "T: %06d, X: %03ld, Y: %03ld\n", (int)tv.tv_usec, ts.xp, ts.yp);
                }
    #endif
                
                input_report_abs(&ts.dev, ABS_X, ts.xp);                  
                input_report_abs(&ts.dev, ABS_Y, ts.yp);
                
                input_report_key(&ts.dev, BTN_TOUCH, 1);
                input_report_abs(&ts.dev, ABS_PRESSURE, 1);
                input_sync(&ts.dev);
            }
            
            ts.xp = 0;                     //将x,y坐标和count设置为0,表示缓冲区中没有数据,也就是没有触屏按下的事件发生
            ts.yp = 0;
            ts.count = 0;
            
            writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);                                 //将AD转换模式设置为自动转模式

    //                                                                              #define S3C2410_ADCTSC_PULL_UP_DISABLE  (1 << 3)  表示将XP上拉,另外

    //                                                                                #define AUTOPST      (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN 

    //                                                                                                                                                      |  S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0)

    ADCOPST宏主要任务是将AD转换器设置为自动XY坐标转换模式。S3C2410_ADCTSC_YM_SEN表示将YMON输出为1;S3C2410_ADCTSC_YP_SEN表示将nYPON输出为1;S3C2410_ADCTSC_XP_SEN表示将nXPOM输出为1;S3C2410_ADCTSC_ATUO_PST表示将ADCTSC寄存器的第二位设置为1,即将AD转换器设置为自动XY坐标转换模式。S3C2410_ADCTSC_XY_PST(0)为0,表示AD转换器没有任何操作


            writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);               //将ADCCON寄存器的第0位设置为1.其中S3C2410_ADCCON_ENABLE_START宏表示第0位为1.这句话的代码功能是启动AD转换功能,当启动后,ADCCON第0位自动设置为0
        } else {      //表示触摸屏没有被按下的操作。此时调用input_report_key()函数向输入子系统报告触摸屏被弹起事件。input_report_key()函数的第三个参数传递0,表示按键被释放。input_report_abs()函数发送触摸屏的一个绝对坐标。它们最终表现在文件系统中,应用程序可以访问Linux的文件系统,从而得到触摸屏的信息。事实上,不使用这两个函数驱动程序仍然能够控制触摸屏设备,但是需要通过其他方法访问触摸屏设备的状态
            ts.count = 0;
            
            input_report_key(&ts.dev, BTN_TOUCH, 0);
            input_report_abs(&ts.dev, ABS_PRESSURE, 0);
            input_sync(&ts.dev);        //通知事件发送者发送一个完整的报告。这里BTN_TOUCH和ABS_PRESSURE事件不能单独发送,必须同时发送
            
            writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);       //将触摸屏重新设置为等待中断模式,等待触摸屏被按下。这些工作是通过设置触摸屏控制寄存器ADCTSC来完成的。WAIT4INT是需要写入的ADCTSC寄存器的值,定义:

    //            #define   WAIT4INT(x)       (((x) << 8) | S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN  | S3C2410_ADCTSC_XY_PST(3))

        }
    }

     

    stylus_action函数:

    触摸屏设备产生的另一个中断是ADC中断(IRQ_ADC)。触摸屏在自动X/Y位置转换模式和独立的X/Y位置转换模式时,当坐标数据转换之后会产生IRQ_ADC中断。中断产生之后会调用stylus_action()函数:

    static irqreturn_t stylus_action(int irq, void *dev_id, struct pt_regs *regs)
    {
        unsigned long data0;
        unsigned long data1;
        data0 = readl(base_addr+S3C2410_ADCDAT0);
        data1 = readl(base_addr+S3C2410_ADCDAT1);
        
        ts.xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;   //获得触摸点的X坐标,把它加到ts.xp上。ADCDAT0寄存器的[0:9]表示X坐标。该坐标在ADC中断产生前存入ADCDAT0
        ts.yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;  //获得触摸点的Y坐标,把它加到ts.yp上。ADCDAT0寄存器的[0:9]表示Y坐标。该坐标在ADC中断产生前存入ADCDAT1
        ts.count++;                 //计数器加1
        
        if (ts.count < (1<<ts.shift)) {                //如果缓冲区为满,再次激活ADC转换器
            writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
            writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
        } else {
            mod_timer(&touch_timer, jiffies+1);                          //修改定时器,将其时间延后一个单位。在下一个定时器时刻将调用touch_timer定时器指定 的函数
            writel(WAIT4INT(1), base_addr+S3C2410_ADCTSC);                  //将触摸屏设置为等待中断模式
        }
        
        return IRQ_HANDLED;
    }

     

    touch_timer定时器:

    touch_timer定时器用来当缓冲区不为空时,不断触发touch_timer_fire()函数。touch_timer_fire()函数读取触摸屏的坐标信息,并传递给内核子系统。

    全局变量:

    static struct timer_list touch_timer =
    TIMER_INITIALIZER(touch_timer_fire, 0, 0);

     

    s3c2440触摸屏驱动模块的remove()函数:
    remove()函数是Linux设备驱动程序中一个非常重要的函数,这个函数实现了与probe()函数相反的功能,体现了Linux内核中,资源分配和释放的思想 。资源应该在使用时分配,在不使用时释放。这个函数释放了申请的中断、时钟、内存。

    static int s3c2410ts_remove(struct device *dev)
    {
        disable_irq(IRQ_ADC);                      //关闭中断,并释放中断    #define IRQ_ADC    S3C2410_IRQ(70)
        disable_irq(IRQ_TC);                         //#define     IRQ_TC       (0x0)
        free_irq(IRQ_TC,&ts.dev);
        free_irq(IRQ_ADC,&ts.dev);
        
        if (adc_clock) {                                  //关闭并释放ADC时钟源
            clk_disable(adc_clock);
            clk_unuse(adc_clock);
            clk_put(adc_clock);
            adc_clock = NULL;
        }
        
        input_unregister_device(&ts.dev);        //注销触摸屏输入设备
        iounmap(base_addr);                           //释放映射的虚拟内存地址
        
        return 0;
    }

    有一种落差是,你配不上自己的野心,也辜负了所受的苦难

    展开全文
  • 简要介绍了Linux 设备驱动程序的概念、分类、基本工作原理和关键技术, 以及嵌入式系统中常用的电阻式触摸屏的组成和 工作原理。给出了基于嵌入式Linux 的触摸屏设备驱动程序设计和实现方法。
  • 电脑的外部设备 设备管理 (1)回顾计算机结构 图: (2)常见的外部设备 1)如何判定是不是外部设备 只要挂接在外设IO接口上的都是外部设备,与所在位置关系不大,可能在芯片内部、也可能在芯片外部,可能在机壳...

    电脑的外部设备

    设备管理

    (1)回顾计算机结构
    图:
    在这里插入图片描述

    (2)常见的外部设备

    1)如何判定是不是外部设备
    只要挂接在外设IO接口上的都是外部设备,与所在位置关系不大,可能在芯片内部、也可能在芯片外部,可能在机壳内部,也可能在机壳外部。

    2)外部设备大致分为三类
    按照用途分的话,大致分为三大类。
    (a)数据的传输:比如网卡,负责数据的发送和接收,即是输入也是输出设备
    (b)数据的存储:比如像磁盘,SSD(固态硬盘),负责数据的存储,既能读数据也能里写数据,所以即是输入也是输出设备。
    c)数据的翻译:比如输入设备MIC,将输入的声音翻译为电信号的二进制数据。比如显示器,将电信号的二进制数据翻译为人看得见的图像和视频。
    不管是哪一类的设备,要么是输入设备,要么是输出设备,要么是即使输入也是输出设备。

    3)输入输出设备
    (a)输入设备
    ·键盘:字符图形输入,按下某个按键,输入动作会被翻译为ASCII编号数据(以电信号的二进制数形式存在)。
    ·鼠标:光标位置输入,将鼠标移动转为电信号二进制的坐标数据
    ·摄像头:图形图像输入,将其翻译为电信号二进制数据
    ·麦克风:声音输入,将其翻译为电信号二进制数据
    ·触摸屏:将触摸位置翻译为电信号二进制坐标数据
    ·网卡:直接接受别的计算机发送的电信号二进制数据,输入给计算机
    ·磁盘、SSD:读取存储的数据,输入给计算机
    (b)输出设备
    ·显示器:将CPU按照程序要求处理后的,电信号的二进制的图形、图像数据,翻译成为图形图像给人看
    ·喇叭:将声数据翻译成为人能听得见的声音
    ·打印机:将数据输出到打印机打印,打印机打印
    ·机械手臂:将输出数据翻译成为机械手臂的动作
    ·Led灯等:将输出数据翻译成为灯的亮灭
    ·网卡:从计算机输出数据,传输给别的计算机
    ·磁盘、SSD:从计算机输出数据,写到磁盘或者SSD中

    4)有关外部设备
    (a)外部设备非常多,根据不同的用途有不同外部设备,如果你是做纯软件开发的,了解即可,如果你是做嵌入式开发的,
    需要掌握一些常见的设备开发,但是不需要掌握所有,没有意义,有了常见设备的开发经验后,根据工作需求掌握其它设备。
    (b)对于嵌入式开发来说,重点不在于研究外部设备制造和工艺,比如研究显示器是怎们被制造出来,显示器实现图像现实的详细技术知怎样的,这些是设备生产者关心的事,嵌入式开发者要做的了解设备的基本工作原理,能够查阅设备手册,编写相关的驱动程序,控制外部设备工作。
    b)嵌入式技术
    单片机、Linux嵌入式中,会有各种常见守备队的驱动课程,驱动课程的目的就是讲解如何开发出驱动程序,驱动这些外部设备工作。

    设备驱动程序

    1)为什么叫要驱动程序
    外部设备绝对不是连上就能用的,必须要有专门的程序来驱动才能工作,能够驱动外部设备工作的程序就是驱动程序。
    图:
    在这里插入图片描述
    驱动程序是属于内核的一部分。

    2)驱动程序到底是如何驱动外部设备
    为了能够驱动外部设备工作,驱动程序关键要要两件事情,
    第一件:配置外设的工作模式
    第二件:通过外设输入输出数据
    (a)第一件:配置外部设备的工作模式
    ·为什么要配置
    因为大多数外部设备都有很多种工作模式,驱动程序需要通过相应的配置,选择让设备工作在那种工作模式下,如果不做配置的话,外部设备不知道该工作在什么模式下,是混乱的。
    驱动程序是如何配置外部设备的呢?
    通过相应的配置开关进行配置,这个配置开关就是“设备的配置寄存器”。
    · 设备的配置寄存器
    就是外设工作模式的配置开关,是外设专用寄存器,与CPU内部的寄存器、cache、内存(DDR)一样,只是这些寄存器被做在了外部设备的内部,是专属于外设的专用小容量内存,驱动程序向设备的配置寄存器中写入相应的
    配置数据,就可以配置好外部设备的工作模式。
    ·为什么向配置寄存器写入配置数据,就能配置好外设的工作模式
    图:
    在这里插入图片描述

    计算机中数据已电信号存在,向设备配置寄存器写入配置数据,其实就是将电信号导入配置寄存器,配置寄存器中就把这个电信号锁存起来,这个电信号承载的是一个二进制数,所以就将电信号的二进制数据写入了配置寄存器中。
    (b)第二件:输入/输出数据
    配置好工作模式后,驱动程序就可以驱动设备工作了,此时需要用外设的“数据寄存器”。
    为什么需要数据寄存器呢?
    因为输入输出数据时,数据需要暂时存放在数据寄存器中,存数据时,存储的其实就是电信号。
    ·输入设备
    输入设备有两种情况,
    第一种:直接得到就是二进制数据,比如像网卡和存储器,能够直接输入数据
    第二种:需要经过传感器的翻译,比如像麦克风、摄像头,需要利用传感器将外部输入的声光等其它信号形式的数据,转为二进制电信号形式的数据。
    CPU执行输入设备驱动程序时,从输入设备的数据寄存器中取出数据,并将数据保存起来,专门进行数据处理的程序就可以处理这些输入的数据了。
    图:
    在这里插入图片描述

    ·输出设备
    输出设备也有两种情况,
    第一种:直接将二进制数据输出给其它设备,比如网卡就是这样的
    第二种:需要将数据翻译为其它信号形式的数据,比如显示器需要将二进制电信号的视频数据,翻译为光信号的图像数据,供人识别。
    CPU执行输出设备的驱动程序时,会将电信号形式的数据写到设备的数据寄存器中,输出设备的
    图:
    在这里插入图片描述

    ·输入输出设备
    有些外部设备既是输入设备也是输出设备,那就是上述的综合情况。

    驱动程序的种类

    stm32 51
    分为两种,第一种是裸机驱动程序,第二种是基于OS的驱动程序。
    1)裸机驱动程序
    (a)裸机驱动程序的特点
    · 裸机程序大致分为两部分,第一部分为业务逻辑代码,第二部分为驱动代码,

    • 业务逻辑代码:专门负责数据的处理,比如计算1+2结果
    • 驱动代码:专门负责驱动外设,实现数据的输入输出,比如控制键盘输入1和2,控制显示屏显示3
      ·裸机程序结构图示
      图:
      在这里插入图片描述

    地址:
    程序使用地址有两种形式,
    第一种:间接使用
    int a;//a一般是4个字节,每个字节都有一个地址,不过只有变量的第一个字节的地址,才作为整个变量的地址
    a = 10;//a->地址,编译器会将变量名和地址联系起来,0x2342
    但是使用变量名操作时,虽然还是使用的是地址来操作的,但是变量名操作会受到限制
    void fun(void)
    {
    int a;//a->地址
    }
    在Java里面全部使用变量名这种形式,也就是间接使用地址的形式,所有的高级语言都有变量这个东西,使用变量名时,其实间接使用的是地址,那么这个变量名到底和什么地址对应起来的,这个就看编译器在编译的时候,怎么对应。
    有些高级为了减少直接使用地址带来的危险,都不在直接使用地址操作,而是使用变量操作。
    第二种:直接使用
    int a;//a->地址
    int *p = &a;//编译器在编译时,会直接使用地址将&替换
    int *p = 0x325234;
    那么我们在底层的驱动程序中,一般来说都是用C语言来开发,在c语言的驱动程序中,访问内存空间,以及寄存器空间时,基本都是以上这两种,直接使用地址操作的形式,来访问对应的空间。
    如果说你的底层驱动程序是使用java来开发的话,java的语法特性是不允许你直接使用地址操作,但是在底层驱动里面,特别是访问寄存器空间时,我们非常需要直接使用地址操作,因为设备手册上,直接给你的就是寄存器地址,那么你只能直接使用地址操作,java没办法直接使用地址操作,所以说底层驱动程序基本不会使用java来编写。
    那么那些情况下会直接开裸机驱动程序呢?
    一般情况下,开发计算机资源有限的单片机产品时,都会直接开发裸机驱动程序,我们开发单片机程序时,程序里面既包含业务逻辑代码,同时也包含驱动程序代码,当然可能是有一个人完成的,也可能由不同人完成。
    (b)基于OS的驱动程序
    图:
    在这里插入图片描述在这里插入图片描述

    (c)以上两种驱动程序的对比
    · 不同点:
    · 相同点:裸机驱动和基于OS的驱动,它们所做的事情都是一样的

    • 驱动程序写配置寄存器,设置设备的工作模式
    • 通过读写设备的数据寄存器,实现数据的收发
    • 驱动程序负责的事情
    • 对上与应用程序对接(可能需要OS对接)
    • 对下驱动设备
      但是驱动的工作到设备寄存器(配置、数据)就ok了,至于设备是如何拿到寄存器的数据去工作的,这就是属于设备的自己的工作范畴,驱动程序已经管不着了,这就好比送餐送到手上就好了,难道还要喂你吃吗。
      你觉得写驱动程序的人,他的工作是什么,简单来讲就是通过驱动程序实现以上这两个目的,一个与应用对接,另一个通过寄存器去驱动设备。
      · 应用程序与驱动是否在一起呢
    • 裸机:应用和驱动代码写在了一起。
      在裸机里面,裸机驱动程序与业务逻辑代码合在了一起,开发时,这两部分代码可以由一个人全部开发,又可以分开由不同的人来开发。
    • 基于OS的驱动:
      应用和驱动懂之间完全是分开的,中间通过OS对接。
      应用和驱动是分开被开发的,由不同的两部人来分别开发,做应用的专门做应用,做驱动的专门做驱动。
      · 裸机驱动与基于OS的驱动,谁更难
      总体上来说,基于OS的更难,原因有两方面。
      - 第一方面
      之所以裸机运行程序,大部分原因是因为计算机资源比较弱,不能跑操作系统,比如类似51这类低级别单片机。
      计算机资源较弱,自然控制的设备也比较简单,比如都是一些小电动机,led灯,数码管,小LCD屏等等这类,很简单的设备,控制简单,编写的驱动程序自然也简单。
      但是基于OS的驱动就不一样,既然能够跑OS,也就意味计算机能力很足,所控制的设备自然也就很复杂,比如什么大型的液晶屏、大号的键盘、鼠标、触摸屏、磁盘、网卡等等这类复杂的设备,设备复杂了,对应的驱动程序自然也简单不了。
      - 第二方面
      有操作系统是,驱动程序必须要和OS对接,将驱动加入OS,变成OS的一部分,由OS来管理驱动程序,和OS对接本身就是一件很复杂的事情,如果是裸机的话,就省去了OS这个复杂的因素。
      但是我们说过,不管是那种驱动程序,工作的内容都是一样的,一个对上与应用对接,另一个是对象驱动设备,如果你只是想了解驱动的工作都做些设么事情,学习单片机这种裸机驱动程序的开发就可以了。
      (5)有关驱动程序的开发
      我们这里所讲的驱动,重点指是基于OS的驱动。
      1)驱动开发的行业特点
      有关驱动的开发可以分为两类
      标准化计算机驱动开发,非标准化计算机驱动开发。
      (a)非标准化计算机
      嵌入式计算机就是非标准化计算机,所谓非标注化的意思就是,硬件和软件没有统一标准化的东西,都是要进行定制的,所谓定制的意思就是说,你具体有什么需求,根据你的特殊需求定制硬件和对应软件。
      比如你的是用来控制锅炉的,那我就是专门给你设计符合锅炉环境的设备,如果你的是用于深水探测的,那我就专门定制符合深水环境的设备,相应的设备的硬件和软件需要定制,嵌入式设备的应用环境是千差万的,没办法给出标准化的东西。
      嵌入式开发时典型的非标准计算机开发和设计。
      嵌入式计算机驱动也分两种
      有OS的嵌入式设备驱动开发:开发基于OS的驱动,比如ucos和Linux系统。
      没有OS的嵌入式设备驱动开发:纯粹的单片机裸机程序开发,其中就包含裸机驱动开发。
    展开全文
  • 为标准触摸屏编写驱动程序  尽管触摸屏正在迅速普及开来,但大多数开发人员以前从来没有开发过触摸屏产品。本文详细介绍了触摸屏产品的设计步骤,指导读者了解使触摸屏首次工作需要的软硬件细节。  触摸屏如今...
  • 在内核中添加触摸屏驱动程序编者:linux2.6.32并没有带S3C2440触摸屏驱动程序,需要自己实现。而在此的触摸屏驱动程序时作为一个输入设备来实现的。在linux中,对于输入设备而言,内核专为其设计了输入子系统,由...

    在内核中添加触摸屏驱动程序

    编者:linux2.6.32并没有带S3C2440触摸屏驱动程序,需要自己实现。而在此的触摸屏驱动程序时作为一个输入设备来实现的。在linux中,对于输入设备而言,内核专为其设计了输入子系统,由核心层处理公共的工作。因为对于输入设备而言,只是中断、读键值/坐标值是与设备相关的,其余的如输入事件的缓冲区的管理以及字符设备驱动的file_operations接口则是输入设备通用的。所以在此是在输入子系统的框架下进行编写触摸屏驱动程序。对于这个驱动的移植以及讲解,参考了网上的一些文章,一部分摒弃了手册。

    1 在内核中添加触摸屏驱动程序

    Linux-2.6.32.2 内核也没有包含支持S3C2440 的触摸屏驱动,因此我们自行设计了一个s3c2410_ts.c,它位于linux-src/drivers/input/touchscreen 目录下,你可以自己增加一个s3c2410_ts.c 文件,并复制如下内容:

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    /* For ts.dev.id.version */

    #define S3C2410TSVERSION 0x0101

    #define WAIT4INT(x) (((x)<<8) | \

    S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \

    S3C2410_ADCTSC_XY_PST(3))

    #define AUTOPST (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN |

    S3C2410_ADCTSC_XP_SEN | \

    S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))

    static char *s3c2410ts_name = "s3c2410 TouchScreen";

    static struct input_dev *dev;

    static long xp;

    static long yp;

    static int count;

    extern struct semaphore ADC_LOCK;

    static int OwnADC = 0;

    static void __iomem *base_addr;

    static inline void s3c2410_ts_connect(void)

    {

    s3c2410_gpio_cfgpin(S3C2410_GPG(12), S3C2410_GPG12_XMON);

    s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPG13_nXPON);

    s3c2410_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPG14_YMON);

    s3c2410_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPG15_nYPON);

    }

    static void touch_timer_fire(unsigned long data)

    {

    unsigned long data0;

    unsigned long data1;

    int updown;

    data0 = ioread32(base_addr+S3C2410_ADCDAT0);

    data1 = ioread32(base_addr+S3C2410_ADCDAT1);

    updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));

    if (updown) {

    if (count != 0) {

    long tmp;

    tmp = xp;

    xp = yp;

    yp = tmp;

    xp >>= 2;

    yp >>= 2;

    input_report_abs(dev, ABS_X, xp);

    input_report_abs(dev, ABS_Y, yp);

    input_report_key(dev, BTN_TOUCH, 1);

    input_report_abs(dev, ABS_PRESSURE, 1);

    input_sync(dev);

    }

    xp = 0;

    yp = 0;

    count = 0;

    iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);

    iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START,

    base_addr+S3C2410_ADCCON);

    } else {

    count = 0;

    input_report_key(dev, BTN_TOUCH, 0);

    input_report_abs(dev, ABS_PRESSURE, 0);

    input_sync(dev);

    iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);

    if (OwnADC) {

    OwnADC = 0;

    up(&ADC_LOCK);

    }

    }

    }

    static struct timer_list touch_timer =

    TIMER_INITIALIZER(touch_timer_fire, 0, 0);

    static irqreturn_t stylus_updown(int irq, void *dev_id)

    {

    unsigned long data0;

    unsigned long data1;

    int updown;

    if (down_trylock(&ADC_LOCK) == 0) {

    OwnADC = 1;

    data0 = ioread32(base_addr+S3C2410_ADCDAT0);

    data1 = ioread32(base_addr+S3C2410_ADCDAT1);

    updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 &

    S3C2410_ADCDAT0_UPDOWN));

    if (updown) {

    touch_timer_fire(0);

    } else {

    OwnADC = 0;

    up(&ADC_LOCK);

    }

    }

    return IRQ_HANDLED;

    }

    static irqreturn_t stylus_action(int irq, void *dev_id)

    {

    unsigned long data0;

    unsigned long data1;

    if (OwnADC) {

    data0 = ioread32(base_addr+S3C2410_ADCDAT0);

    data1 = ioread32(base_addr+S3C2410_ADCDAT1);

    xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;

    yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;

    count++;

    if (count < (1<<2)) {

    iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,

    base_addr+S3C2410_ADCTSC);

    iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START,

    base_addr+S3C2410_ADCCON);

    } else {

    mod_timer(&touch_timer, jiffies+1);

    iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC);

    }

    }

    return IRQ_HANDLED;

    }

    static struct clk *adc_clock;

    static int __init s3c2410ts_init(void)

    {

    struct input_dev *input_dev;

    adc_clock = clk_get(NULL, "adc");

    if (!adc_clock) {

    printk(KERN_ERR "failed to get adc clock source\n");

    return -ENOENT;

    }

    clk_enable(adc_clock);

    base_addr=ioremap(S3C2410_PA_ADC,0x20);

    if (base_addr == NULL) {

    printk(KERN_ERR "Failed to remap register block\n");

    return -ENOMEM;

    }

    /* Configure GPIOs */

    s3c2410_ts_connect();

    iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),\

    base_addr+S3C2410_ADCCON);

    iowrite32(0xffff, base_addr+S3C2410_ADCDLY);

    iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);

    /* Initialise input stuff */

    input_dev = input_allocate_device();

    if (!input_dev) {

    printk(KERN_ERR "Unable to allocate the input device !!\n");

    return -ENOMEM;

    }

    dev = input_dev;

    dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);

    dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);

    input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0);

    input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0);

    input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0);

    dev->name = s3c2410ts_name;

    dev->id.bustype = BUS_RS232;

    dev->id.vendor = 0xDEAD;

    dev->id.product = 0xBEEF;

    dev->id.version = S3C2410TSVERSION;

    /* Get irqs */

    if (request_irq(IRQ_ADC, stylus_action, IRQF_SHARED|IRQF_SAMPLE_RANDOM,

    "s3c2410_action", dev)) {

    printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n");

    iounmap(base_addr);

    return -EIO;

    }

    if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,

    "s3c2410_action", dev)) {

    printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n");

    iounmap(base_addr);

    return -EIO;

    }

    printk(KERN_INFO "%s successfully loaded\n", s3c2410ts_name);

    /* All went ok, so register to the input system */

    input_register_device(dev);

    return 0;

    }

    static void __exit s3c2410ts_exit(void)

    {

    disable_irq(IRQ_ADC);

    disable_irq(IRQ_TC);

    free_irq(IRQ_TC,dev);

    free_irq(IRQ_ADC,dev);

    if (adc_clock) {

    clk_disable(adc_clock);

    clk_put(adc_clock);

    adc_clock = NULL;

    }

    input_unregister_device(dev);

    iounmap(base_addr);

    }

    module_init(s3c2410ts_init);

    module_exit(s3c2410ts_exit);

    然后在linux-2.6.32.2/drivers/input/touchscreen/Makefile 文件中添加该源代码的目标模块,如图红色部分:

    obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o

    obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o

    obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o

    obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o

    再打开linux-2.6.32.2/drivers/input/touchscreen/Kconfig 文件,加入如下红色部分,这样就在内核配置中添加了mini2440 的触摸屏驱动选项:

    menuconfig INPUT_TOUCHSCREEN

    bool "Touchscreens"

    help

    Say Y here, and a list of supported touchscreens will be displayed.

    This option doesn't affect the kernel.

    If unsure, say Y.

    if INPUT_TOUCHSCREEN

    config TOUCHSCREEN_S3C2410

    tristate "Samsung S3C2410 touchscreen input driver"

    depends on MACH_MINI2440 && INPUT && INPUT_TOUCHSCREEN && MINI2440_ADC

    help

    Say Y here if you have the s3c2410 touchscreen.

    If unsure, say N.

    To compile this driver as a module, choose M here: the

    module will be called s3c2410_ts.config TOUCHSCREEN_ADS7846

    tristate "ADS7846/TSC2046 and ADS7843 based touchscreens"

    depends on SPI_MASTER

    depends on HWMON = n || HWMON

    help

    至此,我们就已经在内核中添加完了触摸屏驱动。

    2 配置编译内核并测试触摸屏驱动

    在命令行执行:make menuconfig,然后依次选择如下子菜单,找到刚刚添加的触摸屏驱动选项:

    Device Drivers --->

    Input device support --->

    [*] Touchscreens --->

    按空格键选中触摸屏驱动配置选项:退出并保存以上内核配置,在命令行输入:make zImage,将生成arch/arm/boot/zImage文件,使用supervivi 的“k”命令把它烧写到开发板。在此我们还是使用缺省的文件系统root_qtopia,可以看到屏幕上出现校正界面:依照屏幕提示,使用触摸笔逐步点击“十”型交叉点,即可进入qtopia 系统。

    3、触摸屏驱动程序的详细分析。

    这个内容由于较多,放在下一个文章里,见下链接。

    linux-2.6.32在mini2440开发板上移植(10)之触摸屏工作原理以及驱动程序详细分析。 http://www.linuxidc.com/Linux/2013-04/82383p10.htm0b1331709591d260c1c78e86d0c51c18.png

    展开全文
  • WinCE系统在驱动设计上有一个很方便的功能,就是原始设备制造商(OEMs)和独立硬件开发商(IHVs)可以自主开发设备驱动程序来支持他们的硬件。因此,在动手进行触摸屏驱动程序开发之前,深入了解WinCE系统驱动方式是...
  • 国嵌培训课件Linux驱动程序设计

    热门讨论 2011-01-07 13:57:25
    2.字符设备驱动程序设计 3.驱动调试技术 4. 并发与竞态 第二天 1.Ioctl型驱动 2.内核等待队列 3. 阻塞型驱动程序设计 4.Poll设备操作 第三天 1.Mmap设备操作 2. 硬件访问 3. 混杂设备驱动 4. LED驱动程序...
  • 开发了嵌入式L inux框架下的触摸屏设备驱动程序; 阐述了采用触摸屏作为输入的MiniGU I应用程序的编写方法。  设计触摸屏接口已成功应用在故障诊断仪器产品上, 增强了仪器的人机交互功能, 方便了现场操作人员...
  • 视频及资料链接地址:(上传中) ...提取码:qgox  一、linux驱动的分类 ...LED、KEY、BEEP、声卡、显卡、摄像头、鼠标、键盘、触摸屏、手写板、USB、..... [root@GEC6818 /]#ls /dev -l crw-rw---- 1...
  • 在现代化生产中, 为了确保机械设备...设计了四线电阻式触摸屏与PXA255 处理器的接口电路, 分析了Linux框架下的字符设备驱动程序设计原理, 完成了触摸屏的接口驱动程序开发, 并设计了用触摸屏作为输入设备的MiniG
  • WinCE系统在驱动设计上有一个很方便的功能,就是原始设备制造商(OEMs)和独立硬件开发商(IHVs)可以自主开发设备驱动程序来支持他们的硬件。因此,在动手进行触摸屏驱动程序开发之前,深入了解WinCE系统驱动方式是...
  • 开发了嵌入式L inux框架下的触摸屏设备驱动程序; 阐述了采用触摸屏作为输入的MiniGU I应用程序的编写方法。  设计触摸屏接口已成功应用在故障诊断仪器产品上, 增强了仪器的人机交互功能, 方便了现场操作人员...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,609
精华内容 4,643
关键字:

触摸屏设备驱动程序设计