diff mbox series

[1/1] lib/vsprintf: Add support for printing V4L2 and DRM fourccs

Message ID 20200401140522.966-1-sakari.ailus@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series [1/1] lib/vsprintf: Add support for printing V4L2 and DRM fourccs | expand

Commit Message

Sakari Ailus April 1, 2020, 2:05 p.m. UTC
Add a printk modifier %ppf (for pixel format) for printing V4L2 and DRM
pixel formats denoted by 4ccs. The 4cc encoding is the same for both so
the same implementation can be used.

Suggested-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 Documentation/core-api/printk-formats.rst | 11 +++++++++
 lib/vsprintf.c                            | 29 +++++++++++++++++++++++
 2 files changed, 40 insertions(+)

Comments

Andy Shevchenko April 1, 2020, 3:13 p.m. UTC | #1
On Wed, Apr 01, 2020 at 04:13:51PM +0200, Hans Verkuil wrote:
> On 4/1/20 4:05 PM, Sakari Ailus wrote:
> > Add a printk modifier %ppf (for pixel format) for printing V4L2 and DRM
> > pixel formats denoted by 4ccs. The 4cc encoding is the same for both so
> > the same implementation can be used.

%p4cc ?

> > +	char ch[2] = { 0 };
> 
> This can just be '{ };'

The latter is GCC extension, while above is C standard. Former is slightly
better I think. Though see below.

> > +	unsigned int i;
> > +
> > +	if (check_pointer(&buf, end, fourcc, spec))
> > +		return buf;
> > +
> > +	switch (fmt[1]) {
> > +	case 'f':

> > +		for (i = 0; i < sizeof(*fourcc); i++) {
> > +			ch[0] = *fourcc >> (i << 3);
> 
> You need to AND with 0x7f, otherwise a big endian fourcc (bit 31 is set)
> will look wrong. Also, each character is standard 7 bit ascii, bit 7 isn't
> used except to indicate a BE variant.

Why not to do it once by a flag and do reset it once?

	u32 tmp = *fourcc;
	bool be4cc = tmp & BIT(31);

	tmp &= BIT(31);

On top of that, as promised above, why not simple do it in a simpler way, i.e.
using standard idiom:

	for (i = 0; i < sizeof(*fourcc); i++) {
		if (buf < end)
			*buf = tmp >> (i * 8);
		buf++;
	}
?

> > +			buf = string(buf, end, ch, spec);
> > +		}
> > +
> > +		if (*fourcc & BIT(31))
> > +			buf = string(buf, end, "-BE", spec);

Another possibility

	u8 ch[8];

	if (*fourcc & BIT(31)) {
		put_unaligned_be32(tmp, &ch[0]);
		strcpy(&ch[4], "-BE");
	} else {
		put_unaligned_le32(tmp, &ch[0]);
		strcpy(&ch[4], "-LE");
	}
	return string(buf, end, &ch[0], spec);

> > +		return buf;
> > +	default:
> > +		return error_string(buf, end, "(%pp?)", spec);
> > +	}
> > +}
Sakari Ailus April 2, 2020, 7:18 a.m. UTC | #2
Hi Hans,

Thank you for the review.

On Wed, Apr 01, 2020 at 04:13:51PM +0200, Hans Verkuil wrote:
> On 4/1/20 4:05 PM, Sakari Ailus wrote:
> > Add a printk modifier %ppf (for pixel format) for printing V4L2 and DRM
> > pixel formats denoted by 4ccs. The 4cc encoding is the same for both so
> > the same implementation can be used.
> > 
> > Suggested-by: Mauro Carvalho Chehab <mchehab@kernel.org>
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  Documentation/core-api/printk-formats.rst | 11 +++++++++
> >  lib/vsprintf.c                            | 29 +++++++++++++++++++++++
> >  2 files changed, 40 insertions(+)
> > 
> > diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst
> > index 8ebe46b1af39..b6249f513c09 100644
> > --- a/Documentation/core-api/printk-formats.rst
> > +++ b/Documentation/core-api/printk-formats.rst
> > @@ -545,6 +545,17 @@ For printing netdev_features_t.
> >  
> >  Passed by reference.
> >  
> > +V4L2 and DRM fourcc code (pixel format)
> > +---------------------------------------
> > +
> > +::
> > +
> > +	%ppf
> > +
> > +Print a 4cc code used by V4L2 or DRM.
> 
> FourCC appears to be the more-or-less official name (https://en.wikipedia.org/wiki/FourCC)
> 
> I would explain about the -BE suffix for bigendian fourcc variants.

Agreed, I'll address these in v2.

> 
> > +
> > +Passed by reference.
> > +
> >  Thanks
> >  ======
> >  
> > diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> > index 7c488a1ce318..b39f0ac317c5 100644
> > --- a/lib/vsprintf.c
> > +++ b/lib/vsprintf.c
> > @@ -1721,6 +1721,32 @@ char *netdev_bits(char *buf, char *end, const void *addr,
> >  	return special_hex_number(buf, end, num, size);
> >  }
> >  
> > +static noinline_for_stack
> > +char *pixel_format_string(char *buf, char *end, const u32 *fourcc,
> > +			  struct printf_spec spec, const char *fmt)
> > +{
> > +	char ch[2] = { 0 };
> 
> This can just be '{ };'

As Andy, I also do prefer { 0 }.

> 
> > +	unsigned int i;
> > +
> > +	if (check_pointer(&buf, end, fourcc, spec))
> > +		return buf;
> > +
> > +	switch (fmt[1]) {
> > +	case 'f':
> > +		for (i = 0; i < sizeof(*fourcc); i++) {
> > +			ch[0] = *fourcc >> (i << 3);
> 
> You need to AND with 0x7f, otherwise a big endian fourcc (bit 31 is set)
> will look wrong. Also, each character is standard 7 bit ascii, bit 7 isn't
> used except to indicate a BE variant.

Good point, will fix for v2.

> 
> > +			buf = string(buf, end, ch, spec);
> > +		}
> > +
> > +		if (*fourcc & BIT(31))
> > +			buf = string(buf, end, "-BE", spec);
> > +
> > +		return buf;
> > +	default:
> > +		return error_string(buf, end, "(%pp?)", spec);
> > +	}
> > +}
> > +
> >  static noinline_for_stack
> >  char *address_val(char *buf, char *end, const void *addr,
> >  		  struct printf_spec spec, const char *fmt)
> > @@ -2131,6 +2157,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
> > + * - 'pf' V4L2 or DRM pixel format.
> 
> I'd say 'FourCC format' instead of 'pixel format'.

Will fix.
Sakari Ailus April 2, 2020, 7:32 a.m. UTC | #3
Hi Andy,

Thanks for the review.

On Wed, Apr 01, 2020 at 06:13:32PM +0300, Andy Shevchenko wrote:
> On Wed, Apr 01, 2020 at 04:13:51PM +0200, Hans Verkuil wrote:
> > On 4/1/20 4:05 PM, Sakari Ailus wrote:
> > > Add a printk modifier %ppf (for pixel format) for printing V4L2 and DRM
> > > pixel formats denoted by 4ccs. The 4cc encoding is the same for both so
> > > the same implementation can be used.
> 
> %p4cc ?

Sounds good. Numbers have special handling but AFAIR only right after %
sign, so this should be possible.

> 
> > > +	char ch[2] = { 0 };
> > 
> > This can just be '{ };'
> 
> The latter is GCC extension, while above is C standard. Former is slightly
> better I think. Though see below.
> 
> > > +	unsigned int i;
> > > +
> > > +	if (check_pointer(&buf, end, fourcc, spec))
> > > +		return buf;
> > > +
> > > +	switch (fmt[1]) {
> > > +	case 'f':
> 
> > > +		for (i = 0; i < sizeof(*fourcc); i++) {
> > > +			ch[0] = *fourcc >> (i << 3);
> > 
> > You need to AND with 0x7f, otherwise a big endian fourcc (bit 31 is set)
> > will look wrong. Also, each character is standard 7 bit ascii, bit 7 isn't
> > used except to indicate a BE variant.
> 
> Why not to do it once by a flag and do reset it once?
> 
> 	u32 tmp = *fourcc;
> 	bool be4cc = tmp & BIT(31);
> 
> 	tmp &= BIT(31);

I had two extra temporary variables in a version I didn't send but I
figured they could be removed. :-)

> 
> On top of that, as promised above, why not simple do it in a simpler way, i.e.
> using standard idiom:
> 
> 	for (i = 0; i < sizeof(*fourcc); i++) {
> 		if (buf < end)
> 			*buf = tmp >> (i * 8);
> 		buf++;
> 	}
> ?

I guess that's at least more efficient, and comparing buf to end is
trivial. I'll do that in v2.

> 
> > > +			buf = string(buf, end, ch, spec);
> > > +		}
> > > +
> > > +		if (*fourcc & BIT(31))
> > > +			buf = string(buf, end, "-BE", spec);
> 
> Another possibility
> 
> 	u8 ch[8];
> 
> 	if (*fourcc & BIT(31)) {
> 		put_unaligned_be32(tmp, &ch[0]);
> 		strcpy(&ch[4], "-BE");
> 	} else {
> 		put_unaligned_le32(tmp, &ch[0]);
> 		strcpy(&ch[4], "-LE");
> 	}
> 	return string(buf, end, &ch[0], spec);

I think I prefer the loop. I figured you can only call string once,
otherwise field width handling will be broken. Let's see.

> 
> > > +		return buf;
> > > +	default:
> > > +		return error_string(buf, end, "(%pp?)", spec);
> > > +	}
> > > +}
>
Jani Nikula April 2, 2020, 8:34 a.m. UTC | #4
On Wed, 01 Apr 2020, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> Add a printk modifier %ppf (for pixel format) for printing V4L2 and DRM
> pixel formats denoted by 4ccs. The 4cc encoding is the same for both so
> the same implementation can be used.

I'm not going to take a strong stand in one way or the other regarding
the patch at hand, but I do think at some point we have to draw a line
what should be included in printk formats. Arguably they should be
reserved to things that are generally useful across large parts of the
kernel, right?

I think the more specialized you get, the more you should think about
just using the plain old %s, and your own helpers. Because frankly, the
kernel printk specifiers also start getting more than a little obscure.

Or could we conceive of a way to make this locally extensible yet safe,
letting callers use something like %{foo}, as well as providing a
locally relevant function to do the conversion?


BR,
Jani.


>
> Suggested-by: Mauro Carvalho Chehab <mchehab@kernel.org>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  Documentation/core-api/printk-formats.rst | 11 +++++++++
>  lib/vsprintf.c                            | 29 +++++++++++++++++++++++
>  2 files changed, 40 insertions(+)
>
> diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst
> index 8ebe46b1af39..b6249f513c09 100644
> --- a/Documentation/core-api/printk-formats.rst
> +++ b/Documentation/core-api/printk-formats.rst
> @@ -545,6 +545,17 @@ For printing netdev_features_t.
>  
>  Passed by reference.
>  
> +V4L2 and DRM fourcc code (pixel format)
> +---------------------------------------
> +
> +::
> +
> +	%ppf
> +
> +Print a 4cc code used by V4L2 or DRM.
> +
> +Passed by reference.
> +
>  Thanks
>  ======
>  
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index 7c488a1ce318..b39f0ac317c5 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -1721,6 +1721,32 @@ char *netdev_bits(char *buf, char *end, const void *addr,
>  	return special_hex_number(buf, end, num, size);
>  }
>  
> +static noinline_for_stack
> +char *pixel_format_string(char *buf, char *end, const u32 *fourcc,
> +			  struct printf_spec spec, const char *fmt)
> +{
> +	char ch[2] = { 0 };
> +	unsigned int i;
> +
> +	if (check_pointer(&buf, end, fourcc, spec))
> +		return buf;
> +
> +	switch (fmt[1]) {
> +	case 'f':
> +		for (i = 0; i < sizeof(*fourcc); i++) {
> +			ch[0] = *fourcc >> (i << 3);
> +			buf = string(buf, end, ch, spec);
> +		}
> +
> +		if (*fourcc & BIT(31))
> +			buf = string(buf, end, "-BE", spec);
> +
> +		return buf;
> +	default:
> +		return error_string(buf, end, "(%pp?)", spec);
> +	}
> +}
> +
>  static noinline_for_stack
>  char *address_val(char *buf, char *end, const void *addr,
>  		  struct printf_spec spec, const char *fmt)
> @@ -2131,6 +2157,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
> + * - 'pf' V4L2 or DRM pixel format.
>   * - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with
>   *            a certain separator (' ' by default):
>   *              C colon
> @@ -2223,6 +2250,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 'p':
> +		return pixel_format_string(buf, end, ptr, spec, fmt);
>  	case 'a':
>  		return address_val(buf, end, ptr, spec, fmt);
>  	case 'd':
Sakari Ailus April 2, 2020, 8:52 a.m. UTC | #5
Moi,

On Thu, Apr 02, 2020 at 11:34:48AM +0300, Jani Nikula wrote:
> On Wed, 01 Apr 2020, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> > Add a printk modifier %ppf (for pixel format) for printing V4L2 and DRM
> > pixel formats denoted by 4ccs. The 4cc encoding is the same for both so
> > the same implementation can be used.
> 
> I'm not going to take a strong stand in one way or the other regarding
> the patch at hand, but I do think at some point we have to draw a line
> what should be included in printk formats. Arguably they should be
> reserved to things that are generally useful across large parts of the
> kernel, right?
> 
> I think the more specialized you get, the more you should think about
> just using the plain old %s, and your own helpers. Because frankly, the
> kernel printk specifiers also start getting more than a little obscure.

I don't really disagree... While this is functionality very commonly needed
in drivers, there are alternatives such as posted here:

<URL:https://lore.kernel.org/linux-media/20190916100433.24367-1-hverkuil-cisco@xs4all.nl/>

The 4cc codes added by this set is still relatively generic (while still
Linux subsystem specific and not related to e.g. hardware standards), but I
wonder how many other, possibly similar cases there could be in the kernel,
and how many new specifiers we might get with those all added.

For what it's worth, even C99 defines macros for printing some formats
such as PRIu64 for uint64_t.
Mauro Carvalho Chehab April 2, 2020, 1:53 p.m. UTC | #6
Em Thu, 02 Apr 2020 11:34:48 +0300
Jani Nikula <jani.nikula@linux.intel.com> escreveu:

> On Wed, 01 Apr 2020, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> > Add a printk modifier %ppf (for pixel format) for printing V4L2 and DRM
> > pixel formats denoted by 4ccs. The 4cc encoding is the same for both so
> > the same implementation can be used.  
> 
> I'm not going to take a strong stand in one way or the other regarding
> the patch at hand, but I do think at some point we have to draw a line
> what should be included in printk formats. Arguably they should be
> reserved to things that are generally useful across large parts of the
> kernel, right?
> 
> I think the more specialized you get, the more you should think about
> just using the plain old %s, and your own helpers.

As I suggested it, from my side, I'd like to have it inside printk :-)

There is a subset of formats that are subsystem-specific anyway at
printk, like the network ones. We use extensively fourcc along the
media subsystem (and you probably also use fourcc at DRM). Even some input
devices nowadays may be using V4L2 core (some multi-sensor touching
devices), with depends on it.

So, those fourcc codes are pretty common. Having it at the printk
infra makes a lot easier for people to use them.

> Because frankly, the
> kernel printk specifiers also start getting more than a little obscure.

I liked one of the suggestions of using "%p4cc" (or maybe something
similar, if having a number there is a problem, like "%pAcc" or "%pfcc")
for this printk. This would be very easy for people to identify and 
remember about its meaning.

> Or could we conceive of a way to make this locally extensible yet safe,
> letting callers use something like %{foo}, as well as providing a
> locally relevant function to do the conversion?

That's something that it makes sense to be implemented in the future,
for things that would be self-contained inside an specific subsystem.

Thanks,
Mauro
Joe Perches April 2, 2020, 11:26 p.m. UTC | #7
On Thu, 2020-04-02 at 11:34 +0300, Jani Nikula wrote:
> On Wed, 01 Apr 2020, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> > Add a printk modifier %ppf (for pixel format) for printing V4L2 and DRM
> > pixel formats denoted by 4ccs. The 4cc encoding is the same for both so
> > the same implementation can be used.
> 
> I'm not going to take a strong stand in one way or the other regarding
> the patch at hand, but I do think at some point we have to draw a line
> what should be included in printk formats. Arguably they should be
> reserved to things that are generally useful across large parts of the
> kernel, right?

Definitely yes.

> I think the more specialized you get, the more you should think about
> just using the plain old %s, and your own helpers. Because frankly, the
> kernel printk specifiers also start getting more than a little obscure.
> 
> Or could we conceive of a way to make this locally extensible yet safe,
> letting callers use something like %{foo}, as well as providing a
> locally relevant function to do the conversion?

No.  printf validation would be broken.
Joe Perches April 2, 2020, 11:28 p.m. UTC | #8
On Thu, 2020-04-02 at 15:53 +0200, Mauro Carvalho Chehab wrote:

> I liked one of the suggestions of using "%p4cc" (or maybe something
> similar, if having a number there is a problem, like "%pAcc" or "%pfcc")

Using a number is not a problem.
Jani Nikula April 3, 2020, 6:37 a.m. UTC | #9
On Thu, 02 Apr 2020, Joe Perches <joe@perches.com> wrote:
> On Thu, 2020-04-02 at 11:34 +0300, Jani Nikula wrote:
>> Or could we conceive of a way to make this locally extensible yet safe,
>> letting callers use something like %{foo}, as well as providing a
>> locally relevant function to do the conversion?
>
> No.  printf validation would be broken.

I tossed the idea on a whim, and thinking further I could probably come
up with a number of challenges, but care to elaborate on what you see as
the problem in validation?

BR,
Jani.
Joe Perches April 3, 2020, 1:11 p.m. UTC | #10
On Fri, 2020-04-03 at 09:37 +0300, Jani Nikula wrote:
> On Thu, 02 Apr 2020, Joe Perches <joe@perches.com> wrote:
> > On Thu, 2020-04-02 at 11:34 +0300, Jani Nikula wrote:
> > > Or could we conceive of a way to make this locally extensible yet safe,
> > > letting callers use something like %{foo}, as well as providing a
> > > locally relevant function to do the conversion?
> > 
> > No.  printf validation would be broken.
> 
> I tossed the idea on a whim, and thinking further I could probably come
> up with a number of challenges, but care to elaborate on what you see as
> the problem in validation?

I understand you to want to add something like

	%<m> where m is a non-standard format specifier

so using using gcc's extension of

__attribute__((__format__(printf, string_index, first_to_check))

could not validate the argument type against use of the %<m>
in the format string.

	printk("%a\n", a);

Compiler bleats.
Pekka Paalanen April 6, 2020, 7:37 a.m. UTC | #11
On Wed, 1 Apr 2020 18:13:32 +0300
Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:

> On Wed, Apr 01, 2020 at 04:13:51PM +0200, Hans Verkuil wrote:
> > On 4/1/20 4:05 PM, Sakari Ailus wrote:  
> > > Add a printk modifier %ppf (for pixel format) for printing V4L2 and DRM
> > > pixel formats denoted by 4ccs. The 4cc encoding is the same for both so
> > > the same implementation can be used.  
> 
> %p4cc ?
> 

> Another possibility
> 
> 	u8 ch[8];
> 
> 	if (*fourcc & BIT(31)) {
> 		put_unaligned_be32(tmp, &ch[0]);
> 		strcpy(&ch[4], "-BE");
> 	} else {
> 		put_unaligned_le32(tmp, &ch[0]);
> 		strcpy(&ch[4], "-LE");
> 	}
> 	return string(buf, end, &ch[0], spec);
> 

Hi,

mind, if I guess right what that code does, I think this would confuse
the fourcc code endianness and the pixel data endianness. I think fourcc
codes are always crafted machine-endian, regardless of how the pixel
data is. At least, that is what drm_fourcc.h seems to be doing with
fourcc_code(). That has nothing to do with DRM_FORMAT_BIG_ENDIAN which
refers to the pixel data.


Thanks,
pq
diff mbox series

Patch

diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst
index 8ebe46b1af39..b6249f513c09 100644
--- a/Documentation/core-api/printk-formats.rst
+++ b/Documentation/core-api/printk-formats.rst
@@ -545,6 +545,17 @@  For printing netdev_features_t.
 
 Passed by reference.
 
+V4L2 and DRM fourcc code (pixel format)
+---------------------------------------
+
+::
+
+	%ppf
+
+Print a 4cc code used by V4L2 or DRM.
+
+Passed by reference.
+
 Thanks
 ======
 
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 7c488a1ce318..b39f0ac317c5 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1721,6 +1721,32 @@  char *netdev_bits(char *buf, char *end, const void *addr,
 	return special_hex_number(buf, end, num, size);
 }
 
+static noinline_for_stack
+char *pixel_format_string(char *buf, char *end, const u32 *fourcc,
+			  struct printf_spec spec, const char *fmt)
+{
+	char ch[2] = { 0 };
+	unsigned int i;
+
+	if (check_pointer(&buf, end, fourcc, spec))
+		return buf;
+
+	switch (fmt[1]) {
+	case 'f':
+		for (i = 0; i < sizeof(*fourcc); i++) {
+			ch[0] = *fourcc >> (i << 3);
+			buf = string(buf, end, ch, spec);
+		}
+
+		if (*fourcc & BIT(31))
+			buf = string(buf, end, "-BE", spec);
+
+		return buf;
+	default:
+		return error_string(buf, end, "(%pp?)", spec);
+	}
+}
+
 static noinline_for_stack
 char *address_val(char *buf, char *end, const void *addr,
 		  struct printf_spec spec, const char *fmt)
@@ -2131,6 +2157,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
+ * - 'pf' V4L2 or DRM pixel format.
  * - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with
  *            a certain separator (' ' by default):
  *              C colon
@@ -2223,6 +2250,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 'p':
+		return pixel_format_string(buf, end, ptr, spec, fmt);
 	case 'a':
 		return address_val(buf, end, ptr, spec, fmt);
 	case 'd':