[Linux Input]BITS_TO_LONGS的解释及相关为操作函数
来源:互联网 发布:绣花机打版软件 编辑:程序博客网 时间:2024/05/18 02:03
宏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 long evbit[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);
- }
@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这个结构体时会具体说
- //将addr的第nr(nr为0-31)位置值置为1;
- //nr大于31时,把高27的值做为当前地址的偏移,低5位的值为要置为1的位数
- extern __inline__ int set_bit(int nr,int * addr)
- {
- int mask, retval;
- addr += nr >> 5; //nr大于31时,把高27的值做为当前地址的偏移,
- mask = 1 << (nr & 0x1f); //获取31范围内的值,并把1向左偏移该位数
- cli(); //关所有中断
- retval = (mask & *addr) != 0; //位置置1
- *addr |= mask;
- sti(); //开所有中断
- return retval; //返回置数值
- }
- //将addr的第nr(nr为0-31)位置值置为0;
- //nr大于31时,把高27的值做为当前地址的偏移,低5位的值为要置为0的位数;
- extern __inline__ int clear_bit(int nr, int * addr)
- {
- int mask, retval;
- addr += nr >> 5;
- mask = 1 << (nr & 0x1f);
- cli();
- retval = (mask & *addr) != 0;
- *addr &= ~mask;
- sti();
- return retval;
- }
- //判断addr的第nr(nr为0-31)位置的值是否为1;
- //nr大于31时,把高27的值做为当前地址的偏移,低5位的值为要判断的位数;
- extern __inline__ int test_bit(int nr, int * addr)
- {
- int mask;
- addr += nr >> 5;
- mask = 1 << (nr & 0x1f);
- return ((mask & *addr) != 0);
- }
0 0
- [Linux Input]BITS_TO_LONGS的解释及相关为操作函数
- [Linux Input]BITS_TO_LONGS的解释及相关为操作函数
- Linux C的文件操作及相关函数
- Linux内核中的BITS_TO_LONGS宏的作用
- Linux文件系统及相关操作函数
- 输入设备--宏BITS_TO_LONGS (数组位图操作) —内核源文件input.h分析
- Linux 用户及用户组的相关操作
- PHP之目录操作相关函数解释
- Linux下文件的相关操作函数
- BITS_TO_LONGS宏的作用
- BITS_TO_LONGS宏的作用
- BITS_TO_LONGS宏的作用
- BITS_TO_LONGS宏的作用
- BITS_TO_LONGS宏的作用
- BITS_TO_LONGS宏的作用
- linux新定时器:timefd及相关操作函数
- linux新定时器:timefd及相关操作函数
- Linux系统内存管理及相关操作函数
- 【微框架】之一:从零开始,轻松搞定SpringCloud微框架系列--开山篇
- Android汇总
- [LeetCode]Range Sum Query 2D - Immutable
- opencv自带的haar分类器进行人脸识别
- python selenium 上传本地图片
- [Linux Input]BITS_TO_LONGS的解释及相关为操作函数
- Trinity(3)
- TestNG多suite测试以及报告配置
- java 加密算法-des、md5、aes、base64、rsa
- a.out程序执行的开始与结束
- 与byte数组有关的常用的类型转换总结
- 关于图片或者文件在数据库的存储方式归纳
- 通过iptables 修改数据包TTL,来隐藏traceroute 时的路由跳数
- InnoDB undo log解析(二)