diff mbox series

[1/3] edid-decode: Introduce libedid-decode wrapper

Message ID 20220304125001.1732057-1-contactshashanksharma@gmail.com (mailing list archive)
State New, archived
Headers show
Series [1/3] edid-decode: Introduce libedid-decode wrapper | expand

Commit Message

Shashank Sharma March 4, 2022, 12:49 p.m. UTC
From: Shashank Sharma <shashank.sharma@amd.com>

This patch does some small changes to make the core logic of
edid-decode tool available to a shared library wrapper. With
these changes, the EDID's 'state' variable will be avialble
to another process via some library API calls.

Cc: Pekka Paalanen <ppaalanen@gmail.com>
Cc: Jani Nikula <jani.nikula@intel.com>

Signed-off-by: Shashank Sharma <contactshashanksharma@gmail.com>
---
 Makefile        | 22 +++++++++++++++++++++-
 edid-decode.cpp | 15 ++++++++++++++-
 2 files changed, 35 insertions(+), 2 deletions(-)

Comments

Pekka Paalanen March 7, 2022, 3:54 p.m. UTC | #1
On Fri,  4 Mar 2022 13:49:59 +0100
Shashank Sharma <contactshashanksharma@gmail.com> wrote:

> From: Shashank Sharma <shashank.sharma@amd.com>
> 
> This patch does some small changes to make the core logic of
> edid-decode tool available to a shared library wrapper. With
> these changes, the EDID's 'state' variable will be avialble
> to another process via some library API calls.
> 
> Cc: Pekka Paalanen <ppaalanen@gmail.com>
> Cc: Jani Nikula <jani.nikula@intel.com>
> 
> Signed-off-by: Shashank Sharma <contactshashanksharma@gmail.com>

Hi Shashank,

thank you very much for working on this!

> ---
>  Makefile        | 22 +++++++++++++++++++++-
>  edid-decode.cpp | 15 ++++++++++++++-
>  2 files changed, 35 insertions(+), 2 deletions(-)
> 
> diff --git a/Makefile b/Makefile
> index 1843700..ebf3370 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1,14 +1,20 @@
>  ifeq ($(OS),Windows_NT)
>  	bindir ?= /usr/bin
>  	mandir ?= /usr/share/man
> +	libdir ?= /usr/lib
> +	includedir ?= /usr/include
>  else
>  	UNAME_S := $(shell uname -s)
>  	ifeq ($(UNAME_S),Darwin)
>  		bindir ?= /usr/local/sbin
>  		mandir ?= /usr/local/share/man
> +		libdir ?= /usr/local/lib
> +		includedir ?= /usr/include
>  	else
>  		bindir ?= /usr/bin
>  		mandir ?= /usr/share/man
> +		libdir ?= /usr/lib
> +		includedir ?= /usr/include
>  	endif
>  endif
>  
> @@ -19,6 +25,11 @@ SOURCES = edid-decode.cpp parse-base-block.cpp parse-cta-block.cpp \
>  	  parse-di-ext-block.cpp parse-vtb-ext-block.cpp calc-gtf-cvt.cpp
>  WARN_FLAGS = -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -Wimplicit-fallthrough
>  
> +LIB_NAME = libedid-decode.so
> +LIB_FLAGS = -fPIC
> +LIBLINK_FLAGS = -shared
> +LIB_SOURCES = libedid-decode-api.cpp

libedid-decode-api.cpp does not exist yet in this patch.

> +
>  all: edid-decode
>  
>  sha = -DSHA=$(shell if test -d .git ; then git rev-parse --short=12 HEAD ; fi)
> @@ -30,11 +41,20 @@ edid-decode: $(SOURCES) edid-decode.h oui.h Makefile
>  edid-decode.js: $(SOURCES) edid-decode.h oui.h Makefile
>  	$(EMXX) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(WARN_FLAGS) $(sha) $(date) -s EXPORTED_FUNCTIONS='["_parse_edid"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' -o $@ $(SOURCES) -lm
>  
> +libedid-decode: $(SOURCES) edid-decode.h oui.h Makefile
> +	$(CXX) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(WARN_FLAGS) -g $(LIB_FLAGS) $(sha) $(date) $(LIBLINK_FLAGS) -o $(LIB_NAME) $(LIB_SOURCES) $(SOURCES) -lm
> +
>  clean:
> -	rm -f edid-decode
> +	rm -f edid-decode libedid-decode.so
>  
>  install:
>  	mkdir -p $(DESTDIR)$(bindir)
>  	install -m 0755 edid-decode $(DESTDIR)$(bindir)
>  	mkdir -p $(DESTDIR)$(mandir)/man1
>  	install -m 0644 edid-decode.1 $(DESTDIR)$(mandir)/man1
> +
> +install-lib:
> +	mkdir -p $(DESTDIR)$(libdir)
> +	mkdir -p $(DESTDIR)$(includedir)
> +	install -m 0755 libedid-decode.so $(DESTDIR)$(libdir)
> +	install -m 0644 libedid-decode-api.h $(DESTDIR)$(includedir)

libedid-decode-api.h does not exist yet in this patch.

I find it a little odd to have these targets here without the actual
files. Maybe the first patch could already have a library building but
expose just parse and destroy functions without any getters yet?

> diff --git a/edid-decode.cpp b/edid-decode.cpp
> index 4a90aba..babff4a 100644
> --- a/edid-decode.cpp
> +++ b/edid-decode.cpp
> @@ -21,7 +21,7 @@
>  #define STR(x) #x
>  #define STRING(x) STR(x)
>  
> -static edid_state state;
> +edid_state state;
>  
>  static unsigned char edid[EDID_PAGE_SIZE * EDID_MAX_BLOCKS];
>  static bool odd_hex_digits;
> @@ -1012,6 +1012,19 @@ static bool extract_edid(int fd, FILE *error)
>  	state.edid_size = edid_data.size();
>  	return true;
>  }
> +struct edid_state *extract_edid_state(int fd, FILE *error)
> +{
> +	bool ret;
> +
> +	ret = extract_edid(fd, error);
> +	if (ret) {
> +		/* update the number of blocks */
> +		state.num_blocks = state.edid_size / EDID_PAGE_SIZE;
> +		return &state;

A library should not give out pointers to global mutable data. That
would break having multiple EDIDs loaded at the same time.

I would expect to be able to keep and cache 'struct edid_state'
instances created by this library until I explicitly destroy them.
I would not expect parsing a new EDID to overwrite the previously
returned object. IOW, I would expect to own the object created by the
library.


Thanks,
pq

> +	}
> +
> +	return NULL;
> +}
>  
>  static unsigned char crc_calc(const unsigned char *b)
>  {
Shashank Sharma March 7, 2022, 4:48 p.m. UTC | #2
Hello Pekka,

On 07.03.22 16:54, Pekka Paalanen wrote:
> On Fri,  4 Mar 2022 13:49:59 +0100
> Shashank Sharma <contactshashanksharma@gmail.com> wrote:
>
>> From: Shashank Sharma <shashank.sharma@amd.com>
>>
>> This patch does some small changes to make the core logic of
>> edid-decode tool available to a shared library wrapper. With
>> these changes, the EDID's 'state' variable will be avialble
>> to another process via some library API calls.
>>
>> Cc: Pekka Paalanen <ppaalanen@gmail.com>
>> Cc: Jani Nikula <jani.nikula@intel.com>
>>
>> Signed-off-by: Shashank Sharma <contactshashanksharma@gmail.com>
> Hi Shashank,
>
> thank you very much for working on this!
>
>> ---
>>   Makefile        | 22 +++++++++++++++++++++-
>>   edid-decode.cpp | 15 ++++++++++++++-
>>   2 files changed, 35 insertions(+), 2 deletions(-)
>>
>> diff --git a/Makefile b/Makefile
>> index 1843700..ebf3370 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -1,14 +1,20 @@
>>   ifeq ($(OS),Windows_NT)
>>   	bindir ?= /usr/bin
>>   	mandir ?= /usr/share/man
>> +	libdir ?= /usr/lib
>> +	includedir ?= /usr/include
>>   else
>>   	UNAME_S := $(shell uname -s)
>>   	ifeq ($(UNAME_S),Darwin)
>>   		bindir ?= /usr/local/sbin
>>   		mandir ?= /usr/local/share/man
>> +		libdir ?= /usr/local/lib
>> +		includedir ?= /usr/include
>>   	else
>>   		bindir ?= /usr/bin
>>   		mandir ?= /usr/share/man
>> +		libdir ?= /usr/lib
>> +		includedir ?= /usr/include
>>   	endif
>>   endif
>>   
>> @@ -19,6 +25,11 @@ SOURCES = edid-decode.cpp parse-base-block.cpp parse-cta-block.cpp \
>>   	  parse-di-ext-block.cpp parse-vtb-ext-block.cpp calc-gtf-cvt.cpp
>>   WARN_FLAGS = -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -Wimplicit-fallthrough
>>   
>> +LIB_NAME = libedid-decode.so
>> +LIB_FLAGS = -fPIC
>> +LIBLINK_FLAGS = -shared
>> +LIB_SOURCES = libedid-decode-api.cpp
> libedid-decode-api.cpp does not exist yet in this patch.
Yes, the API is introduced in patch 2, Noted.
>> +
>>   all: edid-decode
>>   
>>   sha = -DSHA=$(shell if test -d .git ; then git rev-parse --short=12 HEAD ; fi)
>> @@ -30,11 +41,20 @@ edid-decode: $(SOURCES) edid-decode.h oui.h Makefile
>>   edid-decode.js: $(SOURCES) edid-decode.h oui.h Makefile
>>   	$(EMXX) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(WARN_FLAGS) $(sha) $(date) -s EXPORTED_FUNCTIONS='["_parse_edid"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' -o $@ $(SOURCES) -lm
>>   
>> +libedid-decode: $(SOURCES) edid-decode.h oui.h Makefile
>> +	$(CXX) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(WARN_FLAGS) -g $(LIB_FLAGS) $(sha) $(date) $(LIBLINK_FLAGS) -o $(LIB_NAME) $(LIB_SOURCES) $(SOURCES) -lm
>> +
>>   clean:
>> -	rm -f edid-decode
>> +	rm -f edid-decode libedid-decode.so
>>   
>>   install:
>>   	mkdir -p $(DESTDIR)$(bindir)
>>   	install -m 0755 edid-decode $(DESTDIR)$(bindir)
>>   	mkdir -p $(DESTDIR)$(mandir)/man1
>>   	install -m 0644 edid-decode.1 $(DESTDIR)$(mandir)/man1
>> +
>> +install-lib:
>> +	mkdir -p $(DESTDIR)$(libdir)
>> +	mkdir -p $(DESTDIR)$(includedir)
>> +	install -m 0755 libedid-decode.so $(DESTDIR)$(libdir)
>> +	install -m 0644 libedid-decode-api.h $(DESTDIR)$(includedir)
> libedid-decode-api.h does not exist yet in this patch.
>
> I find it a little odd to have these targets here without the actual
> files. Maybe the first patch could already have a library building but
> expose just parse and destroy functions without any getters yet?
Yes, this is more like a formatting error. I need to move these files to 
patch 2, where they are introduced.
>> diff --git a/edid-decode.cpp b/edid-decode.cpp
>> index 4a90aba..babff4a 100644
>> --- a/edid-decode.cpp
>> +++ b/edid-decode.cpp
>> @@ -21,7 +21,7 @@
>>   #define STR(x) #x
>>   #define STRING(x) STR(x)
>>   
>> -static edid_state state;
>> +edid_state state;
>>   
>>   static unsigned char edid[EDID_PAGE_SIZE * EDID_MAX_BLOCKS];
>>   static bool odd_hex_digits;
>> @@ -1012,6 +1012,19 @@ static bool extract_edid(int fd, FILE *error)
>>   	state.edid_size = edid_data.size();
>>   	return true;
>>   }
>> +struct edid_state *extract_edid_state(int fd, FILE *error)
>> +{
>> +	bool ret;
>> +
>> +	ret = extract_edid(fd, error);
>> +	if (ret) {
>> +		/* update the number of blocks */
>> +		state.num_blocks = state.edid_size / EDID_PAGE_SIZE;
>> +		return &state;
> A library should not give out pointers to global mutable data. That
> would break having multiple EDIDs loaded at the same time.
>
> I would expect to be able to keep and cache 'struct edid_state'
> instances created by this library until I explicitly destroy them.
> I would not expect parsing a new EDID to overwrite the previously
> returned object. IOW, I would expect to own the object created by the
> library.

Till now, I was under the impression of a design where a compositor 
parses the EDID, and saves all the information in its state immediately, 
so that when the second EDID is loaded, it can override first one. But 
based on your inputs I myself feel that its a bit rigid. Now I am 
thinking about extending it to something which remains until the process 
lifetime. How does this look to you:

- The compositor passes the EDID file node to library.

- The library parses the EDID, creates a state variable and caches it, 
and gives back a handle(unique) to the compositor.

   /* in compositor's display/connector init part */

  connector.handle = libedid_parse_edid(EDID_NODE);


- While calling the subsequent APIs, compositor passes the handle with 
the API, like

  /* Somewhere later in the same compositor */

ret = libedid_is_ycbcr420_supported(connector.handle);

if (ret) {

     /* Prepare a YCBCR420 modeset */

}

and so on .....


This should address your concerns as well.

- Shashank

>
>
> Thanks,
> pq
>
>> +	}
>> +
>> +	return NULL;
>> +}
>>   
>>   static unsigned char crc_calc(const unsigned char *b)
>>   {
Pekka Paalanen March 8, 2022, 11:21 a.m. UTC | #3
On Mon, 7 Mar 2022 17:48:38 +0100
Shashank Sharma <contactshashanksharma@gmail.com> wrote:

> Hello Pekka,
> 
> On 07.03.22 16:54, Pekka Paalanen wrote:
> > On Fri,  4 Mar 2022 13:49:59 +0100
> > Shashank Sharma <contactshashanksharma@gmail.com> wrote:
> >  
> >> From: Shashank Sharma <shashank.sharma@amd.com>
> >>
> >> This patch does some small changes to make the core logic of
> >> edid-decode tool available to a shared library wrapper. With
> >> these changes, the EDID's 'state' variable will be avialble
> >> to another process via some library API calls.
> >>
> >> Cc: Pekka Paalanen <ppaalanen@gmail.com>
> >> Cc: Jani Nikula <jani.nikula@intel.com>
> >>
> >> Signed-off-by: Shashank Sharma <contactshashanksharma@gmail.com>  
> > Hi Shashank,
> >
> > thank you very much for working on this!
> >  
> >> ---
> >>   Makefile        | 22 +++++++++++++++++++++-
> >>   edid-decode.cpp | 15 ++++++++++++++-
> >>   2 files changed, 35 insertions(+), 2 deletions(-)

...

> >> diff --git a/edid-decode.cpp b/edid-decode.cpp
> >> index 4a90aba..babff4a 100644
> >> --- a/edid-decode.cpp
> >> +++ b/edid-decode.cpp
> >> @@ -21,7 +21,7 @@
> >>   #define STR(x) #x
> >>   #define STRING(x) STR(x)
> >>   
> >> -static edid_state state;
> >> +edid_state state;
> >>   
> >>   static unsigned char edid[EDID_PAGE_SIZE * EDID_MAX_BLOCKS];
> >>   static bool odd_hex_digits;
> >> @@ -1012,6 +1012,19 @@ static bool extract_edid(int fd, FILE *error)
> >>   	state.edid_size = edid_data.size();
> >>   	return true;
> >>   }
> >> +struct edid_state *extract_edid_state(int fd, FILE *error)
> >> +{
> >> +	bool ret;
> >> +
> >> +	ret = extract_edid(fd, error);
> >> +	if (ret) {
> >> +		/* update the number of blocks */
> >> +		state.num_blocks = state.edid_size / EDID_PAGE_SIZE;
> >> +		return &state;  
> > A library should not give out pointers to global mutable data. That
> > would break having multiple EDIDs loaded at the same time.
> >
> > I would expect to be able to keep and cache 'struct edid_state'
> > instances created by this library until I explicitly destroy them.
> > I would not expect parsing a new EDID to overwrite the previously
> > returned object. IOW, I would expect to own the object created by the
> > library.  
> 
> Till now, I was under the impression of a design where a compositor 
> parses the EDID, and saves all the information in its state immediately, 

It may well be that all compositors will work like that. However, from
a library API design point of view it makes no sense for to require
that. It would be surprising. Surprises lead to bugs.

If you are thinking of optimizing away a few mallocs of few kB of data
for each new EDID to parse, that would be completely premature. Ease of
use wins this one.

> so that when the second EDID is loaded, it can override first one. But 
> based on your inputs I myself feel that its a bit rigid. Now I am 
> thinking about extending it to something which remains until the process 
> lifetime. How does this look to you:
> 
> - The compositor passes the EDID file node to library.

As mentioned, compositors don't have files for EDID.

> 
> - The library parses the EDID, creates a state variable and caches it, 
> and gives back a handle(unique) to the compositor.
> 
>    /* in compositor's display/connector init part */
> 
>   connector.handle = libedid_parse_edid(EDID_NODE);

Why play with handles when you can simply return a pointer to an opaque
type?

I don't see a good reason to make the library more complicated in order
to guard against invalid handles, nor to garbage-collect everything
allocated even if the user of the library forgot to do so. Doing the
latter would just make memory leaks in the callers undetectable when the
library frees them all on exit.

Handles are just not how C works, contrary to what OpenGL tries to make
us think. Handles (that are not just opaque pointers in disguise) do
have their uses, but this does not seem like one.

> - While calling the subsequent APIs, compositor passes the handle with 
> the API, like
> 
>   /* Somewhere later in the same compositor */
> 
> ret = libedid_is_ycbcr420_supported(connector.handle);
> 
> if (ret) {
> 
>      /* Prepare a YCBCR420 modeset */
> 
> }
> 
> and so on .....

That is good.


Thanks,
pq
Hans Verkuil March 8, 2022, 12:09 p.m. UTC | #4
Hi Shashank,

There is no cover letter for this series, so I'll just reply to the
first patch, but my comments are high-level and not specific to this
patch.

To be honest, I am not at all convinced that using edid-decode as a
parser library is the right thing to do. It was never written with that
in mind. The two purposes of edid-decode are to:

1) Convert the EDID to a human readable text, and
2) Verify if the EDID conforms to the various standards and is internally
   consistent.

As a result the state information that edid-decode stores is just the
state that it needs to check conformity across Extension Blocks and/or
Data Blocks. Most of the parsed data is just printed to stdout and checked
and then forgotten.

I have considered if it would make sense to make a library to parse and
store the EDID data and have edid-decode sit on top of that, but that will
make the conformity tests much harder. It's kind of interwoven with the
parsing and a parser library is really not interested in that anyway.

I think edid-decode can function very well as a reference source for
a real EDID parser since edid-decode is very complete, but not as a
EDID parser library.

BTW, if anyone has detailed info for the AMD Freesync Data Block, then
I'd love to have that. The cta_amd() function is based on reverse engineering
and not everything could be decoded.

Regards,

	Hans

On 3/4/22 13:49, Shashank Sharma wrote:
> From: Shashank Sharma <shashank.sharma@amd.com>
> 
> This patch does some small changes to make the core logic of
> edid-decode tool available to a shared library wrapper. With
> these changes, the EDID's 'state' variable will be avialble
> to another process via some library API calls.
> 
> Cc: Pekka Paalanen <ppaalanen@gmail.com>
> Cc: Jani Nikula <jani.nikula@intel.com>
> 
> Signed-off-by: Shashank Sharma <contactshashanksharma@gmail.com>
> ---
>  Makefile        | 22 +++++++++++++++++++++-
>  edid-decode.cpp | 15 ++++++++++++++-
>  2 files changed, 35 insertions(+), 2 deletions(-)
> 
> diff --git a/Makefile b/Makefile
> index 1843700..ebf3370 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1,14 +1,20 @@
>  ifeq ($(OS),Windows_NT)
>  	bindir ?= /usr/bin
>  	mandir ?= /usr/share/man
> +	libdir ?= /usr/lib
> +	includedir ?= /usr/include
>  else
>  	UNAME_S := $(shell uname -s)
>  	ifeq ($(UNAME_S),Darwin)
>  		bindir ?= /usr/local/sbin
>  		mandir ?= /usr/local/share/man
> +		libdir ?= /usr/local/lib
> +		includedir ?= /usr/include
>  	else
>  		bindir ?= /usr/bin
>  		mandir ?= /usr/share/man
> +		libdir ?= /usr/lib
> +		includedir ?= /usr/include
>  	endif
>  endif
>  
> @@ -19,6 +25,11 @@ SOURCES = edid-decode.cpp parse-base-block.cpp parse-cta-block.cpp \
>  	  parse-di-ext-block.cpp parse-vtb-ext-block.cpp calc-gtf-cvt.cpp
>  WARN_FLAGS = -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -Wimplicit-fallthrough
>  
> +LIB_NAME = libedid-decode.so
> +LIB_FLAGS = -fPIC
> +LIBLINK_FLAGS = -shared
> +LIB_SOURCES = libedid-decode-api.cpp
> +
>  all: edid-decode
>  
>  sha = -DSHA=$(shell if test -d .git ; then git rev-parse --short=12 HEAD ; fi)
> @@ -30,11 +41,20 @@ edid-decode: $(SOURCES) edid-decode.h oui.h Makefile
>  edid-decode.js: $(SOURCES) edid-decode.h oui.h Makefile
>  	$(EMXX) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(WARN_FLAGS) $(sha) $(date) -s EXPORTED_FUNCTIONS='["_parse_edid"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' -o $@ $(SOURCES) -lm
>  
> +libedid-decode: $(SOURCES) edid-decode.h oui.h Makefile
> +	$(CXX) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(WARN_FLAGS) -g $(LIB_FLAGS) $(sha) $(date) $(LIBLINK_FLAGS) -o $(LIB_NAME) $(LIB_SOURCES) $(SOURCES) -lm
> +
>  clean:
> -	rm -f edid-decode
> +	rm -f edid-decode libedid-decode.so
>  
>  install:
>  	mkdir -p $(DESTDIR)$(bindir)
>  	install -m 0755 edid-decode $(DESTDIR)$(bindir)
>  	mkdir -p $(DESTDIR)$(mandir)/man1
>  	install -m 0644 edid-decode.1 $(DESTDIR)$(mandir)/man1
> +
> +install-lib:
> +	mkdir -p $(DESTDIR)$(libdir)
> +	mkdir -p $(DESTDIR)$(includedir)
> +	install -m 0755 libedid-decode.so $(DESTDIR)$(libdir)
> +	install -m 0644 libedid-decode-api.h $(DESTDIR)$(includedir)
> diff --git a/edid-decode.cpp b/edid-decode.cpp
> index 4a90aba..babff4a 100644
> --- a/edid-decode.cpp
> +++ b/edid-decode.cpp
> @@ -21,7 +21,7 @@
>  #define STR(x) #x
>  #define STRING(x) STR(x)
>  
> -static edid_state state;
> +edid_state state;
>  
>  static unsigned char edid[EDID_PAGE_SIZE * EDID_MAX_BLOCKS];
>  static bool odd_hex_digits;
> @@ -1012,6 +1012,19 @@ static bool extract_edid(int fd, FILE *error)
>  	state.edid_size = edid_data.size();
>  	return true;
>  }
> +struct edid_state *extract_edid_state(int fd, FILE *error)
> +{
> +	bool ret;
> +
> +	ret = extract_edid(fd, error);
> +	if (ret) {
> +		/* update the number of blocks */
> +		state.num_blocks = state.edid_size / EDID_PAGE_SIZE;
> +		return &state;
> +	}
> +
> +	return NULL;
> +}
>  
>  static unsigned char crc_calc(const unsigned char *b)
>  {
Pekka Paalanen March 8, 2022, 2:30 p.m. UTC | #5
On Tue, 8 Mar 2022 13:09:37 +0100
Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:

> Hi Shashank,
> 
> There is no cover letter for this series, so I'll just reply to the
> first patch, but my comments are high-level and not specific to this
> patch.
> 
> To be honest, I am not at all convinced that using edid-decode as a
> parser library is the right thing to do. It was never written with that
> in mind.

Hi Hans,

in https://www.spinics.net/lists/linux-media/msg190064.html you wrote:

	"I would be open to that. The best way would be to create a C
	library that turns the EDID blocks into C structures, while
	edid-decode itself remains C++ and uses the C library to do the
	parsing. While edid-decode supports a large range of Extension
	Blocks, a C library could probably limit itself to the base
	block, CTA-861 blocks and DisplayID blocks."

and

	"I think it would make sense if it is grown as a library used
	by edid-decode. The edid-decode utility is under active
	maintenance and follows the latest EDID standards, so that will
	probably help the quality of the library. My main requirement
	would be that the edid-decode functionality is not affected,
	especially the conformity checks are still performed. And that
	support for new/updated EDID standards can easily be
	implemented, but that's exactly what you would want in an edid
	library."

EDID blocks as C structures is not the API we are looking for from a
library, but more like what edid-decode already prints out yet in
native C types rather than strings or bit patterns. The former could
still be the low-level library API while the latter is the high-level
API. So perhaps edid-decode would be using the low-level API directly.
Then the high-level C API is implemented on top of the low-level C API.
Time would tell how much of edid-decode will move behind the low-level
C API.

On the down-side, the high-level API implementation would need to
duplicate the logic that already(?) exists in edid-decode to find the
most accurate source for a piece of information in case one block
overrides another or information from multiple blocks have to be
combined.

In my opinion this draft does not yet have enough structure to tell
what the interfacing between edid-decode tool and library will look
like.

> The two purposes of edid-decode are to:
> 
> 1) Convert the EDID to a human readable text, and
> 2) Verify if the EDID conforms to the various standards and is internally
>    consistent.
> 
> As a result the state information that edid-decode stores is just the
> state that it needs to check conformity across Extension Blocks and/or
> Data Blocks. Most of the parsed data is just printed to stdout and checked
> and then forgotten.

Sounds like it should be easy to store the data everywhere where
anything is printed. Is something wrong with that? (This would be a
different approach than what you drafted a year ago.)

> I have considered if it would make sense to make a library to parse and
> store the EDID data and have edid-decode sit on top of that, but that will
> make the conformity tests much harder. It's kind of interwoven with the
> parsing and a parser library is really not interested in that anyway.

Why would conformity testing be contradictory to a parsing library?

Does edid-decode just stop when it finds a problem without looking at
the rest of the data, and would doing the latter be somehow difficult?

I would naively think that conformity testing would be easy to make
conditional, or leave it unconditional but redirect the reports when
the user needs to use the information even when it is broken.

The more I think of it, the more I think that display servers should do
EDID conformance testing as part of their normal operations and log the
results. A desktop environment could even have an UI for that: "We
found something strange with your monitor, it might not work as
expected. Details here..." in the more serious cases.

In the long run, maybe it would make people return more monitors to
sellers, which might cause manufacturers to pay more attention to
getting EDID/DisplayID right. I can dream, right? :-)

> I think edid-decode can function very well as a reference source for
> a real EDID parser since edid-decode is very complete, but not as a
> EDID parser library.

It would be a shame to have to fork edid-decode into something else and
then play catch-up with the real edid-decode for all times to come. Or
are you perhaps hoping that the fork would eventually completely
supersede the original project and developers would migrate to the new
one?

It would be really nice to be able to involve the community around
edid-decode to make sure we get the library right, but if the library
is somewhere else, would that happen? Or are we left with yet another
half-written ad hoc EDID parsing code base used by maybe two display
servers?

Maybe we could at least work on this proposal for a while to see what
it will start to look like before dismissing it?

If all that fails and there is still someone left to do some work, it's
not unthinkable to set up a completely new project with the goal to
replicate exactly the output of edid-decode with the full EDID sample
database you have gathered. That just feels like a lot of work without
any help until it's perfect.


Thanks,
pq

> On 3/4/22 13:49, Shashank Sharma wrote:
> > From: Shashank Sharma <shashank.sharma@amd.com>
> > 
> > This patch does some small changes to make the core logic of
> > edid-decode tool available to a shared library wrapper. With
> > these changes, the EDID's 'state' variable will be avialble
> > to another process via some library API calls.
> > 
> > Cc: Pekka Paalanen <ppaalanen@gmail.com>
> > Cc: Jani Nikula <jani.nikula@intel.com>
> > 
> > Signed-off-by: Shashank Sharma <contactshashanksharma@gmail.com>
> > ---
> >  Makefile        | 22 +++++++++++++++++++++-
> >  edid-decode.cpp | 15 ++++++++++++++-
> >  2 files changed, 35 insertions(+), 2 deletions(-)
Hans Verkuil March 8, 2022, 4:36 p.m. UTC | #6
Hi Pekka,

On 3/8/22 15:30, Pekka Paalanen wrote:
> On Tue, 8 Mar 2022 13:09:37 +0100
> Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
> 
>> Hi Shashank,
>>
>> There is no cover letter for this series, so I'll just reply to the
>> first patch, but my comments are high-level and not specific to this
>> patch.
>>
>> To be honest, I am not at all convinced that using edid-decode as a
>> parser library is the right thing to do. It was never written with that
>> in mind.
> 
> Hi Hans,
> 
> in https://www.spinics.net/lists/linux-media/msg190064.html you wrote:
> 
> 	"I would be open to that. The best way would be to create a C
> 	library that turns the EDID blocks into C structures, while
> 	edid-decode itself remains C++ and uses the C library to do the
> 	parsing. While edid-decode supports a large range of Extension
> 	Blocks, a C library could probably limit itself to the base
> 	block, CTA-861 blocks and DisplayID blocks."
> 
> and
> 
> 	"I think it would make sense if it is grown as a library used
> 	by edid-decode. The edid-decode utility is under active
> 	maintenance and follows the latest EDID standards, so that will
> 	probably help the quality of the library. My main requirement
> 	would be that the edid-decode functionality is not affected,
> 	especially the conformity checks are still performed. And that
> 	support for new/updated EDID standards can easily be
> 	implemented, but that's exactly what you would want in an edid
> 	library."

Yeah, that's written a year ago. I think I was a bit too optimistic.

> 
> EDID blocks as C structures is not the API we are looking for from a
> library, but more like what edid-decode already prints out yet in
> native C types rather than strings or bit patterns. The former could
> still be the low-level library API while the latter is the high-level
> API. So perhaps edid-decode would be using the low-level API directly.
> Then the high-level C API is implemented on top of the low-level C API.
> Time would tell how much of edid-decode will move behind the low-level
> C API.
> 
> On the down-side, the high-level API implementation would need to
> duplicate the logic that already(?) exists in edid-decode to find the
> most accurate source for a piece of information in case one block
> overrides another or information from multiple blocks have to be
> combined.
> 
> In my opinion this draft does not yet have enough structure to tell
> what the interfacing between edid-decode tool and library will look
> like.

I agree. If this can be done in a reasonable way, then I have no objection.
But I will have to see some proof-of-concept code that isn't as trivial as
this.

You also need to think about which information you want to extract from the
EDID. Some things like DI-EXT, LS-EXT and VTB-EXT make no sense today as
it is rarely if ever used.

> 
>> The two purposes of edid-decode are to:
>>
>> 1) Convert the EDID to a human readable text, and
>> 2) Verify if the EDID conforms to the various standards and is internally
>>    consistent.
>>
>> As a result the state information that edid-decode stores is just the
>> state that it needs to check conformity across Extension Blocks and/or
>> Data Blocks. Most of the parsed data is just printed to stdout and checked
>> and then forgotten.
> 
> Sounds like it should be easy to store the data everywhere where
> anything is printed. Is something wrong with that? (This would be a
> different approach than what you drafted a year ago.)

I suspect that the code will become *very* messy.

> 
>> I have considered if it would make sense to make a library to parse and
>> store the EDID data and have edid-decode sit on top of that, but that will
>> make the conformity tests much harder. It's kind of interwoven with the
>> parsing and a parser library is really not interested in that anyway.
> 
> Why would conformity testing be contradictory to a parsing library?

Because some of the things that are tested are e.g. checks if padding
bytes are valid. You don't care about that when you just want to parse
an EDID into a form usable by code.

> 
> Does edid-decode just stop when it finds a problem without looking at
> the rest of the data, and would doing the latter be somehow difficult?

It continues parsing.

> 
> I would naively think that conformity testing would be easy to make
> conditional, or leave it unconditional but redirect the reports when
> the user needs to use the information even when it is broken.
> 
> The more I think of it, the more I think that display servers should do
> EDID conformance testing as part of their normal operations and log the
> results. A desktop environment could even have an UI for that: "We
> found something strange with your monitor, it might not work as
> expected. Details here..." in the more serious cases.

That's a good point.

> 
> In the long run, maybe it would make people return more monitors to
> sellers, which might cause manufacturers to pay more attention to
> getting EDID/DisplayID right. I can dream, right? :-)
> 
>> I think edid-decode can function very well as a reference source for
>> a real EDID parser since edid-decode is very complete, but not as a
>> EDID parser library.
> 
> It would be a shame to have to fork edid-decode into something else and
> then play catch-up with the real edid-decode for all times to come. Or
> are you perhaps hoping that the fork would eventually completely
> supersede the original project and developers would migrate to the new
> one?
> 
> It would be really nice to be able to involve the community around
> edid-decode to make sure we get the library right, but if the library
> is somewhere else, would that happen? Or are we left with yet another
> half-written ad hoc EDID parsing code base used by maybe two display
> servers?
> 
> Maybe we could at least work on this proposal for a while to see what
> it will start to look like before dismissing it?

If you are willing to put in the effort, then I think you would have to
first rework the code bit by bit into different layers:

E.g. parse_base_block() would be split into two functions: a parse_base_block()
that parses the base block into C structures, and it also does the conformity
checks, where the output of that is just written to an internal buffer, as
happens today. The --check-inline option functionality would be hard to support,
I suspect, but I think it is OK to drop that. I at least rarely use it.

And on top of that there is a print_base_block that produces the human
readable output based on the result of the parse_base_block.

Later the parse functions can be put in a library which edid-decode uses.

It should be possible to do this conversion bit by bit, so it's easier to merge
and maintain.

But it is a *lot* of work since you will also have to make C headers for all
the EDID structures.

Can the library be C++ or do you need C structs only? If C++ is OK, then that
will simplify matters.

In any case, I think I would like to see a proof-of-concept where the base
block parsing is modified in such a way as I described above. If that makes
sense, then this can be extended to the other extension blocks. And for the
CTA and DisplayID extension blocks you can probably do the conversion one
Data Block type at a time.

In any case, this series is just not useful as proof-of-concept.

Regards,

	Hans

> If all that fails and there is still someone left to do some work, it's
> not unthinkable to set up a completely new project with the goal to
> replicate exactly the output of edid-decode with the full EDID sample
> database you have gathered. That just feels like a lot of work without
> any help until it's perfect.
> 
> 
> Thanks,
> pq
> 
>> On 3/4/22 13:49, Shashank Sharma wrote:
>>> From: Shashank Sharma <shashank.sharma@amd.com>
>>>
>>> This patch does some small changes to make the core logic of
>>> edid-decode tool available to a shared library wrapper. With
>>> these changes, the EDID's 'state' variable will be avialble
>>> to another process via some library API calls.
>>>
>>> Cc: Pekka Paalanen <ppaalanen@gmail.com>
>>> Cc: Jani Nikula <jani.nikula@intel.com>
>>>
>>> Signed-off-by: Shashank Sharma <contactshashanksharma@gmail.com>
>>> ---
>>>  Makefile        | 22 +++++++++++++++++++++-
>>>  edid-decode.cpp | 15 ++++++++++++++-
>>>  2 files changed, 35 insertions(+), 2 deletions(-)
Pekka Paalanen March 9, 2022, 2:09 p.m. UTC | #7
On Tue, 8 Mar 2022 17:36:47 +0100
Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:

> Hi Pekka,
> 
> On 3/8/22 15:30, Pekka Paalanen wrote:
> > On Tue, 8 Mar 2022 13:09:37 +0100
> > Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
> >   
> >> Hi Shashank,
> >>
> >> There is no cover letter for this series, so I'll just reply to the
> >> first patch, but my comments are high-level and not specific to this
> >> patch.
> >>
> >> To be honest, I am not at all convinced that using edid-decode as a
> >> parser library is the right thing to do. It was never written with that
> >> in mind.  
> > 
> > Hi Hans,
> > 
> > in https://www.spinics.net/lists/linux-media/msg190064.html you wrote:

...

> >> I think edid-decode can function very well as a reference source for
> >> a real EDID parser since edid-decode is very complete, but not as a
> >> EDID parser library.  
> > 
> > It would be a shame to have to fork edid-decode into something else and
> > then play catch-up with the real edid-decode for all times to come. Or
> > are you perhaps hoping that the fork would eventually completely
> > supersede the original project and developers would migrate to the new
> > one?
> > 
> > It would be really nice to be able to involve the community around
> > edid-decode to make sure we get the library right, but if the library
> > is somewhere else, would that happen? Or are we left with yet another
> > half-written ad hoc EDID parsing code base used by maybe two display
> > servers?
> > 
> > Maybe we could at least work on this proposal for a while to see what
> > it will start to look like before dismissing it?  
> 
> If you are willing to put in the effort, then I think you would have to
> first rework the code bit by bit into different layers:

Hi Hans,

thanks! If Shashank agrees, we can see how this would start to look
like. I suppose there would be the occasional patch series sent to this
mailing list and publicly discussed between me and Shashank while we
iterate. You could mostly ignore it if you want until the two of us
need your guidance.

Even if it turns out that this cannot go into edid-decode upstream, I
don't think the exercise is going to go to waste. It would be the
beginnings of a new project.

> E.g. parse_base_block() would be split into two functions: a parse_base_block()
> that parses the base block into C structures, and it also does the conformity
> checks, where the output of that is just written to an internal buffer, as
> happens today. The --check-inline option functionality would be hard to support,
> I suspect, but I think it is OK to drop that. I at least rarely use it.

For --check-inline, maybe, maybe not. open_memstream() is a thing,
giving us a FILE*. Depending on --check-inline, the FILE* to complain
to could be either stderr or an internal buffer from open_memstream().
Or the C++ equivalent.

> And on top of that there is a print_base_block that produces the human
> readable output based on the result of the parse_base_block.
> 
> Later the parse functions can be put in a library which edid-decode uses.
> 
> It should be possible to do this conversion bit by bit, so it's easier to merge
> and maintain.
> 
> But it is a *lot* of work since you will also have to make C headers for all
> the EDID structures.

Thank you for the suggestions and warnings. I suspect we shouldn't aim
to land the first part until we have a good idea of the later parts, so
that edid-decode does not end up with half a conversion if the later
parts turn out too messy.

> Can the library be C++ or do you need C structs only? If C++ is OK, then that
> will simplify matters.

The only thing that absolutely must be C is the library public API.
What I've been imagining so far is that we would have a low-level and a
high-level API, as I alluded to in my previous email. Other than that,
I don't know yet.

Internals are totally fine to keep as C++.

> In any case, I think I would like to see a proof-of-concept where the base
> block parsing is modified in such a way as I described above. If that makes
> sense, then this can be extended to the other extension blocks. And for the
> CTA and DisplayID extension blocks you can probably do the conversion one
> Data Block type at a time.
> 
> In any case, this series is just not useful as proof-of-concept.

I agree. A cover letter to set up your expectations would have been in order.

Btw. how does edid-decode regression testing work? I thought I asked in
the past, but I can't find my question or answer. I know what
edid-decode README and test/README says about it, but how does one
actually run through the tests?

One thing I'm a little wary of is the edid-decode.js target in the
Makefile. How do you test that?

On the other hand, if merging into edid-decode does not work, a new
project could have several benefits if I get to decide:

- Meson build system
- automated test suite in the project
- Gitlab workflow hosted by freedesktop.org
- CI

I must admit it is really tempting, but I'm scared of the amount of
work needed to establish a new project.

I assume you are not interested in any of that in the current upstream
project, are you?


Thanks,
pq
Sharma, Shashank March 9, 2022, 2:31 p.m. UTC | #8
Hello Hans, Pekka,

Thank you for providing your feedbacks on the first level draft of the 
library, and for your inputs.

On 3/9/2022 3:09 PM, Pekka Paalanen wrote:
> Hi Hans,
> 
> thanks! If Shashank agrees, we can see how this would start to look
> like. I suppose there would be the occasional patch series sent to this
> mailing list and publicly discussed between me and Shashank while we
> iterate. You could mostly ignore it if you want until the two of us
> need your guidance.
> 
> Even if it turns out that this cannot go into edid-decode upstream, I
> don't think the exercise is going to go to waste. It would be the
> beginnings of a new project.

Based on what I could understand from the discussion so far, I could see 
that we have some basic requirements which are suggested by both of you, 
like:

- We want to keep the current structure of EDID-decode as unchanged as 
possible, and want to keep the C++ states internal.
- We want to make sure that the new library (if any) is C API, and apart 
from parsing the EDID, should be independent of EDID-decode core logic.

May I propose something which might be able to keep both the 
expectations maintained upto a certain point, and does solve the purpose 
as well ? Please consider this and let me know how does it sounds:

- We add a C wrapper library with following set of functions:
	- parse_edid_init()
	- query_a_particular_info_from_edid()
	- destroy_edid()
- At init, Client app calls the library parse_edid_init() function with 
EDID (file node or raw data), this is when The library layer allocates a 
C struct for this EDID, which has two parts
	- base block stuff,
	- extension blocks stuff,
- The library calls the internal edid-decode core function just to parse 
EDID, and get the edid-state, and then fills this C structure with all 
the information from edid-state.
- The library caches the C structure for the EDID, and gives user an 
identifier for this EDID.
- At a later stage, when this client tries to extract a particular 
infomration from EDID (like does this display support YCBCR420), the 
library identifies the EDID from cached EDID, and extracts the 
information from cached C struct and responds to the caller API.
- During the display disconnection, client calls and asks the library to 
destroy the EDID structures, and it does.

In this way, this library becomes the CPP->C translation layer, and it 
takes all the overheads like, and will use the edid-decode core APIs 
just for parsing the EDID. The edid-decode state remains internal, used 
immediately, and not being exposed to another process.

Will that be something you guys would like to see as a prototype code ?

- Shashank
Hans Verkuil March 9, 2022, 2:45 p.m. UTC | #9
On 3/9/22 15:09, Pekka Paalanen wrote:
> On Tue, 8 Mar 2022 17:36:47 +0100
> Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
> 
>> Hi Pekka,
>>
>> On 3/8/22 15:30, Pekka Paalanen wrote:
>>> On Tue, 8 Mar 2022 13:09:37 +0100
>>> Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
>>>   
>>>> Hi Shashank,
>>>>
>>>> There is no cover letter for this series, so I'll just reply to the
>>>> first patch, but my comments are high-level and not specific to this
>>>> patch.
>>>>
>>>> To be honest, I am not at all convinced that using edid-decode as a
>>>> parser library is the right thing to do. It was never written with that
>>>> in mind.  
>>>
>>> Hi Hans,
>>>
>>> in https://www.spinics.net/lists/linux-media/msg190064.html you wrote:
> 
> ...
> 
>>>> I think edid-decode can function very well as a reference source for
>>>> a real EDID parser since edid-decode is very complete, but not as a
>>>> EDID parser library.  
>>>
>>> It would be a shame to have to fork edid-decode into something else and
>>> then play catch-up with the real edid-decode for all times to come. Or
>>> are you perhaps hoping that the fork would eventually completely
>>> supersede the original project and developers would migrate to the new
>>> one?
>>>
>>> It would be really nice to be able to involve the community around
>>> edid-decode to make sure we get the library right, but if the library
>>> is somewhere else, would that happen? Or are we left with yet another
>>> half-written ad hoc EDID parsing code base used by maybe two display
>>> servers?
>>>
>>> Maybe we could at least work on this proposal for a while to see what
>>> it will start to look like before dismissing it?  
>>
>> If you are willing to put in the effort, then I think you would have to
>> first rework the code bit by bit into different layers:
> 
> Hi Hans,
> 
> thanks! If Shashank agrees, we can see how this would start to look
> like. I suppose there would be the occasional patch series sent to this
> mailing list and publicly discussed between me and Shashank while we
> iterate. You could mostly ignore it if you want until the two of us
> need your guidance.

I am generally available on irc (channel #linux-media at irc.oftc.net)
during office hours (CET), so if you want to discuss this a bit more
interactively, then contact me there.

> Even if it turns out that this cannot go into edid-decode upstream, I
> don't think the exercise is going to go to waste. It would be the
> beginnings of a new project.
> 
>> E.g. parse_base_block() would be split into two functions: a parse_base_block()
>> that parses the base block into C structures, and it also does the conformity
>> checks, where the output of that is just written to an internal buffer, as
>> happens today. The --check-inline option functionality would be hard to support,
>> I suspect, but I think it is OK to drop that. I at least rarely use it.
> 
> For --check-inline, maybe, maybe not. open_memstream() is a thing,
> giving us a FILE*. Depending on --check-inline, the FILE* to complain
> to could be either stderr or an internal buffer from open_memstream().
> Or the C++ equivalent.
> 
>> And on top of that there is a print_base_block that produces the human
>> readable output based on the result of the parse_base_block.
>>
>> Later the parse functions can be put in a library which edid-decode uses.
>>
>> It should be possible to do this conversion bit by bit, so it's easier to merge
>> and maintain.
>>
>> But it is a *lot* of work since you will also have to make C headers for all
>> the EDID structures.
> 
> Thank you for the suggestions and warnings. I suspect we shouldn't aim
> to land the first part until we have a good idea of the later parts, so
> that edid-decode does not end up with half a conversion if the later
> parts turn out too messy.

Definitely.

Just to make expectations clear: I'm happy to give advice, and of course review
patches, but I don't have the time to help with the actual coding.

> 
>> Can the library be C++ or do you need C structs only? If C++ is OK, then that
>> will simplify matters.
> 
> The only thing that absolutely must be C is the library public API.
> What I've been imagining so far is that we would have a low-level and a
> high-level API, as I alluded to in my previous email. Other than that,
> I don't know yet.
> 
> Internals are totally fine to keep as C++.

The main reason C++ is used for edid-decode (originally it was written in plain
C) are the STL containers. It's a pain to do that in C.

Creating data structures for the parsed EDID data is definitely going to be
tricky. And remember that e.g. new CTA/DisplayID Data Block types appear
regularly, or new fields are added to existing Data Block types. So this
will need some careful thought.

> 
>> In any case, I think I would like to see a proof-of-concept where the base
>> block parsing is modified in such a way as I described above. If that makes
>> sense, then this can be extended to the other extension blocks. And for the
>> CTA and DisplayID extension blocks you can probably do the conversion one
>> Data Block type at a time.
>>
>> In any case, this series is just not useful as proof-of-concept.
> 
> I agree. A cover letter to set up your expectations would have been in order.
> 
> Btw. how does edid-decode regression testing work? I thought I asked in
> the past, but I can't find my question or answer. I know what
> edid-decode README and test/README says about it, but how does one
> actually run through the tests?

I clone https://github.com/linuxhw/EDID.git, then I have a little create.sh script
located in the checked-out EDID directory:

$ cat create.sh
rm -rf data test x.pl update.sh lst
cp -r ../edid-decode/data .
cp -r ../edid-decode/test .
rm test/README
find Analog Digital data test -type f >lst
cat <<'EOF' >x.pl
while (<>) {
        chomp;
        $f = $_;
        printf("( edid-decode --skip-sha -c -p -n \"$f\" >\"$f.new\" ; mv \"$f.new\" \"$f\" ) &\n");
        if (++$cnt % 5000 == 0) {
                printf("sleep 5;\n");
        }
}
EOF
perl x.pl lst >update.sh

echo >>update.sh
echo 'echo Test for non-ASCII characters:' >>update.sh
echo "git grep '[^ -~]' Analog Digital data" >>update.sh
chmod +x update.sh

rm x.pl lst
------------------------------------------------------

It assumes the edid-decode directory is a sibling directory.

Run this, and it will generate an update.sh script. Then run that in turn
and it will update all EDIDs using the currently installed edid-decode.
Then do 'git add data test' to add the data and test directories, and
'git commit -an' to commit it all (you probably want to make a branch
first).

Then, whenever I make changes to edid-decode I install it and run update.sh
again and check with 'git diff' that the changes are what I expected.

> 
> One thing I'm a little wary of is the edid-decode.js target in the
> Makefile. How do you test that?

Not :-)

Someone else contributed that code, and it worked for him. I really should
try to set something up so I can check it locally.

> 
> On the other hand, if merging into edid-decode does not work, a new
> project could have several benefits if I get to decide:
> 
> - Meson build system
> - automated test suite in the project
> - Gitlab workflow hosted by freedesktop.org
> - CI
> 
> I must admit it is really tempting, but I'm scared of the amount of
> work needed to establish a new project.
> 
> I assume you are not interested in any of that in the current upstream
> project, are you?

It's currently too small of a project for Meson, but if this library thing
becomes a reality, then that makes sense.

Better automated testing is always welcome. I don't want to move it to
freedesktop, mostly because as media kernel developer I do all my work
on linuxtv.org. So as long as I remain maintainer that's unlikely to change.

CI is already done: it's build every day together with the kernel media code
and v4l-utils in my daily build. Results of that are posted on the linux-media
mailinglist.

Regards,

	Hans
Pekka Paalanen March 9, 2022, 3:41 p.m. UTC | #10
On Wed, 9 Mar 2022 15:31:11 +0100
"Sharma, Shashank" <shashank.sharma@amd.com> wrote:

> Hello Hans, Pekka,
> 
> Thank you for providing your feedbacks on the first level draft of the 
> library, and for your inputs.
> 
> On 3/9/2022 3:09 PM, Pekka Paalanen wrote:
> > Hi Hans,
> > 
> > thanks! If Shashank agrees, we can see how this would start to look
> > like. I suppose there would be the occasional patch series sent to this
> > mailing list and publicly discussed between me and Shashank while we
> > iterate. You could mostly ignore it if you want until the two of us
> > need your guidance.
> > 
> > Even if it turns out that this cannot go into edid-decode upstream, I
> > don't think the exercise is going to go to waste. It would be the
> > beginnings of a new project.  
> 
> Based on what I could understand from the discussion so far, I could see 
> that we have some basic requirements which are suggested by both of you, 
> like:
> 
> - We want to keep the current structure of EDID-decode as unchanged as 
> possible, and want to keep the C++ states internal.
> - We want to make sure that the new library (if any) is C API, and apart 
> from parsing the EDID, should be independent of EDID-decode core logic.
> 
> May I propose something which might be able to keep both the 
> expectations maintained upto a certain point, and does solve the purpose 
> as well ? Please consider this and let me know how does it sounds:
> 
> - We add a C wrapper library with following set of functions:
> 	- parse_edid_init()
> 	- query_a_particular_info_from_edid()
> 	- destroy_edid()
> - At init, Client app calls the library parse_edid_init() function with 
> EDID (file node or raw data), this is when The library layer allocates a 
> C struct for this EDID, which has two parts
> 	- base block stuff,
> 	- extension blocks stuff,
> - The library calls the internal edid-decode core function just to parse 
> EDID, and get the edid-state, and then fills this C structure with all 
> the information from edid-state.
> - The library caches the C structure for the EDID, and gives user an 
> identifier for this EDID.
> - At a later stage, when this client tries to extract a particular 
> infomration from EDID (like does this display support YCBCR420), the 
> library identifies the EDID from cached EDID, and extracts the 
> information from cached C struct and responds to the caller API.
> - During the display disconnection, client calls and asks the library to 
> destroy the EDID structures, and it does.
> 
> In this way, this library becomes the CPP->C translation layer, and it 
> takes all the overheads like, and will use the edid-decode core APIs 
> just for parsing the EDID. The edid-decode state remains internal, used 
> immediately, and not being exposed to another process.
> 
> Will that be something you guys would like to see as a prototype code ?

Hi Shashank,

from what I understood from Hans, edid-state structure just does not
contain most of the information the library would need to deliver. So
this won't work. You cannot just "wrap" edid-decode, because it does
not store all the information it parsed, it only prints it.

Try with the monitor make, model and serial number strings first to see
for yourself, e.g. "Display Product Name" entry.

I do not understand why "identifier for EDID" and searching instead of
just a plain opaque pointer. Like fopen() gives you a FILE* and then
it's up to you to fclose() it when you're done. The FILE* is not an
identifier or a handle, it's a pointer to some data structure whose
contents you must not access directly (the pointer is opaque).


Thanks,
pq
Pekka Paalanen March 9, 2022, 3:57 p.m. UTC | #11
On Wed, 9 Mar 2022 15:45:29 +0100
Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:

> On 3/9/22 15:09, Pekka Paalanen wrote:
> > On Tue, 8 Mar 2022 17:36:47 +0100
> > Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
> >   
> >> Hi Pekka,
> >>
> >> On 3/8/22 15:30, Pekka Paalanen wrote:  
> >>> On Tue, 8 Mar 2022 13:09:37 +0100
> >>> Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
> >>>     
> >>>> Hi Shashank,
> >>>>
> >>>> There is no cover letter for this series, so I'll just reply to the
> >>>> first patch, but my comments are high-level and not specific to this
> >>>> patch.
> >>>>
> >>>> To be honest, I am not at all convinced that using edid-decode as a
> >>>> parser library is the right thing to do. It was never written with that
> >>>> in mind.    
> >>>
> >>> Hi Hans,
> >>>
> >>> in https://www.spinics.net/lists/linux-media/msg190064.html you wrote:  
> > 
> > ...
> >   
> >>>> I think edid-decode can function very well as a reference source for
> >>>> a real EDID parser since edid-decode is very complete, but not as a
> >>>> EDID parser library.    
> >>>
> >>> It would be a shame to have to fork edid-decode into something else and
> >>> then play catch-up with the real edid-decode for all times to come. Or
> >>> are you perhaps hoping that the fork would eventually completely
> >>> supersede the original project and developers would migrate to the new
> >>> one?
> >>>
> >>> It would be really nice to be able to involve the community around
> >>> edid-decode to make sure we get the library right, but if the library
> >>> is somewhere else, would that happen? Or are we left with yet another
> >>> half-written ad hoc EDID parsing code base used by maybe two display
> >>> servers?
> >>>
> >>> Maybe we could at least work on this proposal for a while to see what
> >>> it will start to look like before dismissing it?    
> >>
> >> If you are willing to put in the effort, then I think you would have to
> >> first rework the code bit by bit into different layers:  
> > 
> > Hi Hans,
> > 
> > thanks! If Shashank agrees, we can see how this would start to look
> > like. I suppose there would be the occasional patch series sent to this
> > mailing list and publicly discussed between me and Shashank while we
> > iterate. You could mostly ignore it if you want until the two of us
> > need your guidance.  
> 
> I am generally available on irc (channel #linux-media at irc.oftc.net)
> during office hours (CET), so if you want to discuss this a bit more
> interactively, then contact me there.

Cool, I'm on EET.

> Just to make expectations clear: I'm happy to give advice, and of course review
> patches, but I don't have the time to help with the actual coding.

That is what I was hoping for, thanks!

> The main reason C++ is used for edid-decode (originally it was written in plain
> C) are the STL containers. It's a pain to do that in C.
> 
> Creating data structures for the parsed EDID data is definitely going to be
> tricky. And remember that e.g. new CTA/DisplayID Data Block types appear
> regularly, or new fields are added to existing Data Block types. So this
> will need some careful thought.

Right.

> > Btw. how does edid-decode regression testing work? I thought I asked in
> > the past, but I can't find my question or answer. I know what
> > edid-decode README and test/README says about it, but how does one
> > actually run through the tests?  
> 
> I clone https://github.com/linuxhw/EDID.git, then I have a little create.sh script
> located in the checked-out EDID directory:
> 
> $ cat create.sh
> rm -rf data test x.pl update.sh lst
> cp -r ../edid-decode/data .
> cp -r ../edid-decode/test .
> rm test/README
> find Analog Digital data test -type f >lst
> cat <<'EOF' >x.pl
> while (<>) {
>         chomp;
>         $f = $_;
>         printf("( edid-decode --skip-sha -c -p -n \"$f\" >\"$f.new\" ; mv \"$f.new\" \"$f\" ) &\n");
>         if (++$cnt % 5000 == 0) {
>                 printf("sleep 5;\n");
>         }
> }
> EOF
> perl x.pl lst >update.sh
> 
> echo >>update.sh
> echo 'echo Test for non-ASCII characters:' >>update.sh
> echo "git grep '[^ -~]' Analog Digital data" >>update.sh
> chmod +x update.sh
> 
> rm x.pl lst
> ------------------------------------------------------
> 
> It assumes the edid-decode directory is a sibling directory.
> 
> Run this, and it will generate an update.sh script. Then run that in turn
> and it will update all EDIDs using the currently installed edid-decode.
> Then do 'git add data test' to add the data and test directories, and
> 'git commit -an' to commit it all (you probably want to make a branch
> first).
> 
> Then, whenever I make changes to edid-decode I install it and run update.sh
> again and check with 'git diff' that the changes are what I expected.

Thanks for explaining.

Shashank, I think you need to use this testing procedure routinely to
make sure your patches do not change edid-decode behaviour, at least
with a sub-set of the EDID files.

> > 
> > One thing I'm a little wary of is the edid-decode.js target in the
> > Makefile. How do you test that?  
> 
> Not :-)
> 
> Someone else contributed that code, and it worked for him. I really should
> try to set something up so I can check it locally.

Do you mind if we won't be testing that either?

> > 
> > On the other hand, if merging into edid-decode does not work, a new
> > project could have several benefits if I get to decide:
> > 
> > - Meson build system
> > - automated test suite in the project
> > - Gitlab workflow hosted by freedesktop.org
> > - CI
> > 
> > I must admit it is really tempting, but I'm scared of the amount of
> > work needed to establish a new project.
> > 
> > I assume you are not interested in any of that in the current upstream
> > project, are you?  
> 
> It's currently too small of a project for Meson, but if this library thing
> becomes a reality, then that makes sense.
> 
> Better automated testing is always welcome.

Those are great to hear!

> I don't want to move it to
> freedesktop, mostly because as media kernel developer I do all my work
> on linuxtv.org. So as long as I remain maintainer that's unlikely to change.

Of course.

> CI is already done: it's build every day together with the kernel media code
> and v4l-utils in my daily build. Results of that are posted on the linux-media
> mailinglist.

Nice, but that is after merging patches, right? I was thinking
pre-merge.


Thanks,
pq
Hans Verkuil March 9, 2022, 4 p.m. UTC | #12
Hi Pekka,

On 3/9/22 16:57, Pekka Paalanen wrote:
> On Wed, 9 Mar 2022 15:45:29 +0100
> Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
> 
>> On 3/9/22 15:09, Pekka Paalanen wrote:
>>> On Tue, 8 Mar 2022 17:36:47 +0100
>>> Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
>>>   
>>>> Hi Pekka,
>>>>
>>>> On 3/8/22 15:30, Pekka Paalanen wrote:  
>>>>> On Tue, 8 Mar 2022 13:09:37 +0100
>>>>> Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
>>>>>     
>>>>>> Hi Shashank,
>>>>>>
>>>>>> There is no cover letter for this series, so I'll just reply to the
>>>>>> first patch, but my comments are high-level and not specific to this
>>>>>> patch.
>>>>>>
>>>>>> To be honest, I am not at all convinced that using edid-decode as a
>>>>>> parser library is the right thing to do. It was never written with that
>>>>>> in mind.    
>>>>>
>>>>> Hi Hans,
>>>>>
>>>>> in https://www.spinics.net/lists/linux-media/msg190064.html you wrote:  
>>>
>>> ...
>>>   
>>>>>> I think edid-decode can function very well as a reference source for
>>>>>> a real EDID parser since edid-decode is very complete, but not as a
>>>>>> EDID parser library.    
>>>>>
>>>>> It would be a shame to have to fork edid-decode into something else and
>>>>> then play catch-up with the real edid-decode for all times to come. Or
>>>>> are you perhaps hoping that the fork would eventually completely
>>>>> supersede the original project and developers would migrate to the new
>>>>> one?
>>>>>
>>>>> It would be really nice to be able to involve the community around
>>>>> edid-decode to make sure we get the library right, but if the library
>>>>> is somewhere else, would that happen? Or are we left with yet another
>>>>> half-written ad hoc EDID parsing code base used by maybe two display
>>>>> servers?
>>>>>
>>>>> Maybe we could at least work on this proposal for a while to see what
>>>>> it will start to look like before dismissing it?    
>>>>
>>>> If you are willing to put in the effort, then I think you would have to
>>>> first rework the code bit by bit into different layers:  
>>>
>>> Hi Hans,
>>>
>>> thanks! If Shashank agrees, we can see how this would start to look
>>> like. I suppose there would be the occasional patch series sent to this
>>> mailing list and publicly discussed between me and Shashank while we
>>> iterate. You could mostly ignore it if you want until the two of us
>>> need your guidance.  
>>
>> I am generally available on irc (channel #linux-media at irc.oftc.net)
>> during office hours (CET), so if you want to discuss this a bit more
>> interactively, then contact me there.
> 
> Cool, I'm on EET.
> 
>> Just to make expectations clear: I'm happy to give advice, and of course review
>> patches, but I don't have the time to help with the actual coding.
> 
> That is what I was hoping for, thanks!
> 
>> The main reason C++ is used for edid-decode (originally it was written in plain
>> C) are the STL containers. It's a pain to do that in C.
>>
>> Creating data structures for the parsed EDID data is definitely going to be
>> tricky. And remember that e.g. new CTA/DisplayID Data Block types appear
>> regularly, or new fields are added to existing Data Block types. So this
>> will need some careful thought.
> 
> Right.
> 
>>> Btw. how does edid-decode regression testing work? I thought I asked in
>>> the past, but I can't find my question or answer. I know what
>>> edid-decode README and test/README says about it, but how does one
>>> actually run through the tests?  
>>
>> I clone https://github.com/linuxhw/EDID.git, then I have a little create.sh script
>> located in the checked-out EDID directory:
>>
>> $ cat create.sh
>> rm -rf data test x.pl update.sh lst
>> cp -r ../edid-decode/data .
>> cp -r ../edid-decode/test .
>> rm test/README
>> find Analog Digital data test -type f >lst
>> cat <<'EOF' >x.pl
>> while (<>) {
>>         chomp;
>>         $f = $_;
>>         printf("( edid-decode --skip-sha -c -p -n \"$f\" >\"$f.new\" ; mv \"$f.new\" \"$f\" ) &\n");
>>         if (++$cnt % 5000 == 0) {
>>                 printf("sleep 5;\n");
>>         }
>> }
>> EOF
>> perl x.pl lst >update.sh
>>
>> echo >>update.sh
>> echo 'echo Test for non-ASCII characters:' >>update.sh
>> echo "git grep '[^ -~]' Analog Digital data" >>update.sh
>> chmod +x update.sh
>>
>> rm x.pl lst
>> ------------------------------------------------------
>>
>> It assumes the edid-decode directory is a sibling directory.
>>
>> Run this, and it will generate an update.sh script. Then run that in turn
>> and it will update all EDIDs using the currently installed edid-decode.
>> Then do 'git add data test' to add the data and test directories, and
>> 'git commit -an' to commit it all (you probably want to make a branch
>> first).
>>
>> Then, whenever I make changes to edid-decode I install it and run update.sh
>> again and check with 'git diff' that the changes are what I expected.
> 
> Thanks for explaining.
> 
> Shashank, I think you need to use this testing procedure routinely to
> make sure your patches do not change edid-decode behaviour, at least
> with a sub-set of the EDID files.
> 
>>>
>>> One thing I'm a little wary of is the edid-decode.js target in the
>>> Makefile. How do you test that?  
>>
>> Not :-)
>>
>> Someone else contributed that code, and it worked for him. I really should
>> try to set something up so I can check it locally.
> 
> Do you mind if we won't be testing that either?

That's fine.

> 
>>>
>>> On the other hand, if merging into edid-decode does not work, a new
>>> project could have several benefits if I get to decide:
>>>
>>> - Meson build system
>>> - automated test suite in the project
>>> - Gitlab workflow hosted by freedesktop.org
>>> - CI
>>>
>>> I must admit it is really tempting, but I'm scared of the amount of
>>> work needed to establish a new project.
>>>
>>> I assume you are not interested in any of that in the current upstream
>>> project, are you?  
>>
>> It's currently too small of a project for Meson, but if this library thing
>> becomes a reality, then that makes sense.
>>
>> Better automated testing is always welcome.
> 
> Those are great to hear!
> 
>> I don't want to move it to
>> freedesktop, mostly because as media kernel developer I do all my work
>> on linuxtv.org. So as long as I remain maintainer that's unlikely to change.
> 
> Of course.
> 
>> CI is already done: it's build every day together with the kernel media code
>> and v4l-utils in my daily build. Results of that are posted on the linux-media
>> mailinglist.
> 
> Nice, but that is after merging patches, right? I was thinking
> pre-merge.

Not sure what useful pre-merge testing can be done other than just running 'make' :-)

Regards,

	Hans

> 
> 
> Thanks,
> pq
Pekka Paalanen March 10, 2022, 12:52 p.m. UTC | #13
On Wed, 9 Mar 2022 17:00:37 +0100
Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:

> Hi Pekka,
> 
> On 3/9/22 16:57, Pekka Paalanen wrote:
> > On Wed, 9 Mar 2022 15:45:29 +0100
> > Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
> >   

...

> >> CI is already done: it's build every day together with the kernel media code
> >> and v4l-utils in my daily build. Results of that are posted on the linux-media
> >> mailinglist.  
> > 
> > Nice, but that is after merging patches, right? I was thinking
> > pre-merge.  
> 
> Not sure what useful pre-merge testing can be done other than just running 'make' :-)

To ensure that patches that are not intended to change the output
indeed do not change the output, or do not introduce crashes. Other
popular tests are checking for compiler warnings against a specific
compiler version, and commit messages e.g. for S-o-b if that's used.

For example wayland-scanner (a code generator) has tests in the Wayland
test suite that verify the output for certain test inputs does not
change. The test inputs and reference outputs are committed into git.
If a patch intentionally changes the output, then that patch also
includes changes to the reference output files. Simply reading a patch
will also show how the output changed.

But your test corpus is huge, and this method does not scale up to that
directly. You could maybe have a few chosen test EDIDs for this, but
running the full corpus needs something quite different. Maybe the full
corpus is best the way you do it now.


Thanks,
pq
Pekka Paalanen April 13, 2022, 10:40 a.m. UTC | #14
On Tue, 8 Mar 2022 13:09:37 +0100
Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:

> Hi Shashank,
> 
> There is no cover letter for this series, so I'll just reply to the
> first patch, but my comments are high-level and not specific to this
> patch.
> 
> To be honest, I am not at all convinced that using edid-decode as a
> parser library is the right thing to do. It was never written with that
> in mind. The two purposes of edid-decode are to:
> 
> 1) Convert the EDID to a human readable text, and
> 2) Verify if the EDID conforms to the various standards and is internally
>    consistent.
> 
> As a result the state information that edid-decode stores is just the
> state that it needs to check conformity across Extension Blocks and/or
> Data Blocks. Most of the parsed data is just printed to stdout and checked
> and then forgotten.
> 
> I have considered if it would make sense to make a library to parse and
> store the EDID data and have edid-decode sit on top of that, but that will
> make the conformity tests much harder. It's kind of interwoven with the
> parsing and a parser library is really not interested in that anyway.
> 
> I think edid-decode can function very well as a reference source for
> a real EDID parser since edid-decode is very complete, but not as a
> EDID parser library.
> 

Hi all,

since this discussion, more people have joined the effort and the
consensus became to start a new project instead of pushing to
edid-decode upstream.

The new project is at
https://gitlab.freedesktop.org/emersion/libdisplay-info
where we are currently discussing what the API should look like in the
issues and merge request comments, so there is essentially no code yet.

If the project gains enough traction, I expect it will be moved into a
non-personal namespace under fd.o to live a life of its own.


Thanks,
pq
diff mbox series

Patch

diff --git a/Makefile b/Makefile
index 1843700..ebf3370 100644
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,20 @@ 
 ifeq ($(OS),Windows_NT)
 	bindir ?= /usr/bin
 	mandir ?= /usr/share/man
+	libdir ?= /usr/lib
+	includedir ?= /usr/include
 else
 	UNAME_S := $(shell uname -s)
 	ifeq ($(UNAME_S),Darwin)
 		bindir ?= /usr/local/sbin
 		mandir ?= /usr/local/share/man
+		libdir ?= /usr/local/lib
+		includedir ?= /usr/include
 	else
 		bindir ?= /usr/bin
 		mandir ?= /usr/share/man
+		libdir ?= /usr/lib
+		includedir ?= /usr/include
 	endif
 endif
 
@@ -19,6 +25,11 @@  SOURCES = edid-decode.cpp parse-base-block.cpp parse-cta-block.cpp \
 	  parse-di-ext-block.cpp parse-vtb-ext-block.cpp calc-gtf-cvt.cpp
 WARN_FLAGS = -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -Wimplicit-fallthrough
 
+LIB_NAME = libedid-decode.so
+LIB_FLAGS = -fPIC
+LIBLINK_FLAGS = -shared
+LIB_SOURCES = libedid-decode-api.cpp
+
 all: edid-decode
 
 sha = -DSHA=$(shell if test -d .git ; then git rev-parse --short=12 HEAD ; fi)
@@ -30,11 +41,20 @@  edid-decode: $(SOURCES) edid-decode.h oui.h Makefile
 edid-decode.js: $(SOURCES) edid-decode.h oui.h Makefile
 	$(EMXX) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(WARN_FLAGS) $(sha) $(date) -s EXPORTED_FUNCTIONS='["_parse_edid"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' -o $@ $(SOURCES) -lm
 
+libedid-decode: $(SOURCES) edid-decode.h oui.h Makefile
+	$(CXX) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(WARN_FLAGS) -g $(LIB_FLAGS) $(sha) $(date) $(LIBLINK_FLAGS) -o $(LIB_NAME) $(LIB_SOURCES) $(SOURCES) -lm
+
 clean:
-	rm -f edid-decode
+	rm -f edid-decode libedid-decode.so
 
 install:
 	mkdir -p $(DESTDIR)$(bindir)
 	install -m 0755 edid-decode $(DESTDIR)$(bindir)
 	mkdir -p $(DESTDIR)$(mandir)/man1
 	install -m 0644 edid-decode.1 $(DESTDIR)$(mandir)/man1
+
+install-lib:
+	mkdir -p $(DESTDIR)$(libdir)
+	mkdir -p $(DESTDIR)$(includedir)
+	install -m 0755 libedid-decode.so $(DESTDIR)$(libdir)
+	install -m 0644 libedid-decode-api.h $(DESTDIR)$(includedir)
diff --git a/edid-decode.cpp b/edid-decode.cpp
index 4a90aba..babff4a 100644
--- a/edid-decode.cpp
+++ b/edid-decode.cpp
@@ -21,7 +21,7 @@ 
 #define STR(x) #x
 #define STRING(x) STR(x)
 
-static edid_state state;
+edid_state state;
 
 static unsigned char edid[EDID_PAGE_SIZE * EDID_MAX_BLOCKS];
 static bool odd_hex_digits;
@@ -1012,6 +1012,19 @@  static bool extract_edid(int fd, FILE *error)
 	state.edid_size = edid_data.size();
 	return true;
 }
+struct edid_state *extract_edid_state(int fd, FILE *error)
+{
+	bool ret;
+
+	ret = extract_edid(fd, error);
+	if (ret) {
+		/* update the number of blocks */
+		state.num_blocks = state.edid_size / EDID_PAGE_SIZE;
+		return &state;
+	}
+
+	return NULL;
+}
 
 static unsigned char crc_calc(const unsigned char *b)
 {