3 * Helper functions for bitmap.h.
5 * This source code is licensed under the GNU General Public License,
6 * Version 2. See the file COPYING for more details.
8 #include <linux/module.h>
9 #include <linux/ctype.h>
10 #include <linux/errno.h>
11 #include <linux/bitmap.h>
12 #include <asm/bitops.h>
13 #include <asm/uaccess.h>
15 #define MAX_BITMAP_BITS 512U /* for ia64 NR_CPUS maximum */
17 int bitmap_empty(const unsigned long *bitmap
, int bits
)
19 int k
, lim
= bits
/BITS_PER_LONG
;
20 for (k
= 0; k
< lim
; ++k
)
24 if (bits
% BITS_PER_LONG
)
25 if (bitmap
[k
] & ((1UL << (bits
% BITS_PER_LONG
)) - 1))
30 EXPORT_SYMBOL(bitmap_empty
);
32 int bitmap_full(const unsigned long *bitmap
, int bits
)
34 int k
, lim
= bits
/BITS_PER_LONG
;
35 for (k
= 0; k
< lim
; ++k
)
39 if (bits
% BITS_PER_LONG
)
40 if (~bitmap
[k
] & ((1UL << (bits
% BITS_PER_LONG
)) - 1))
45 EXPORT_SYMBOL(bitmap_full
);
47 int bitmap_equal(const unsigned long *bitmap1
,
48 unsigned long *bitmap2
, int bits
)
50 int k
, lim
= bits
/BITS_PER_LONG
;
51 for (k
= 0; k
< lim
; ++k
)
52 if (bitmap1
[k
] != bitmap2
[k
])
55 if (bits
% BITS_PER_LONG
)
56 if ((bitmap1
[k
] ^ bitmap2
[k
]) &
57 ((1UL << (bits
% BITS_PER_LONG
)) - 1))
62 EXPORT_SYMBOL(bitmap_equal
);
64 void bitmap_complement(unsigned long *bitmap
, int bits
)
67 int nr
= BITS_TO_LONGS(bits
);
69 for (k
= 0; k
< nr
; ++k
)
70 bitmap
[k
] = ~bitmap
[k
];
72 EXPORT_SYMBOL(bitmap_complement
);
74 void bitmap_shift_right(unsigned long *dst
,
75 const unsigned long *src
, int shift
, int bits
)
78 DECLARE_BITMAP(__shr_tmp
, MAX_BITMAP_BITS
);
80 BUG_ON(bits
> MAX_BITMAP_BITS
);
81 bitmap_clear(__shr_tmp
, bits
);
82 for (k
= 0; k
< bits
- shift
; ++k
)
83 if (test_bit(k
+ shift
, src
))
84 set_bit(k
, __shr_tmp
);
85 bitmap_copy(dst
, __shr_tmp
, bits
);
87 EXPORT_SYMBOL(bitmap_shift_right
);
89 void bitmap_shift_left(unsigned long *dst
,
90 const unsigned long *src
, int shift
, int bits
)
93 DECLARE_BITMAP(__shl_tmp
, MAX_BITMAP_BITS
);
95 BUG_ON(bits
> MAX_BITMAP_BITS
);
96 bitmap_clear(__shl_tmp
, bits
);
97 for (k
= bits
; k
>= shift
; --k
)
98 if (test_bit(k
- shift
, src
))
99 set_bit(k
, __shl_tmp
);
100 bitmap_copy(dst
, __shl_tmp
, bits
);
102 EXPORT_SYMBOL(bitmap_shift_left
);
104 void bitmap_and(unsigned long *dst
, const unsigned long *bitmap1
,
105 const unsigned long *bitmap2
, int bits
)
108 int nr
= BITS_TO_LONGS(bits
);
110 for (k
= 0; k
< nr
; k
++)
111 dst
[k
] = bitmap1
[k
] & bitmap2
[k
];
113 EXPORT_SYMBOL(bitmap_and
);
115 void bitmap_or(unsigned long *dst
, const unsigned long *bitmap1
,
116 const unsigned long *bitmap2
, int bits
)
119 int nr
= BITS_TO_LONGS(bits
);
121 for (k
= 0; k
< nr
; k
++)
122 dst
[k
] = bitmap1
[k
] | bitmap2
[k
];
124 EXPORT_SYMBOL(bitmap_or
);
126 #if BITS_PER_LONG == 32
127 int bitmap_weight(const unsigned long *bitmap
, int bits
)
129 int k
, w
= 0, lim
= bits
/BITS_PER_LONG
;
131 for (k
= 0; k
< lim
; k
++)
132 w
+= hweight32(bitmap
[k
]);
134 if (bits
% BITS_PER_LONG
)
135 w
+= hweight32(bitmap
[k
] &
136 ((1UL << (bits
% BITS_PER_LONG
)) - 1));
141 int bitmap_weight(const unsigned long *bitmap
, int bits
)
143 int k
, w
= 0, lim
= bits
/BITS_PER_LONG
;
145 for (k
= 0; k
< lim
; k
++)
146 w
+= hweight64(bitmap
[k
]);
148 if (bits
% BITS_PER_LONG
)
149 w
+= hweight64(bitmap
[k
] &
150 ((1UL << (bits
% BITS_PER_LONG
)) - 1));
155 EXPORT_SYMBOL(bitmap_weight
);
158 * Bitmap printing & parsing functions: first version by Bill Irwin,
159 * second version by Paul Jackson, third by Joe Korty.
163 #define nbits_to_hold_value(val) fls(val)
164 #define roundup_power2(val,modulus) (((val) + (modulus) - 1) & ~((modulus) - 1))
165 #define unhex(c) (isdigit(c) ? (c - '0') : (toupper(c) - 'A' + 10))
168 * bitmap_scnprintf - convert bitmap to an ASCII hex string.
169 * @buf: byte buffer into which string is placed
170 * @buflen: reserved size of @buf, in bytes
171 * @maskp: pointer to bitmap to convert
172 * @nmaskbits: size of bitmap, in bits
174 * Exactly @nmaskbits bits are displayed. Hex digits are grouped into
175 * comma-separated sets of eight digits per set.
177 int bitmap_scnprintf(char *buf
, unsigned int buflen
,
178 const unsigned long *maskp
, int nmaskbits
)
180 int i
, word
, bit
, len
= 0;
182 const char *sep
= "";
186 chunksz
= nmaskbits
& (CHUNKSZ
- 1);
190 i
= roundup_power2(nmaskbits
, CHUNKSZ
) - CHUNKSZ
;
191 for (; i
>= 0; i
-= CHUNKSZ
) {
192 chunkmask
= ((1ULL << chunksz
) - 1);
193 word
= i
/ BITS_PER_LONG
;
194 bit
= i
% BITS_PER_LONG
;
195 val
= (maskp
[word
] >> bit
) & chunkmask
;
196 len
+= scnprintf(buf
+len
, buflen
-len
, "%s%0*lx", sep
,
203 EXPORT_SYMBOL(bitmap_scnprintf
);
206 * bitmap_parse - convert an ASCII hex string into a bitmap.
207 * @buf: pointer to buffer in user space containing string.
208 * @buflen: buffer size in bytes. If string is smaller than this
209 * then it must be terminated with a \0.
210 * @maskp: pointer to bitmap array that will contain result.
211 * @nmaskbits: size of bitmap, in bits.
213 * Commas group hex digits into chunks. Each chunk defines exactly 32
214 * bits of the resultant bitmask. No chunk may specify a value larger
215 * than 32 bits (-EOVERFLOW), and if a chunk specifies a smaller value
216 * then leading 0-bits are prepended. -EINVAL is returned for illegal
217 * characters and for grouping errors such as "1,,5", ",44", "," and "".
218 * Leading and trailing whitespace accepted, but not embedded whitespace.
220 int bitmap_parse(const char __user
*ubuf
, unsigned int ubuflen
,
221 unsigned long *maskp
, int nmaskbits
)
223 int c
, old_c
, totaldigits
, ndigits
, nchunks
, nbits
;
226 bitmap_clear(maskp
, nmaskbits
);
228 nchunks
= nbits
= totaldigits
= c
= 0;
232 /* Get the next chunk of the bitmap */
235 if (get_user(c
, ubuf
++))
242 * If the last character was a space and the current
243 * character isn't '\0', we've got embedded whitespace.
244 * This is a no-no, so throw an error.
246 if (totaldigits
&& c
&& isspace(old_c
))
249 /* A '\0' or a ',' signal the end of the chunk */
250 if (c
== '\0' || c
== ',')
257 * Make sure there are at least 4 free bits in 'chunk'.
258 * If not, this hexdigit will overflow 'chunk', so
261 if (chunk
& ~((1UL << (CHUNKSZ
- 4)) - 1))
264 chunk
= (chunk
<< 4) | unhex(c
);
265 ndigits
++; totaldigits
++;
269 if (nchunks
== 0 && chunk
== 0)
272 bitmap_shift_right(maskp
, maskp
, CHUNKSZ
, nmaskbits
);
275 nbits
+= (nchunks
== 1) ? nbits_to_hold_value(chunk
) : CHUNKSZ
;
276 if (nbits
> nmaskbits
)
278 } while (ubuflen
&& c
== ',');
282 EXPORT_SYMBOL(bitmap_parse
);