BITS_TO_LONGS的解釋及相關為操作函式
巨集BITS_TO_LONGS
#define BITS_PER_BYTE 8
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
sizeof(long) = 4,所以BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, 32)
BITS_TO_LONGS(nr)就是((nr) + (32 -1) / (32))
就是判斷nr這個數是屬於幾個long型別
nr = 1~32:1
nr = 32~64:2
nr = 65~96:3
nr = 97~128:4
nr = 129~160:5
//…
//…
結合定義unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
就是根據EV_CNT的個數定義一個數組,如果EV_CNT小於32,就定義成evbit[1],如果大於32就裝不下了就要使用evbit[2]這麼大的陣列了。
這麼做一方面是為了提高相容性,萬一數量改變,還要記得修改定義的陣列大小,定義成巨集,定義陣列的時候會根據數量自動判斷應該建立多大的陣列
另一方面也是提供了一種通用的解決辦法,為下面的keybit,relbit等都提供了通用好用的解決方案,佩服這種思想!
另外幾個函式我們也分析一下,以後也會用到。
static inline void clear_bit(int nr, unsigned long *addr)
{
addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG));
}
引數@nr,要設定成1的位。
@addr,是一個unsigned long型的陣列
這個函式就是實現把addr陣列的nr位置為1。為了通用型和健壯性的考慮,unsigned long型陣列,一個元素只有32位,如果超過了32位,就要使用
unsigned long addr[2],這種方法,那麼在置位操作的時候,還是要轉換成單個數組元素的方法,只不過陣列的下表變了,如
addr[0]代表位0~31
addr[1]代表位32~63
//依次類推
假如我要把第5位置為1的話我只需要addr[0] |= 1 << 5;就可以了,
但是我要把第35位置為1的話,我就需要addr[35/32] |= 1 << (35 % 32),即addr[1] |= 1 << 3;就可以了
這也就是set_bit這個函式的意義
static inline void clear_bit(int nr, unsigned long *addr)
{
addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG));
}
搞懂了第一個,下面的就都很輕鬆了,只不過清除某一位的操作使用 &=~來進行
static __always_inline int test_bit(unsigned int nr, const unsigned long *addr) { return ((1UL << (nr % BITS_PER_LONG)) & (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0; }
測試某一位是否為1,讓那一位和1行&運算,如果為1,那麼那一位就是1,如果為0,那一位就為0
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];這個陣列代表input裝置所支援的事件,使用點陣圖的方法來表示。什麼是點陣圖,就是使用某一位來代表一個事件,
如果這一位被為1,那麼就代表它支援這類事件。那麼我們看看,input裝置都支援哪些事件。
在include/linux/input.h中定以了
/*
* Event types
*/
#define EV_SYN 0x00 //位0
#define EV_KEY 0x01 //位1
#define EV_REL 0x02 //位2
#define EV_ABS 0x03 //位3
#define EV_MSC 0x04 //位4
#define EV_SW 0x05 //位5
#define EV_LED 0x11 //位17
#define EV_SND 0x12 //位18
#define EV_REP 0x14 //位20
#define EV_FF 0x15 //位21
#define EV_PWR 0x16 //位22
#define EV_FF_STATUS 0x17 //位23
#define EV_MAX 0x1f //一共支援31種事件
#define EV_CNT (EV_MAX+1)
如果我們想讓input裝置支援按鍵事件,那麼我們只需要讓evbit陣列的EV_KEY即第1位置為1就可以了。我們可以使用巨集set_bit(EV_KEY, input_dev->evbit)就可以了,為什麼是input_dev->evbit呢,
因為input_dev下面掛載了一個evbit的陣列,表示這個裝置支援的事件。分析input_dev這個結構體時會具體說
作者:andrinux
來源:CSDN
原文:https://blog.csdn.net/andrinux/article/details/38925827
版權宣告:本文為博主原創文章,轉載請附上博文連結!