On Mon, 2020-04-27 at 09:02 -0700, Joe Perches wrote: > On Mon, 2020-04-27 at 17:53 +0300, Sakari Ailus wrote: > > Add a printk modifier %p4cc (for pixel format) for printing V4L2 and DRM > > pixel formats denoted by fourccs. The fourcc encoding is the same for both > > so the same implementation can be used. > [] > > - Added WARN_ON_ONCE() sanity checks. Comments on these are welcome; I'd > > expect them mostly be covered by the tests. perhaps this is simpler? --- lib/vsprintf.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 7c488a..3e1dbd7 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1721,6 +1721,46 @@ char *netdev_bits(char *buf, char *end, const void *addr, return special_hex_number(buf, end, num, size); } +static noinline_for_stack +char *fourcc_string(char *buf, char *end, const u32 *fourcc, + struct printf_spec spec, const char *fmt) +{ + char output[sizeof("(xx)(xx)(xx)(xx) little-endian (0x01234567)")]; + char *p = output; + int i; + u32 val; + + if (check_pointer(&buf, end, fourcc, spec)) + return buf; + + if (fmt[1] != 'c' || fmt[2] != 'c') + return error_string(buf, end, "(%p4?)", spec); + + val = *fourcc & ~BIT(31); + + for (i = 0; i < 4; i++) { + unsigned char c = val >> (i * 8); + + if (isascii(c) && isprint(c)) { + *p++ = c; + } else { + *p++ = '('; + p = hex_byte_pack(p, c); + *p++ = ')'; + } + } + + strcpy(p, *fourcc & BIT(31) ? "big endian" : "little endian"); + p += strlen(p); + *p++ = ' '; + *p++ = '('; + p = special_hex_number(p, p + 10, val, 4); + *p++ = ')'; + *p = 0; + + return string(buf, end, output, spec); +} + static noinline_for_stack char *address_val(char *buf, char *end, const void *addr, struct printf_spec spec, const char *fmt) @@ -2131,6 +2171,7 @@ char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode, * correctness of the format string and va_list arguments. * - 'K' For a kernel pointer that should be hidden from unprivileged users * - 'NF' For a netdev_features_t + * - '4cc' V4L2 or DRM FourCC code, with endianness and raw numerical value. * - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with * a certain separator (' ' by default): * C colon @@ -2223,6 +2264,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, return restricted_pointer(buf, end, ptr, spec); case 'N': return netdev_bits(buf, end, ptr, spec, fmt); + case '4': + return fourcc_string(buf, end, ptr, spec, fmt); case 'a': return address_val(buf, end, ptr, spec, fmt); case 'd':