1. 程式人生 > >BITS_TO_LONGS的解釋及相關為操作函式

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
版權宣告:本文為博主原創文章,轉載請附上博文連結!