A lot of drivers are open-coding the "replace these bits in __be32 with the following value" kind of primitives. Let's add them to byteorder.h.
Primitives: {be,le}{16,32,64}_replace_bits(old, v, bit, nbits) {be,le}{16,32,64}_get_bits(val, bit, nbits) Essentially, it gives helpers for work with bitfields in fixed-endian. Suppose we have e.g. a little-endian 32bit value with fixed layout; expressing that as a bitfield would go like struct foo { unsigned foo:4; /* bits 0..3 */ unsigned :2; unsigned bar:12; /* bits 6..17 */ unsigned baz:14; /* bits 18..31 */ } Even for host-endian it doesn't work all that well - you end up with ifdefs in structure definition and generated code stinks. For fixed-endian it gets really painful, and people tend to use explicit shift-and-mask kind of macros for accessing the fields (and often enough get the endianness conversions wrong, at that). With these primitives struct foo v <=> __le32 v v.foo = i ? 1 : 2 <=> v = le32_replace_bits(v, i ? 1 : 2, 0, 4) f(4 + v.baz) <=> f(4 + le32_get_bits(v, 18, 14)) Signed-off-by: Al Viro <v...@zeniv.linux.org.uk> --- diff --git a/include/linux/byteorder/generic.h b/include/linux/byteorder/generic.h index 451aaa0786ae..d8f169a7104a 100644 --- a/include/linux/byteorder/generic.h +++ b/include/linux/byteorder/generic.h @@ -187,4 +187,26 @@ static inline void be32_to_cpu_array(u32 *dst, const __be32 *src, size_t len) dst[i] = be32_to_cpu(src[i]); } +#define ____MASK(bit, nbits) ((((1ULL << ((nbits) - 1)) << 1) - 1) << (bit)) +#define ____MAKE_OP(type,base) \ +static inline __##type type##_replace_bits(__##type old, \ + base val, int bit, int nbits) \ +{ \ + __##type mask = cpu_to_##type(____MASK(bit, nbits)); \ + return (old & ~mask) | (cpu_to_##type(val << bit) & mask); \ +} \ +static inline base type##_get_bits(__##type val, int bit, int nbits) \ +{ \ + return (type##_to_cpu(val) >> bit) & ____MASK(0, nbits); \ +} + +____MAKE_OP(le16,u16) +____MAKE_OP(le32,u32) +____MAKE_OP(le64,u64) +____MAKE_OP(be16,u16) +____MAKE_OP(be32,u32) +____MAKE_OP(be64,u64) +#undef ____MAKE_OP +#undef ____MASK + #endif /* _LINUX_BYTEORDER_GENERIC_H */