输入设备--宏BITS_TO_LONGS (数组位图操作) —内核源文件input.h分析

struct input_dev {
	const char *name; //输入设备名
	const char *phys;   
	const char *uniq;
	struct input_id id;

	unsigned long evbit[BITS_TO_LONGS(EV_CNT)];    /*个数组代表input设备所支持的事件:按键,使用位图的方法来表示。什么是位图,就是使用某一位来代表一个事件*/
	unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];   ////本设备支持的按键码 
	unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
	unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
	unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
	unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
	unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
	unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
	unsigned long swbit[BITS_TO_LONGS(SW_CNT)];

	unsigned int keycodemax;
	unsigned int keycodesize;
	void *keycode;
	int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
	int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);

	struct ff_device *ff;

	unsigned int repeat_key;
	struct timer_list timer;

	int sync;

	int abs[ABS_MAX + 1];
	int rep[REP_MAX + 1];

	unsigned long key[BITS_TO_LONGS(KEY_CNT)];
	unsigned long led[BITS_TO_LONGS(LED_CNT)];
	unsigned long snd[BITS_TO_LONGS(SND_CNT)];
	unsigned long sw[BITS_TO_LONGS(SW_CNT)];

	int absmax[ABS_MAX + 1];
	int absmin[ABS_MAX + 1];
	int absfuzz[ABS_MAX + 1];
	int absflat[ABS_MAX + 1];
	int absres[ABS_MAX + 1];

	int (*open)(struct input_dev *dev);
	void (*close)(struct input_dev *dev);
	int (*flush)(struct input_dev *dev, struct file *file);
	int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);

	struct input_handle *grab;

	spinlock_t event_lock;
	struct mutex mutex;

	unsigned int users;
	bool going_away;

	struct device dev;

	struct list_head	h_list;
	struct list_head	node;
};

 

 

宏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 = 33~64:2
nr = 65~96:3
nr = 97~128:4
nr = 129~160:5
//...
//...
结合定义unsigned longevbit[BITS_TO_LONGS(EV_CNT)];
就是根据EV_CNT的个数定义一个数组,如果EV_CNT小于32,就定义成evbit[1],如果大于32就装不下了就要使用evbit[2]这么大的数组了。
这么做一方面是为了提高兼容性,万一数量改变,还要记得修改定义的数组大小,定义成宏,定义数组的时候会根据数量自动判断应该创建多大的数组
另一方面也是提供了一种通用的解决办法,为下面的keybit,relbit等都提供了通用好用的解决方案,佩服这种思想!

另外几个函数我们也分析一下,以后也会用到。

static inline void set_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这个结构体时会具体说

 



 



你可能感兴趣的:(linu-驱动)