linux輸入子系統(3)

來源:互聯網
上載者:User
1.4      


input_dev




的註冊




在輸入裝置驅動的初始化函數的最後一步就是調用
input_register_device
註冊裝置。這個函數如
程式清單
1
.9

所示。

程式清單

1


.

9


 
input_register_device

/* driver/input/input.c */

int input_register_device(struct input_dev *dev)

{

        
static
atomic_t input_no = ATOMIC_INIT(0);

        
struct
input_handler *handler;

        
const
char *path;

        
int
error;

 

        
__set_bit(EV_SYN,
dev->evbit);                                                                                                

 

        
init_timer(&dev->timer);                                                                                                             

        
if
(!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {

                  
dev->timer.data
= (long) dev;

                  
dev->timer.function
= input_repeat_key;

                  
dev->rep[REP_DELAY]
= 250;

                  
dev->rep[REP_PERIOD]
= 33;

        
}

 

        
if
(!dev->getkeycode)                                                                                                                  

                  
dev->getkeycode
= input_default_getkeycode;

        
if
(!dev->setkeycode)

                  
dev->setkeycode
= input_default_setkeycode;

 

        
snprintf(dev->dev.bus_id,
sizeof(dev->dev.bus_id),

                  
 
"input%ld", (unsigned long)
atomic_inc_return(&input_no) - 1);

 

        
error =
device_add(&dev->dev);

        
if
(error)

                  
return
error;

 

        
path =
kobject_get_path(&dev->dev.kobj, GFP_KERNEL);

        
printk(KERN_INFO
"input: %s as %s/n",

                  
dev->name
? dev->name : "Unspecified device", path ? path :
"N/A");

        
kfree(path);

 

        
error =
mutex_lock_interruptible(&input_mutex);

        
if
(error) {

                  
device_del(&dev->dev);

                  
return
error;

        
}

 

        
list_add_tail(&dev->node,
&input_dev_list);                                                                              

 

        
list_for_each_entry(handler,
&input_handler_list, node)                                                             

                  
input_attach_handler(dev,
handler);

 

        
input_wakeup_procfs_readers();

 

        
mutex_unlock(&input_mutex);

        
return
0;

}

下面就標記的幾點進行說明:


註冊同步事件為支援的類型,任何裝置都預設支援同步事件。


初始化裝置連擊計時器,如果驅動沒有填寫連擊參數就使用預設值。


如果驅動沒有實現映射修改和查看的函數,填充預設函數。


將本裝置加入裝置鏈表
(
這個鏈表是全域的
)


將本裝置和已經存在的
handler
進行比較,與
id
相匹配的
handler
建立串連。需要說明的是裝置可能跟多個
handler
串連,這樣此裝置產生的事件會分發給所有串連的
handler

可以看出上面第五步是最重要的一步,下面繼續分析
input_attach_handler
這個函數。它的代碼如
程式清單
1
.10

所示。

程式清單

1


.

10


 
 
input_attach_handler

/* driver/input/input.c */

static int input_attach_handler(struct input_dev *dev,
struct input_handler *handler)

{

        
const
struct input_device_id *id;

        
int
error;

 

        
if
(handler->blacklist && input_match_device(handler->blacklist,
dev))                                    

                  
return
-ENODEV;

 

        
id =
input_match_device(handler->id_table, dev);                                                                       

        
if (!id)

                  
return
-ENODEV;

 

        
error =
handler->connect(handler, dev, id);                                                                                 

        
if
(error && error != -ENODEV)

                  
printk(KERN_ERR

                           
"input:
failed to attach handler %s to device %s, "

                           
"error:
%d/n",

                           
handler->name,
kobject_name(&dev->dev.kobj), error);

 

        
return
error;

}

需要說明的地方有三點:




handler->blacklist
中儲存的是禁止串連的裝置
id
,因此首先查看該裝置是否允許串連。


handler->id_table
儲存
handler
支援的裝置
id
。如果能夠找到匹配的
id
,則建立
dev

handler
之間的串連。


建立
dev

handler
之間的串連。

connect
函數的實現下章再講,下面看看
input_match_device
的實現。代碼如
程式清單
1
.11

所示。

程式清單

1


.

11


 
input_match_device

/* driver/input/input.c */

#define MATCH_BIT(bit, max) /

                  
for
(i = 0; i < BITS_TO_LONGS(max); i++) /                                                                 

                           
if
((id->bit[i] & dev->bit[i]) != id->bit[i]) /                                                               

                                    
break;
/

                  
if
(i != BITS_TO_LONGS(max)) /

                           
continue;

 

static const struct input_device_id
*input_match_device(const struct input_device_id *id,

                                                                
struct
input_dev *dev)

{

        
int i;

 

        
for (;
id->flags || id->driver_info; id++) {

                  
if
(id->flags & INPUT_DEVICE_ID_MATCH_BUS)                                                    

                           
if
(id->bustype != dev->id.bustype)

                                    
continue;

 

                  
if
(id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)

                           
if
(id->vendor != dev->id.vendor)

                                    
continue;

 

                  
if
(id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)

                           
if
(id->product != dev->id.product)

                                    
continue;

 

                  
if
(id->flags & INPUT_DEVICE_ID_MATCH_VERSION)

                           
if
(id->version != dev->id.version)

                                    
continue;

 

                  
MATCH_BIT(evbit, 
EV_MAX);                                                                                            

                  
MATCH_BIT(keybit,
KEY_MAX);

                  
MATCH_BIT(relbit,
REL_MAX);

                  
MATCH_BIT(absbit,
ABS_MAX);

                  
MATCH_BIT(mscbit,
MSC_MAX);

                  
MATCH_BIT(ledbit,
LED_MAX);

                  
MATCH_BIT(sndbit,
SND_MAX);

                  
MATCH_BIT(ffbit, 
FF_MAX);

                  
MATCH_BIT(swbit, 
SW_MAX);

                  
return
id;

        
}

        
return
NULL;

}

匹配的過程主要做了兩件事:


根據
id->flag
檢查
id
是否匹配。
id->flag
記錄需要匹配哪些域。


檢查支援的事件種類是否一致。

第二種檢查用到的宏
MATCH_BIT
定義在

處。其中最重要的一句是“
if ((id->bit[i] &
dev->bit[i]) != id->bit[i])
”,這句話意味著
id
支援的事件種類是
dev
支援的事件的子集就算匹配了。如果某個
handler

id
除了
id->driver_info
之外的域都為
0
,那麼此
handler
可以和任意
dev
匹配。實際上
<
核心
>/driver/input/evdev.c
中就是這麼初始化
id
的。

現在總結一下
input_dev
註冊的過程:一個
input_dev
註冊的過程主要是在將自己加入
input_dev_list
,然後在
input_handler_list
中找到
id
和事件種類相匹配的
handler
並與之建立串連的過程。

input_dev
產生的事件會分發給所有建立串連的
handler
。下面繼續分析事件的傳遞。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.