【Linux高級驅動】input子系統框架

【1.input子系統框架(drivers\input)】

如何得出某個驅動所遵循的框架?
    1) 經過網絡搜索
    2) 本身想辦法跟內核代碼!
         2.1 定位此驅動是屬於哪一種類型的(觸摸屏驅動爲字符設備)
         2.2 搜索register_chrdev獲得,input.c
         2.3 分析input.c文件node

/*入口函數*/
 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子系統linux

    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)
    功能:專門用來爲設備驅動層上報事件的app

/*入口函數*/
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子系統框架完整版】

 

@成鵬致遠async

(email:wwwlllll@126.com)函數

(qq:552158509spa

 



相關文章
相關標籤/搜索