zoukankan      html  css  js  c++  java
  • 【Linux高级驱动】input子系统框架【转】

    转自:http://www.cnblogs.com/lcw/p/3802617.html

    【1.input子系统框架(driversinput)】

    如何得出某个驱动所遵循的框架?
        1) 通过网络搜索
        2) 自己想办法跟内核代码!
             2.1 定位此驱动是属于哪种类型的(触摸屏驱动为字符设备)
             2.2 搜索register_chrdev得到,input.c
             2.3 分析input.c文件

    /*入口函数*/
     subsys_initcall(input_init); 
     input_init
      /*1.创建一个设备类*/
      class_register(&input_class);
      /*2.申请主设备号,注册操作方法,注册字符设备*/
      register_chrdev(13, "input", &input_fops);
      
      static const struct file_operations input_fops = {
       .owner = THIS_MODULE,
       .open  = input_open_file,
      };

           

            2.4 分析如何来用input子系统

       app:  open("/dev/xxx",...)
       =============================
       vfs:  sys_open
        ...
        ...
       input.c struct file_operations input_fops
         .open = input_open_file,
          
          /*1.根据次设备号,从input_table数组中,取出一个input_handler结构体*/
          handler = input_table[iminor(inode) >> 5];   //2
          /*2.取出input_handler里面的操作方法*/
          if (handler)
           new_fops = fops_get(handler->fops);      //evdev_fops
          old_fops = file->f_op;
          file->f_op = new_fops;       //file中的f_op覆盖了
          /*3.执行底层的open函数*/
          new_fops->open(inode, file);   //事件处理层的操作方法里面的open函数evdev_open
          evdev_open

           
          
            2.5 根据handler = input_table[iminor(inode) >> 5];
                猜测,有某段代码将input_handler放入了input_table[iminor(inode) >> 5]
                搜索input_table,看在哪里放了

       module_init(evdev_init);
       evdev_init    //driver/input/evdev.c
        /*注册一个handler*/
        input_register_handler(struct input_handler *handler)
         
         /*将input_handler放入input_table数组中*/
         input_table[handler->minor >> 5] = handler;
       static struct input_handler evdev_handler = {
        .event   = evdev_event,
        .connect  = evdev_connect,
        .disconnect  = evdev_disconnect,
        .fops   = &evdev_fops,
        .minor   = EVDEV_MINOR_BASE,
        .name   = "evdev",
        .id_table   = evdev_ids,
       };

    【input子系统框架讲解】

    1.input子系统的核心层(input.c)
        功能:1)给用户提供接口(register_chrdev,cdev,file_operations结构体)
             2)给用input子系统内部组件提供接口,建立三者之间的联系

    /*入口函数*/
    subsys_initcall(input_init); 
    input_init
     /*1.创建一个设备类*/
     class_register(&input_class);
     /*2.申请主设备号,注册操作方法,注册字符设备*/
     register_chrdev(13, "input", &input_fops);
     
     static const struct file_operations input_fops = {
      .owner = THIS_MODULE,
      .open = input_open_file,
     };


    2.input子系统的事件处理层(evdev.c)
        功能:专门用来为设备驱动层上报事件的

    /*入口函数*/
    module_init(evdev_init);
    evdev_init    //driver/input/evdev.c
     /*注册一个handler*/
     input_register_handler(struct input_handler *handler)
      
      /*将input_handler放入input_table数组中*/
      input_table[handler->minor >> 5] = handler;   //64/32 =2
    static struct input_handler evdev_handler = {  //表示事件处理句柄
     .event   = evdev_event,     //上报事件的时候,会调用此函数
     .connect  = evdev_connect,    //建立连接的时候,会调用此函数
     .disconnect  = evdev_disconnect,
     .fops   = &evdev_fops,     //事件处理方法(xxx_read)
     .minor   = EVDEV_MINOR_BASE,    //64
     .name   = "evdev",
     .id_table  = evdev_ids,
    };
    static const struct file_operations evdev_fops = {
     .owner   = THIS_MODULE,
     .read   = evdev_read,      //当应用程序来读数据的时候,便会调用此函数
     .write   = evdev_write,
     .poll   = evdev_poll,
     .open   = evdev_open,
     .release  = evdev_release,
     .unlocked_ioctl = evdev_ioctl,
     .fasync   = evdev_fasync,
     .flush   = evdev_flush
    };

    3.input子系统的设备驱动层(s3c2410_ts.c为例子)(是驱动工作人员的主要任务)
        功能:1)跟硬件交互,操作硬件,获取硬件的外部事件
             2)提交事件给事件处理层

    /*入口函数*/
    module_init(s3c2410ts_init);
     s3c2410ts_init
      /*注册一个平台驱动*/
      platform_driver_register(&s3c_ts_driver);
    static struct platform_driver s3c_ts_driver = {
     .driver         = {
      .name   = "samsung-ts",
      .owner  = THIS_MODULE,
    #ifdef CONFIG_PM
      .pm = &s3c_ts_pmops,
    #endif
     },
     .id_table = s3cts_driver_ids,
     .probe  = s3c2410ts_probe,
     .remove  = __devexit_p(s3c2410ts_remove),
    };
    /*匹配成功,则调用平台驱动中的probe函数*/
    s3c2410ts_probe
     /*猜测*/
     /*1.获取资源*/
     /*1.1 获取平台数据*/
     info = pdev->dev.platform_data;
     /*1.2 使能时钟*/
     ts.clock = clk_get(dev, "adc");
     clk_enable(ts.clock);
     /*1.3 获取中断资源*/
     ts.irq_tc = ret = platform_get_irq(pdev, 0);
     /*1.4 获取IO内存资源*/
     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
     /*1.5 映射*/
     ts.io = ioremap(res->start, resource_size(res));
     /*1.6 注册中断*/
     ret = request_irq(ts.irq_tc, stylus_irq, IRQF_DISABLED,
         "s3c2410_ts_pen", ts.input);
     /*2. 申请ADC服务*/
     /*3. 初始化硬件(初始化触摸屏控制器)*/
     /*4. 构建一个struct input_dev结构体*/
     struct input_dev *input_dev;                //表示一个输入设备
     /*4.1 设置input_dev*/
     /*4.2 注册input_dev,注册到子系统(input子系统中)*/
     input_register_device(ts.input);


     

    【input子系统里面涉及的几个重要结构体】

    struct input_dev     //用来表示一个输入设备
    {
     unsigned long evbit[BITS_TO_LONGS(EV_CNT)];   //事件类型
     unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];  //按键类当中什么按键
     unsigned long relbit[BITS_TO_LONGS(REL_CNT)];  //相对位移的什么事件
     unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];  //绝对位移的什么事件
     ...
    };

    struct input_handler   //用来表示一个事件处理句柄
    {
     /*上报事件*/
     void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
     /*建立连接的*/
     int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
     const struct file_operations *fops;
     ...
    }

    struct input_handle    //用来建立input_dev与input_handler的连接的
    {
     ...
     struct input_dev *dev;
     struct input_handler *handler;
     struct list_head d_node;
     struct list_head h_node;
    }

    struct input_event    //用来表示一个输入事件
    {
     struct timeval time;  //事件产生的时间
     __u16 type;     //事件类型 EV_KEY
     __u16 code;     //事件码   KEY_A KEY_B
     __s32 value;    //事件值   1-按下 0-松开
    }

    【input子系统中涉及的重要函数:(input.c)】


     

    /*注册一个事件处理句柄*/
    int input_register_handler(struct input_handler *handler)
    void input_unregister_handler(struct input_handler *handler)
    /*注册一个输入设备*/
    int input_register_device(struct input_dev *dev)
    void input_unregister_device(struct input_dev *dev)
    /*提交事件到事件处理层*/
    void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)
    /*提交按键类事件*/
    void input_report_key(struct input_dev *dev, unsigned int code, int value)
    /*提交相对位移事件*/
    void input_report_rel(struct input_dev *dev, unsigned int code, int value)
    /*提交绝对位移事件*/
    void input_report_abs(struct input_dev *dev, unsigned int code, int value)
    /*提交同步类事件,每上报完一次事件后,都必须要上报一个同步事件*/
    void input_sync(struct input_dev *dev)
    /*分配一个input_dev结构体*/
    struct input_dev *input_allocate_device(void)
    /*设置input_dev,设置它能产生哪类事件,设置它能产生哪些*/
    方法一:BIT_MASK(事件类型)  事件类型都在:linux/input.h
    例如:
    ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
    方法二:set_bit
    例如:
    set_bit(EV_KEY,ts.input->evbit);
    set_bit(EV_ABS,ts.input->evbit);
    set_bit(BIN_TOUCH,ts.input->keybit);

    【input子系统框架】

    【input子系统框架完整版】

    @成鹏致远

    (email:wwwlllll@126.com)

    (qq:552158509

  • 相关阅读:
    数据结构-栈
    virtualenvwrapper 的安装和使用
    MySQL命令行本地登陆,远程登陆MySQL 的快捷键
    关于mysql8授权的问题,mysql萌新小白采坑记录
    史上最直接小白式的Sourcetree的分支创建与合并
    验证两个集合是否相等的方法
    VS开发工具的常用插件
    C# 数据库并发的解决方案(通用版、EF版)
    Jquery实现div左右重复来回走动
    描述符的应用
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/9214340.html
Copyright © 2011-2022 走看看