All of lore.kernel.org
 help / color / mirror / Atom feed
* [GIT PULL] ViewCast O820E capture support added
@ 2012-08-12 23:16 Steven Toth
  2012-08-13 14:04 ` Hans Verkuil
  0 siblings, 1 reply; 18+ messages in thread
From: Steven Toth @ 2012-08-12 23:16 UTC (permalink / raw)
  To: Linux-Media; +Cc: Mauro Chehab

Hi Mauro,

A new PCIe bridge driver below. It was released a couple of months ago
to the public, probably about time
we got this into the request queue. I'll review the linux-firmware
additions shortly, I have a firmware blob
and flexible license for the distros.

The following changes since commit da2cd767f537082be0a02d83f87e0da4270e25b2:

  [media] ttpci: add support for Omicom S2 PCI (2012-08-12 14:41:26 -0300)

are available in the git repository at:
  git://git.kernellabs.com/stoth/media_tree.git o820e

Steven Toth (1):
      [media] vc8x0: Add support for the ViewCast O820E card.

 drivers/media/video/Kconfig                 |    2 +
 drivers/media/video/Makefile                |    1 +
 drivers/media/video/vc8x0/Kconfig           |   14 +
 drivers/media/video/vc8x0/Makefile          |   10 +
 drivers/media/video/vc8x0/vc8x0-ad7441.c    | 3057 +++++++++++++++++++++++++++
 drivers/media/video/vc8x0/vc8x0-audio.c     |  736 +++++++
 drivers/media/video/vc8x0/vc8x0-buffer.c    |  338 +++
 drivers/media/video/vc8x0/vc8x0-cards.c     |  138 ++
 drivers/media/video/vc8x0/vc8x0-channel.c   |  934 ++++++++
 drivers/media/video/vc8x0/vc8x0-core.c      |  887 ++++++++
 drivers/media/video/vc8x0/vc8x0-display.c   | 1359 ++++++++++++
 drivers/media/video/vc8x0/vc8x0-dma.c       | 2677 +++++++++++++++++++++++
 drivers/media/video/vc8x0/vc8x0-eeprom.c    |   71 +
 drivers/media/video/vc8x0/vc8x0-fw.c        |  429 ++++
 drivers/media/video/vc8x0/vc8x0-i2c.c       |  290 +++
 drivers/media/video/vc8x0/vc8x0-pcm3052.c   |  192 ++
 drivers/media/video/vc8x0/vc8x0-reg.h       |  214 ++
 drivers/media/video/vc8x0/vc8x0-timestamp.c |  156 ++
 drivers/media/video/vc8x0/vc8x0-vga.c       |  430 ++++
 drivers/media/video/vc8x0/vc8x0-video.c     | 2650 +++++++++++++++++++++++
 drivers/media/video/vc8x0/vc8x0.h           |  995 +++++++++
 21 files changed, 15580 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/vc8x0/Kconfig
 create mode 100644 drivers/media/video/vc8x0/Makefile
 create mode 100644 drivers/media/video/vc8x0/vc8x0-ad7441.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-audio.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-buffer.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-cards.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-channel.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-core.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-display.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-dma.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-eeprom.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-fw.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-i2c.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-pcm3052.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-reg.h
 create mode 100644 drivers/media/video/vc8x0/vc8x0-timestamp.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-vga.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0-video.c
 create mode 100644 drivers/media/video/vc8x0/vc8x0.h

Regards,

- Steve

-- 
Steven Toth - Kernel Labs
http://www.kernellabs.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-08-12 23:16 [GIT PULL] ViewCast O820E capture support added Steven Toth
@ 2012-08-13 14:04 ` Hans Verkuil
  2012-08-13 14:46   ` Steven Toth
  0 siblings, 1 reply; 18+ messages in thread
From: Hans Verkuil @ 2012-08-13 14:04 UTC (permalink / raw)
  To: Steven Toth; +Cc: Linux-Media, Mauro Chehab

Hi Steve!

On Mon August 13 2012 01:16:30 Steven Toth wrote:
> Hi Mauro,
> 
> A new PCIe bridge driver below. It was released a couple of months ago
> to the public, probably about time
> we got this into the request queue. I'll review the linux-firmware
> additions shortly, I have a firmware blob
> and flexible license for the distros.

I went through this driver from a high-level point of view, and I'm afraid I
have quite a number of issues with this driver.

One of the bigger ones is that vc8x0-ad7441.c should be implemented as
a subdevice. I have two other AD drivers in my queue (adv7604 and ad9389b),
so you can look at those for comparison.

See: http://www.spinics.net/lists/linux-media/msg51501.html

These Analog Devices chips are quite complex, and you really want to be able
to reuse drivers.

Some of the other issues are:

- Please use the control framework. All new drivers must use it, unless there
  are very, very good reasons not to. I'm gradually converting all drivers to
  the control framework, so I really don't want to introduce new drivers to
  that list.

- TRY_FMT can actually set the format, something that should never happen.

- Use the new DV_TIMINGS ioctls for the HDTV formats. S_FMT should not be used
  to select the HDTV format!

- The procfs additions seem unnecessary to me. VIDIOC_LOG_STATUS or perhaps
  debugfs are probably much more suitable.

- Using videobuf2 is very much recommended.

- Please run v4l2-compliance and fix any reported issues!

It's a pretty big driver, so I only looked skimmed the patch, but these are
IMHO fairly major issues. As it stands it is only suitable to be merged in
drivers/staging/media.

Regards,

	Hans

> 
> The following changes since commit da2cd767f537082be0a02d83f87e0da4270e25b2:
> 
>   [media] ttpci: add support for Omicom S2 PCI (2012-08-12 14:41:26 -0300)
> 
> are available in the git repository at:
>   git://git.kernellabs.com/stoth/media_tree.git o820e
> 
> Steven Toth (1):
>       [media] vc8x0: Add support for the ViewCast O820E card.
> 
>  drivers/media/video/Kconfig                 |    2 +
>  drivers/media/video/Makefile                |    1 +
>  drivers/media/video/vc8x0/Kconfig           |   14 +
>  drivers/media/video/vc8x0/Makefile          |   10 +
>  drivers/media/video/vc8x0/vc8x0-ad7441.c    | 3057 +++++++++++++++++++++++++++
>  drivers/media/video/vc8x0/vc8x0-audio.c     |  736 +++++++
>  drivers/media/video/vc8x0/vc8x0-buffer.c    |  338 +++
>  drivers/media/video/vc8x0/vc8x0-cards.c     |  138 ++
>  drivers/media/video/vc8x0/vc8x0-channel.c   |  934 ++++++++
>  drivers/media/video/vc8x0/vc8x0-core.c      |  887 ++++++++
>  drivers/media/video/vc8x0/vc8x0-display.c   | 1359 ++++++++++++
>  drivers/media/video/vc8x0/vc8x0-dma.c       | 2677 +++++++++++++++++++++++
>  drivers/media/video/vc8x0/vc8x0-eeprom.c    |   71 +
>  drivers/media/video/vc8x0/vc8x0-fw.c        |  429 ++++
>  drivers/media/video/vc8x0/vc8x0-i2c.c       |  290 +++
>  drivers/media/video/vc8x0/vc8x0-pcm3052.c   |  192 ++
>  drivers/media/video/vc8x0/vc8x0-reg.h       |  214 ++
>  drivers/media/video/vc8x0/vc8x0-timestamp.c |  156 ++
>  drivers/media/video/vc8x0/vc8x0-vga.c       |  430 ++++
>  drivers/media/video/vc8x0/vc8x0-video.c     | 2650 +++++++++++++++++++++++
>  drivers/media/video/vc8x0/vc8x0.h           |  995 +++++++++
>  21 files changed, 15580 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/media/video/vc8x0/Kconfig
>  create mode 100644 drivers/media/video/vc8x0/Makefile
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-ad7441.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-audio.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-buffer.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-cards.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-channel.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-core.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-display.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-dma.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-eeprom.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-fw.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-i2c.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-pcm3052.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-reg.h
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-timestamp.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-vga.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0-video.c
>  create mode 100644 drivers/media/video/vc8x0/vc8x0.h
> 
> Regards,
> 
> - Steve
> 
> 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-08-13 14:04 ` Hans Verkuil
@ 2012-08-13 14:46   ` Steven Toth
  2012-08-13 15:49     ` Hans Verkuil
  0 siblings, 1 reply; 18+ messages in thread
From: Steven Toth @ 2012-08-13 14:46 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: Linux-Media, Mauro Chehab

Hans,

Thanks for your feedback.

Oh dear. I don't think you're going to like my response, but I think
we know each other well enough to realize that neither of us are
trying to antagonize or upset either other. We're simply stating our
positions. Please read on.

> I went through this driver from a high-level point of view, and I'm afraid I
> have quite a number of issues with this driver.
>
> One of the bigger ones is that vc8x0-ad7441.c should be implemented as
> a subdevice. I have two other AD drivers in my queue (adv7604 and ad9389b),
> so you can look at those for comparison.
>
> See: http://www.spinics.net/lists/linux-media/msg51501.html

Oh, I understand how to write video decoder drivers. I just chose
specifically not to do it. This was intensional on my part. If when
another card comes along with an ad7441 when they are welcome to split
the code and/or create the subdevs. It's extra engineering today that
does't improve the support for the 820 card and doesn't benefit any
other known product. It's a feature that's exclusive to the 820.
Future developers are welcome to fork, slice and/or copy the code.

Today, the driver is tuned exactly for the card, it works very nicely
for end users and the code is easy to read, simple to debug and relies
on only a handful of v4l2 framework apis.

If anyone knew how much time and suffering I've had with the cx25840
over the years, why I think has gotten worse with the subdev controls,
you'd be shocked. The subdev framework (in my opinion) has become
unwieldily and difficult to debug, based on my recent experience
dealing with some cx23885 issues. I'm intensionally trying not to use
it.

I should be clear, my comments are not mean to antagonize or inflame,
I'm simply pointing out that when at all possible I chose not to use
the subdev framework because if it's delays and difficulties when it
comes to debugging.

When did the subdev framework become a mandatory requirement for any
driver merge?

>
> These Analog Devices chips are quite complex, and you really want to be able
> to reuse drivers.

I am certainly more than willing to discuss re-use, when re-use make
sense. Right now we have no-practical re-use for this part to speak
of. The code is targeted towards the 820, in the use case that end
users need. If someone would like to build a ad7441 subdevice and use
that in their driver then they are welcome to the code. In practise,
sharing complex video decoders across driver designs leads to massive
regressions, as witnessed on the list this year.

I am also aware that the cx25840 driver is complex, and the end result
was that driver maintainers effectively forked the cx25840 and brought
the codebase back into their core drivers (cx18 for example), to avoid
issues where regression testing was troublesome across so many cards.
If I had the time and/or energy, we'd do the same with the cx25840.
Keeping complex code close to the PCI/PCIe bridge bring big dividends
when debugging complex problems and mitigating issues where code is
re-used across multiple products (growing any regression test
requirements).

The entire driver was intensionally written to be self-enclosed,
highly portable between 2.6.3x and v3.x kernels without subdev
breakages and/or api changes. With a small external Makefile it even
builds very nicely outside of the kernel on any kernel you like, that
shipped in the last 2-3 years.

>
> Some of the other issues are:
>
> - Please use the control framework. All new drivers must use it, unless there
>   are very, very good reasons not to. I'm gradually converting all drivers to
>   the control framework, so I really don't want to introduce new drivers to
>   that list.

I think the control framework is a great design, it's just too
difficult to debug and when I go near it - it breaks, or I spend an
hour trying to understand why my subdev call doesn't reach the subdev
device. My comments are not designed to inflame or upset you, I'm
simply pointing out that any work I've done recently (on two new PCIe
bridges - unreleased code) I've decided not to use it.

Again, I specifically chosen to isolate this driver from certain key
areas of the (now enormous) v4l2 infrastructure.

>
> - TRY_FMT can actually set the format, something that should never happen.

I can check, but I think gstreamer or tvtime actually relies on that behavior.

>
> - Use the new DV_TIMINGS ioctls for the HDTV formats. S_FMT should not be used
>   to select the HDTV format!

gstreamer on 2.6.37 and better didn't support DVTIMINGs. I would
certainly like to discuss adding better timing support once
applications are fully aware and can control the hardware using it.
The lack of a good timin API (and adoption by the application
developers) forced my hand to use S_FMT.

Right now the driver works today, on old and new systems, for hardware
that's shipping. It satisfies end user needs.

>
> - The procfs additions seem unnecessary to me. VIDIOC_LOG_STATUS or perhaps
>   debugfs are probably much more suitable.

I agree. It can probably be removed altogether.

>
> - Using videobuf2 is very much recommended.

I went with what I know to be honest. I neither agree nor disagree
with your comments. If videobuf2 is supported on 2.6.3x then this is
good news.

>
> - Please run v4l2-compliance and fix any reported issues!
>
> It's a pretty big driver, so I only looked skimmed the patch, but these are
> IMHO fairly major issues. As it stands it is only suitable to be merged in
> drivers/staging/media.

I'm not sure I agree. I think I don't agree in general that subdev and
the control framework is mandatory for any driver. I think they are
accelerator frameworks designed to help. I my case I don't think they
do. So I avoided using them.

I guess Mauro has the final decision.

-- 
Steven Toth - Kernel Labs
http://www.kernellabs.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-08-13 14:46   ` Steven Toth
@ 2012-08-13 15:49     ` Hans Verkuil
  2012-08-13 17:36       ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 18+ messages in thread
From: Hans Verkuil @ 2012-08-13 15:49 UTC (permalink / raw)
  To: Steven Toth; +Cc: Linux-Media, Mauro Chehab

On Mon August 13 2012 16:46:45 Steven Toth wrote:
> Hans,
> 
> Thanks for your feedback.
> 
> Oh dear. I don't think you're going to like my response, but I think
> we know each other well enough to realize that neither of us are
> trying to antagonize or upset either other. We're simply stating our
> positions. Please read on.

I didn't think you'd like my response either :-)

> > I went through this driver from a high-level point of view, and I'm afraid I
> > have quite a number of issues with this driver.
> >
> > One of the bigger ones is that vc8x0-ad7441.c should be implemented as
> > a subdevice. I have two other AD drivers in my queue (adv7604 and ad9389b),
> > so you can look at those for comparison.
> >
> > See: http://www.spinics.net/lists/linux-media/msg51501.html
> 
> Oh, I understand how to write video decoder drivers. I just chose
> specifically not to do it. This was intensional on my part. If when
> another card comes along with an ad7441 when they are welcome to split
> the code and/or create the subdevs. It's extra engineering today that
> does't improve the support for the 820 card and doesn't benefit any
> other known product. It's a feature that's exclusive to the 820.
> Future developers are welcome to fork, slice and/or copy the code.
> Today, the driver is tuned exactly for the card, it works very nicely
> for end users and the code is easy to read, simple to debug and relies
> on only a handful of v4l2 framework apis.

The problem is that it is very hard, if not impossible, to split something
up after the fact. There are almost no drivers left that still have an
integral i2c driver as opposed to a separate i2c driver. I only know of
a few old ones and at least one in staging (not counting reverse
engineered drivers such as in gspca where there is no choice).

The main advantage is that it is much easier to extend the functionality
of your driver, particularly for devices with a lot of functionality like
those ADV drivers.

> If anyone knew how much time and suffering I've had with the cx25840
> over the years, why I think has gotten worse with the subdev controls,
> you'd be shocked.

As someone who has been heavily involved with the cx25840 I know how you
feel. However, in my opinion that is mostly caused by the cx25840 hardware
itself which is a piece of sh*t. Most other subdevices see much less change
and are not as sensitive to breakage as that one.

> The subdev framework (in my opinion) has become
> unwieldily and difficult to debug, based on my recent experience
> dealing with some cx23885 issues. I'm intensionally trying not to use
> it.

In what respect does the subdev framework make debugging hard? I'd like to
know about it so we can try and improve it.

The subdev framework was made to make reuse possible. If everyone refuses
to use it, then we're back to the bad old times where you get 20
almost-but-not-quite identical i2c driver implementations.

> I should be clear, my comments are not mean to antagonize or inflame,
> I'm simply pointing out that when at all possible I chose not to use
> the subdev framework because if it's delays and difficulties when it
> comes to debugging.
> 
> When did the subdev framework become a mandatory requirement for any
> driver merge?

It is certainly highly recommended, and in my opinion there should be
very good reasons for not doing it. In the end it is Mauro who decides,
although I personally would be in favor of mandating it. Not to pester
people, but it is so much harder to split it up after the fact. Just like
the fact that documentation is now required if a new API is added, because
nobody ever writes documentation afterwards.

> >
> > These Analog Devices chips are quite complex, and you really want to be able
> > to reuse drivers.
> 
> I am certainly more than willing to discuss re-use, when re-use make
> sense. Right now we have no-practical re-use for this part to speak
> of. The code is targeted towards the 820, in the use case that end
> users need. If someone would like to build a ad7441 subdevice and use
> that in their driver then they are welcome to the code. In practise,
> sharing complex video decoders across driver designs leads to massive
> regressions, as witnessed on the list this year.
> 
> I am also aware that the cx25840 driver is complex, and the end result
> was that driver maintainers effectively forked the cx25840 and brought
> the codebase back into their core drivers (cx18 for example), to avoid
> issues where regression testing was troublesome across so many cards.

I don't think the cx18 ever used the cx25840 codebase: while the cx23418
uses a similar IP as the cx25840 there were too many differences to allow
us (actually, I think it was me who wrote it initially for the cx18) to
reuse the cx25840.

That's a general problem, BTW: reuse works well for the exact same chip.
But when you get variants of the chip (or it gets integrated in another chip
as an IP block), then at some point keeping track of those differences and
preventing regressions becomes harder than it would be if they were done as
separate drivers.

Where that boundary is is not always clear, and for the cx25840 we probably
exceeded it.

But sharing a subdevice driver for a single chip among different boards has
never been much of a problem in my experience. I'm not saying we never got
regressions, but not many and they were generally quickly caught.

> If I had the time and/or energy, we'd do the same with the cx25840.
> Keeping complex code close to the PCI/PCIe bridge bring big dividends
> when debugging complex problems and mitigating issues where code is
> re-used across multiple products (growing any regression test
> requirements).
> 
> The entire driver was intensionally written to be self-enclosed,
> highly portable between 2.6.3x and v3.x kernels without subdev
> breakages and/or api changes. With a small external Makefile it even
> builds very nicely outside of the kernel on any kernel you like, that
> shipped in the last 2-3 years.

??? We have the media_build system for that, so why care about older kernels?

> >
> > Some of the other issues are:
> >
> > - Please use the control framework. All new drivers must use it, unless there
> >   are very, very good reasons not to. I'm gradually converting all drivers to
> >   the control framework, so I really don't want to introduce new drivers to
> >   that list.
> 
> I think the control framework is a great design, it's just too
> difficult to debug and when I go near it - it breaks, or I spend an
> hour trying to understand why my subdev call doesn't reach the subdev
> device. My comments are not designed to inflame or upset you, I'm
> simply pointing out that any work I've done recently (on two new PCIe
> bridges - unreleased code) I've decided not to use it.

Ask me if there are problems with the control framework! I'm happy to help out.

I can't fix it, improve it, etc. if I don't here about it.

The reason why all drivers should use it is that is behaves the same for all
drivers, and apps can start to rely on that behavior. If something doesn't work,
and you can't figure it out, then I am more than happy to help.

But I will NACK this driver unless it is using the control framework. Otherwise
I just have to do that later, and I really don't want to. There aren't many
controls in this driver so it should be pretty quick to do it.

In addition, the control framework will make it easy to implement control events,
another thing that should be rolled out to all drivers.

> Again, I specifically chosen to isolate this driver from certain key
> areas of the (now enormous) v4l2 infrastructure.

There is a reason for that infrastructure, you know. Consistent behavior from
the point of view of applications is the most important one. And it actually
takes a lot of work off your hands. Again, if there are questions, then I'm
happy to help out (and possible improve the code or documentation).

> 
> >
> > - TRY_FMT can actually set the format, something that should never happen.
> 
> I can check, but I think gstreamer or tvtime actually relies on that behavior.

Highly unlikely. TRY_FMT should *never* change the actual format. It's been like
that since the very beginning.

> 
> >
> > - Use the new DV_TIMINGS ioctls for the HDTV formats. S_FMT should not be used
> >   to select the HDTV format!
> 
> gstreamer on 2.6.37 and better didn't support DVTIMINGs. I would
> certainly like to discuss adding better timing support once
> applications are fully aware and can control the hardware using it.
> The lack of a good timin API (and adoption by the application
> developers) forced my hand to use S_FMT.

You said that it was in your queue for some time, so it may be that it wasn't
available when you started out. The problem is, the API is now available, and
if drivers do not implement it, then there is also no reason for applications
to use it, isn't it? Chicken and egg.

I will NACK if the driver doesn't add support for it. Otherwise we end up with
some drivers that implement it correctly, and others that use a different
method. No application writer will ever thank us for that.

Also, I didn't go through all the hard work of designing and adding an API and
then see it being ignored in favor of a non-standard solution.

> Right now the driver works today, on old and new systems, for hardware
> that's shipping. It satisfies end user needs.
> 
> >
> > - The procfs additions seem unnecessary to me. VIDIOC_LOG_STATUS or perhaps
> >   debugfs are probably much more suitable.
> 
> I agree. It can probably be removed altogether.
> 
> >
> > - Using videobuf2 is very much recommended.
> 
> I went with what I know to be honest. I neither agree nor disagree
> with your comments. If videobuf2 is supported on 2.6.3x then this is
> good news.

If you use media_build to compile your driver, then everything including vb2
is supported from 2.6.31 onwards (the oldest kernel supported by media_build).

> 
> >
> > - Please run v4l2-compliance and fix any reported issues!
> >
> > It's a pretty big driver, so I only looked skimmed the patch, but these are
> > IMHO fairly major issues. As it stands it is only suitable to be merged in
> > drivers/staging/media.
> 
> I'm not sure I agree. I think I don't agree in general that subdev and
> the control framework is mandatory for any driver. I think they are
> accelerator frameworks designed to help. I my case I don't think they
> do. So I avoided using them.
>
> I guess Mauro has the final decision.

Of course.

BTW, I saw another thing that must be changed: you use the .ioctl file
operation instead of unlocked_ioctl. This is no longer allowed for new
drivers since the removal of the BKL. The v4l2 core implementation of
.ioctl attempts to simulate the old BKL and is very inefficient, in
particular for drivers like this that do not use struct v4l2_device.
If you have multiple ViewCast cards, then all v4l2 ioctls will go through
a single V4L2 core lock, leading to substantial latencies.

See also the comment in v4l2_ioctl() in v4l2_dev.c.

New drivers must use unlocked_ioctl. I am in the (very slow, but steady)
process of fixing any old drivers that still use .ioctl and once all are
converted .ioctl will be removed altogether.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-08-13 15:49     ` Hans Verkuil
@ 2012-08-13 17:36       ` Mauro Carvalho Chehab
  2012-08-14 15:07         ` Steven Toth
  0 siblings, 1 reply; 18+ messages in thread
From: Mauro Carvalho Chehab @ 2012-08-13 17:36 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: Steven Toth, Linux-Media, Mauro Chehab

Em 13-08-2012 12:49, Hans Verkuil escreveu:
> On Mon August 13 2012 16:46:45 Steven Toth wrote:
>> Hans,
>>
>> Thanks for your feedback.
>>
>> Oh dear. I don't think you're going to like my response, but I think
>> we know each other well enough to realize that neither of us are
>> trying to antagonize or upset either other. We're simply stating our
>> positions. Please read on.
> 
> I didn't think you'd like my response either :-)

You probably won't like my answer too, yet I'm also simply 
stating my positions.

> 
>>> I went through this driver from a high-level point of view, and I'm afraid I
>>> have quite a number of issues with this driver.
>>>
>>> One of the bigger ones is that vc8x0-ad7441.c should be implemented as
>>> a subdevice. I have two other AD drivers in my queue (adv7604 and ad9389b),
>>> so you can look at those for comparison.
>>>
>>> See: http://www.spinics.net/lists/linux-media/msg51501.html
>>
>> Oh, I understand how to write video decoder drivers. I just chose
>> specifically not to do it. This was intensional on my part. If when
>> another card comes along with an ad7441 when they are welcome to split
>> the code and/or create the subdevs. It's extra engineering today that
>> does't improve the support for the 820 card and doesn't benefit any
>> other known product. It's a feature that's exclusive to the 820.
>> Future developers are welcome to fork, slice and/or copy the code.
>> Today, the driver is tuned exactly for the card, it works very nicely
>> for end users and the code is easy to read, simple to debug and relies
>> on only a handful of v4l2 framework apis.
> 
> The problem is that it is very hard, if not impossible, to split something
> up after the fact. There are almost no drivers left that still have an
> integral i2c driver as opposed to a separate i2c driver. I only know of
> a few old ones and at least one in staging (not counting reverse
> engineered drivers such as in gspca where there is no choice).
> 
> The main advantage is that it is much easier to extend the functionality
> of your driver, particularly for devices with a lot of functionality like
> those ADV drivers.

Agreed. I also noticed that the I2C code there is currently
highly-coupled with the bridge one. For example, you're setting the DV 
timings via a direct call to vc8x0_ad7441_set_format(), which is a
method of the I2C ad7441 driver (with, btw, is not an independent driver,
but it is part of the same driver).

We only allow such kind of designs as a temporary measure, for drivers
under drivers/staging/media, where the developer is going to fix them
in order to fully use the V4L core, as highly coupled designs like that
are really hard to review, as the interactions between the drivers
aren't at the usual/expected places.

>> Today, the driver is tuned exactly for the card, it works very nicely
>> for end users and the code is easy to read, simple to debug and relies
>> on only a handful of v4l2 framework apis.

It looks easy to read for you, not for me, and likely not for the
others:

 21 files changed, 15580 insertions(+)

A 15000+ lines driver is not easy to read/understand. Having it highly
coupled and not using the core API's, but using something else makes
even harder to understand it.

>> The subdev framework (in my opinion) has become
>> unwieldily and difficult to debug, based on my recent experience
>> dealing with some cx23885 issues. I'm intensionally trying not to use
>> it.
> 
> In what respect does the subdev framework make debugging hard? I'd like to
> know about it so we can try and improve it.
> 
> The subdev framework was made to make reuse possible. If everyone refuses
> to use it, then we're back to the bad old times where you get 20
> almost-but-not-quite identical i2c driver implementations.

>> I should be clear, my comments are not mean to antagonize or inflame,
>> I'm simply pointing out that when at all possible I chose not to use
>> the subdev framework because if it's delays and difficulties when it
>> comes to debugging.
>>
>> When did the subdev framework become a mandatory requirement for any
>> driver merge?

This was always a requirement: complex drivers should be broken into
per-component drivers, in order to make easier to review and to re-use
the code. Even the drivers at Kernel 2.5.x followed that idea, and
we're working hard to simplify drivers code by making them modular
and loosely coupled.

With modular, loosely coupled drivers, a complex logic is broken into
smaller and easier to understand logic.

> It is certainly highly recommended, and in my opinion there should be
> very good reasons for not doing it. In the end it is Mauro who decides,
> although I personally would be in favor of mandating it. Not to pester
> people, but it is so much harder to split it up after the fact. Just like
> the fact that documentation is now required if a new API is added, because
> nobody ever writes documentation afterwards.

I agree. Of course exceptions might apply, if there are really very
good and well accepted reasons for not doing that.

>>> These Analog Devices chips are quite complex, and you really want to be able
>>> to reuse drivers.
>>
>> I am certainly more than willing to discuss re-use, when re-use make
>> sense. Right now we have no-practical re-use for this part to speak
>> of. The code is targeted towards the 820, in the use case that end
>> users need. If someone would like to build a ad7441 subdevice and use
>> that in their driver then they are welcome to the code. In practise,
>> sharing complex video decoders across driver designs leads to massive
>> regressions, as witnessed on the list this year.

Regressions happen even if no re-use is done: core, other parts of the
Kernel and userspace apps changes all the times, causing regressions.
That's called bitrotten[1].

[1] http://en.wikipedia.org/wiki/Bit_rot

One good example is with regards to firmware loading: today's userspace
requirement is that firmware load can't happen during driver's probe. 
All drivers that do that (almost all media drivers with firmware) are
broken (or only loads after timeout - 120 seconds?) with newer udev's,
even if you run an old kernel.

Side note: your Viewcast 0820E driver also suffers from request_firmware()
regression, as it doesn't use request_firmware_nowait() and tries to load
the firmware during device probe.

The only way to be sure that regressions aren't introduced is to run
a testbench on every new kernel release.

>> I am also aware that the cx25840 driver is complex, and the end result
>> was that driver maintainers effectively forked the cx25840 and brought
>> the codebase back into their core drivers (cx18 for example), to avoid
>> issues where regression testing was troublesome across so many cards.
> 
> I don't think the cx18 ever used the cx25840 codebase: while the cx23418
> uses a similar IP as the cx25840 there were too many differences to allow
> us (actually, I think it was me who wrote it initially for the cx18) to
> reuse the cx25840.
> 
> That's a general problem, BTW: reuse works well for the exact same chip.
> But when you get variants of the chip (or it gets integrated in another chip
> as an IP block), then at some point keeping track of those differences and
> preventing regressions becomes harder than it would be if they were done as
> separate drivers.
> 
> Where that boundary is is not always clear, and for the cx25840 we probably
> exceeded it.

Agreed.

> But sharing a subdevice driver for a single chip among different boards has
> never been much of a problem in my experience. I'm not saying we never got
> regressions, but not many and they were generally quickly caught.
> 
>> If I had the time and/or energy, we'd do the same with the cx25840.
>> Keeping complex code close to the PCI/PCIe bridge bring big dividends
>> when debugging complex problems and mitigating issues where code is
>> re-used across multiple products (growing any regression test
>> requirements).
>>
>> The entire driver was intensionally written to be self-enclosed,
>> highly portable between 2.6.3x and v3.x kernels without subdev
>> breakages and/or api changes. With a small external Makefile it even
>> builds very nicely outside of the kernel on any kernel you like, that
>> shipped in the last 2-3 years.
> 
> ??? We have the media_build system for that, so why care about older kernels?
> 
>>>
>>> Some of the other issues are:
>>>
>>> - Please use the control framework. All new drivers must use it, unless there
>>>   are very, very good reasons not to. I'm gradually converting all drivers to
>>>   the control framework, so I really don't want to introduce new drivers to
>>>   that list.
>>
>> I think the control framework is a great design, it's just too
>> difficult to debug and when I go near it - it breaks, or I spend an
>> hour trying to understand why my subdev call doesn't reach the subdev
>> device. My comments are not designed to inflame or upset you, I'm
>> simply pointing out that any work I've done recently (on two new PCIe
>> bridges - unreleased code) I've decided not to use it.
> 
> Ask me if there are problems with the control framework! I'm happy to help out.
> 
> I can't fix it, improve it, etc. if I don't here about it.
> 
> The reason why all drivers should use it is that is behaves the same for all
> drivers, and apps can start to rely on that behavior. If something doesn't work,
> and you can't figure it out, then I am more than happy to help.
> 
> But I will NACK this driver unless it is using the control framework. Otherwise
> I just have to do that later, and I really don't want to. There aren't many
> controls in this driver so it should be pretty quick to do it.
> 
> In addition, the control framework will make it easy to implement control events,
> another thing that should be rolled out to all drivers.
> 
>> Again, I specifically chosen to isolate this driver from certain key
>> areas of the (now enormous) v4l2 infrastructure.
> 
> There is a reason for that infrastructure, you know. Consistent behavior from
> the point of view of applications is the most important one. And it actually
> takes a lot of work off your hands. Again, if there are questions, then I'm
> happy to help out (and possible improve the code or documentation).
> 
>>
>>>
>>> - TRY_FMT can actually set the format, something that should never happen.
>>
>> I can check, but I think gstreamer or tvtime actually relies on that behavior.
> 
> Highly unlikely. TRY_FMT should *never* change the actual format. It's been like
> that since the very beginning.

I doubt tvtime or gstreamer would be relying on that: API is clear that try_* doesn't
change it, and drivers don't change format on try_fmt.

If your driver is working with those apps, It is probably pretty much the reverse: 
the applications are either not using try_fmt, or doing an s_fmt before streaming,
reverting any changes that might be happening with try_fmt.

>>> - Use the new DV_TIMINGS ioctls for the HDTV formats. S_FMT should not be used
>>>   to select the HDTV format!
>>
>> gstreamer on 2.6.37 and better didn't support DVTIMINGs. I would
>> certainly like to discuss adding better timing support once
>> applications are fully aware and can control the hardware using it.
>> The lack of a good timin API (and adoption by the application
>> developers) forced my hand to use S_FMT.
> 
> You said that it was in your queue for some time, so it may be that it wasn't
> available when you started out. The problem is, the API is now available, and
> if drivers do not implement it, then there is also no reason for applications
> to use it, isn't it? Chicken and egg.
> 
> I will NACK if the driver doesn't add support for it. Otherwise we end up with
> some drivers that implement it correctly, and others that use a different
> method. No application writer will ever thank us for that.
> 
> Also, I didn't go through all the hard work of designing and adding an API and
> then see it being ignored in favor of a non-standard solution.
> 
>> Right now the driver works today, on old and new systems, for hardware
>> that's shipping. It satisfies end user needs.
>>
>>>
>>> - The procfs additions seem unnecessary to me. VIDIOC_LOG_STATUS or perhaps
>>>   debugfs are probably much more suitable.
>>
>> I agree. It can probably be removed altogether.
>>
>>>
>>> - Using videobuf2 is very much recommended.
>>
>> I went with what I know to be honest. I neither agree nor disagree
>> with your comments. If videobuf2 is supported on 2.6.3x then this is
>> good news.
> 
> If you use media_build to compile your driver, then everything including vb2
> is supported from 2.6.31 onwards (the oldest kernel supported by media_build).

Btw, 2.6.31 limit is just because none cares to have it supported on older
releases. Once I needed to test a driver on 2.6.28, and it was not hard to
add the very few missing bits for that driver to work there.

>>
>>>
>>> - Please run v4l2-compliance and fix any reported issues!
>>>
>>> It's a pretty big driver, so I only looked skimmed the patch, but these are
>>> IMHO fairly major issues. As it stands it is only suitable to be merged in
>>> drivers/staging/media.
>>
>> I'm not sure I agree. I think I don't agree in general that subdev and
>> the control framework is mandatory for any driver. I think they are
>> accelerator frameworks designed to help. I my case I don't think they
>> do. So I avoided using them.
>>
>> I guess Mauro has the final decision.
> 
> Of course.

I would accept it only if you have very strong technical reasons why not
using the existing infrastructure, e. g. you need to clearly explain
what makes your driver so different that the v4l infrastructure won't work
and can't be fixed to work with?

If you're willing to change it to fulfill the requirements, the driver
could be merged into staging, if think you'll take more than 4-5 weeks
to address the pointed issues.

> BTW, I saw another thing that must be changed: you use the .ioctl file
> operation instead of unlocked_ioctl. This is no longer allowed for new
> drivers since the removal of the BKL. The v4l2 core implementation of
> .ioctl attempts to simulate the old BKL and is very inefficient, in
> particular for drivers like this that do not use struct v4l2_device.
> If you have multiple ViewCast cards, then all v4l2 ioctls will go through
> a single V4L2 core lock, leading to substantial latencies.
> 
> See also the comment in v4l2_ioctl() in v4l2_dev.c.
> 
> New drivers must use unlocked_ioctl. I am in the (very slow, but steady)
> process of fixing any old drivers that still use .ioctl and once all are
> converted .ioctl will be removed altogether.

Regards,
Mauro


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-08-13 17:36       ` Mauro Carvalho Chehab
@ 2012-08-14 15:07         ` Steven Toth
  2012-08-15 11:14           ` Hans Verkuil
  0 siblings, 1 reply; 18+ messages in thread
From: Steven Toth @ 2012-08-14 15:07 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Hans Verkuil, Linux-Media, Mauro Chehab

On Mon, Aug 13, 2012 at 1:36 PM, Mauro Carvalho Chehab
<mchehab@redhat.com> wrote:
> Em 13-08-2012 12:49, Hans Verkuil escreveu:
>> On Mon August 13 2012 16:46:45 Steven Toth wrote:
>>> Hans,
>>>
>>> Thanks for your feedback.
>>>
>>> Oh dear. I don't think you're going to like my response, but I think
>>> we know each other well enough to realize that neither of us are
>>> trying to antagonize or upset either other. We're simply stating our
>>> positions. Please read on.
>>
>> I didn't think you'd like my response either :-)
>
> You probably won't like my answer too, yet I'm also simply
> stating my positions.

Hans / Mauro, thank you for your comments and review, very good
feedback and technical discussion. Truly, thank you. :)

While I don't necessarily agree with Mauro that adoption of subdev is
"MANDATORY" (in the larger sense of the kernel driver development -
and common practices throughout the entire source base), I do hear and
value your comments and concerns from a peer review perspective.

1) A handful of simple improvements have been suggested, Eg.
ioctl_unlocked, double-checking v4l2-compliance, try_fmt, /proc
removal, firmware loading etc

Ack. I have no objections. Items like this are fairly trivial, easy to
address, I can absorb this and provide new patches quickly and easily.
I'll go back over the detailed comments this weekend and prepare
additional patches (and retest).

2) ... and some larger discussion items have been raised, Eg.
Absorbing more of the V4L2 kernel infrastructure into the vc8x0 driver
vs a fairly self-contained driver with very limited opportunities for
future breakage.

Are you really willing to say that all drivers, with unique and new
pieces of silicon, need to be split out into independent modules,
adopting a subdev type interfaces or mainline merge is refused? It's
not that I'm asking you to merge duplicate functionality, duplicate
driver code, replicating functionality for new hardware or for an
existing modules (tuner/demod/whatever). (Like has already happened in
the past - 18271 for example).

If the answer is Yes, then my second questions is:

Assuming the comments / issues mentioned in #1 are addressed, are you
really willing to stand up in front of the world-wide Kernel
development community and justify why a driver that passes user-facing
v4l2-compliance tests, is fairly clean, passes 99% of the reasonable
checkpatch rules, is fully operational, cannot be merged? Really? Is
this truly an illegal or inappropriate driver implementation that
would prohibit mainline merge?

The ViewCast 820 is a (circa) $1800 video capture card. It's not the
kind of hardware that everyone has laying around for regression
testing purposes. If I 1) split this up and people begin to absorb
ad7441 functionality into other designs, and start patching it and 2)
adopt the subdev framework for that matter... then nobody is able to
regression test the impact to the 820. That puts an incredible amount
of burden on me. I'm attempting to mitigate all of this risk, but also
provide a GPL driver so everyone can benefit - without creating a
future maintenance / regression problem, by relying on subsystems the
driver simply doesn't need.

As always, I do welcome and appreciate your comments and thoughts, no
flames from me. I do find the 'MANDATORY' comments worthy of
discussion, or perhaps I've miss-understood something.

Regards,

- Steve

-- 
Steven Toth - Kernel Labs
http://www.kernellabs.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-08-14 15:07         ` Steven Toth
@ 2012-08-15 11:14           ` Hans Verkuil
  2012-08-16 13:27             ` Steven Toth
  0 siblings, 1 reply; 18+ messages in thread
From: Hans Verkuil @ 2012-08-15 11:14 UTC (permalink / raw)
  To: Steven Toth; +Cc: Mauro Carvalho Chehab, Linux-Media, Mauro Chehab

On Tue August 14 2012 17:07:55 Steven Toth wrote:
> On Mon, Aug 13, 2012 at 1:36 PM, Mauro Carvalho Chehab
> <mchehab@redhat.com> wrote:
> > Em 13-08-2012 12:49, Hans Verkuil escreveu:
> >> On Mon August 13 2012 16:46:45 Steven Toth wrote:
> >>> Hans,
> >>>
> >>> Thanks for your feedback.
> >>>
> >>> Oh dear. I don't think you're going to like my response, but I think
> >>> we know each other well enough to realize that neither of us are
> >>> trying to antagonize or upset either other. We're simply stating our
> >>> positions. Please read on.
> >>
> >> I didn't think you'd like my response either :-)
> >
> > You probably won't like my answer too, yet I'm also simply
> > stating my positions.
> 
> Hans / Mauro, thank you for your comments and review, very good
> feedback and technical discussion. Truly, thank you. :)
> 
> While I don't necessarily agree with Mauro that adoption of subdev is
> "MANDATORY" (in the larger sense of the kernel driver development -
> and common practices throughout the entire source base), I do hear and
> value your comments and concerns from a peer review perspective.

You're awfully polite for someone whose code has been shot down :-)
Don't worry, I'll buy you a beer in San Diego to soften the pain (or to
drown your sorrows!).

> 1) A handful of simple improvements have been suggested, Eg.
> ioctl_unlocked, double-checking v4l2-compliance, try_fmt, /proc
> removal, firmware loading etc
> 
> Ack. I have no objections. Items like this are fairly trivial, easy to
> address, I can absorb this and provide new patches quickly and easily.
> I'll go back over the detailed comments this weekend and prepare
> additional patches (and retest).

Note that the v4l2-compliance tests are generally more strict than the
spec itself. For example, it assumes that the control framework is used,
that control events are implemented, and that vb2 is used.

Take a look at vivi.c: it implements all the latest infrastructure and it
is now actually a pretty good example of how things should work.

It's also one of the few drivers that passes all v4l2-compliance tests.

The only ioctls that aren't covered yet by v4l2-compliance are:

           VIDIOC_CROPCAP, VIDIOC_G/S_CROP, VIDIOC_G/S_SELECTION
           VIDIOC_S_FBUF/OVERLAY
           VIDIOC_(TRY_)ENCODER_CMD
           VIDIOC_(TRY_)DECODER_CMD
           VIDIOC_G_ENC_INDEX
           VIDIOC_QBUF/DQBUF/QUERYBUF/PREPARE_BUFS
           VIDIOC_STREAMON/OFF

So basically cropping, compression encoder/decoder control and actual
streaming. And the subdev and media API is also not tested, although
those might be beyond the scope of this utility anyway.

Everything else is now tested fairly exhaustively.

> 2) ... and some larger discussion items have been raised, Eg.
> Absorbing more of the V4L2 kernel infrastructure into the vc8x0 driver
> vs a fairly self-contained driver with very limited opportunities for
> future breakage.
> 
> Are you really willing to say that all drivers, with unique and new
> pieces of silicon, need to be split out into independent modules,
> adopting a subdev type interfaces or mainline merge is refused? It's
> not that I'm asking you to merge duplicate functionality, duplicate
> driver code, replicating functionality for new hardware or for an
> existing modules (tuner/demod/whatever). (Like has already happened in
> the past - 18271 for example).

Speaking for myself, I would probably NACK it, yes. I would hate to do it,
but there are IMHO good technical reasons why the ad7441 code should be
implemented as a subdev driver.

> If the answer is Yes, then my second questions is:
> 
> Assuming the comments / issues mentioned in #1 are addressed, are you
> really willing to stand up in front of the world-wide Kernel
> development community and justify why a driver that passes user-facing
> v4l2-compliance tests, is fairly clean, passes 99% of the reasonable
> checkpatch rules, is fully operational, cannot be merged? Really? Is
> this truly an illegal or inappropriate driver implementation that
> would prohibit mainline merge?

Yes. Currently nobody else uses the ad7441 but the viewcast driver. So
splitting it up really shouldn't be too much of a problem: you don't have
to take care of anyone else, and it only has to support the functionality
that you need right now. And as long as nobody else uses that driver it
shouldn't make a difference to you maintenance-wise.

But *if* someone else comes along then that will help them enormously if
an ad7441 driver already exists. We definitely do not want to have duplicate
drivers in the kernel for i2c devices, so either they or you would have to
split up the ad7441 driver from the ViewCast driver, and what are the chances
of that ever happening? Slim to none.

You just want to get your driver merged, which is perfectly understandable,
but I also want to ensure that whatever gets merged can also be reused by
others, where applicable.

In addition to that I have to say that I have been working with Analog Devices
i2c receivers and transmitters for the past 4-5 years, and these things are
complex. I consider it very unlikely that your ad7441 driver covers the full
functionality of the ad7441. By implementing it as a separate driver it will
be much easier for others to work on it and improve it. Yes, that might
require you to do the occasional testing, but hopefully that will improve the
functionality of the ViewCast driver as well by e.g. supporting more formats,
have better colorspace handling, or whatever.

Also note that the Analog Devices receivers/transmitters are fairly popular,
particularly within the embedded hardware world. So it wouldn't surprise me
at all if other products will appear that want to use it.

One other difference with such subdev drivers is that they can be in the
kernel, while the actual V4L2 driver for an embedded product isn't.

Typically on embedded systems the platform V4L2 driver is too product-specific
to ever be considered for upstreaming (and it is usually fairly trivial as
well). But being able to reuse an ad7441-like driver saves companies a huge
amount of time. The adv7604 and ad9883b drivers that are in my queue are like
that: the actual V4L2 driver that uses them won't be upstreamed, but we and
other companies will reuse the subdev drivers. Even better, with a bit of
luck Analog Devices themselves might get involved and start making their own
drivers.

The complexity of V4L2 drivers is in the DMA engine (for embedded devices
this is often provided by the SoC vendor) and in the video receivers,
transmitters and/or sensors (usually i2c devices). More advanced SoCs also
have video processing capabilities, but that too is/should be provided by
the SoC vendor. So as an embedded product developer you generally have the
code for the DMA engine/video processing from your SoC vendor (and V4L2 is
making steady progress there), and that leaves the other complex part: the
i2c receiver/transmitter/sensor. So having that available for reuse in the
kernel makes a big difference in development time. Particularly if you also
want to support analog video input or output (analog takes 10 times as much
development effort as digital does).

BTW, we are talking about the adv7441a, right?
See here: http://ez.analog.com/docs/DOC-1546

There is also a chip called ad7441, but that seems to be something else.
AD has the annoying habit of renaming chips, but at least they've started
making their datasheets freely available, which is very good news for linux.

> The ViewCast 820 is a (circa) $1800 video capture card. It's not the
> kind of hardware that everyone has laying around for regression
> testing purposes. If I 1) split this up and people begin to absorb
> ad7441 functionality into other designs, and start patching it and 2)
> adopt the subdev framework for that matter... then nobody is able to
> regression test the impact to the 820. That puts an incredible amount
> of burden on me. I'm attempting to mitigate all of this risk, but also
> provide a GPL driver so everyone can benefit - without creating a
> future maintenance / regression problem, by relying on subsystems the
> driver simply doesn't need.

What you are basically saying is that you don't want to split it up because
if you do, then other people might reuse the code, change it, and might cause
you a lot of work.

What I am saying is that if you split it up, then other people might reuse it,
improve it and with a relatively small amount of work improve the ViewCast
820 support as well.

I suspect your view of the amount of work it might cost you to test changes
from other people is too pessimistic. It's based on your experiences with the
cx25840, but from my perspective the cx25840 is the exception, not the rule.

And the cx25840 provides a good lesson how it may be counterproductive trying
to support multiple variants of a device in one driver. It only works if the
differences are really small, otherwise it is probably better to make separate
drivers, or make separate drivers, but have them share some common code. It's
something I'm considering for the adv drivers as I have two more drivers in
my queue that are similar, but not identical, to the adv7604 and ad9389b.

On the one hand, there is just too much identical code to justify two fully
independent drivers, but on the other hand there are too many differences as
well. I think it is possible to refactor out clearly common parts that do not
directly touch on registers. I don't know for certain yet, though.

> As always, I do welcome and appreciate your comments and thoughts, no
> flames from me. I do find the 'MANDATORY' comments worthy of
> discussion, or perhaps I've miss-understood something.

No, you understood it perfectly :-)

Regards,

	Hans

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-08-15 11:14           ` Hans Verkuil
@ 2012-08-16 13:27             ` Steven Toth
  2012-08-16 14:49               ` Hans Verkuil
  0 siblings, 1 reply; 18+ messages in thread
From: Steven Toth @ 2012-08-16 13:27 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: Mauro Carvalho Chehab, Linux-Media, Mauro Chehab

>> While I don't necessarily agree with Mauro that adoption of subdev is
>> "MANDATORY" (in the larger sense of the kernel driver development -
>> and common practices throughout the entire source base), I do hear and
>> value your comments and concerns from a peer review perspective.
>
> You're awfully polite for someone whose code has been shot down :-)
> Don't worry, I'll buy you a beer in San Diego to soften the pain (or to
> drown your sorrows!).

:)

It benefits everyone when rationale discussion can be had, even when
points of view differ. The alternative is we shout at each other over
email. Shouting gets old very quickly and never accomplishes anything.

>
>> 1) A handful of simple improvements have been suggested, Eg.
>> ioctl_unlocked, double-checking v4l2-compliance, try_fmt, /proc
>> removal, firmware loading etc
>>
>> Ack. I have no objections. Items like this are fairly trivial, easy to
>> address, I can absorb this and provide new patches quickly and easily.
>> I'll go back over the detailed comments this weekend and prepare
>> additional patches (and retest).
>
> Note that the v4l2-compliance tests are generally more strict than the
> spec itself. For example, it assumes that the control framework is used,
> that control events are implemented, and that vb2 is used.

I made some patches to the current tree to fixup some of the earlier
comments, firmware loading via nowait, unlocked_ioctl2, /proc removal.
I also ran the compliance testing tool. After realizing my version of
v4l2-compliance was a little out of date - and building fresh from
v4l2-utils, it turned out some highly useful information about the
driver.

So, I've ran v4l2-compliance and it pointed out a few things that I've
fixed, but it also does a few things that (for some reason) I can't
seem to catch. One particular test is on (iirc) s_fmt. It attempts to
set ATSC but by ioctl callback never receives ATSC in the norm/id arg,
it actually receives 0x0. This feels more like a bug in the test.
Either way, I have some if (std & ATSC) return -EINVAL, but it still
appears to fail the test.

I see some tests which report failure (testing videobuf) but given
that I essentially pass the ioctl directly into the videbug core, very
much like every oher driver I've ever done, it's probably either a
quirk of the tool, or something inside videobuf core itself that needs
some adjustment. (userptr/mmap for capture or output buffers related
test).

In summary, the v4l2-compliance tool has pointed out a few things that
were worth fixing for sure, and thus I've fixed. It it also feels like
the tool itself is still evolving. When I get a moment I'll run the
compliance tool and paste the results here for comment.

I'd welcome your feedback on the compliance feedback.

>
> Take a look at vivi.c: it implements all the latest infrastructure and it
> is now actually a pretty good example of how things should work.

Noted, that's a useful reference point.

>
> It's also one of the few drivers that passes all v4l2-compliance tests.
>
> The only ioctls that aren't covered yet by v4l2-compliance are:
>
>            VIDIOC_CROPCAP, VIDIOC_G/S_CROP, VIDIOC_G/S_SELECTION
>            VIDIOC_S_FBUF/OVERLAY
>            VIDIOC_(TRY_)ENCODER_CMD
>            VIDIOC_(TRY_)DECODER_CMD
>            VIDIOC_G_ENC_INDEX
>            VIDIOC_QBUF/DQBUF/QUERYBUF/PREPARE_BUFS
>            VIDIOC_STREAMON/OFF
>
> So basically cropping, compression encoder/decoder control and actual
> streaming. And the subdev and media API is also not tested, although
> those might be beyond the scope of this utility anyway.
>
> Everything else is now tested fairly exhaustively.
>
>> 2) ... and some larger discussion items have been raised, Eg.
>> Absorbing more of the V4L2 kernel infrastructure into the vc8x0 driver
>> vs a fairly self-contained driver with very limited opportunities for
>> future breakage.
>>
>> Are you really willing to say that all drivers, with unique and new
>> pieces of silicon, need to be split out into independent modules,
>> adopting a subdev type interfaces or mainline merge is refused? It's
>> not that I'm asking you to merge duplicate functionality, duplicate
>> driver code, replicating functionality for new hardware or for an
>> existing modules (tuner/demod/whatever). (Like has already happened in
>> the past - 18271 for example).
>
> Speaking for myself, I would probably NACK it, yes. I would hate to do it,
> but there are IMHO good technical reasons why the ad7441 code should be
> implemented as a subdev driver.

I hear you. In the spirit of co-operation I'll take a shot at turning
ad7441 into a subdev and see what odd problems shake out of the
process. I should be clear that the resulting subdevice will likely be
very 820 specific in terms of configuration, but it's a reasonable
cut-point.

>
>> If the answer is Yes, then my second questions is:
>>
>> Assuming the comments / issues mentioned in #1 are addressed, are you
>> really willing to stand up in front of the world-wide Kernel
>> development community and justify why a driver that passes user-facing
>> v4l2-compliance tests, is fairly clean, passes 99% of the reasonable
>> checkpatch rules, is fully operational, cannot be merged? Really? Is
>> this truly an illegal or inappropriate driver implementation that
>> would prohibit mainline merge?
>
> Yes. Currently nobody else uses the ad7441 but the viewcast driver. So
> splitting it up really shouldn't be too much of a problem: you don't have
> to take care of anyone else, and it only has to support the functionality
> that you need right now. And as long as nobody else uses that driver it
> shouldn't make a difference to you maintenance-wise.

Fair enough.

>
> But *if* someone else comes along then that will help them enormously if
> an ad7441 driver already exists. We definitely do not want to have duplicate
> drivers in the kernel for i2c devices, so either they or you would have to
> split up the ad7441 driver from the ViewCast driver, and what are the chances
> of that ever happening? Slim to none.
>
> You just want to get your driver merged, which is perfectly understandable,
> but I also want to ensure that whatever gets merged can also be reused by
> others, where applicable.
>
> In addition to that I have to say that I have been working with Analog Devices
> i2c receivers and transmitters for the past 4-5 years, and these things are
> complex. I consider it very unlikely that your ad7441 driver covers the full
> functionality of the ad7441. By implementing it as a separate driver it will

Yes.

> be much easier for others to work on it and improve it. Yes, that might
> require you to do the occasional testing, but hopefully that will improve the
> functionality of the ViewCast driver as well by e.g. supporting more formats,
> have better colorspace handling, or whatever.

<snip>

> Also note that the Analog Devices receivers/transmitters are fairly popular,
> particularly within the embedded hardware world. So it wouldn't surprise me
> at all if other products will appear that want to use it.

(7441 commentary removed)

Agreed.

>
> BTW, we are talking about the adv7441a, right?
> See here: http://ez.analog.com/docs/DOC-1546

Yes.

>
> There is also a chip called ad7441, but that seems to be something else.
> AD has the annoying habit of renaming chips, but at least they've started
> making their datasheets freely available, which is very good news for linux.

Force of habit on my part, it's the adv7441a.

>
>> The ViewCast 820 is a (circa) $1800 video capture card. It's not the
>> kind of hardware that everyone has laying around for regression
>> testing purposes. If I 1) split this up and people begin to absorb
>> ad7441 functionality into other designs, and start patching it and 2)
>> adopt the subdev framework for that matter... then nobody is able to
>> regression test the impact to the 820. That puts an incredible amount
>> of burden on me. I'm attempting to mitigate all of this risk, but also
>> provide a GPL driver so everyone can benefit - without creating a
>> future maintenance / regression problem, by relying on subsystems the
>> driver simply doesn't need.
>
> What you are basically saying is that you don't want to split it up because
> if you do, then other people might reuse the code, change it, and might cause
> you a lot of work.

Yes.

>
> What I am saying is that if you split it up, then other people might reuse it,
> improve it and with a relatively small amount of work improve the ViewCast
> 820 support as well.

... and it would require regression testing on every change.

>
> I suspect your view of the amount of work it might cost you to test changes
> from other people is too pessimistic. It's based on your experiences with the
> cx25840, but from my perspective the cx25840 is the exception, not the rule.

My comments are largely influenced by the 25840, and we both agree
we've stretched that driver too far and too thinly, beyond reasonable
use - to the point where we're causing regressions even with small
amounts of rework. In hindsight we all know not to let that happen
again - but these things have a habit of slowly creeping up on you and
they're a problem before you know it.

My goal is/was to head that off right at the outset, but without
limiting anyone else by my actions. I've implemented just enough of
the 7441 for what the 820 needs. A full blown subdev implementation
(for all features) is beyond the 820 needs, out of scope. I'll take a
shot at converting the limited functionality into a subdev as-is,
let's see. If you accept that it's likely to be fairly 820 specific
(not unreasonable to begin with) then that's a reasonable compromise.

>
> And the cx25840 provides a good lesson how it may be counterproductive trying
> to support multiple variants of a device in one driver. It only works if the
> differences are really small, otherwise it is probably better to make separate
> drivers, or make separate drivers, but have them share some common code. It's
> something I'm considering for the adv drivers as I have two more drivers in
> my queue that are similar, but not identical, to the adv7604 and ad9389b.

Agreed.

>
> On the one hand, there is just too much identical code to justify two fully
> independent drivers, but on the other hand there are too many differences as
> well. I think it is possible to refactor out clearly common parts that do not
> directly touch on registers. I don't know for certain yet, though.

It's tough. I air on the side of keeping the code reasonable and
readable, easy to digest and support - even if it means small amounts
of duplication. If the goal of LinuxTV is to welcome less experience
video kernel developers then it's off-putting to have very abstract,
scientific driver creations that can only be maintained by one or two
people.

I don't know the 7604 or the 9389 but I'd suggest simple is better
(for the rest of the group), unless they're 99% identical (unlikely).

>
>> As always, I do welcome and appreciate your comments and thoughts, no
>> flames from me. I do find the 'MANDATORY' comments worthy of
>> discussion, or perhaps I've miss-understood something.
>
> No, you understood it perfectly :-)

Regards,

-- 
Steven Toth - Kernel Labs
http://www.kernellabs.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-08-16 13:27             ` Steven Toth
@ 2012-08-16 14:49               ` Hans Verkuil
  2012-08-16 17:39                 ` Steven Toth
  0 siblings, 1 reply; 18+ messages in thread
From: Hans Verkuil @ 2012-08-16 14:49 UTC (permalink / raw)
  To: Steven Toth; +Cc: Mauro Carvalho Chehab, Linux-Media, Mauro Chehab

On Thu August 16 2012 15:27:51 Steven Toth wrote:
> >> While I don't necessarily agree with Mauro that adoption of subdev is
> >> "MANDATORY" (in the larger sense of the kernel driver development -
> >> and common practices throughout the entire source base), I do hear and
> >> value your comments and concerns from a peer review perspective.
> >
> > You're awfully polite for someone whose code has been shot down :-)
> > Don't worry, I'll buy you a beer in San Diego to soften the pain (or to
> > drown your sorrows!).
> 
> :)
> 
> It benefits everyone when rationale discussion can be had, even when
> points of view differ. The alternative is we shout at each other over
> email. Shouting gets old very quickly and never accomplishes anything.
> 
> >
> >> 1) A handful of simple improvements have been suggested, Eg.
> >> ioctl_unlocked, double-checking v4l2-compliance, try_fmt, /proc
> >> removal, firmware loading etc
> >>
> >> Ack. I have no objections. Items like this are fairly trivial, easy to
> >> address, I can absorb this and provide new patches quickly and easily.
> >> I'll go back over the detailed comments this weekend and prepare
> >> additional patches (and retest).
> >
> > Note that the v4l2-compliance tests are generally more strict than the
> > spec itself. For example, it assumes that the control framework is used,
> > that control events are implemented, and that vb2 is used.
> 
> I made some patches to the current tree to fixup some of the earlier
> comments, firmware loading via nowait, unlocked_ioctl2, /proc removal.
> I also ran the compliance testing tool. After realizing my version of
> v4l2-compliance was a little out of date - and building fresh from
> v4l2-utils, it turned out some highly useful information about the
> driver.
> 
> So, I've ran v4l2-compliance and it pointed out a few things that I've
> fixed, but it also does a few things that (for some reason) I can't
> seem to catch. One particular test is on (iirc) s_fmt. It attempts to
> set ATSC but by ioctl callback never receives ATSC in the norm/id arg,
> it actually receives 0x0. This feels more like a bug in the test.
> Either way, I have some if (std & ATSC) return -EINVAL, but it still
> appears to fail the test.

I think it might be because vdev->tvnorms isn't set for the video node.
It's set for the VBI node, though. If tvnorms is 0, then ENUMSTD will
probably return an empty list, and that might be the cause of the ATSC
test. I also see that current_norm is used: don't do that. Instead store
the current standard yourself and return it in g_std. I'm slowly phasing
out current_norm because 1) it's ugly and 2) it doesn't work if you have
both a vbi and a video node.

> I see some tests which report failure (testing videobuf) but given
> that I essentially pass the ioctl directly into the videbug core, very
> much like every oher driver I've ever done, it's probably either a
> quirk of the tool, or something inside videobuf core itself that needs
> some adjustment. (userptr/mmap for capture or output buffers related
> test).

videobuf does not follow the spec in several areas (most notably and extremely
annoyingly it does not support calling REQBUFS with a count of 0). So any
driver that uses videobuf will fail a number of tests in v4l2-compliance.

These problems are fixed in vb2, which is why I strongly recommend its use in
new drivers. In addition, work on the new DMABUF mechanism for sharing buffers
between v4l2 and drm will only be implemented in vb2.

> In summary, the v4l2-compliance tool has pointed out a few things that
> were worth fixing for sure, and thus I've fixed. It it also feels like
> the tool itself is still evolving. When I get a moment I'll run the
> compliance tool and paste the results here for comment.

It is steadily being improved, that's correct.

BTW, don't forget to also run it for the vbi node (option '-V /dev/vbiX').

Feedback on the tool is very much appreciated! E.g. how to improve it, whether
there are missing, confusing or incorrect tests, etc.

> I'd welcome your feedback on the compliance feedback.

No problem. One set of errors that v4l2-compliance produces is that it fails
if you can change VBI formats using a video node or vice versa. I want to
address that in the V4L2 core rather than having to fix all drivers. It's one
of the topics in the V4L2 ambiguities list for the upcoming workshop.

> > Take a look at vivi.c: it implements all the latest infrastructure and it
> > is now actually a pretty good example of how things should work.
> 
> Noted, that's a useful reference point.
> 
> >
> > It's also one of the few drivers that passes all v4l2-compliance tests.
> >
> > The only ioctls that aren't covered yet by v4l2-compliance are:
> >
> >            VIDIOC_CROPCAP, VIDIOC_G/S_CROP, VIDIOC_G/S_SELECTION
> >            VIDIOC_S_FBUF/OVERLAY
> >            VIDIOC_(TRY_)ENCODER_CMD
> >            VIDIOC_(TRY_)DECODER_CMD
> >            VIDIOC_G_ENC_INDEX
> >            VIDIOC_QBUF/DQBUF/QUERYBUF/PREPARE_BUFS
> >            VIDIOC_STREAMON/OFF
> >
> > So basically cropping, compression encoder/decoder control and actual
> > streaming. And the subdev and media API is also not tested, although
> > those might be beyond the scope of this utility anyway.
> >
> > Everything else is now tested fairly exhaustively.
> >
> >> 2) ... and some larger discussion items have been raised, Eg.
> >> Absorbing more of the V4L2 kernel infrastructure into the vc8x0 driver
> >> vs a fairly self-contained driver with very limited opportunities for
> >> future breakage.
> >>
> >> Are you really willing to say that all drivers, with unique and new
> >> pieces of silicon, need to be split out into independent modules,
> >> adopting a subdev type interfaces or mainline merge is refused? It's
> >> not that I'm asking you to merge duplicate functionality, duplicate
> >> driver code, replicating functionality for new hardware or for an
> >> existing modules (tuner/demod/whatever). (Like has already happened in
> >> the past - 18271 for example).
> >
> > Speaking for myself, I would probably NACK it, yes. I would hate to do it,
> > but there are IMHO good technical reasons why the ad7441 code should be
> > implemented as a subdev driver.
> 
> I hear you. In the spirit of co-operation I'll take a shot at turning
> ad7441 into a subdev and see what odd problems shake out of the
> process. I should be clear that the resulting subdevice will likely be
> very 820 specific in terms of configuration, but it's a reasonable
> cut-point.

That's a perfectly valid approach. Frankly, I think it is counter productive
to try and make a more general implementation. You only end up with code that
you can't test on your hardware. Such code generally suffers badly from bitrot
over time.

> >
> >> If the answer is Yes, then my second questions is:
> >>
> >> Assuming the comments / issues mentioned in #1 are addressed, are you
> >> really willing to stand up in front of the world-wide Kernel
> >> development community and justify why a driver that passes user-facing
> >> v4l2-compliance tests, is fairly clean, passes 99% of the reasonable
> >> checkpatch rules, is fully operational, cannot be merged? Really? Is
> >> this truly an illegal or inappropriate driver implementation that
> >> would prohibit mainline merge?
> >
> > Yes. Currently nobody else uses the ad7441 but the viewcast driver. So
> > splitting it up really shouldn't be too much of a problem: you don't have
> > to take care of anyone else, and it only has to support the functionality
> > that you need right now. And as long as nobody else uses that driver it
> > shouldn't make a difference to you maintenance-wise.
> 
> Fair enough.
> 
> >
> > But *if* someone else comes along then that will help them enormously if
> > an ad7441 driver already exists. We definitely do not want to have duplicate
> > drivers in the kernel for i2c devices, so either they or you would have to
> > split up the ad7441 driver from the ViewCast driver, and what are the chances
> > of that ever happening? Slim to none.
> >
> > You just want to get your driver merged, which is perfectly understandable,
> > but I also want to ensure that whatever gets merged can also be reused by
> > others, where applicable.
> >
> > In addition to that I have to say that I have been working with Analog Devices
> > i2c receivers and transmitters for the past 4-5 years, and these things are
> > complex. I consider it very unlikely that your ad7441 driver covers the full
> > functionality of the ad7441. By implementing it as a separate driver it will
> 
> Yes.
> 
> > be much easier for others to work on it and improve it. Yes, that might
> > require you to do the occasional testing, but hopefully that will improve the
> > functionality of the ViewCast driver as well by e.g. supporting more formats,
> > have better colorspace handling, or whatever.
> 
> <snip>
> 
> > Also note that the Analog Devices receivers/transmitters are fairly popular,
> > particularly within the embedded hardware world. So it wouldn't surprise me
> > at all if other products will appear that want to use it.
> 
> (7441 commentary removed)
> 
> Agreed.
> 
> >
> > BTW, we are talking about the adv7441a, right?
> > See here: http://ez.analog.com/docs/DOC-1546
> 
> Yes.
> 
> >
> > There is also a chip called ad7441, but that seems to be something else.
> > AD has the annoying habit of renaming chips, but at least they've started
> > making their datasheets freely available, which is very good news for linux.
> 
> Force of habit on my part, it's the adv7441a.

It would be nice if you can do a search and replace so that the correct name
is used in the sources.

And a comment in the source with the URL of the datasheets as I gave above
is very useful as well. Analog Devices did/are doing a good job when it comes
to publishing datasheets.

> >
> >> The ViewCast 820 is a (circa) $1800 video capture card. It's not the
> >> kind of hardware that everyone has laying around for regression
> >> testing purposes. If I 1) split this up and people begin to absorb
> >> ad7441 functionality into other designs, and start patching it and 2)
> >> adopt the subdev framework for that matter... then nobody is able to
> >> regression test the impact to the 820. That puts an incredible amount
> >> of burden on me. I'm attempting to mitigate all of this risk, but also
> >> provide a GPL driver so everyone can benefit - without creating a
> >> future maintenance / regression problem, by relying on subsystems the
> >> driver simply doesn't need.
> >
> > What you are basically saying is that you don't want to split it up because
> > if you do, then other people might reuse the code, change it, and might cause
> > you a lot of work.
> 
> Yes.
> 
> >
> > What I am saying is that if you split it up, then other people might reuse it,
> > improve it and with a relatively small amount of work improve the ViewCast
> > 820 support as well.
> 
> ... and it would require regression testing on every change.
> 
> >
> > I suspect your view of the amount of work it might cost you to test changes
> > from other people is too pessimistic. It's based on your experiences with the
> > cx25840, but from my perspective the cx25840 is the exception, not the rule.
> 
> My comments are largely influenced by the 25840, and we both agree
> we've stretched that driver too far and too thinly, beyond reasonable
> use - to the point where we're causing regressions even with small
> amounts of rework. In hindsight we all know not to let that happen
> again - but these things have a habit of slowly creeping up on you and
> they're a problem before you know it.
> 
> My goal is/was to head that off right at the outset, but without
> limiting anyone else by my actions. I've implemented just enough of
> the 7441 for what the 820 needs. A full blown subdev implementation
> (for all features) is beyond the 820 needs, out of scope. I'll take a
> shot at converting the limited functionality into a subdev as-is,
> let's see. If you accept that it's likely to be fairly 820 specific
> (not unreasonable to begin with) then that's a reasonable compromise.

As I mentioned above, that's a perfectly reasonable approach, and actually
one that I would recommend regardless.

I have a few remarks with regards to converting the 7441 driver to a subdev
driver: I recommend doing this last and fixing all other items first. The
reason is that you probably need two additional pieces of code. The first
is some additional API support to handle HDMI/DVI/etc. connectors correctly,
esp. with respect to hotplug support and EDID support. I'll post what is
hopefully the final pull request for this infrastructure tomorrow. See in the
meantime my hdmi3 tree:

http://git.linuxtv.org/hverkuil/media_tree.git/shortlog/refs/heads/hdmi3

The other part is that there is no easy way at the moment to have a subdev
driver notify the bridge driver when a control changes value. This is relevant
for these adv drivers since the new API adds read-only status controls that
are updated whenever e.g. RX Sense detects power on an input. For embedded systems
you can simply receive a control event whenever those read-only controls change
value, but for a bridge driver there is no simple method to get that event.

It may not be a big deal for your driver since this tends to be more important
for transmitters, but it is something I have to fix regardless.

My plan is that the bridge driver's notify function (part of struct v4l2_device)
is called, but I need to do some refactoring in the event code to make that
possible. I want to work on that in the very near future since others need it
as well. The workaround at the moment would be to add a manual notify call
after updating the control's value.

> > And the cx25840 provides a good lesson how it may be counterproductive trying
> > to support multiple variants of a device in one driver. It only works if the
> > differences are really small, otherwise it is probably better to make separate
> > drivers, or make separate drivers, but have them share some common code. It's
> > something I'm considering for the adv drivers as I have two more drivers in
> > my queue that are similar, but not identical, to the adv7604 and ad9389b.
> 
> Agreed.
> 
> >
> > On the one hand, there is just too much identical code to justify two fully
> > independent drivers, but on the other hand there are too many differences as
> > well. I think it is possible to refactor out clearly common parts that do not
> > directly touch on registers. I don't know for certain yet, though.
> 
> It's tough. I air on the side of keeping the code reasonable and
> readable, easy to digest and support - even if it means small amounts
> of duplication. If the goal of LinuxTV is to welcome less experience
> video kernel developers then it's off-putting to have very abstract,
> scientific driver creations that can only be maintained by one or two
> people.
> 
> I don't know the 7604 or the 9389 but I'd suggest simple is better
> (for the rest of the group), unless they're 99% identical (unlikely).

Regards,

	Hans

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-08-16 14:49               ` Hans Verkuil
@ 2012-08-16 17:39                 ` Steven Toth
  2012-08-16 18:49                   ` Hans Verkuil
  0 siblings, 1 reply; 18+ messages in thread
From: Steven Toth @ 2012-08-16 17:39 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: Mauro Carvalho Chehab, Linux-Media, Mauro Chehab

>> So, I've ran v4l2-compliance and it pointed out a few things that I've
>> fixed, but it also does a few things that (for some reason) I can't
>> seem to catch. One particular test is on (iirc) s_fmt. It attempts to
>> set ATSC but by ioctl callback never receives ATSC in the norm/id arg,
>> it actually receives 0x0. This feels more like a bug in the test.
>> Either way, I have some if (std & ATSC) return -EINVAL, but it still
>> appears to fail the test.

Oddly enough. If I set tvnorms to something valid, then compliance
passes but gstreamer
fails to run, looks like some kind of confusion about either the
current established
norm, or a failure to establish a norm.

For the time being I've set tvnorms to 0 (with a comment) and removed
current_norm.

>
> I think it might be because vdev->tvnorms isn't set for the video node.
> It's set for the VBI node, though. If tvnorms is 0, then ENUMSTD will
> probably return an empty list, and that might be the cause of the ATSC
> test. I also see that current_norm is used: don't do that. Instead store
> the current standard yourself and return it in g_std. I'm slowly phasing
> out current_norm because 1) it's ugly and 2) it doesn't work if you have
> both a vbi and a video node.

Done.

>
>> I see some tests which report failure (testing videobuf) but given
>> that I essentially pass the ioctl directly into the videbug core, very
>> much like every oher driver I've ever done, it's probably either a
>> quirk of the tool, or something inside videobuf core itself that needs
>> some adjustment. (userptr/mmap for capture or output buffers related
>> test).
>
> videobuf does not follow the spec in several areas (most notably and extremely
> annoyingly it does not support calling REQBUFS with a count of 0). So any
> driver that uses videobuf will fail a number of tests in v4l2-compliance.

Compliance as of today (with changes), now gives:

"Buffer ioctls:
		fail: v4l2-test-buffers.cpp(76): can_stream && !mmap_valid && !userptr_valid
	test VIDIOC_REQBUFS/CREATE_BUFS: FAIL
	test read/write: OK"


>
> These problems are fixed in vb2, which is why I strongly recommend its use in
> new drivers. In addition, work on the new DMABUF mechanism for sharing buffers
> between v4l2 and drm will only be implemented in vb2.
>
>> In summary, the v4l2-compliance tool has pointed out a few things that
>> were worth fixing for sure, and thus I've fixed. It it also feels like
>> the tool itself is still evolving. When I get a moment I'll run the
>> compliance tool and paste the results here for comment.
>
> It is steadily being improved, that's correct.
>
> BTW, don't forget to also run it for the vbi node (option '-V /dev/vbiX').

It's got a couple more failures I need to take care of, nothing huge.

>
> Feedback on the tool is very much appreciated! E.g. how to improve it, whether
> there are missing, confusing or incorrect tests, etc.
>
>> I'd welcome your feedback on the compliance feedback.
>
> No problem. One set of errors that v4l2-compliance produces is that it fails
> if you can change VBI formats using a video node or vice versa. I want to
> address that in the V4L2 core rather than having to fix all drivers. It's one
> of the topics in the V4L2 ambiguities list for the upcoming workshop.
>
>> > Take a look at vivi.c: it implements all the latest infrastructure and it
>> > is now actually a pretty good example of how things should work.
>>
>> Noted, that's a useful reference point.
>>
>> >
>> > It's also one of the few drivers that passes all v4l2-compliance tests.
>> >
>> > The only ioctls that aren't covered yet by v4l2-compliance are:
>> >
>> >            VIDIOC_CROPCAP, VIDIOC_G/S_CROP, VIDIOC_G/S_SELECTION
>> >            VIDIOC_S_FBUF/OVERLAY
>> >            VIDIOC_(TRY_)ENCODER_CMD
>> >            VIDIOC_(TRY_)DECODER_CMD
>> >            VIDIOC_G_ENC_INDEX
>> >            VIDIOC_QBUF/DQBUF/QUERYBUF/PREPARE_BUFS
>> >            VIDIOC_STREAMON/OFF
>> >
>> > So basically cropping, compression encoder/decoder control and actual
>> > streaming. And the subdev and media API is also not tested, although
>> > those might be beyond the scope of this utility anyway.
>> >
>> > Everything else is now tested fairly exhaustively.
>> >
>> >> 2) ... and some larger discussion items have been raised, Eg.
>> >> Absorbing more of the V4L2 kernel infrastructure into the vc8x0 driver
>> >> vs a fairly self-contained driver with very limited opportunities for
>> >> future breakage.
>> >>
>> >> Are you really willing to say that all drivers, with unique and new
>> >> pieces of silicon, need to be split out into independent modules,
>> >> adopting a subdev type interfaces or mainline merge is refused? It's
>> >> not that I'm asking you to merge duplicate functionality, duplicate
>> >> driver code, replicating functionality for new hardware or for an
>> >> existing modules (tuner/demod/whatever). (Like has already happened in
>> >> the past - 18271 for example).
>> >
>> > Speaking for myself, I would probably NACK it, yes. I would hate to do it,
>> > but there are IMHO good technical reasons why the ad7441 code should be
>> > implemented as a subdev driver.
>>
>> I hear you. In the spirit of co-operation I'll take a shot at turning
>> ad7441 into a subdev and see what odd problems shake out of the
>> process. I should be clear that the resulting subdevice will likely be
>> very 820 specific in terms of configuration, but it's a reasonable
>> cut-point.
>
> That's a perfectly valid approach. Frankly, I think it is counter productive
> to try and make a more general implementation. You only end up with code that
> you can't test on your hardware. Such code generally suffers badly from bitrot
> over time.
>
>> >
>> >> If the answer is Yes, then my second questions is:
>> >>
>> >> Assuming the comments / issues mentioned in #1 are addressed, are you
>> >> really willing to stand up in front of the world-wide Kernel
>> >> development community and justify why a driver that passes user-facing
>> >> v4l2-compliance tests, is fairly clean, passes 99% of the reasonable
>> >> checkpatch rules, is fully operational, cannot be merged? Really? Is
>> >> this truly an illegal or inappropriate driver implementation that
>> >> would prohibit mainline merge?
>> >
>> > Yes. Currently nobody else uses the ad7441 but the viewcast driver. So
>> > splitting it up really shouldn't be too much of a problem: you don't have
>> > to take care of anyone else, and it only has to support the functionality
>> > that you need right now. And as long as nobody else uses that driver it
>> > shouldn't make a difference to you maintenance-wise.
>>
>> Fair enough.
>>
>> >
>> > But *if* someone else comes along then that will help them enormously if
>> > an ad7441 driver already exists. We definitely do not want to have duplicate
>> > drivers in the kernel for i2c devices, so either they or you would have to
>> > split up the ad7441 driver from the ViewCast driver, and what are the chances
>> > of that ever happening? Slim to none.
>> >
>> > You just want to get your driver merged, which is perfectly understandable,
>> > but I also want to ensure that whatever gets merged can also be reused by
>> > others, where applicable.
>> >
>> > In addition to that I have to say that I have been working with Analog Devices
>> > i2c receivers and transmitters for the past 4-5 years, and these things are
>> > complex. I consider it very unlikely that your ad7441 driver covers the full
>> > functionality of the ad7441. By implementing it as a separate driver it will
>>
>> Yes.
>>
>> > be much easier for others to work on it and improve it. Yes, that might
>> > require you to do the occasional testing, but hopefully that will improve the
>> > functionality of the ViewCast driver as well by e.g. supporting more formats,
>> > have better colorspace handling, or whatever.
>>
>> <snip>
>>
>> > Also note that the Analog Devices receivers/transmitters are fairly popular,
>> > particularly within the embedded hardware world. So it wouldn't surprise me
>> > at all if other products will appear that want to use it.
>>
>> (7441 commentary removed)
>>
>> Agreed.
>>
>> >
>> > BTW, we are talking about the adv7441a, right?
>> > See here: http://ez.analog.com/docs/DOC-1546
>>
>> Yes.
>>
>> >
>> > There is also a chip called ad7441, but that seems to be something else.
>> > AD has the annoying habit of renaming chips, but at least they've started
>> > making their datasheets freely available, which is very good news for linux.
>>
>> Force of habit on my part, it's the adv7441a.
>
> It would be nice if you can do a search and replace so that the correct name
> is used in the sources.

Yeah, I'll take of that.

>
> And a comment in the source with the URL of the datasheets as I gave above
> is very useful as well. Analog Devices did/are doing a good job when it comes
> to publishing datasheets.
>
>> >
>> >> The ViewCast 820 is a (circa) $1800 video capture card. It's not the
>> >> kind of hardware that everyone has laying around for regression
>> >> testing purposes. If I 1) split this up and people begin to absorb
>> >> ad7441 functionality into other designs, and start patching it and 2)
>> >> adopt the subdev framework for that matter... then nobody is able to
>> >> regression test the impact to the 820. That puts an incredible amount
>> >> of burden on me. I'm attempting to mitigate all of this risk, but also
>> >> provide a GPL driver so everyone can benefit - without creating a
>> >> future maintenance / regression problem, by relying on subsystems the
>> >> driver simply doesn't need.
>> >
>> > What you are basically saying is that you don't want to split it up because
>> > if you do, then other people might reuse the code, change it, and might cause
>> > you a lot of work.
>>
>> Yes.
>>
>> >
>> > What I am saying is that if you split it up, then other people might reuse it,
>> > improve it and with a relatively small amount of work improve the ViewCast
>> > 820 support as well.
>>
>> ... and it would require regression testing on every change.
>>
>> >
>> > I suspect your view of the amount of work it might cost you to test changes
>> > from other people is too pessimistic. It's based on your experiences with the
>> > cx25840, but from my perspective the cx25840 is the exception, not the rule.
>>
>> My comments are largely influenced by the 25840, and we both agree
>> we've stretched that driver too far and too thinly, beyond reasonable
>> use - to the point where we're causing regressions even with small
>> amounts of rework. In hindsight we all know not to let that happen
>> again - but these things have a habit of slowly creeping up on you and
>> they're a problem before you know it.
>>
>> My goal is/was to head that off right at the outset, but without
>> limiting anyone else by my actions. I've implemented just enough of
>> the 7441 for what the 820 needs. A full blown subdev implementation
>> (for all features) is beyond the 820 needs, out of scope. I'll take a
>> shot at converting the limited functionality into a subdev as-is,
>> let's see. If you accept that it's likely to be fairly 820 specific
>> (not unreasonable to begin with) then that's a reasonable compromise.
>
> As I mentioned above, that's a perfectly reasonable approach, and actually
> one that I would recommend regardless.
>
> I have a few remarks with regards to converting the 7441 driver to a subdev
> driver: I recommend doing this last and fixing all other items first. The
> reason is that you probably need two additional pieces of code. The first
> is some additional API support to handle HDMI/DVI/etc. connectors correctly,
> esp. with respect to hotplug support and EDID support. I'll post what is
> hopefully the final pull request for this infrastructure tomorrow. See in the
> meantime my hdmi3 tree:

Noted.

In the meantime, here's the compliance report for the current driver:

http://git.kernellabs.com/?p=stoth/media_tree.git;a=shortlog;h=refs/heads/o820e

I have a couple of questions...

-bash-4.1$ ./v4l2-compliance -d /dev/video0
Driver Info:
	Driver name   : vc8x0
	Card type     : ViewCast 820e
	Bus info      : PCIe:0000:02:00.0
	Driver version: 3.0.1
	Capabilities  : 0x84020001
		Video Capture
		Audio
		Streaming
		Device Capabilities
	Device Caps   : 0x04020001
		Video Capture
		Audio
		Streaming

Compliance test for device /dev/video0 (not using libv4l2):

Required ioctls:
	test VIDIOC_QUERYCAP: OK

Allow for multiple opens:
	test second video open: OK
	test VIDIOC_QUERYCAP: OK
		fail: v4l2-compliance.cpp(323): doioctl(node, VIDIOC_G_PRIORITY, &prio)
	test VIDIOC_G/S_PRIORITY: FAIL

^^^ If I read the compliance test correctly then I think this may be a
bug in the tool. The driver doesn't support g_priority so why mark a
failure?


Debug ioctls:
	test VIDIOC_DBG_G_CHIP_IDENT: Not Supported
	test VIDIOC_DBG_G/S_REGISTER: Not Supported
	test VIDIOC_LOG_STATUS: Not Supported


Debuggung was removed as part of removing the /proc support, but
likely this will return in the form of the above
calls when the next major rev of this 820 card ships (and the driver
is subsequently asked to support a variation of the 820 hardware).

Input ioctls:
	test VIDIOC_G/S_TUNER: Not Supported
	test VIDIOC_G/S_FREQUENCY: Not Supported
	test VIDIOC_S_HW_FREQ_SEEK: OK
	test VIDIOC_ENUMAUDIO: OK
	test VIDIOC_G/S/ENUMINPUT: OK
	test VIDIOC_G/S_AUDIO: OK
	Inputs: 7 Audio Inputs: 1 Tuners: 0

Output ioctls:
	test VIDIOC_G/S_MODULATOR: Not Supported
	test VIDIOC_G/S_FREQUENCY: Not Supported
	test VIDIOC_ENUMAUDOUT: Not Supported
	test VIDIOC_G/S/ENUMOUTPUT: Not Supported
	test VIDIOC_G/S_AUDOUT: Not Supported
	Outputs: 0 Audio Outputs: 0 Modulators: 0

Control ioctls:
		fail: v4l2-test-controls.cpp(275): does not support V4L2_CTRL_FLAG_NEXT_CTRL
	test VIDIOC_QUERYCTRL/MENU: FAIL
	test VIDIOC_G/S_CTRL: OK
	test VIDIOC_G/S/TRY_EXT_CTRLS: Not Supported
	test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: Not Supported
	test VIDIOC_G/S_JPEGCOMP: Not Supported
	Standard Controls: 0 Private Controls: 0

^^^ I'm not sure how to handle V4L2_CTRL_FLAG_NEXT_CTRL. I've read the
spec a couple of times
and I think I just don't get it. I don't have any ext ctrls and I
think I'm returning EINVAL at the right moment.
If it's not mandatory then why the FAIL?

Input/Output configuration ioctls:
		fail: v4l2-test-io-config.cpp(63): could set standard to ATSC, which
is not supported anymore
		fail: v4l2-test-io-config.cpp(126): STD failed for input 0.
	test VIDIOC_ENUM/G/S/QUERY_STD: FAIL
	test VIDIOC_ENUM/G/S/QUERY_DV_PRESETS: Not Supported
	test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: Not Supported
	test VIDIOC_DV_TIMINGS_CAP: Not Supported


^^^ See my comments on gstreamer failing to operate if tvnorms is
non-zero. I have a feeling something in
the core objects to this. I tried NTSC, I also have g_std returning
NTSC, but gstreamer refuses to negotiate
a format/std unless 0 is specified..... And so the test fails. my
s_std is passed 0 for the ID so while the code
exists to EINVAL an attempt on setting ATSC, it's not triggering.

Format ioctls:
		fail: v4l2-test-formats.cpp(252): duplicate format 56595559
	test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: FAIL

^^^ This is don't get. The compliance code implies you should never
have a duplicate pixel format. Perhaps because I have multiple
identical width/height formats with differing framerates and this
confuses things.

	test VIDIOC_G/S_PARM: OK
	test VIDIOC_G_FBUF: Not Supported
	test VIDIOC_G_FMT: OK
		fail: v4l2-test-formats.cpp(549): VBI Capture is valid, but no
TRY_FMT was implemented
	test VIDIOC_TRY_FMT: FAIL
		fail: v4l2-test-formats.cpp(600): Video Capture is valid, but no
S_FMT was implemented
	test VIDIOC_S_FMT: FAIL
	test VIDIOC_G_SLICED_VBI_CAP: Not Supported

^^^ I've looked at the S_FMT many many times and tried a few
workaround. effectively the compliance tool sets the struct to FF,
passed ANY_FIELD and sets set. I refuse the call in the driver, which
I think it's bogus. The Spec is unclear what to do but the compliance
tool still fails. If you have thoughts on this then I'd appreciate it.

Buffer ioctls:
		fail: v4l2-test-buffers.cpp(76): can_stream && !mmap_valid && !userptr_valid
	test VIDIOC_REQBUFS/CREATE_BUFS: FAIL
	test read/write:
	test read/write: OK

The tool shows: fail_on_test(can_stream && !mmap_valid && !userptr_valid);

^^^^ I'm drawing a blank on this failure. I don't deal with either of
these, they're deep in video buf. A bogus error, or something I've
overlooked in videobuf1?

Total: 36, Succeeded: 29, Failed: 7, Warnings: 0

(VBI compliance has a couple more failures I'll take care of this afternoon).

Regards,

- Steve

-- 
Steven Toth - Kernel Labs
http://www.kernellabs.com
+1.646.355.8490

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-08-16 17:39                 ` Steven Toth
@ 2012-08-16 18:49                   ` Hans Verkuil
  2012-08-18 15:48                     ` Steven Toth
  0 siblings, 1 reply; 18+ messages in thread
From: Hans Verkuil @ 2012-08-16 18:49 UTC (permalink / raw)
  To: Steven Toth; +Cc: Mauro Carvalho Chehab, Linux-Media, Mauro Chehab

On Thu August 16 2012 19:39:51 Steven Toth wrote:
> >> So, I've ran v4l2-compliance and it pointed out a few things that I've
> >> fixed, but it also does a few things that (for some reason) I can't
> >> seem to catch. One particular test is on (iirc) s_fmt. It attempts to
> >> set ATSC but by ioctl callback never receives ATSC in the norm/id arg,
> >> it actually receives 0x0. This feels more like a bug in the test.
> >> Either way, I have some if (std & ATSC) return -EINVAL, but it still
> >> appears to fail the test.
> 
> Oddly enough. If I set tvnorms to something valid, then compliance
> passes but gstreamer
> fails to run, looks like some kind of confusion about either the
> current established
> norm, or a failure to establish a norm.
> 
> For the time being I've set tvnorms to 0 (with a comment) and removed
> current_norm.

Well, this needs to be sorted, because something is clearly amiss.

> >
> > I think it might be because vdev->tvnorms isn't set for the video node.
> > It's set for the VBI node, though. If tvnorms is 0, then ENUMSTD will
> > probably return an empty list, and that might be the cause of the ATSC
> > test. I also see that current_norm is used: don't do that. Instead store
> > the current standard yourself and return it in g_std. I'm slowly phasing
> > out current_norm because 1) it's ugly and 2) it doesn't work if you have
> > both a vbi and a video node.
> 
> Done.
> 
> >
> >> I see some tests which report failure (testing videobuf) but given
> >> that I essentially pass the ioctl directly into the videbug core, very
> >> much like every oher driver I've ever done, it's probably either a
> >> quirk of the tool, or something inside videobuf core itself that needs
> >> some adjustment. (userptr/mmap for capture or output buffers related
> >> test).
> >
> > videobuf does not follow the spec in several areas (most notably and extremely
> > annoyingly it does not support calling REQBUFS with a count of 0). So any
> > driver that uses videobuf will fail a number of tests in v4l2-compliance.
> 
> Compliance as of today (with changes), now gives:
> 
> "Buffer ioctls:
> 		fail: v4l2-test-buffers.cpp(76): can_stream && !mmap_valid && !userptr_valid
> 	test VIDIOC_REQBUFS/CREATE_BUFS: FAIL
> 	test read/write: OK"

Yeah, that's because videobuf is used instead of vb2.

<snip>

> In the meantime, here's the compliance report for the current driver:
> 
> http://git.kernellabs.com/?p=stoth/media_tree.git;a=shortlog;h=refs/heads/o820e
> 
> I have a couple of questions...
> 
> -bash-4.1$ ./v4l2-compliance -d /dev/video0
> Driver Info:
> 	Driver name   : vc8x0
> 	Card type     : ViewCast 820e
> 	Bus info      : PCIe:0000:02:00.0
> 	Driver version: 3.0.1
> 	Capabilities  : 0x84020001
> 		Video Capture
> 		Audio
> 		Streaming
> 		Device Capabilities
> 	Device Caps   : 0x04020001
> 		Video Capture
> 		Audio
> 		Streaming
> 
> Compliance test for device /dev/video0 (not using libv4l2):
> 
> Required ioctls:
> 	test VIDIOC_QUERYCAP: OK
> 
> Allow for multiple opens:
> 	test second video open: OK
> 	test VIDIOC_QUERYCAP: OK
> 		fail: v4l2-compliance.cpp(323): doioctl(node, VIDIOC_G_PRIORITY, &prio)
> 	test VIDIOC_G/S_PRIORITY: FAIL
> 
> ^^^ If I read the compliance test correctly then I think this may be a
> bug in the tool. The driver doesn't support g_priority so why mark a
> failure?

The tool is more strict in some places than the spec is. One of those cases
is that is requires that priority handling is implemented. The reason for that
is 1) if you use the latest framework support (struct v4l2_fh in particular),
then you get priority handling for free by just setting a single bit, so there
is no excuse not to implement it, and 2) the reason few if any applications use
it is that too few drivers implemented it, so apps couldn't rely on it. It's
again a chicken and egg problem and the only way to improve matters is to have
a check that clearly tells you to add support for this.

> 
> 
> Debug ioctls:
> 	test VIDIOC_DBG_G_CHIP_IDENT: Not Supported
> 	test VIDIOC_DBG_G/S_REGISTER: Not Supported
> 	test VIDIOC_LOG_STATUS: Not Supported
> 
> 
> Debuggung was removed as part of removing the /proc support, but
> likely this will return in the form of the above
> calls when the next major rev of this 820 card ships (and the driver
> is subsequently asked to support a variation of the 820 hardware).

OK.

> Input ioctls:
> 	test VIDIOC_G/S_TUNER: Not Supported
> 	test VIDIOC_G/S_FREQUENCY: Not Supported
> 	test VIDIOC_S_HW_FREQ_SEEK: OK
> 	test VIDIOC_ENUMAUDIO: OK
> 	test VIDIOC_G/S/ENUMINPUT: OK
> 	test VIDIOC_G/S_AUDIO: OK
> 	Inputs: 7 Audio Inputs: 1 Tuners: 0
> 
> Output ioctls:
> 	test VIDIOC_G/S_MODULATOR: Not Supported
> 	test VIDIOC_G/S_FREQUENCY: Not Supported
> 	test VIDIOC_ENUMAUDOUT: Not Supported
> 	test VIDIOC_G/S/ENUMOUTPUT: Not Supported
> 	test VIDIOC_G/S_AUDOUT: Not Supported
> 	Outputs: 0 Audio Outputs: 0 Modulators: 0
> 
> Control ioctls:
> 		fail: v4l2-test-controls.cpp(275): does not support V4L2_CTRL_FLAG_NEXT_CTRL
> 	test VIDIOC_QUERYCTRL/MENU: FAIL
> 	test VIDIOC_G/S_CTRL: OK
> 	test VIDIOC_G/S/TRY_EXT_CTRLS: Not Supported
> 	test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: Not Supported
> 	test VIDIOC_G/S_JPEGCOMP: Not Supported
> 	Standard Controls: 0 Private Controls: 0
> 
> ^^^ I'm not sure how to handle V4L2_CTRL_FLAG_NEXT_CTRL. I've read the
> spec a couple of times
> and I think I just don't get it. I don't have any ext ctrls and I
> think I'm returning EINVAL at the right moment.
> If it's not mandatory then why the FAIL?

This is another place where the tool is more strict than the spec: by requiring
that extended controls are also implemented it ensures a more consistent API
towards applications. By using the control framework you get all this for free,
so it is also a nice way of enforcing the use of the proper frameworks.

And you should use the control framework anyway: it's trivial for this driver
to implement.

By using struct v4l2_fh and the control framework you will get automatic support
for priority handling, control events and extended controls without having to
think about it.

> 
> Input/Output configuration ioctls:
> 		fail: v4l2-test-io-config.cpp(63): could set standard to ATSC, which
> is not supported anymore
> 		fail: v4l2-test-io-config.cpp(126): STD failed for input 0.
> 	test VIDIOC_ENUM/G/S/QUERY_STD: FAIL
> 	test VIDIOC_ENUM/G/S/QUERY_DV_PRESETS: Not Supported
> 	test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: Not Supported
> 	test VIDIOC_DV_TIMINGS_CAP: Not Supported
> 
> 
> ^^^ See my comments on gstreamer failing to operate if tvnorms is
> non-zero. I have a feeling something in
> the core objects to this. I tried NTSC, I also have g_std returning
> NTSC, but gstreamer refuses to negotiate
> a format/std unless 0 is specified..... And so the test fails. my
> s_std is passed 0 for the ID so while the code
> exists to EINVAL an attempt on setting ATSC, it's not triggering.

I would have to see the latest code, I guess.

> 
> Format ioctls:
> 		fail: v4l2-test-formats.cpp(252): duplicate format 56595559
> 	test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: FAIL
> 
> ^^^ This is don't get. The compliance code implies you should never
> have a duplicate pixel format. Perhaps because I have multiple
> identical width/height formats with differing framerates and this
> confuses things.

ENUM_FMT returns duplicate formats, and it shouldn't do that.

With ENUM_FRAMESIZES you can enumerate the available framesizes for each
format, and with ENUM_FRAMEINTERVALS you enumerate the available framerates
for each format/size combination.

I know the spec doesn't say anything about whether enum_fmt can return duplicate
formats, but it makes no sense IMHO. Enumeration implies that you enumerate over
unique values.

> 
> 	test VIDIOC_G/S_PARM: OK
> 	test VIDIOC_G_FBUF: Not Supported
> 	test VIDIOC_G_FMT: OK
> 		fail: v4l2-test-formats.cpp(549): VBI Capture is valid, but no
> TRY_FMT was implemented
> 	test VIDIOC_TRY_FMT: FAIL
> 		fail: v4l2-test-formats.cpp(600): Video Capture is valid, but no
> S_FMT was implemented
> 	test VIDIOC_S_FMT: FAIL
> 	test VIDIOC_G_SLICED_VBI_CAP: Not Supported
> 
> ^^^ I've looked at the S_FMT many many times and tried a few
> workaround. effectively the compliance tool sets the struct to FF,
> passed ANY_FIELD and sets set. I refuse the call in the driver, which
> I think it's bogus. The Spec is unclear what to do but the compliance
> tool still fails. If you have thoughts on this then I'd appreciate it.

This is an area that will be clarified during the workshop. The question
is: can S_FMT ever return an error if you give it an invalid format. The
spec currently allows it, but it is my believe (and that of others as
well) that that should change. S_FMT (and TRY_FMT) should always return
some valid format and never an error (unless the type is wrong or streaming
is in progress and you can't change the format midstream).

The v4l2-compliance tool is currently assuming that behavior, so it sets
all fields with bogus values (and field to ANY to test whether the driver
can handle that value correctly), and checks whether it can do a S_FMT
without it returning an error.

> 
> Buffer ioctls:
> 		fail: v4l2-test-buffers.cpp(76): can_stream && !mmap_valid && !userptr_valid
> 	test VIDIOC_REQBUFS/CREATE_BUFS: FAIL
> 	test read/write:
> 	test read/write: OK
> 
> The tool shows: fail_on_test(can_stream && !mmap_valid && !userptr_valid);
> 
> ^^^^ I'm drawing a blank on this failure. I don't deal with either of
> these, they're deep in video buf. A bogus error, or something I've
> overlooked in videobuf1?

It's a consequence of using videobuf instead of vb2. This code is testing
REQBUFS with a count of 0, which isn't supported by videobuf. Switch to vb2
and this will work. It's one of the reasons why vb2 was made.

Regards,

	Hans

> 
> Total: 36, Succeeded: 29, Failed: 7, Warnings: 0
> 
> (VBI compliance has a couple more failures I'll take care of this afternoon).
> 
> Regards,
> 
> - Steve
> 
> 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-08-16 18:49                   ` Hans Verkuil
@ 2012-08-18 15:48                     ` Steven Toth
  2012-08-18 18:56                       ` Hans Verkuil
  2012-09-13 23:19                       ` Mauro Carvalho Chehab
  0 siblings, 2 replies; 18+ messages in thread
From: Steven Toth @ 2012-08-18 15:48 UTC (permalink / raw)
  To: Hans Verkuil, Mauro Chehab; +Cc: Mauro Carvalho Chehab, Linux-Media

Mauro, please read below, a new set of patches I'm submitting for merge.

On Thu, Aug 16, 2012 at 2:49 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On Thu August 16 2012 19:39:51 Steven Toth wrote:
>> >> So, I've ran v4l2-compliance and it pointed out a few things that I've
>> >> fixed, but it also does a few things that (for some reason) I can't
>> >> seem to catch. One particular test is on (iirc) s_fmt. It attempts to
>> >> set ATSC but by ioctl callback never receives ATSC in the norm/id arg,
>> >> it actually receives 0x0. This feels more like a bug in the test.
>> >> Either way, I have some if (std & ATSC) return -EINVAL, but it still
>> >> appears to fail the test.
>>
>> Oddly enough. If I set tvnorms to something valid, then compliance
>> passes but gstreamer
>> fails to run, looks like some kind of confusion about either the
>> current established
>> norm, or a failure to establish a norm.
>>
>> For the time being I've set tvnorms to 0 (with a comment) and removed
>> current_norm.
>
> Well, this needs to be sorted, because something is clearly amiss.

Agreed. I just can't see what's wrong. I may need your advise /
eyeballs on this. I'd be willing to provide logs that show gstreamer
accessing the driver and exiting. It needs fixed, I've tried, I just
can't see why gstreamer fails.

On the main topic of merge.... As promised, I spent quite a bit of
time this week reworking the code based on the feedback. I also
flattened all of these patches into a single patchset and upgraded to
the latest re-org tree.

The source notes describe in a little more detail the major changes:
http://git.kernellabs.com/?p=stoth/media_tree.git;a=commit;h=f295dd63e2f7027e327daad730eb86f2c17e3b2c

Mauro, so, I hereby submit for your review/merge again, the updated
patchset. *** Please comment. ***

The following changes since commit 9b78c5a3007e10a172d4e83bea18509fdff2e8e3:

  [media] b2c2: export b2c2_flexcop_debug symbol (2012-08-17 11:09:19 -0300)

are available in the git repository at:
  git://git.kernellabs.com/stoth/media_tree.git o820e

Steven Toth (4):
      [media] adv7441a: Adding limited support for a new video decoder.
      [media] adv7441a: Adding the module author macro
      [media] pcm3052: Adding support for a new ADC.
      [media] vc8x0: Adding support for the ViewCast O820E Capture Card.

 drivers/media/i2c/Kconfig                 |   18 +
 drivers/media/i2c/Makefile                |    2 +
 drivers/media/i2c/adv7441a.c              | 4258 +++++++++++++++++++++++++++++
 drivers/media/i2c/pcm3052.c               |  248 ++
 drivers/media/pci/Kconfig                 |    1 +
 drivers/media/pci/Makefile                |    1 +
 drivers/media/pci/vc8x0/Kconfig           |   15 +
 drivers/media/pci/vc8x0/Makefile          |    9 +
 drivers/media/pci/vc8x0/vc8x0-audio.c     |  741 +++++
 drivers/media/pci/vc8x0/vc8x0-buffer.c    |  338 +++
 drivers/media/pci/vc8x0/vc8x0-cards.c     |  138 +
 drivers/media/pci/vc8x0/vc8x0-channel.c   |  805 ++++++
 drivers/media/pci/vc8x0/vc8x0-core.c      |  678 +++++
 drivers/media/pci/vc8x0/vc8x0-display.c   | 1359 +++++++++
 drivers/media/pci/vc8x0/vc8x0-dma.c       | 2677 ++++++++++++++++++
 drivers/media/pci/vc8x0/vc8x0-fw.c        |  466 ++++
 drivers/media/pci/vc8x0/vc8x0-i2c.c       |  368 +++
 drivers/media/pci/vc8x0/vc8x0-reg.h       |  214 ++
 drivers/media/pci/vc8x0/vc8x0-timestamp.c |  156 ++
 drivers/media/pci/vc8x0/vc8x0-video.c     | 2796 +++++++++++++++++++
 drivers/media/pci/vc8x0/vc8x0.h           |  732 +++++
 include/media/adv7441a.h                  |   88 +
 include/media/v4l2-chip-ident.h           |    6 +
 23 files changed, 16114 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/i2c/adv7441a.c
 create mode 100644 drivers/media/i2c/pcm3052.c
 create mode 100644 drivers/media/pci/vc8x0/Kconfig
 create mode 100644 drivers/media/pci/vc8x0/Makefile
 create mode 100644 drivers/media/pci/vc8x0/vc8x0-audio.c
 create mode 100644 drivers/media/pci/vc8x0/vc8x0-buffer.c
 create mode 100644 drivers/media/pci/vc8x0/vc8x0-cards.c
 create mode 100644 drivers/media/pci/vc8x0/vc8x0-channel.c
 create mode 100644 drivers/media/pci/vc8x0/vc8x0-core.c
 create mode 100644 drivers/media/pci/vc8x0/vc8x0-display.c
 create mode 100644 drivers/media/pci/vc8x0/vc8x0-dma.c
 create mode 100644 drivers/media/pci/vc8x0/vc8x0-fw.c
 create mode 100644 drivers/media/pci/vc8x0/vc8x0-i2c.c
 create mode 100644 drivers/media/pci/vc8x0/vc8x0-reg.h
 create mode 100644 drivers/media/pci/vc8x0/vc8x0-timestamp.c
 create mode 100644 drivers/media/pci/vc8x0/vc8x0-video.c
 create mode 100644 drivers/media/pci/vc8x0/vc8x0.h
 create mode 100644 include/media/adv7441a.h

Regards,

-- 
Steven Toth - Kernel Labs
http://www.kernellabs.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-08-18 15:48                     ` Steven Toth
@ 2012-08-18 18:56                       ` Hans Verkuil
  2012-09-13 23:19                       ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 18+ messages in thread
From: Hans Verkuil @ 2012-08-18 18:56 UTC (permalink / raw)
  To: Steven Toth; +Cc: Mauro Chehab, Mauro Carvalho Chehab, Linux-Media

On Sat August 18 2012 17:48:52 Steven Toth wrote:
> Mauro, please read below, a new set of patches I'm submitting for merge.
> 
> On Thu, Aug 16, 2012 at 2:49 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> > On Thu August 16 2012 19:39:51 Steven Toth wrote:
> >> >> So, I've ran v4l2-compliance and it pointed out a few things that I've
> >> >> fixed, but it also does a few things that (for some reason) I can't
> >> >> seem to catch. One particular test is on (iirc) s_fmt. It attempts to
> >> >> set ATSC but by ioctl callback never receives ATSC in the norm/id arg,
> >> >> it actually receives 0x0. This feels more like a bug in the test.
> >> >> Either way, I have some if (std & ATSC) return -EINVAL, but it still
> >> >> appears to fail the test.
> >>
> >> Oddly enough. If I set tvnorms to something valid, then compliance
> >> passes but gstreamer
> >> fails to run, looks like some kind of confusion about either the
> >> current established
> >> norm, or a failure to establish a norm.
> >>
> >> For the time being I've set tvnorms to 0 (with a comment) and removed
> >> current_norm.
> >
> > Well, this needs to be sorted, because something is clearly amiss.
> 
> Agreed. I just can't see what's wrong. I may need your advise /
> eyeballs on this. I'd be willing to provide logs that show gstreamer
> accessing the driver and exiting. It needs fixed, I've tried, I just
> can't see why gstreamer fails.

You definitely need to set tvnorms for the video node as well. Take a look
at v4l_s_std in v4l2-ioctl.c: if tvnorms == 0, then your s_std function
is called with a std of 0 as well. The v4l_s_std function could do with a
WARN_ON(!vfd->tvnorms), by the way. This is why that ATSC test is also
always failing (and so can be removed).

The tvnorms value for the vbi and video node must also be identical.

You can easily debug what gstreamer is doing by running:

	echo 2 >/sys/class/video4linux/video0/debug

This will turn on core logging of all v4l2 ioctls, and it should help you
figuring out why gstreamer is failing.

This debug facility is new and is very handy.

One small thing I saw in querycap: don't set cap->version. The core sets that
to the kernel version automatically (and if built with media_build, then it's
set to the kernel version of the media tree).

There are still a few blocking issues here that I've told you about before.
Ignore this if you were planning to do that in a next version of the patch.

- use the control framework in the bridge driver
- use struct v4l2_fh

It's all trivial to add and you get control events and prio handling all for
free. I'm almost tempted to do it for you since it's 1 hour work tops for me,
but that's not really my job.

- use the new dv_timings API for the HDTV formats, both in the bridge driver
  and in the adv7441a driver.

This really must be done. As I mentioned before: I didn't implement this for
nothing. It's easy to test this with the qv4l2 utility which fully supports the
new API.

If you need help with any of this, please mail me and we can set up an irc
session.

I also strongly recommend using vb2 instead of videobuf. It's so much better.

What I don't quite understand BTW is how you detect and set formats for the
adv7441 driver. You must have something similar to VIDIOC_QUERY_DV_TIMINGS or
VIDIOC_S_DV_TIMINGS, but I don't see it offhand. How does this work?

Regards,

	Hans

> On the main topic of merge.... As promised, I spent quite a bit of
> time this week reworking the code based on the feedback. I also
> flattened all of these patches into a single patchset and upgraded to
> the latest re-org tree.
> 
> The source notes describe in a little more detail the major changes:
> http://git.kernellabs.com/?p=stoth/media_tree.git;a=commit;h=f295dd63e2f7027e327daad730eb86f2c17e3b2c
> 
> Mauro, so, I hereby submit for your review/merge again, the updated
> patchset. *** Please comment. ***
> 
> The following changes since commit 9b78c5a3007e10a172d4e83bea18509fdff2e8e3:
> 
>   [media] b2c2: export b2c2_flexcop_debug symbol (2012-08-17 11:09:19 -0300)
> 
> are available in the git repository at:
>   git://git.kernellabs.com/stoth/media_tree.git o820e
> 
> Steven Toth (4):
>       [media] adv7441a: Adding limited support for a new video decoder.
>       [media] adv7441a: Adding the module author macro
>       [media] pcm3052: Adding support for a new ADC.
>       [media] vc8x0: Adding support for the ViewCast O820E Capture Card.
> 
>  drivers/media/i2c/Kconfig                 |   18 +
>  drivers/media/i2c/Makefile                |    2 +
>  drivers/media/i2c/adv7441a.c              | 4258 +++++++++++++++++++++++++++++
>  drivers/media/i2c/pcm3052.c               |  248 ++
>  drivers/media/pci/Kconfig                 |    1 +
>  drivers/media/pci/Makefile                |    1 +
>  drivers/media/pci/vc8x0/Kconfig           |   15 +
>  drivers/media/pci/vc8x0/Makefile          |    9 +
>  drivers/media/pci/vc8x0/vc8x0-audio.c     |  741 +++++
>  drivers/media/pci/vc8x0/vc8x0-buffer.c    |  338 +++
>  drivers/media/pci/vc8x0/vc8x0-cards.c     |  138 +
>  drivers/media/pci/vc8x0/vc8x0-channel.c   |  805 ++++++
>  drivers/media/pci/vc8x0/vc8x0-core.c      |  678 +++++
>  drivers/media/pci/vc8x0/vc8x0-display.c   | 1359 +++++++++
>  drivers/media/pci/vc8x0/vc8x0-dma.c       | 2677 ++++++++++++++++++
>  drivers/media/pci/vc8x0/vc8x0-fw.c        |  466 ++++
>  drivers/media/pci/vc8x0/vc8x0-i2c.c       |  368 +++
>  drivers/media/pci/vc8x0/vc8x0-reg.h       |  214 ++
>  drivers/media/pci/vc8x0/vc8x0-timestamp.c |  156 ++
>  drivers/media/pci/vc8x0/vc8x0-video.c     | 2796 +++++++++++++++++++
>  drivers/media/pci/vc8x0/vc8x0.h           |  732 +++++
>  include/media/adv7441a.h                  |   88 +
>  include/media/v4l2-chip-ident.h           |    6 +
>  23 files changed, 16114 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/media/i2c/adv7441a.c
>  create mode 100644 drivers/media/i2c/pcm3052.c
>  create mode 100644 drivers/media/pci/vc8x0/Kconfig
>  create mode 100644 drivers/media/pci/vc8x0/Makefile
>  create mode 100644 drivers/media/pci/vc8x0/vc8x0-audio.c
>  create mode 100644 drivers/media/pci/vc8x0/vc8x0-buffer.c
>  create mode 100644 drivers/media/pci/vc8x0/vc8x0-cards.c
>  create mode 100644 drivers/media/pci/vc8x0/vc8x0-channel.c
>  create mode 100644 drivers/media/pci/vc8x0/vc8x0-core.c
>  create mode 100644 drivers/media/pci/vc8x0/vc8x0-display.c
>  create mode 100644 drivers/media/pci/vc8x0/vc8x0-dma.c
>  create mode 100644 drivers/media/pci/vc8x0/vc8x0-fw.c
>  create mode 100644 drivers/media/pci/vc8x0/vc8x0-i2c.c
>  create mode 100644 drivers/media/pci/vc8x0/vc8x0-reg.h
>  create mode 100644 drivers/media/pci/vc8x0/vc8x0-timestamp.c
>  create mode 100644 drivers/media/pci/vc8x0/vc8x0-video.c
>  create mode 100644 drivers/media/pci/vc8x0/vc8x0.h
>  create mode 100644 include/media/adv7441a.h
> 
> Regards,
> 
> 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-08-18 15:48                     ` Steven Toth
  2012-08-18 18:56                       ` Hans Verkuil
@ 2012-09-13 23:19                       ` Mauro Carvalho Chehab
  2012-09-13 23:23                         ` Mauro Carvalho Chehab
  1 sibling, 1 reply; 18+ messages in thread
From: Mauro Carvalho Chehab @ 2012-09-13 23:19 UTC (permalink / raw)
  To: Steven Toth; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Linux-Media

Em Sat, 18 Aug 2012 11:48:52 -0400
Steven Toth <stoth@kernellabs.com> escreveu:

> Mauro, please read below, a new set of patches I'm submitting for merge.
> 
> On Thu, Aug 16, 2012 at 2:49 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> > On Thu August 16 2012 19:39:51 Steven Toth wrote:
> >> >> So, I've ran v4l2-compliance and it pointed out a few things that I've
> >> >> fixed, but it also does a few things that (for some reason) I can't
> >> >> seem to catch. One particular test is on (iirc) s_fmt. It attempts to
> >> >> set ATSC but by ioctl callback never receives ATSC in the norm/id arg,
> >> >> it actually receives 0x0. This feels more like a bug in the test.
> >> >> Either way, I have some if (std & ATSC) return -EINVAL, but it still
> >> >> appears to fail the test.
> >>
> >> Oddly enough. If I set tvnorms to something valid, then compliance
> >> passes but gstreamer
> >> fails to run, looks like some kind of confusion about either the
> >> current established
> >> norm, or a failure to establish a norm.
> >>
> >> For the time being I've set tvnorms to 0 (with a comment) and removed
> >> current_norm.
> >
> > Well, this needs to be sorted, because something is clearly amiss.
> 
> Agreed. I just can't see what's wrong. I may need your advise /
> eyeballs on this. I'd be willing to provide logs that show gstreamer
> accessing the driver and exiting. It needs fixed, I've tried, I just
> can't see why gstreamer fails.
> 
> On the main topic of merge.... As promised, I spent quite a bit of
> time this week reworking the code based on the feedback. I also
> flattened all of these patches into a single patchset and upgraded to
> the latest re-org tree.
> 
> The source notes describe in a little more detail the major changes:
> http://git.kernellabs.com/?p=stoth/media_tree.git;a=commit;h=f295dd63e2f7027e327daad730eb86f2c17e3b2c
> 
> Mauro, so, I hereby submit for your review/merge again, the updated
> patchset. *** Please comment. ***

I'll comment patch by patch. Let's hope the ML will get this email. Not sure,
as it tends to discard big emails like that.

This is the comment of patch 1/4.


> From 6e5182ab70c5bc561304db7206f5235d826bb0dd Mon Sep 17 00:00:00 2001
> From: Steven Toth <stoth@kernellabs.com>
> Date: Sat, 18 Aug 2012 10:45:32 -0400
> Subject: [media] adv7441a: Adding limited support for a new video decoder.
> Cc: Linux Media Mailing List <linux-media@vger.kernel.org>
> 
> The Analog Devices ADV7441a.
> 
> The driver has been written and tested against the ViewCast O820E
> PCIe capture card (patches to follow).
> 
> The driver has it's auto-detection currently disabled, as part
> of the migration from a standalone driver to a subdev. This
> functionality will be restored in the comming days.
> 
> Signed-off-by: Steven Toth <stoth@kernellabs.com>
> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
> ---
>  drivers/media/i2c/Kconfig       |    9 +
>  drivers/media/i2c/Makefile      |    1 +
>  drivers/media/i2c/adv7441a.c    | 4257 +++++++++++++++++++++++++++++++++++++++
>  include/media/adv7441a.h        |   88 +
>  include/media/v4l2-chip-ident.h |    3 +
>  5 files changed, 4358 insertions(+)
>  create mode 100644 drivers/media/i2c/adv7441a.c
>  create mode 100644 include/media/adv7441a.h
> 
> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> index 7fe4acf..0de229d 100644
> --- a/drivers/media/i2c/Kconfig
> +++ b/drivers/media/i2c/Kconfig

(note, I ran the rename_patch.pl script, found at the media_build tree,
 for it to allow applying the patches after the big patch rename)

> @@ -388,6 +388,15 @@ config VIDEO_ADV7393
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called adv7393.
>  
> +config VIDEO_ADV7441A
> +	tristate "ADV7441A video encoder"
> +	depends on I2C
> +	help
> +	  Support for Analog Devices I2C bus based ADV7441A encoder.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called adv7441a.
> +
>  config VIDEO_AK881X
>  	tristate "AK8813/AK8814 video encoders"
>  	depends on I2C
> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
> index 088a460..9adc5f2 100644
> --- a/drivers/media/i2c/Makefile
> +++ b/drivers/media/i2c/Makefile
> @@ -25,6 +25,7 @@ obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o
>  obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o
>  obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
>  obj-$(CONFIG_VIDEO_ADV7393) += adv7393.o
> +obj-$(CONFIG_VIDEO_ADV7441A) += adv7441a.o
>  obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
>  obj-$(CONFIG_VIDEO_VS6624)  += vs6624.o
>  obj-$(CONFIG_VIDEO_BT819) += bt819.o
> diff --git a/drivers/media/i2c/adv7441a.c b/drivers/media/i2c/adv7441a.c
> new file mode 100644
> index 0000000..d9aa5de
> --- /dev/null
> +++ b/drivers/media/i2c/adv7441a.c
> @@ -0,0 +1,4257 @@
> +/*
> + *  Driver for the Analog Devices ADV7441A Video Decoder.
> + *
> + *  Copyright 2011/2012, Kernel Labs Inc. www.kernellabs.com.
> + *   - Steven Toth <stoth@kernellabs.com>
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, write to the Free Software
> + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/ctype.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/module.h>
> +#include <linux/videodev2.h>
> +#include <linux/uaccess.h>
> +
> +#include <media/adv7441a.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-chip-ident.h>
> +#include <media/v4l2-ctrls.h>
> +
> +MODULE_DESCRIPTION("ADV7393 video encoder driver");
> +MODULE_LICENSE("GPL");
> +
> +static unsigned int debug;
> +module_param_named(debug, debug, int, 0644);
> +MODULE_PARM_DESC(debug, "enable debug messages [adv7441a]");
> +
> +#define dprintk(level, fmt, arg...)\
> +	do { \
> +		if (debug >= level)\
> +			pr_err(" " fmt, ## arg);\
> +	} while (0)
> +
> +static u8 edid_data[256] = {
> +	0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
> +	0x06, 0x96, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00,
> +	0x0F, 0x14, 0x01, 0x04, 0x80, 0x31, 0x1C, 0xA0,
> +	0x2A, 0xAA, 0x33, 0xA4, 0x55, 0x48, 0x93, 0x25,
> +	0x10, 0x45, 0x47, 0x2F, 0xCF, 0x00, 0x31, 0x59,
> +	0x45, 0x59, 0x61, 0x59, 0x81, 0x80, 0xA9, 0x40,
> +	0xD1, 0x00, 0xB3, 0x00, 0x95, 0x00, 0x02, 0x3A,
> +	0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C,
> +	0x45, 0x00, 0xE8, 0x12, 0x11, 0x00, 0x00, 0x1E,
> +	0x00, 0x00, 0x00, 0xFD, 0x00, 0x17, 0x56, 0x0F,
> +	0x6F, 0x11, 0x04, 0x10, 0x00, 0x00, 0xF0, 0x38,
> +	0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x4F,
> +	0x73, 0x70, 0x72, 0x65, 0x79, 0x38, 0x30, 0x30,
> +	0x20, 0x31, 0x2E, 0x34, 0x00, 0x00, 0x00, 0xF7,
> +	0x00, 0x0A, 0x1F, 0xFF, 0xFF, 0x64, 0x02, 0x00,
> +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xED,
> +	0x02, 0x03, 0x2A, 0x72, 0x55, 0x90, 0x05, 0x1F,
> +	0x14, 0x04, 0x13, 0x01, 0x02, 0x03, 0x11, 0x12,
> +	0x06, 0x07, 0x15, 0x16, 0x22, 0x21, 0x20, 0x3E,
> +	0x3D, 0x3C, 0x23, 0x0F, 0x57, 0x07, 0x83, 0x4F,
> +	0x00, 0x00, 0x67, 0x03, 0x0C, 0x00, 0x10, 0x00,
> +	0xA8, 0x2D, 0x01, 0x1D, 0x80, 0x18, 0x71, 0x1C,
> +	0x16, 0x20, 0x58, 0x2C, 0x25, 0x00, 0xE8, 0x12,
> +	0x11, 0x00, 0x00, 0x9E, 0x01, 0x1D, 0x80, 0xD0,
> +	0x72, 0x1C, 0x16, 0x20, 0x10, 0x2C, 0x25, 0x80,
> +	0xE8, 0x12, 0x11, 0x00, 0x00, 0x9E, 0x01, 0x1D,
> +	0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, 0x6E, 0x28,
> +	0x55, 0x00, 0xE8, 0x12, 0x11, 0x00, 0x00, 0x1E,
> +	0x01, 0x1D, 0x00, 0xBC, 0x52, 0xD0, 0x1E, 0x20,
> +	0xB8, 0x28, 0x55, 0x40, 0xE8, 0x12, 0x11, 0x00,
> +	0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91,
> +};

Hmm... Doesn't the driver support reading the EDID table from the
hardware?

> +
> +struct vga_size_t {
> +	u32 lcf_min;
> +	u32 lcf_max;
> +	u32 width;
> +	u32 height[2];
> +	u32 interlaced;
> +};
> +
> +struct vga_rate_t {
> +	u32 fcl_min;
> +	u32 fcl_max;
> +	u32 ulInterval10M;
> +	u32 ucFps100;
> +	u32 ucFps099;
> +	u32 rate;
> +};
> +
> +/* We cross reference video_input_type into out formats array, allowing the
> + * driver to determine whether a video format is appropriate for a given
> + * input. The following enum is used internally only for cross referencing.
> + */
> +enum format_input_type {
> +	FMT_INPUT_UNKNOWN       = 0x00,
> +	FMT_INPUT_DVI           = 0x01,
> +	FMT_INPUT_YPRPB         = 0x02,
> +	FMT_INPUT_VGA           = 0x04,
> +	FMT_INPUT_SVIDEO        = 0x08,
> +	FMT_INPUT_COMPOSITE1    = 0x10,
> +	FMT_INPUT_COMPOSITE2    = 0x20,
> +	FMT_INPUT_COMPOSITE3    = 0x40,
> +};
> +
> +struct adv7441a_format {
> +	char  *name;
> +	u32 fourcc;          /* v4l2 format id */
> +	int depth, width, height;
> +	int flags;
> +	int id;
> +	int frate;
> +
> +	/* VBI Related */
> +	u32 vbi_total_lines;
> +	u32 vbi_field0_lines;
> +	u32 vbi_field1_lines;
> +
> +	/* The types of cable inputs this vodeo format is compatible with */
> +	enum format_input_type input;
> +};
> +
> +struct vga_timing_t {
> +	u32 timing_mode;
> +	u32 spec_height;
> +	u32 spec_width;
> +	u32 active_pixels;
> +	u32 active_lines;
> +	u32 total_pixels;
> +	u32 total_lines;
> +	u32 fcl;
> +	u32 bl;
> +	double spec_frequency;
> +	double pixel_clock;
> +	double h_freq;
> +	double v_freq;
> +	double real_field_rate;
> +	double real_frame_rate;

double? That looks weird on my eyes, are you using floating point
numbers on this driver?

> +	u32 h_blanking;
> +	u32 h_sync;
> +	u32 h_front_porch;
> +	u32 h_back_porch;
> +	u32 h_start;
> +	u32 h_end;
> +	u32 v_blaking;
> +	u32 v_sync;
> +	u32 v_front_porch;
> +	u32 v_back_porch;
> +	u32 v_start;
> +	u32 v_end;
> +	u32 left_margin;
> +	u32 right_margin;
> +	u32 top_margin;
> +	u32 bottom_margin;
> +	u32 reduced_blanking;
> +	u32 interlaced;
> +};
> +
> +struct adv7441a_state {
> +
> +	struct v4l2_subdev sd;
> +	struct v4l2_ctrl_handler hdl;
> +	struct i2c_client *client;
> +#if 0
> +	struct workqueue_struct *work_queues;
> +	struct delayed_work delayed_work_enable_hotplug;
> +#endif
> +	u32 vbi_enabled;
> +
> +	/* I2C Addresses */
> +	struct vc8x0_i2c *bus;
> +	u8 usermap_addr;
> +	struct i2c_client *usermap_client;
> +
> +	u8 user1map_addr;
> +	struct i2c_client *user1map_client;
> +
> +	u8 user2map_addr;
> +	struct i2c_client *user2map_client;
> +
> +	u8 user3map_addr;
> +	struct i2c_client *user3map_client;
> +
> +	u8 reservedmap_addr;
> +	struct i2c_client *reservedmap_client;
> +
> +	u8 hdmimap_addr;
> +	struct i2c_client *hdmimap_client;
> +
> +	u8 rksvmap_addr;
> +	struct i2c_client *rksvmap_client;
> +
> +	u8 edidmap_addr;
> +	struct i2c_client *edidmap_client;
> +
> +	struct adv7441a_format *fmt;
> +
> +	/* Controls */
> +	u32 brightness;
> +	u32 contrast;
> +	u32 hue;
> +	u32 saturation;
> +
> +	/* Detected settings */
> +	/* jiffy last time in ms, when we attempt a fmt and lock detect */
> +	u64 last_detected;
> +	u64 last_locked;
> +	u32 detected_width;
> +	u32 detected_height;
> +	u32 detected_interlaced;
> +	struct adv7441a_format *detected_fmt;
> +	struct vga_timing_t *vga_timing_mode;
> +
> +	/* physical video input */
> +	u32 video_input_nr;
> +
> +	struct detection_t {
> +		/* false(0) / true(1) */
> +		u32 valid;
> +		u32 locked;
> +		u32 interlaced;

Huh? Just declare them with "bool" type, instead, if they are
booleans.

> +
> +		/* 00 Invalid
> +		 * 01 Separate HS and VS sync on pins
> +		 * 10 External CS sync on HS IN pin
> +		 * 11 Embedded SOG/SOY
> +		 */
> +		u32 sync_mask;
> +
> +		/* 0 - VS IN pin positiv
> +		 * 1 - HS IN pin positive
> +		 */
> +		/* 00 Invalid
> +		 * 01 GTF (in vga timings as 00)
> +		 * 10 CVT  (in vga timings as 01)
> +		 * 11 DMT (in vga timings as 02)
> +		 */
> +		u32 sync_polarity;
> +
> +		u32 bl;
> +
> +		/* Number of lines in the field */
> +		u32 lcf;
> +
> +		/* Number of lines in a vsync period */
> +		u32 lcvs;
> +
> +		/* Field Length Count - Number of clock cycles between
> +		 * successive vsyncs */
> +		u32 fcl28;
> +
> +		/* Field Rate Hz * 100, eg 5994 */
> +		u32 field_rate;
> +
> +		/* Raw register data */
> +		u8 stat_10[4], stdi_b1[5], fcl[2];
> +
> +	} detection;
> +};
> +
> +/* TODO: Review how many of these fields are required and
> + * how many are redundant after the cloned struct from the
> + * vc8x0.
> + */
> +static struct adv7441a_format formats[] = {
> +	{
> +		.name     = "422packed,YUYV,640x480p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 640,
> +		.height   = 480,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_640x480p60,

The DV API defines the formats for digital video. Use it, instead of
adding a new type here.

> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_VGA,
> +	},
> +/* 720 x 480 */
> +	{
> +		.name     = "422packed,YUYV,720x480i59",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 720,
> +		.height   = 480,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_INTERLACED,
> +		.id       = ADV7441A_FORMAT_720x480i59,
> +		.frate    = ADV7441A_FRAMERATE_59,
> +		.vbi_total_lines = 45,
> +		.vbi_field0_lines = 22,
> +		.vbi_field1_lines = 23,
> +		.input    = FMT_INPUT_DVI |
> +			FMT_INPUT_YPRPB |
> +			FMT_INPUT_SVIDEO |
> +			FMT_INPUT_COMPOSITE1 |
> +			FMT_INPUT_COMPOSITE2 |
> +			FMT_INPUT_COMPOSITE3,
> +	},
> +	{
> +		.name     = "422packed,YUYV,720x480i60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 720,
> +		.height   = 480,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_INTERLACED,
> +		.id       = ADV7441A_FORMAT_720x480i60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.vbi_total_lines = 45,
> +		.vbi_field0_lines = 22,
> +		.vbi_field1_lines = 23,
> +		.input    = FMT_INPUT_DVI |
> +			FMT_INPUT_YPRPB |
> +			FMT_INPUT_SVIDEO |
> +			FMT_INPUT_COMPOSITE1 |
> +			FMT_INPUT_COMPOSITE2 |
> +			FMT_INPUT_COMPOSITE3,
> +	},
> +/* 720 x 576 */
> +	{
> +		.name     = "422packed,YUYV,720x576p25",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 720,
> +		.height   = 576,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_720x576p25,
> +		.frate    = ADV7441A_FRAMERATE_25,
> +		.input    = FMT_INPUT_DVI |
> +			FMT_INPUT_YPRPB |
> +			FMT_INPUT_SVIDEO |
> +			FMT_INPUT_COMPOSITE1 |
> +			FMT_INPUT_COMPOSITE2 |
> +			FMT_INPUT_COMPOSITE3,
> +	},
> +	{
> +		.name     = "422packed,YUYV,720x576i50",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 720,
> +		.height   = 576,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_INTERLACED,
> +		.id       = ADV7441A_FORMAT_720x576i50,
> +		.frate    = ADV7441A_FRAMERATE_50,
> +		.input    = FMT_INPUT_DVI |
> +			FMT_INPUT_YPRPB |
> +			FMT_INPUT_SVIDEO |
> +			FMT_INPUT_COMPOSITE1 |
> +			FMT_INPUT_COMPOSITE2 |
> +			FMT_INPUT_COMPOSITE3,
> +	},
> +/* 800 x 600 */
> +	{
> +		.name     = "422packed,YUYV,800x600p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 800,
> +		.height   = 600,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_800x600p60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_VGA,
> +	},
> +/* 1024 x 768 */
> +	{
> +		.name     = "422packed,YUYV,1024x768p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1024,
> +		.height   = 768,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1024x768p60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_VGA,
> +	},
> +/* 1280 x 960 */
> +	{
> +		.name     = "422packed,YUYV,1280x960p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1280,
> +		.height   = 960,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1280x960p60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_VGA,
> +	},
> +	{
> +		.name     = "422packed,YUYV,1280x1024p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1280,
> +		.height   = 1024,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1280x1024p60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_VGA,
> +	},
> +/* 1280 x 720 */
> +	{
> +		.name     = "422packed,YUYV,1280x720p23",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1280,
> +		.height   = 720,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1280x720p23,
> +		.frate    = ADV7441A_FRAMERATE_23,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	}, {
> +		.name     = "422packed,YUYV,1280x720p24",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1280,
> +		.height   = 720,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1280x720p24,
> +		.frate    = ADV7441A_FRAMERATE_24,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	}, {
> +		.name     = "422packed,YUYV,1280x720p25",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1280,
> +		.height   = 720,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1280x720p25,
> +		.frate    = ADV7441A_FRAMERATE_25,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	}, {
> +		.name     = "422packed,YUYV,1280x720p29",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1280,
> +		.height   = 720,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1280x720p29,
> +		.frate    = ADV7441A_FRAMERATE_29,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	}, {
> +		.name     = "422packed,YUYV,1280x720p30",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1280,
> +		.height   = 720,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1280x720p30,
> +		.frate    = ADV7441A_FRAMERATE_30,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	}, {
> +		.name     = "422packed,YUYV,1280x720p50",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1280,
> +		.height   = 720,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1280x720p50,
> +		.frate    = ADV7441A_FRAMERATE_50,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	}, {
> +		.name     = "422packed,YUYV,1280x720p59",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1280,
> +		.height   = 720,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1280x720p59,
> +		.frate    = ADV7441A_FRAMERATE_59,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	}, {
> +		.name     = "422packed,YUYV,1280x720p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1280,
> +		.height   = 720,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1280x720p60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB | FMT_INPUT_VGA,
> +	},
> +/* 1400 x 1050 */
> +	{
> +		.name     = "422packed,YUYV,1400x1050p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1400,
> +		.height   = 1050,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1400x1050p60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_VGA,
> +	},
> +/* 1600 x 1200 */
> +	{
> +		.name     = "422packed,YUYV,1600x1200p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1600,
> +		.height   = 1200,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1600x1200p60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_VGA,
> +	},
> +/* 1920 x 1080 */
> +	{
> +		.name     = "422packed,YUYV,1920x1080i50",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1920,
> +		.height   = 1080,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_INTERLACED,
> +		.id       = ADV7441A_FORMAT_1920x1080i50,
> +		.frate    = ADV7441A_FRAMERATE_50,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	},
> +	{
> +		.name     = "422packed,YUYV,1920x1080i59",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1920,
> +		.height   = 1080,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_INTERLACED,
> +		.id       = ADV7441A_FORMAT_1920x1080i59,
> +		.frate    = ADV7441A_FRAMERATE_59,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	}, {
> +		.name     = "422packed,YUYV,1920x1080i60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1920,
> +		.height   = 1080,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_INTERLACED,
> +		.id       = ADV7441A_FORMAT_1920x1080i60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	},
> +	{
> +		.name     = "422packed,YUYV,1920x1080p23",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1920,
> +		.height   = 1080,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1920x1080p23,
> +		.frate    = ADV7441A_FRAMERATE_23,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	}, {
> +		.name     = "422packed,YUYV,1920x1080p24",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1920,
> +		.height   = 1080,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1920x1080p24,
> +		.frate    = ADV7441A_FRAMERATE_24,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	}, {
> +		.name     = "422packed,YUYV,1920x1080p25",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1920,
> +		.height   = 1080,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1920x1080p25,
> +		.frate    = ADV7441A_FRAMERATE_25,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	}, {
> +		.name     = "422packed,YUYV,1920x1080p30",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1920,
> +		.height   = 1080,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1920x1080p30,
> +		.frate    = ADV7441A_FRAMERATE_30,
> +		.input    = FMT_INPUT_DVI | FMT_INPUT_YPRPB,
> +	}, {
> +		.name     = "422packed,YUYV,1920x1080p50",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1920,
> +		.height   = 1080,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1920x1080p50,
> +		.frate    = ADV7441A_FRAMERATE_50,
> +		.input    = FMT_INPUT_DVI,
> +	},
> +	{
> +		.name     = "422packed,YUYV,1920x1080p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1920,
> +		.height   = 1080,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_1920x1080p60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_DVI,
> +	},
> +	{
> +		.name     = "422packed,YUYV,1600x1200p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1600,
> +		.height   = 1200,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_UXGA_1600x1200p60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_VGA,
> +	},
> +	{
> +		.name     = "422packed,YUYV,1440x900p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1440,
> +		.height   = 900,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_WXGA_1440x900p60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_VGA,
> +	},
> +	{
> +		.name     = "422packed,YUYV,1680x1050p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1680,
> +		.height   = 1050,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_WSXGA_1680x1050p60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_VGA,
> +	},
> +	{
> +		.name     = "422packed,YUYV,1920x1080p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 1920,
> +		.height   = 1080,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_VGAHD_1920x1080p60,
> +		.frate    = ADV7441A_FRAMERATE_60,
> +		.input    = FMT_INPUT_VGA,
> +	},
> +};
> +
> +/*
> +Timing Mode,Spec Height,Spec Width,Active Pixels,Active Lines,Total Pixels,Total Lines,FCL,BL,Spec Frequency,Pixel Clock,H Freq,V Freq,Real Field Rate,Real Frame Rate,H Blanking,H Sync,H Front Porch,H Back Porch,H Start,H End,V Blanking,V Sync,V Front Porch,V Back Porch,V Start,V End,Left Margin,Right Margin,Top Margin,Bottom Margin,Reduced Blanking,Interlaced
> +*/
> +static struct vga_timing_t vga_timings[] = {
> +{ 0, 200, 320, 320, 200, 400, 212, 1896, 18323, 60.000000, 5.000000, 12.500000, 60.000000, 58.960000, 58.960000, 80, 32, 8, 40, 328, 360, 12, 6, 3, 3, 203, 209, 0, 0, 0, 0, 0, 0 },
> +{ 0, 200, 320, 320, 200, 480, 215, 1923, 18323, 60.000000, 6.000000, 12.500000, 60.000000, 58.130000, 58.130000, 80, 32, 8, 40, 328, 360, 14, 6, 3, 5, 203, 209, 0, 0, 0, 0, 1, 0 },
> +{ 0, 200, 320, 320, 200, 400, 112, 2004, 36646, 60.000000, 2.500000, 6.250000, 60.000000, 55.550000, 27.770000, 80, 32, 8, 40, 328, 360, 12, 6, 3, 3, 203, 209, 0, 0, 0, 0, 0, 1 },
> +{ 0, 200, 320, 320, 200, 480, 115, 1899, 33827, 60.000000, 3.250000, 6.770000, 60.000000, 58.620000, 29.310000, 80, 32, 8, 40, 328, 360, 11, 6, 3, 2, 203, 209, 0, 0, 0, 0, 1, 1 },
> +{ 0, 240, 320, 320, 240, 400, 252, 1878, 15269, 60.000000, 6.000000, 15.000000, 60.000000, 59.520000, 59.520000, 80, 32, 8, 40, 328, 360, 12, 4, 3, 5, 243, 247, 0, 0, 0, 0, 0, 0 },
> +{ 0, 240, 320, 320, 240, 480, 253, 1873, 15164, 60.000000, 7.250000, 15.100000, 60.000000, 59.690000, 59.690000, 80, 32, 8, 40, 328, 360, 13, 4, 3, 6, 243, 247, 0, 0, 0, 0, 1, 0 },
> +{ 0, 240, 320, 320, 240, 400, 130, 1938, 30538, 60.000000, 3.000000, 7.500000, 60.000000, 57.470000, 28.730000, 80, 32, 8, 40, 328, 360, 10, 4, 3, 3, 243, 247, 0, 0, 0, 0, 0, 1 },
> +{ 0, 240, 320, 320, 240, 480, 133, 1903, 29317, 60.000000, 3.750000, 7.810000, 60.000000, 58.520000, 29.260000, 80, 32, 8, 40, 328, 360, 9, 4, 3, 2, 243, 247, 0, 0, 0, 0, 1, 1 },
> +{ 0, 480, 640, 640, 480, 800, 500, 1883, 7715, 60.000000, 23.750000, 29.680000, 60.000000, 59.370000, 59.370000, 160, 64, 16, 80, 656, 720, 20, 4, 3, 13, 483, 487, 0, 0, 0, 0, 0, 0 },
> +{ 0, 480, 640, 640, 480, 800, 500, 1863, 7634, 60.000000, 24.000000, 30.000000, 60.000000, 60.000000, 60.000000, 160, 32, 48, 80, 688, 720, 20, 4, 3, 13, 483, 487, 0, 0, 0, 0, 1, 0 },
> +{ 0, 480, 640, 640, 480, 800, 252, 1878, 15269, 60.000000, 12.000000, 15.000000, 60.000000, 59.400000, 29.700000, 160, 64, 16, 80, 656, 720, 12, 4, 3, 5, 483, 487, 0, 0, 0, 0, 0, 1 },
> +{ 0, 480, 640, 640, 480, 800, 253, 1886, 15269, 60.000000, 12.000000, 15.000000, 60.000000, 59.170000, 29.580000, 160, 32, 48, 80, 688, 720, 13, 4, 3, 6, 483, 487, 0, 0, 0, 0, 1, 1 },
> +{ 0, 400, 720, 720, 400, 880, 438, 2652, 12403, 85.000000, 16.250000, 18.466000, 85.000000, 84.127563, 42.063782, 176, 32, 56, 88, 776, 808, 20, 10, 3, 7, 403, 413, 0, 0, 0, 0, 1, 1 },
> +{ 0, 400, 720, 720, 400, 896, 432, 2663, 12628, 85.000000, 16.250000, 18.136000, 85.000000, 83.769051, 41.884525, 176, 64, 24, 88, 744, 808, 16, 10, 3, 3, 403, 413, 0, 0, 0, 0, 0, 1 },
> +{ 0, 400, 720, 720, 400, 880, 419, 1319, 6449, 85.000000, 31.250000, 35.511002, 85.000000, 84.751793, 84.751793, 192, 32, 64, 96, 784, 816, 28, 10, 3, 15, 403, 413, 0, 0, 0, 0, 1, 0 },
> +{ 0, 400, 720, 720, 400, 912, 423, 1317, 6378, 85.000000, 32.750000, 35.910000, 85.000000, 84.893616, 84.893616, 192, 72, 24, 96, 744, 816, 23, 10, 3, 10, 403, 413, 0, 0, 0, 0, 0, 0 },
> +{ 0, 480, 720, 720, 480, 880, 259, 1888, 14930, 60.000000, 13.500000, 15.340000, 60.000000, 59.110000, 29.550000, 176, 32, 56, 88, 776, 808, 19, 10, 3, 6, 483, 493, 0, 0, 0, 0, 1, 1 },
> +{ 0, 480, 720, 720, 480, 880, 259, 3776, 29860, 30.000000, 6.750000, 7.670000, 30.000000, 29.556841, 14.778420, 176, 32, 56, 88, 776, 808, 15, 10, 3, 2, 483, 493, 0, 0, 0, 0, 1, 1 },
> +{ 0, 480, 720, 720, 480, 896, 256, 3946, 31572, 30.000000, 6.500000, 7.254000, 30.000000, 28.280703, 14.140351, 176, 64, 24, 88, 744, 808, 16, 10, 3, 3, 483, 493, 0, 0, 0, 0, 0, 1 },
> +{ 0, 480, 720, 720, 480, 880, 499, 3777, 15504, 30.000000, 13.000000, 14.773000, 30.000000, 29.605209, 29.605209, 176, 32, 56, 88, 776, 808, 19, 10, 3, 6, 483, 493, 0, 0, 0, 0, 1, 0 },
> +{ 0, 480, 720, 720, 480, 896, 496, 3823, 15786, 30.000000, 13.000000, 14.509000, 30.000000, 29.252016, 29.252016, 176, 64, 24, 88, 744, 808, 16, 10, 3, 3, 483, 493, 0, 0, 0, 0, 0, 0 },
> +{ 0, 480, 720, 720, 480, 880, 259, 3776, 29860, 29.969999, 6.750000, 7.670000, 29.969999, 29.556841, 14.778420, 176, 32, 56, 88, 776, 808, 15, 10, 3, 2, 483, 493, 0, 0, 0, 0, 1, 1 },
> +{ 0, 480, 720, 720, 480, 896, 256, 3946, 31572, 29.969999, 6.500000, 7.254000, 29.969999, 28.280703, 14.140351, 176, 64, 24, 88, 744, 808, 16, 10, 3, 3, 483, 493, 0, 0, 0, 0, 0, 1 },
> +{ 0, 480, 720, 720, 480, 880, 499, 3777, 15504, 29.969999, 13.000000, 14.773000, 29.969999, 29.605209, 29.605209, 176, 32, 56, 88, 776, 808, 19, 10, 3, 6, 483, 493, 0, 0, 0, 0, 1, 0 },
> +{ 0, 480, 720, 720, 480, 896, 496, 3823, 15786, 29.969999, 13.000000, 14.509000, 29.969999, 29.252016, 29.252016, 176, 64, 24, 88, 744, 808, 16, 10, 3, 3, 483, 493, 0, 0, 0, 0, 0, 0 },
> +{ 0, 480, 720, 720, 480, 896, 256, 1900, 15201, 60.000000, 13.500000, 15.600000, 60.000000, 58.740000, 29.370000, 176, 64, 24, 88, 744, 808, 16, 10, 3, 3, 483, 493, 0, 0, 0, 0, 0, 1 },
> +{ 0, 480, 720, 720, 480, 880, 499, 1870, 7678, 60.000000, 26.250000, 29.830000, 60.000000, 59.770000, 59.770000, 176, 32, 56, 88, 776, 808, 26, 10, 3, 13, 483, 493, 0, 0, 0, 0, 1, 0 },
> +{ 0, 480, 720, 720, 480, 896, 500, 1872, 7671, 60.000000, 26.750000, 29.850000, 60.000000, 59.700000, 59.700000, 176, 64, 24, 88, 744, 808, 20, 10, 3, 7, 483, 493, 0, 0, 0, 0, 0, 0 },
> +{ 0, 576, 768, 768, 576, 928, 301, 1865, 12689, 60.000000, 16.750000, 18.390000, 60.000000, 59.860000, 29.930000, 192, 32, 64, 96, 832, 864, 14, 4, 3, 7, 579, 583, 0, 0, 0, 0, 1, 1 },
> +{ 0, 576, 768, 768, 576, 960, 301, 1873, 12746, 60.000000, 17.250000, 17.960000, 60.000000, 59.590000, 29.790000, 192, 72, 24, 96, 792, 864, 13, 4, 3, 6, 579, 583, 0, 0, 0, 0, 0, 1 },
> +{ 0, 576, 768, 768, 576, 928, 598, 1866, 6392, 60.000000, 33.250000, 35.830000, 60.000000, 59.910000, 59.910000, 208, 32, 72, 104, 840, 872, 22, 4, 3, 15, 579, 583, 0, 0, 0, 0, 1, 0 },
> +{ 0, 576, 768, 768, 576, 976, 599, 1868, 6386, 60.000000, 35.000000, 35.860000, 60.000000, 59.860000, 59.860000, 208, 72, 32, 104, 800, 872, 23, 4, 3, 16, 579, 583, 0, 0, 0, 0, 0, 0 },
> +{ 0, 480, 800, 800, 480, 960, 256, 1863, 14907, 60.000000, 14.750000, 15.360000, 60.000000, 59.900000, 29.950000, 192, 32, 64, 96, 864, 896, 16, 7, 3, 6, 483, 490, 0, 0, 0, 0, 1, 1 },
> +{ 0, 480, 800, 800, 480, 992, 253, 1902, 15403, 60.000000, 14.750000, 14.860000, 60.000000, 58.650000, 29.320000, 192, 72, 24, 96, 824, 896, 13, 7, 3, 3, 483, 490, 0, 0, 0, 0, 0, 1 },
> +{ 0, 480, 800, 800, 480, 960, 496, 1868, 7715, 60.000000, 28.500000, 29.680000, 60.000000, 59.850000, 59.850000, 192, 32, 64, 96, 864, 896, 23, 7, 3, 13, 483, 490, 0, 0, 0, 0, 1, 0 },
> +{ 0, 480, 800, 800, 480, 992, 500, 1880, 7701, 60.000000, 29.500000, 29.730000, 60.000000, 59.470000, 59.470000, 192, 72, 24, 96, 824, 896, 20, 7, 3, 10, 483, 490, 0, 0, 0, 0, 0, 0 },
> +{ 0, 600, 800, 800, 600, 960, 313, 1866, 12215, 60.000000, 18.000000, 18.750000, 60.000000, 59.800000, 29.900000, 192, 32, 64, 96, 864, 896, 15, 4, 3, 8, 603, 607, 0, 0, 0, 0, 1, 1 },
> +{ 0, 600, 800, 800, 600, 992, 314, 1883, 12281, 60.000000, 18.500000, 18.640000, 60.000000, 59.290000, 29.640000, 192, 72, 24, 96, 824, 896, 14, 4, 3, 7, 603, 607, 0, 0, 0, 0, 0, 1 },
> +{ 0, 600, 800, 800, 600, 960, 623, 1870, 6150, 60.000000, 35.750000, 37.240000, 60.000000, 59.770000, 59.770000, 224, 32, 80, 112, 880, 912, 23, 4, 3, 16, 603, 607, 0, 0, 0, 0, 1, 0 },
> +{ 0, 600, 800, 800, 600, 1024, 624, 1868, 6131, 60.000000, 38.250000, 37.350000, 60.000000, 59.860000, 59.860000, 224, 80, 32, 112, 832, 912, 24, 4, 3, 17, 603, 607, 0, 0, 0, 0, 0, 0 },
> +{ 0, 768, 1024, 1024, 768, 1184, 397, 1877, 9685, 60.000000, 28.000000, 23.640000, 60.000000, 59.490000, 29.740000, 256, 32, 96, 128, 1120, 1152, 17, 4, 3, 10, 771, 775, 0, 0, 0, 0, 1, 1 },
> +{ 0, 768, 1024, 1024, 768, 1280, 401, 1866, 9534, 60.000000, 30.750000, 24.200000, 60.000000, 59.830000, 29.910000, 256, 96, 32, 128, 1056, 1152, 17, 4, 3, 10, 771, 775, 0, 0, 0, 0, 0, 1 },
> +{ 0, 768, 1024, 1024, 768, 1184, 796, 1865, 4799, 60.000000, 56.500000, 47.720000, 60.000000, 59.940000, 59.940000, 304, 32, 120, 152, 1144, 1176, 28, 4, 3, 21, 771, 775, 0, 0, 0, 0, 1, 0 },
> +{ 0, 768, 1024, 1024, 768, 1328, 798, 1866, 4790, 60.000000, 63.500000, 47.810000, 60.000000, 59.910000, 59.910000, 304, 104, 48, 152, 1072, 1176, 30, 4, 3, 23, 771, 775, 0, 0, 0, 0, 0, 0 },
> +{ 0, 768, 1152, 1152, 768, 1312, 403, 1862, 9464, 60.000000, 31.750000, 24.200000, 60.000000, 59.970000, 29.980000, 288, 32, 112, 144, 1264, 1296, 23, 10, 3, 10, 771, 781, 0, 0, 0, 0, 1, 1 },
> +{ 0, 768, 1152, 1152, 768, 1440, 401, 1871, 9559, 60.000000, 34.500000, 23.950000, 60.000000, 59.670000, 29.830000, 288, 112, 32, 144, 1184, 1296, 17, 10, 3, 4, 771, 781, 0, 0, 0, 0, 0, 1 },
> +{ 0, 768, 1152, 1152, 768, 1312, 802, 1867, 4769, 60.000000, 63.000000, 48.100000, 60.000000, 59.870000, 59.870000, 352, 32, 144, 176, 1296, 1328, 34, 10, 3, 21, 771, 781, 0, 0, 0, 0, 1, 0 },
> +{ 0, 768, 1152, 1152, 768, 1504, 798, 1870, 4801, 60.000000, 71.750000, 47.700000, 60.000000, 59.780000, 59.780000, 352, 120, 56, 176, 1208, 1328, 30, 10, 3, 17, 771, 781, 0, 0, 0, 0, 0, 0 },
> +{ 0, 864, 1152, 1152, 864, 1312, 445, 1865, 8585, 60.000000, 35.000000, 26.677000, 60.000000, 59.881031, 29.940516, 288, 32, 112, 144, 1264, 1296, 18, 4, 3, 11, 867, 871, 0, 0, 0, 0, 1, 1 },
> +{ 0, 864, 1152, 1152, 864, 1440, 450, 1870, 8511, 60.000000, 38.750000, 26.910000, 60.000000, 59.733627, 29.866814, 288, 112, 32, 144, 1184, 1296, 18, 4, 3, 11, 867, 871, 0, 0, 0, 0, 0, 1 },
> +{ 0, 864, 1152, 1152, 864, 1312, 895, 1869, 4277, 60.000000, 70.250000, 53.543999, 60.000000, 59.825695, 59.825695, 368, 32, 152, 184, 1304, 1336, 31, 4, 3, 24, 867, 871, 0, 0, 0, 0, 1, 0 },
> +{ 0, 864, 1152, 1152, 864, 1520, 897, 1865, 4258, 60.000000, 81.750000, 53.783001, 60.000000, 59.958752, 59.958752, 368, 120, 64, 184, 1216, 1336, 33, 4, 3, 26, 867, 871, 0, 0, 0, 0, 0, 0 },
> +{ 0, 720, 1280, 1280, 720, 1440, 374, 1867, 10226, 60.000000, 32.250000, 22.390000, 60.000000, 59.800000, 29.900000, 320, 32, 128, 160, 1408, 1440, 17, 5, 3, 9, 723, 728, 0, 0, 0, 0, 1, 1 },
> +{ 0, 720, 1280, 1280, 720, 1600, 376, 1868, 10179, 60.000000, 36.000000, 22.500000, 60.000000, 59.760000, 29.880000, 320, 128, 32, 160, 1312, 1440, 16, 5, 3, 8, 723, 728, 0, 0, 0, 0, 0, 1 },
> +{ 0, 720, 1280, 1280, 720, 1440, 747, 1865, 5113, 60.000000, 64.500000, 44.790000, 60.000000, 59.960000, 59.960000, 384, 32, 160, 192, 1440, 1472, 27, 5, 3, 19, 723, 728, 0, 0, 0, 0, 1, 0 },
> +{ 0, 720, 1280, 1280, 720, 1664, 748, 1868, 5115, 60.000000, 74.500000, 44.770000, 60.000000, 59.850000, 59.850000, 384, 128, 64, 192, 1344, 1472, 28, 5, 3, 20, 723, 728, 0, 0, 0, 0, 0, 0 },
> +{ 0, 768, 1280, 1280, 768, 1440, 400, 1867, 9559, 60.000000, 34.500000, 23.950000, 60.000000, 59.820000, 29.910000, 320, 32, 128, 160, 1408, 1440, 20, 7, 3, 10, 771, 778, 0, 0, 0, 0, 1, 1 },
> +{ 0, 768, 1280, 1280, 768, 1600, 401, 1875, 9580, 60.000000, 38.250000, 23.900000, 60.000000, 59.540000, 29.770000, 320, 128, 32, 160, 1312, 1440, 17, 7, 3, 7, 771, 778, 0, 0, 0, 0, 0, 1 },
> +{ 0, 768, 1280, 1280, 768, 1440, 799, 1864, 4779, 60.000000, 69.000000, 47.910000, 60.000000, 59.970000, 59.970000, 384, 32, 160, 192, 1440, 1472, 31, 7, 3, 21, 771, 778, 0, 0, 0, 0, 1, 0 },
> +{ 0, 768, 1280, 1280, 768, 1664, 798, 1867, 4793, 60.000000, 79.500000, 47.770000, 60.000000, 59.860000, 59.860000, 384, 128, 64, 192, 1344, 1472, 30, 7, 3, 20, 771, 778, 0, 0, 0, 0, 0, 0 },
> +{ 0, 800, 1280, 1280, 800, 1440, 415, 1869, 9225, 60.000000, 35.750000, 24.820000, 60.000000, 59.740000, 29.870000, 320, 32, 128, 160, 1408, 1440, 19, 6, 3, 10, 803, 809, 0, 0, 0, 0, 1, 1 },
> +{ 0, 800, 1280, 1280, 800, 1600, 417, 1865, 9161, 60.000000, 40.000000, 25.000000, 60.000000, 59.880000, 29.940000, 320, 128, 32, 160, 1312, 1440, 17, 6, 3, 8, 803, 809, 0, 0, 0, 0, 0, 1 },
> +{ 0, 800, 1280, 1280, 800, 1440, 831, 1865, 4596, 60.000000, 71.750000, 49.820000, 60.000000, 59.950000, 59.950000, 400, 32, 168, 200, 1448, 1480, 31, 6, 3, 22, 803, 809, 0, 0, 0, 0, 1, 0 },
> +{ 0, 800, 1280, 1280, 800, 1680, 831, 1869, 4608, 60.000000, 83.500000, 49.700000, 60.000000, 59.800000, 59.800000, 400, 128, 72, 200, 1352, 1480, 31, 6, 3, 22, 803, 809, 0, 0, 0, 0, 0, 0 },
> +{ 0, 960, 1280, 1280, 960, 1440, 500, 1872, 7670, 60.000000, 43.000000, 29.860000, 60.000000, 59.660000, 29.830000, 320, 32, 128, 160, 1408, 1440, 20, 4, 3, 13, 963, 967, 0, 0, 0, 0, 1, 1 },
> +{ 0, 960, 1280, 1280, 960, 1600, 500, 1863, 7634, 60.000000, 48.000000, 30.000000, 60.000000, 59.940000, 29.970000, 320, 128, 32, 160, 1312, 1440, 20, 4, 3, 13, 963, 967, 0, 0, 0, 0, 0, 1 },
> +{ 0, 960, 1280, 1280, 960, 1440, 993, 1864, 3846, 60.000000, 85.750000, 59.540000, 60.000000, 59.960000, 59.960000, 416, 32, 176, 208, 1456, 1488, 33, 4, 3, 26, 963, 967, 0, 0, 0, 0, 1, 0 },
> +{ 0, 960, 1280, 1280, 960, 1696, 996, 1865, 3836, 60.000000, 101.250000, 59.690000, 60.000000, 59.930000, 59.930000, 416, 128, 80, 208, 1360, 1488, 36, 4, 3, 29, 963, 967, 0, 0, 0, 0, 0, 0 },
> +{ 0, 1024, 1280, 1280, 1024, 1440, 528, 1868, 7248, 60.000000, 45.500000, 31.590000, 60.000000, 59.780000, 29.890000, 320, 32, 128, 160, 1408, 1440, 24, 7, 3, 14, 1027, 1034, 0, 0, 0, 0, 1, 1 },
> +{ 0, 1024, 1280, 1280, 1024, 1600, 533, 1870, 7185, 60.000000, 51.000000, 31.870000, 60.000000, 59.740000, 29.870000, 320, 128, 32, 160, 1312, 1440, 21, 7, 3, 11, 1027, 1034, 0, 0, 0, 0, 0, 1 },
> +{ 0, 1024, 1280, 1280, 1024, 1440, 1062, 1864, 3594, 60.000000, 91.750000, 63.710000, 60.000000, 59.990000, 59.990000, 432, 32, 184, 216, 1464, 1496, 38, 7, 3, 28, 1027, 1034, 0, 0, 0, 0, 1, 0 },
> +{ 0, 1024, 1280, 1280, 1024, 1712, 1063, 1867, 3597, 60.000000, 109.000000, 63.660000, 60.000000, 59.890000, 59.890000, 432, 136, 80, 216, 1360, 1496, 39, 7, 3, 29, 1027, 1034, 0, 0, 0, 0, 0, 0 },
> +{ 0, 768, 1366, 1360, 768, 1520, 398, 1866, 9603, 60.000000, 36.250000, 23.840000, 60.000000, 59.840000, 29.920000, 336, 32, 136, 168, 1496, 1528, 18, 5, 3, 10, 771, 776, 0, 0, 0, 0, 1, 1 },
> +{ 0, 768, 1366, 1360, 768, 1696, 401, 1866, 9532, 60.000000, 40.750000, 24.200000, 60.000000, 59.840000, 29.920000, 336, 128, 40, 168, 1400, 1528, 17, 5, 3, 9, 771, 776, 0, 0, 0, 0, 0, 1 },
> +{ 0, 768, 1366, 1360, 768, 1520, 797, 1868, 4801, 60.000000, 72.500000, 47.690000, 60.000000, 59.840000, 59.840000, 416, 32, 176, 208, 1536, 1568, 29, 5, 3, 21, 771, 776, 0, 0, 0, 0, 1, 0 },
> +{ 0, 768, 1366, 1360, 768, 1776, 798, 1870, 4799, 60.000000, 84.750000, 47.720000, 60.000000, 59.790000, 59.790000, 416, 136, 72, 208, 1432, 1568, 30, 5, 3, 22, 771, 776, 0, 0, 0, 0, 0, 0 },
> +{ 0, 1050, 1400, 1400, 1050, 1560, 546, 1867, 7005, 60.000000, 51.000000, 32.690000, 60.000000, 59.820000, 29.910000, 352, 32, 144, 176, 1544, 1576, 21, 4, 3, 14, 1053, 1057, 0, 0, 0, 0, 1, 1 },
> +{ 0, 1050, 1400, 1400, 1050, 1768, 547, 1872, 7011, 60.000000, 57.750000, 32.650000, 60.000000, 59.660000, 29.830000, 368, 136, 48, 184, 1448, 1584, 22, 4, 3, 15, 1053, 1057, 0, 0, 0, 0, 0, 1 },
> +{ 0, 1050, 1400, 1400, 1050, 1560, 1086, 1866, 3520, 60.000000, 101.500000, 65.590000, 60.000000, 59.910000, 59.910000, 464, 32, 200, 232, 1600, 1632, 36, 4, 3, 29, 1053, 1057, 0, 0, 0, 0, 1, 0 },
> +{ 0, 1050, 1400, 1400, 1050, 1864, 1089, 1864, 3506, 60.000000, 121.750000, 65.310000, 60.000000, 59.970000, 59.970000, 464, 144, 88, 232, 1488, 1632, 39, 4, 3, 32, 1053, 1057, 0, 0, 0, 0, 0, 0 },
> +{ 0, 900, 1440, 1440, 900, 1600, 465, 1869, 8235, 60.000000, 44.500000, 27.810000, 60.000000, 59.740000, 29.870000, 352, 32, 144, 176, 1584, 1616, 21, 6, 3, 12, 903, 909, 0, 0, 0, 0, 1, 1 },
> +{ 0, 900, 1440, 1440, 900, 1792, 469, 1870, 8167, 60.000000, 50.250000, 28.400000, 60.000000, 59.720000, 29.860000, 352, 136, 40, 176, 1480, 1616, 19, 6, 3, 10, 903, 909, 0, 0, 0, 0, 0, 1 },
> +{ 0, 900, 1440, 1440, 900, 1600, 934, 1867, 4094, 60.000000, 89.500000, 55.930000, 60.000000, 59.890000, 59.890000, 464, 32, 200, 232, 1640, 1672, 34, 6, 3, 25, 903, 909, 0, 0, 0, 0, 1, 0 },
> +{ 0, 900, 1440, 1440, 900, 1904, 934, 1867, 4094, 60.000000, 106.500000, 55.930000, 60.000000, 59.880000, 59.880000, 464, 152, 80, 232, 1520, 1672, 34, 6, 3, 25, 903, 909, 0, 0, 0, 0, 0, 0 },
> +{ 0, 960, 1440, 1440, 960, 1600, 499, 1869, 7674, 60.000000, 47.750000, 29.840000, 60.000000, 59.740000, 29.870000, 352, 32, 144, 176, 1584, 1616, 26, 10, 3, 13, 963, 973, 0, 0, 0, 0, 1, 1 },
> +{ 0, 960, 1440, 1440, 960, 1792, 500, 1864, 7636, 60.000000, 53.750000, 29.990000, 60.000000, 59.920000, 29.960000, 352, 136, 40, 176, 1480, 1616, 20, 10, 3, 7, 963, 973, 0, 0, 0, 0, 0, 1 },
> +{ 0, 960, 1440, 1440, 960, 1600, 999, 1866, 3827, 60.000000, 95.750000, 59.840000, 60.000000, 59.900000, 59.900000, 464, 32, 200, 232, 1640, 1672, 39, 10, 3, 26, 963, 973, 0, 0, 0, 0, 1, 0 },
> +{ 0, 960, 1440, 1440, 960, 1904, 996, 1864, 3833, 60.000000, 113.750000, 59.740000, 60.000000, 59.980000, 59.980000, 464, 152, 80, 232, 1520, 1672, 36, 10, 3, 23, 963, 973, 0, 0, 0, 0, 0, 0 },
> +{ 0, 1200, 1600, 1600, 1200, 1760, 623, 1865, 6130, 60.000000, 65.750000, 37.350000, 60.000000, 59.910000, 29.950000, 448, 32, 192, 224, 1792, 1824, 23, 4, 3, 16, 1203, 1207, 0, 0, 0, 0, 1, 1 },
> +{ 0, 1200, 1600, 1600, 1200, 2048, 624, 1868, 6131, 60.000000, 76.500000, 37.350000, 60.000000, 59.810000, 29.900000, 448, 160, 64, 224, 1664, 1824, 24, 4, 3, 17, 1203, 1207, 0, 0, 0, 0, 0, 1 },
> +{ 0, 1200, 1600, 1600, 1200, 1760, 1240, 1866, 3083, 60.000000, 130.750000, 74.290000, 60.000000, 59.910000, 59.910000, 560, 32, 248, 280, 1848, 1880, 40, 4, 3, 33, 1203, 1207, 0, 0, 0, 0, 1, 0 },
> +{ 0, 1200, 1600, 1600, 1200, 2160, 1245, 1868, 3072, 60.000000, 161.000000, 74.530000, 60.000000, 59.860000, 59.860000, 560, 168, 112, 280, 1712, 1880, 45, 4, 3, 38, 1203, 1207, 0, 0, 0, 0, 0, 0 },
> +{ 0, 1050, 1780, 1776, 1050, 1936, 544, 1869, 7038, 60.000000, 63.000000, 32.540000, 60.000000, 59.760000, 29.880000, 464, 32, 200, 232, 1976, 2008, 27, 10, 3, 14, 1053, 1063, 0, 0, 0, 0, 1, 1 },
> +{ 0, 1050, 1780, 1776, 1050, 2240, 547, 1870, 7004, 60.000000, 73.250000, 32.700000, 60.000000, 59.720000, 29.860000, 464, 176, 56, 232, 1832, 2008, 22, 10, 3, 9, 1053, 1063, 0, 0, 0, 0, 0, 1 },
> +{ 0, 1050, 1780, 1776, 1050, 1936, 1092, 1865, 3498, 60.000000, 126.750000, 65.470000, 60.000000, 59.950000, 59.950000, 592, 32, 264, 296, 2040, 2072, 42, 10, 3, 29, 1053, 1063, 0, 0, 0, 0, 1, 0 },
> +{ 0, 1050, 1780, 1776, 1050, 2368, 1089, 1866, 3510, 60.000000, 154.500000, 65.230000, 60.000000, 59.910000, 59.910000, 592, 184, 112, 296, 1888, 2072, 39, 10, 3, 26, 1053, 1063, 0, 0, 0, 0, 0, 0 },
> +{ 0, 1080, 1920, 1920, 1080, 2080, 562, 1867, 6805, 60.000000, 70.000000, 33.650000, 60.000000, 59.820000, 29.910000, 496, 32, 216, 248, 2136, 2168, 22, 5, 3, 14, 1083, 1088, 0, 0, 0, 0, 1, 1 },
> +{ 0, 1080, 1920, 1920, 1080, 2432, 562, 1864, 6792, 60.000000, 82.000000, 33.710000, 60.000000, 59.940000, 29.970000, 512, 192, 64, 256, 1984, 2176, 22, 5, 3, 14, 1083, 1088, 0, 0, 0, 0, 0, 1 },
> +{ 0, 1080, 1920, 1920, 1080, 2080, 1118, 1864, 3415, 60.000000, 139.500000, 67.590000, 60.000000, 59.980000, 59.980000, 656, 32, 296, 328, 2216, 2248, 38, 5, 3, 30, 1083, 1088, 0, 0, 0, 0, 1, 0 },
> +{ 0, 1080, 1920, 1920, 1080, 2576, 1120, 1865, 3410, 60.000000, 173.000000, 67.150000, 60.000000, 59.960000, 59.960000, 656, 200, 128, 328, 2048, 2248, 40, 5, 3, 32, 1083, 1088, 0, 0, 0, 0, 0, 0 },
> +{ 1, 200, 320, 320, 200, 336, 208, 1863, 18352, 60.000000, 4.190000, 12.480000, 60.000000, 60.000000, 60.000000, 16, 3, -2, 1, 304, 328, 8, 3, 1, 4, 201, 204, 0, 0, 0, 0, 0, 0 },
> +{ 1, 200, 320, 320, 200, 336, 208, 1863, 18352, 60.000000, 4.190000, 12.480000, 60.000000, 60.000000, 60.000000, 16, 3, -2, 1, 304, 328, 8, 3, 1, 4, 201, 204, 0, 0, 0, 0, 1, 0 },
> +{ 1, 200, 320, 320, 200, 336, 108, 927, 17591, 60.000000, 4.370000, 13.200000, 60.000000, 120.000000, 60.000000, 16, 3, -2, 1, 304, 328, 8, 3, 1, 4, 101, 104, 0, 0, 0, 0, 0, 1 },
> +{ 1, 200, 320, 320, 200, 336, 108, 927, 17591, 60.000000, 4.370000, 13.200000, 60.000000, 120.000000, 60.000000, 16, 3, -2, 1, 304, 328, 8, 3, 1, 4, 101, 104, 0, 0, 0, 0, 1, 1 },
> +{ 1, 240, 320, 320, 240, 352, 249, 1863, 15330, 60.000000, 5.250000, 14.930000, 59.990000, 59.990000, 59.990000, 32, 4, -2, 2, 304, 336, 9, 3, 1, 5, 241, 244, 0, 0, 0, 0, 0, 0 },
> +{ 1, 240, 320, 320, 240, 352, 249, 1863, 15330, 60.000000, 5.250000, 14.930000, 59.990000, 59.990000, 59.990000, 32, 4, -2, 2, 304, 336, 9, 3, 1, 5, 241, 244, 0, 0, 0, 0, 1, 0 },
> +{ 1, 240, 320, 320, 240, 352, 130, 928, 14625, 60.000000, 5.510000, 15.660000, 60.000000, 120.000000, 60.000000, 32, 4, -2, 2, 304, 336, 10, 3, 1, 6, 121, 124, 0, 0, 0, 0, 0, 1 },
> +{ 1, 240, 320, 320, 240, 352, 130, 928, 14625, 60.000000, 5.510000, 15.660000, 60.000000, 120.000000, 60.000000, 32, 4, -2, 2, 304, 336, 10, 3, 1, 6, 121, 124, 0, 0, 0, 0, 1, 1 },
> +{ 1, 480, 640, 640, 480, 800, 497, 1863, 7680, 60.000000, 23.850000, 29.820000, 60.000000, 60.000000, 60.000000, 160, 8, 2, 10, 656, 720, 17, 3, 1, 13, 481, 484, 0, 0, 0, 0, 0, 0 },
> +{ 1, 480, 640, 640, 480, 800, 497, 1863, 7680, 60.000000, 23.850000, 29.820000, 60.000000, 60.000000, 60.000000, 160, 8, 2, 10, 656, 720, 17, 3, 1, 13, 481, 484, 0, 0, 0, 0, 1, 0 },
> +{ 1, 480, 640, 640, 480, 800, 258, 930, 7383, 60.000000, 24.810000, 31.200000, 60.000000, 120.000000, 60.000000, 160, 8, 2, 10, 656, 720, 18, 3, 1, 14, 241, 244, 0, 0, 0, 0, 0, 1 },
> +{ 1, 480, 640, 640, 480, 800, 258, 930, 7383, 60.000000, 24.810000, 31.200000, 60.000000, 120.000000, 60.000000, 160, 8, 2, 10, 656, 720, 18, 3, 1, 14, 241, 244, 0, 0, 0, 0, 1, 1 },
> +{ 1, 400, 720, 720, 400, 928, 444, 1312, 6055, 85.000000, 35.101601, 37.825001, 85.000000, 170.000000, 85.000000, 208, 9, 4, 13, 752, 824, 22, 3, 1, 18, 201, 204, 0, 0, 0, 0, 1, 1 },
> +{ 1, 400, 720, 720, 400, 928, 444, 1312, 6055, 85.000000, 35.101601, 37.825001, 85.000000, 170.000000, 85.000000, 208, 9, 4, 13, 752, 824, 22, 3, 1, 18, 201, 204, 0, 0, 0, 0, 0, 1 },
> +{ 1, 400, 720, 720, 400, 912, 421, 1315, 6400, 85.000000, 32.635921, 35.785000, 85.000000, 85.000000, 85.000000, 192, 9, 3, 12, 744, 816, 21, 3, 1, 17, 401, 404, 0, 0, 0, 0, 1, 0 },
> +{ 1, 400, 720, 720, 400, 912, 421, 1315, 6400, 85.000000, 32.635921, 35.785000, 85.000000, 85.000000, 85.000000, 192, 9, 3, 12, 744, 816, 21, 3, 1, 17, 401, 404, 0, 0, 0, 0, 0, 0 },
> +{ 1, 480, 720, 720, 480, 896, 258, 930, 7383, 60.000000, 27.790000, 31.200000, 60.000000, 120.000000, 60.000000, 176, 9, 2, 11, 736, 808, 18, 3, 1, 14, 241, 244, 0, 0, 0, 0, 1, 1 },
> +{ 1, 480, 720, 720, 480, 800, 249, 1860, 15299, 30.000000, 11.976001, 14.970001, 30.000002, 60.000004, 30.000002, 80, 8, -3, 5, 696, 760, 9, 3, 1, 5, 241, 244, 0, 0, 0, 0, 1, 1 },
> +{ 1, 480, 720, 720, 480, 800, 249, 1860, 15299, 30.000000, 11.976001, 14.970001, 30.000002, 60.000004, 30.000002, 80, 8, -3, 5, 696, 760, 9, 3, 1, 5, 241, 244, 0, 0, 0, 0, 0, 1 },
> +{ 1, 480, 720, 720, 480, 800, 489, 3727, 15612, 30.000000, 11.735999, 14.669999, 29.999998, 29.999998, 29.999998, 80, 8, -3, 5, 696, 760, 9, 3, 1, 5, 481, 484, 0, 0, 0, 0, 1, 0 },
> +{ 1, 480, 720, 720, 480, 800, 489, 3727, 15612, 30.000000, 11.735999, 14.669999, 29.999998, 29.999998, 29.999998, 80, 8, -3, 5, 696, 760, 9, 3, 1, 5, 481, 484, 0, 0, 0, 0, 0, 0 },
> +{ 1, 480, 720, 720, 480, 800, 249, 1862, 15315, 29.969999, 11.964024, 14.955030, 29.969999, 59.939999, 29.969999, 80, 8, -3, 5, 696, 760, 9, 3, 1, 5, 241, 244, 0, 0, 0, 0, 1, 1 },
> +{ 1, 480, 720, 720, 480, 800, 249, 1862, 15315, 29.969999, 11.964024, 14.955030, 29.969999, 59.939999, 29.969999, 80, 8, -3, 5, 696, 760, 9, 3, 1, 5, 241, 244, 0, 0, 0, 0, 0, 1 },
> +{ 1, 480, 720, 720, 480, 800, 489, 3731, 15628, 29.969999, 11.724264, 14.655331, 29.970001, 29.970001, 29.970001, 80, 8, -3, 5, 696, 760, 9, 3, 1, 5, 481, 484, 0, 0, 0, 0, 1, 0 },
> +{ 1, 480, 720, 720, 480, 800, 489, 3731, 15628, 29.969999, 11.724264, 14.655331, 29.970001, 29.970001, 29.970001, 80, 8, -3, 5, 696, 760, 9, 3, 1, 5, 481, 484, 0, 0, 0, 0, 0, 0 },
> +{ 1, 480, 720, 720, 480, 896, 258, 930, 7383, 60.000000, 27.790000, 31.200000, 60.000000, 120.000000, 60.000000, 176, 9, 2, 11, 736, 808, 18, 3, 1, 14, 241, 244, 0, 0, 0, 0, 0, 1 },
> +{ 1, 480, 720, 720, 480, 896, 497, 1863, 7680, 60.000000, 26.710000, 29.820000, 60.000000, 60.000000, 60.000000, 176, 9, 2, 11, 736, 808, 17, 3, 1, 13, 481, 484, 0, 0, 0, 0, 1, 0 },
> +{ 1, 480, 720, 720, 480, 896, 497, 1863, 7680, 60.000000, 26.710000, 29.820000, 60.000000, 60.000000, 60.000000, 176, 9, 2, 11, 736, 808, 17, 3, 1, 13, 481, 484, 0, 0, 0, 0, 0, 0 },
> +{ 1, 576, 768, 768, 576, 976, 309, 930, 6166, 60.000000, 36.240000, 37.130000, 60.000000, 120.000000, 60.000000, 208, 10, 3, 13, 792, 872, 21, 3, 1, 17, 289, 292, 0, 0, 0, 0, 1, 1 },
> +{ 1, 576, 768, 768, 576, 976, 309, 930, 6166, 60.000000, 36.240000, 37.130000, 60.000000, 120.000000, 60.000000, 208, 10, 3, 13, 792, 872, 21, 3, 1, 17, 289, 292, 0, 0, 0, 0, 0, 1 },
> +{ 1, 576, 768, 768, 576, 976, 597, 1863, 6394, 60.000000, 34.960000, 35.820000, 59.990000, 59.990000, 59.990000, 208, 10, 3, 13, 792, 872, 21, 3, 1, 17, 577, 580, 0, 0, 0, 0, 1, 0 },
> +{ 1, 576, 768, 768, 576, 976, 597, 1863, 6394, 60.000000, 34.960000, 35.820000, 59.990000, 59.990000, 59.990000, 208, 10, 3, 13, 792, 872, 21, 3, 1, 17, 577, 580, 0, 0, 0, 0, 0, 0 },
> +{ 1, 480, 800, 800, 480, 1008, 258, 930, 7383, 60.000000, 31.260000, 31.200000, 60.000000, 120.000000, 60.000000, 208, 10, 3, 13, 824, 904, 18, 3, 1, 14, 241, 244, 0, 0, 0, 0, 1, 1 },
> +{ 1, 480, 800, 800, 480, 1008, 258, 930, 7383, 60.000000, 31.260000, 31.200000, 60.000000, 120.000000, 60.000000, 208, 10, 3, 13, 824, 904, 18, 3, 1, 14, 241, 244, 0, 0, 0, 0, 0, 1 },
> +{ 1, 480, 800, 800, 480, 992, 497, 1863, 7680, 60.000000, 29.580000, 29.820000, 60.000000, 60.000000, 60.000000, 192, 10, 2, 12, 816, 896, 17, 3, 1, 13, 481, 484, 0, 0, 0, 0, 1, 0 },
> +{ 1, 480, 800, 800, 480, 992, 497, 1863, 7680, 60.000000, 29.580000, 29.820000, 60.000000, 60.000000, 60.000000, 192, 10, 2, 12, 816, 896, 17, 3, 1, 13, 481, 484, 0, 0, 0, 0, 0, 0 },
> +{ 1, 600, 800, 800, 600, 1024, 322, 930, 5918, 60.000000, 39.610000, 38.700000, 60.000000, 120.000000, 60.000000, 224, 10, 4, 14, 832, 912, 22, 3, 1, 18, 301, 304, 0, 0, 0, 0, 1, 1 },
> +{ 1, 600, 800, 800, 600, 1024, 322, 930, 5918, 60.000000, 39.610000, 38.700000, 60.000000, 120.000000, 60.000000, 224, 10, 4, 14, 832, 912, 22, 3, 1, 18, 301, 304, 0, 0, 0, 0, 0, 1 },
> +{ 1, 600, 800, 800, 600, 1024, 622, 1863, 6137, 60.000000, 38.210000, 37.320000, 60.000000, 60.000000, 60.000000, 224, 10, 4, 14, 832, 912, 22, 3, 1, 18, 601, 604, 0, 0, 0, 0, 1, 0 },
> +{ 1, 600, 800, 800, 600, 1024, 622, 1863, 6137, 60.000000, 38.210000, 37.320000, 60.000000, 60.000000, 60.000000, 224, 10, 4, 14, 832, 912, 22, 3, 1, 18, 601, 604, 0, 0, 0, 0, 0, 0 },
> +{ 1, 768, 1024, 1024, 768, 1344, 412, 930, 4627, 60.000000, 66.520000, 49.500000, 60.000000, 120.000000, 60.000000, 320, 13, 7, 20, 1080, 1184, 28, 3, 1, 24, 385, 388, 0, 0, 0, 0, 1, 1 },
> +{ 1, 768, 1024, 1024, 768, 1344, 412, 930, 4627, 60.000000, 66.520000, 49.500000, 60.000000, 120.000000, 60.000000, 320, 13, 7, 20, 1080, 1184, 28, 3, 1, 24, 385, 388, 0, 0, 0, 0, 0, 1 },
> +{ 1, 768, 1024, 1024, 768, 1344, 795, 1863, 4801, 60.000000, 64.900000, 47.690000, 60.000000, 60.000000, 60.000000, 320, 13, 7, 20, 1080, 1184, 27, 3, 1, 23, 769, 772, 0, 0, 0, 0, 1, 0 },
> +{ 1, 768, 1024, 1024, 768, 1344, 795, 1863, 4801, 60.000000, 64.900000, 47.690000, 60.000000, 60.000000, 60.000000, 320, 13, 7, 20, 1080, 1184, 27, 3, 1, 23, 769, 772, 0, 0, 0, 0, 0, 0 },
> +{ 1, 768, 1152, 1152, 768, 1520, 412, 930, 4627, 60.000000, 75.230000, 49.500000, 60.000000, 120.000000, 60.000000, 368, 15, 8, 23, 1216, 1336, 28, 3, 1, 24, 385, 388, 0, 0, 0, 0, 1, 1 },
> +{ 1, 768, 1152, 1152, 768, 1520, 412, 930, 4627, 60.000000, 75.230000, 49.500000, 60.000000, 120.000000, 60.000000, 368, 15, 8, 23, 1216, 1336, 28, 3, 1, 24, 385, 388, 0, 0, 0, 0, 0, 1 },
> +{ 1, 768, 1152, 1152, 768, 1504, 795, 1863, 4801, 60.000000, 71.730000, 47.690000, 60.000000, 60.000000, 60.000000, 352, 15, 7, 22, 1208, 1328, 27, 3, 1, 23, 769, 772, 0, 0, 0, 0, 1, 0 },
> +{ 1, 768, 1152, 1152, 768, 1504, 795, 1863, 4801, 60.000000, 71.730000, 47.690000, 60.000000, 60.000000, 60.000000, 352, 15, 7, 22, 1208, 1328, 27, 3, 1, 23, 769, 772, 0, 0, 0, 0, 0, 0 },
> +{ 1, 864, 1152, 1152, 864, 1536, 464, 930, 4109, 60.000000, 85.616646, 55.740002, 60.000000, 120.000000, 60.000000, 384, 15, 9, 24, 1224, 1344, 32, 3, 1, 28, 433, 436, 0, 0, 0, 0, 1, 1 },
> +{ 1, 864, 1152, 1152, 864, 1536, 464, 930, 4109, 60.000000, 85.616646, 55.740002, 60.000000, 120.000000, 60.000000, 384, 15, 9, 24, 1224, 1344, 32, 3, 1, 28, 433, 436, 0, 0, 0, 0, 0, 1 },
> +{ 1, 864, 1152, 1152, 864, 1520, 895, 1863, 4265, 60.000000, 81.624001, 53.700001, 60.000004, 60.000004, 60.000004, 368, 15, 8, 23, 1216, 1336, 31, 3, 1, 27, 865, 868, 0, 0, 0, 0, 1, 0 },
> +{ 1, 864, 1152, 1152, 864, 1520, 895, 1863, 4265, 60.000000, 81.624001, 53.700001, 60.000004, 60.000004, 60.000004, 368, 15, 8, 23, 1216, 1336, 31, 3, 1, 27, 865, 868, 0, 0, 0, 0, 0, 0 },
> +{ 1, 720, 1280, 1280, 720, 1680, 387, 930, 4925, 60.000000, 78.110000, 46.500000, 60.000000, 120.000000, 60.000000, 400, 17, 8, 25, 1344, 1480, 27, 3, 1, 23, 361, 364, 0, 0, 0, 0, 1, 1 },
> +{ 1, 720, 1280, 1280, 720, 1680, 387, 930, 4925, 60.000000, 78.110000, 46.500000, 60.000000, 120.000000, 60.000000, 400, 17, 8, 25, 1344, 1480, 27, 3, 1, 23, 361, 364, 0, 0, 0, 0, 0, 1 },
> +{ 1, 720, 1280, 1280, 720, 1664, 746, 1863, 5117, 60.000000, 74.480000, 44.750000, 59.990000, 59.990000, 59.990000, 384, 17, 7, 24, 1336, 1472, 26, 3, 1, 22, 721, 724, 0, 0, 0, 0, 1, 0 },
> +{ 1, 720, 1280, 1280, 720, 1664, 746, 1863, 5117, 60.000000, 74.480000, 44.750000, 59.990000, 59.990000, 59.990000, 384, 17, 7, 24, 1336, 1472, 26, 3, 1, 22, 721, 724, -4, 0, 0, 0, 0, 0 },
> +{ 1, 768, 1280, 1280, 768, 1680, 412, 930, 4627, 60.000000, 83.150000, 49.500000, 60.000000, 120.000000, 60.000000, 400, 17, 8, 25, 1344, 1480, 28, 3, 1, 24, 385, 388, 0, 0, 0, 0, 1, 1 },
> +{ 1, 768, 1280, 1280, 768, 1680, 412, 930, 4627, 60.000000, 83.150000, 49.500000, 60.000000, 120.000000, 60.000000, 400, 17, 8, 25, 1344, 1480, 28, 3, 1, 24, 385, 388, 0, 0, 0, 0, 0, 1 },
> +{ 1, 768, 1280, 1280, 768, 1680, 795, 1863, 4801, 60.000000, 80.130000, 47.690000, 60.000000, 60.000000, 60.000000, 400, 17, 8, 25, 1344, 1480, 27, 3, 1, 23, 769, 772, 0, 0, 0, 0, 1, 0 },
> +{ 1, 768, 1280, 1280, 768, 1680, 795, 1863, 4801, 60.000000, 80.130000, 47.690000, 60.000000, 60.000000, 60.000000, 400, 17, 8, 25, 1344, 1480, 27, 3, 1, 23, 769, 772, 0, 0, 0, 0, 0, 0 },
> +{ 1, 800, 1280, 1280, 800, 1696, 429, 930, 4443, 60.000000, 87.410000, 51.540000, 60.000000, 120.000000, 60.000000, 416, 17, 9, 26, 1352, 1488, 29, 3, 1, 25, 401, 404, 0, 0, 0, 0, 1, 1 },
> +{ 1, 800, 1280, 1280, 800, 1696, 429, 930, 4443, 60.000000, 87.410000, 51.540000, 60.000000, 120.000000, 60.000000, 416, 17, 9, 26, 1352, 1488, 29, 3, 1, 25, 401, 404, 0, 0, 0, 0, 0, 1 },
> +{ 1, 800, 1280, 1280, 800, 1680, 828, 1863, 4610, 60.000000, 83.460000, 49.680000, 60.000000, 60.000000, 60.000000, 400, 17, 8, 25, 1344, 1480, 28, 3, 1, 24, 801, 804, 0, 0, 0, 0, 1, 0 },
> +{ 1, 800, 1280, 1280, 800, 1680, 828, 1863, 4610, 60.000000, 83.460000, 49.680000, 60.000000, 60.000000, 60.000000, 400, 17, 8, 25, 1344, 1480, 28, 3, 1, 24, 801, 804, -2, 0, 0, 0, 0, 0 },
> +{ 1, 960, 1280, 1280, 960, 1712, 515, 931, 3702, 60.000000, 105.900000, 61.860000, 60.000000, 120.000000, 60.000000, 432, 17, 10, 27, 1360, 1496, 35, 3, 1, 31, 481, 484, 0, 0, 0, 0, 1, 1 },
> +{ 1, 960, 1280, 1280, 960, 1712, 515, 931, 3702, 60.000000, 105.900000, 61.860000, 60.000000, 120.000000, 60.000000, 432, 17, 10, 27, 1360, 1496, 35, 3, 1, 31, 481, 484, 0, 0, 0, 0, 0, 1 },
> +{ 1, 960, 1280, 1280, 960, 1712, 994, 1863, 3840, 60.000000, 102.100000, 59.630000, 59.990000, 59.990000, 59.990000, 432, 17, 10, 27, 1360, 1496, 34, 3, 1, 30, 961, 964, 0, 0, 0, 0, 1, 0 },
> +{ 1, 960, 1280, 1280, 960, 1712, 994, 1863, 3840, 60.000000, 102.100000, 59.630000, 59.990000, 59.990000, 59.990000, 432, 17, 10, 27, 1360, 1496, 34, 3, 1, 30, 961, 964, 0, 0, 0, 0, 0, 0 },
> +{ 1, 1024, 1280, 1280, 1024, 1712, 549, 931, 3473, 60.000000, 112.880000, 65.930000, 59.990000, 119.990000, 59.990000, 432, 17, 10, 27, 1360, 1496, 37, 3, 1, 33, 513, 516, 0, 0, 0, 0, 1, 1 },
> +{ 1, 1024, 1280, 1280, 1024, 1712, 549, 931, 3473, 60.000000, 112.880000, 65.930000, 59.990000, 119.990000, 59.990000, 432, 17, 10, 27, 1360, 1496, 37, 3, 1, 33, 513, 516, 0, 0, 0, 0, 0, 1 },
> +{ 1, 1024, 1280, 1280, 1024, 1712, 1060, 1863, 3601, 60.000000, 108.880000, 63.590000, 60.000000, 60.000000, 60.000000, 432, 17, 10, 27, 1360, 1496, 36, 3, 1, 32, 1025, 1028, 0, 0, 0, 0, 1, 0 },
> +{ 1, 1024, 1280, 1280, 1024, 1712, 1060, 1863, 3601, 60.000000, 108.880000, 63.590000, 60.000000, 60.000000, 60.000000, 432, 17, 10, 27, 1360, 1496, 36, 3, 1, 32, 1025, 1028, 0, 0, 0, 0, 0, 0 },
> +{ 1, 768, 1366, 1368, 768, 1800, 412, 930, 4627, 60.000000, 89.900000, 49.500000, 60.000000, 120.000000, 60.000000, 432, 18, 9, 27, 1440, 1584, 28, 3, 1, 24, 385, 388, 0, 0, 0, 0, 1, 1 },
> +{ 1, 768, 1366, 1368, 768, 1800, 412, 930, 4627, 60.000000, 89.900000, 49.500000, 60.000000, 120.000000, 60.000000, 432, 18, 9, 27, 1440, 1584, 28, 3, 1, 24, 385, 388, 0, 0, 0, 0, 0, 1 },
> +{ 1, 768, 1366, 1368, 768, 1800, 795, 1863, 4801, 60.000000, 85.860000, 47.690000, 60.000000, 60.000000, 60.000000, 432, 18, 9, 27, 1440, 1584, 27, 3, 1, 23, 769, 772, 0, 0, 0, 0, 1, 0 },
> +{ 1, 768, 1366, 1368, 768, 1800, 795, 1863, 4801, 60.000000, 85.860000, 47.690000, 60.000000, 60.000000, 60.000000, 432, 18, 9, 27, 1440, 1584, 27, 3, 1, 23, 769, 772, 0, 0, 0, 0, 0, 0 },
> +{ 1, 1050, 1400, 1400, 1050, 1880, 563, 931, 3387, 60.000000, 127.120000, 67.620000, 60.000000, 120.000000, 60.000000, 480, 19, 11, 30, 1488, 1640, 38, 3, 1, 34, 526, 529, 0, 0, 0, 0, 1, 1 },
> +{ 1, 1050, 1400, 1400, 1050, 1880, 563, 931, 3387, 60.000000, 127.120000, 67.620000, 60.000000, 120.000000, 60.000000, 480, 19, 11, 30, 1488, 1640, 38, 3, 1, 34, 526, 529, 0, 0, 0, 0, 0, 1 },
> +{ 1, 1050, 1400, 1400, 1050, 1880, 1087, 1863, 3511, 60.000000, 122.610000, 65.220000, 60.000000, 60.000000, 60.000000, 480, 19, 11, 30, 1488, 1640, 37, 3, 1, 33, 1051, 1054, 0, 0, 0, 0, 1, 0 },
> +{ 1, 1050, 1400, 1400, 1050, 1880, 1087, 1863, 3511, 60.000000, 122.610000, 65.220000, 60.000000, 60.000000, 60.000000, 480, 19, 11, 30, 1488, 1640, 37, 3, 1, 33, 1051, 1054, 0, 0, 0, 0, 0, 0 },
> +{ 1, 900, 1440, 1440, 900, 1920, 483, 931, 3947, 60.000000, 111.390000, 58.200000, 60.000000, 120.000000, 60.000000, 480, 19, 11, 30, 1528, 1680, 33, 3, 1, 29, 451, 454, 0, 0, 0, 0, 1, 1 },
> +{ 1, 900, 1440, 1440, 900, 1920, 483, 931, 3947, 60.000000, 111.390000, 58.200000, 60.000000, 120.000000, 60.000000, 480, 19, 11, 30, 1528, 1680, 33, 3, 1, 29, 451, 454, 0, 0, 0, 0, 0, 1 },
> +{ 1, 900, 1440, 1440, 900, 1904, 932, 1863, 4095, 60.000000, 106.470000, 55.910000, 59.990000, 59.990000, 59.990000, 464, 19, 10, 29, 1520, 1672, 32, 3, 1, 28, 901, 904, 0, 0, 0, 0, 1, 0 },
> +{ 1, 900, 1440, 1440, 900, 1904, 932, 1863, 4095, 60.000000, 106.470000, 55.910000, 59.990000, 59.990000, 59.990000, 464, 19, 10, 29, 1520, 1672, 32, 3, 1, 28, 901, 904, 0, 0, 0, 0, 0, 0 },
> +{ 1, 960, 1440, 1440, 960, 1920, 515, 931, 3702, 60.000000, 118.770000, 61.860000, 60.000000, 120.000000, 60.000000, 480, 19, 11, 30, 1528, 1680, 35, 3, 1, 31, 481, 484, 0, 0, 0, 0, 1, 1 },
> +{ 1, 960, 1440, 1440, 960, 1920, 515, 931, 3702, 60.000000, 118.770000, 61.860000, 60.000000, 120.000000, 60.000000, 480, 19, 11, 30, 1528, 1680, 35, 3, 1, 31, 481, 484, 0, 0, 0, 0, 0, 1 },
> +{ 1, 960, 1440, 1440, 960, 1920, 994, 1863, 3840, 60.000000, 114.500000, 59.630000, 59.990000, 59.990000, 59.990000, 480, 19, 11, 30, 1528, 1680, 34, 3, 1, 30, 961, 964, 0, 0, 0, 0, 1, 0 },
> +{ 1, 960, 1440, 1440, 960, 1920, 994, 1863, 3840, 60.000000, 114.500000, 59.630000, 59.990000, 59.990000, 59.990000, 480, 19, 11, 30, 1528, 1680, 34, 3, 1, 30, 961, 964, 0, 0, 0, 0, 0, 0 },
> +{ 1, 1200, 1600, 1600, 1200, 2160, 644, 931, 2961, 60.000000, 167.500000, 77.330000, 60.000000, 120.000000, 60.000000, 560, 22, 13, 35, 1704, 1880, 44, 3, 1, 40, 601, 604, 0, 0, 0, 0, 1, 1 },
> +{ 1, 1200, 1600, 1600, 1200, 2160, 644, 931, 2961, 60.000000, 167.500000, 77.330000, 60.000000, 120.000000, 60.000000, 560, 22, 13, 35, 1704, 1880, 44, 3, 1, 40, 601, 604, 0, 0, 0, 0, 0, 1 },
> +{ 1, 1200, 1600, 1600, 1200, 2160, 1242, 1863, 3073, 60.000000, 160.960000, 74.520000, 60.000000, 60.000000, 60.000000, 560, 22, 13, 35, 1704, 1880, 42, 3, 1, 38, 1201, 1204, 0, 0, 0, 0, 1, 0 },
> +{ 1, 1200, 1600, 1600, 1200, 2160, 1242, 1863, 3073, 60.000000, 160.960000, 74.520000, 60.000000, 60.000000, 60.000000, 560, 22, 13, 35, 1704, 1880, 42, 3, 1, 38, 1201, 1204, 0, 0, 0, 0, 0, 0 },
> +{ 1, 1050, 1780, 1784, 1050, 2392, 563, 931, 3387, 60.000000, 161.740000, 67.620000, 60.000000, 120.000000, 60.000000, 608, 24, 14, 38, 1896, 2088, 38, 3, 1, 34, 526, 529, 0, 0, 0, 0, 1, 1 },
> +{ 1, 1050, 1780, 1784, 1050, 2392, 563, 931, 3387, 60.000000, 161.740000, 67.620000, 60.000000, 120.000000, 60.000000, 608, 24, 14, 38, 1896, 2088, 38, 3, 1, 34, 526, 529, 0, 0, 0, 0, 0, 1 },
> +{ 1, 1050, 1780, 1784, 1050, 2392, 1087, 1863, 3511, 60.000000, 156.000000, 65.220000, 60.000000, 60.000000, 60.000000, 608, 24, 14, 38, 1896, 2088, 37, 3, 1, 33, 1051, 1054, 0, 0, 0, 0, 1, 0 },
> +{ 1, 1050, 1780, 1784, 1050, 2392, 1087, 1863, 3511, 60.000000, 156.000000, 65.220000, 60.000000, 60.000000, 60.000000, 608, 24, 14, 38, 1896, 2088, 37, 3, 1, 33, 1051, 1054, 0, 0, 0, 0, 0, 0 },
> +
> +{ 1, 1080, 1920, 1920, 1080, 2576, 1118, 1863, 3414, 60.000000, 172.790000, 67.800000, 60.000000, 60.000000, 60.000000, 656, 26, 15, 41, 2040, 2248, 38, 3, 1, 34, 1081, 1084, 0, 0, 0, 0, 1, 0 },
> +
> +{ 1, 1080, 1920, 1920, 1080, 2576, 1118, 1863, 3414, 60.000000, 172.790000, 67.800000, 60.000000, 60.000000, 60.000000, 656, 26, 15, 41, 2040, 2248, 38, 3, 1, 34, 1081, 1084, 0, 0, 0, 0, 0, 0 },
> +
> +{ 1, 1080, 1920, 1920, 1080, 2576, 1118, 1863, 3414, 60.000000, 172.790000, 67.800000, 60.000000, 60.000000, 60.000000, 656, 26, 15, 41, 2040, 2248, 38, 3, 1, 34, 1081, 1084, 0, 0, 0, 0, 0, 0 },
> +
> +{ 1, 1080, 1920, 1920, 1080, 2576, 1118, 1863, 3414, 60.000000, 172.790000, 67.800000, 60.000000, 60.000000, 60.000000, 656, 26, 15, 41, 2040, 2248, 38, 3, 1, 34, 1081, 1084, 0, 0, 0, 0, 1, 0 },
> +
> +{ 1, 1080, 1920, 1920, 1080, 2576, 579, 931, 3293, 60.000000, 179.130000, 69.540000, 60.000000, 120.000000, 60.000000, 656, 26, 15, 41, 2040, 2248, 39, 3, 1, 35, 541, 544, 0, 0, 0, 0, 0, 1 },
> +
> +{ 1, 1080, 1920, 1920, 1080, 2576, 579, 931, 3293, 60.000000, 179.130000, 69.540000, 60.000000, 120.000000, 60.000000, 656, 26, 15, 41, 2040, 2248, 39, 3, 1, 35, 541, 544, 0, 0, 0, 0, 1, 1 },
> +
> +{ 2, 350, 640, 640, 350, 832, 445, 1314, 6049, 85.000000, 31.500000, 37.861000, 85.080000, 85.000000, 85.000000, 192, 64, 32, 96, 672, 736, 95, 3, 32, 60, 382, 385, 0, 0, 0, 0, 0, 0 },
> +{ 2, 400, 640, 640, 400, 832, 445, 1314, 6049, 85.000000, 31.500000, 37.861000, 85.080000, 85.000000, 85.000000, 192, 32, 64, 96, 704, 736, 45, 3, 1, 41, 401, 404, 0, 0, 0, 0, 0, 0 },
> +{ 2, 480, 640, 640, 480, 800, 525, 1865, 7278, 60.000000, 25.175000, 31.429000, 59.940000, 60.000000, 60.000000, 144, 96, 8, 40, 656, 752, 29, 2, 2, 25, 490, 492, 0, 0, 0, 0, 0, 0 },
> +{ 2, 480, 640, 640, 480, 832, 520, 1536, 6049, 72.000000, 31.500000, 37.861000, 72.809000, 72.000000, 72.000000, 176, 40, 16, 120, 664, 704, 24, 3, 1, 20, 489, 492, 0, 0, 0, 0, 0, 0 },
> +{ 2, 480, 640, 640, 480, 840, 500, 1491, 6107, 75.000000, 31.500000, 37.500000, 75.000000, 75.000000, 75.000000, 200, 64, 16, 120, 656, 720, 20, 3, 1, 16, 481, 484, 0, 0, 0, 0, 0, 0 },
> +{ 2, 480, 640, 640, 480, 832, 509, 1315, 5293, 85.000000, 36.000000, 43.269000, 85.008000, 85.000000, 85.000000, 192, 56, 56, 80, 696, 752, 29, 3, 1, 25, 481, 484, 0, 0, 0, 0, 0, 0 },
> +{ 2, 400, 720, 720, 400, 936, 446, 1315, 6038, 85.000000, 35.500000, 37.927000, 85.039000, 85.000000, 85.000000, 216, 72, 36, 108, 756, 828, 46, 3, 1, 42, 401, 404, 0, 0, 0, 0, 0, 0 },
> +{ 2, 480, 720, 720, 480, 858, 525, 1863, 7271, 60.000000, 27.027000, 31.500000, 60.000000, 60.000000, 60.000000, 138, 67, 22, 49, 742, 809, 45, 3, 3, 39, 483, 486, 0, 0, 0, 0, 0, 0 },
> +{ 2, 480, 720, 720, 480, 858, 525, 0, 0, 30.000000, 13.514000, 15.750000, 30.000000, 60.000000, 30.000000, 138, 64, 20, 54, 740, 804, 45, 3, 3, 39, 483, 486, 0, 0, 0, 0, 0, 1 },
> +{ 2, 480, 720, 720, 480, 900, 525, 932, 7278, 29.969999, 28.322000, 31.469000, 29.970000, 59.939999, 29.969999, 180, 108, 18, 54, 738, 846, 45, 2, 10, 33, 490, 492, 0, 0, 0, 0, 0, 1 },
> +{ 2, 487, 720, 720, 487, 858, 525, 1865, 14556, 29.969999, 13.500000, 15.734000, 29.970000, 59.939999, 29.969999, 138, 56, 18, 64, 738, 794, 38, 3, 2, 33, 489, 492, 0, 0, 0, 0, 0, 1 },
> +{ 2, 576, 720, 720, 576, 864, 625, 2236, 14658, 25.000000, 13.500000, 15.625000, 25.000000, 50.000000, 25.000000, 144, 56, 18, 70, 738, 794, 49, 3, 2, 44, 578, 581, 0, 0, 0, 0, 0, 1 },
> +{ 2, 600, 800, 800, 600, 1056, 628, 1854, 6046, 60.000000, 40.000000, 37.879000, 60.317000, 60.000000, 60.000000, 256, 128, 40, 88, 840, 968, 28, 4, 1, 23, 601, 605, 0, 0, 0, 0, 0, 0 },
> +{ 2, 600, 800, 800, 600, 1040, 666, 1549, 4764, 72.000000, 50.000000, 48.077000, 72.188000, 72.000000, 72.000000, 240, 120, 56, 64, 856, 976, 66, 6, 37, 23, 637, 643, 0, 0, 0, 0, 0, 0 },
> +{ 2, 600, 800, 800, 600, 1056, 625, 1491, 4886, 75.000000, 49.500000, 46.875000, 75.000000, 75.000000, 75.000000, 256, 80, 16, 160, 816, 896, 25, 3, 1, 21, 637, 640, 0, 0, 0, 0, 0, 0 },
> +{ 2, 600, 800, 800, 600, 1048, 631, 1314, 4267, 85.000000, 56.250000, 53.674000, 85.061000, 85.000000, 85.000000, 248, 64, 32, 152, 832, 896, 31, 3, 1, 27, 601, 604, 0, 0, 0, 0, 0, 0 },
> +{ 2, 768, 1024, 1024, 768, 1344, 806, 1863, 4735, 60.000000, 65.000000, 48.363000, 60.004000, 60.000000, 60.000000, 320, 136, 24, 160, 1048, 1184, 38, 6, 3, 29, 771, 777, 0, 0, 0, 0, 0, 0 },
> +{ 2, 768, 1024, 1024, 768, 1264, 817, 1286, 6447, 43.480000, 44.900000, 35.522000, 43.479000, 86.959999, 43.480000, 240, 176, 8, 56, 1032, 1208, 49, 4, 0, 45, 768, 772, 0, 0, 0, 0, 0, 1 },
> +{ 2, 768, 1024, 1024, 768, 1328, 806, 1596, 4055, 70.000000, 75.000000, 56.476000, 70.069000, 70.000000, 70.000000, 304, 136, 24, 144, 1048, 1184, 38, 6, 3, 29, 771, 777, 0, 0, 0, 0, 0, 0 },
> +{ 2, 768, 1024, 1024, 768, 1312, 800, 1490, 3815, 75.000000, 78.750000, 60.023000, 75.029000, 75.000000, 75.000000, 288, 96, 16, 176, 1040, 1136, 32, 3, 1, 28, 769, 772, 0, 0, 0, 0, 0, 0 },
> +{ 2, 768, 1024, 1024, 768, 1376, 808, 1315, 3335, 85.000000, 94.500000, 68.667000, 84.997000, 85.000000, 85.000000, 352, 96, 12, 208, 1072, 1168, 40, 3, 1, 36, 769, 772, 0, 0, 0, 0, 0, 0 },
> +{ 2, 864, 1152, 1152, 864, 1600, 900, 1491, 3393, 75.000000, 108.000000, 67.500000, 75.000000, 75.000000, 75.000000, 448, 128, 64, 256, 1216, 1344, 36, 3, 1, 32, 865, 868, 0, 0, 0, 0, 0, 0 },
> +{ 2, 720, 1280, 1280, 720, 1650, 750, 1863, 5089, 60.000000, 74.250000, 45.000000, 60.000000, 60.000000, 60.000000, 370, 80, 70, 220, 1350, 1430, 30, 5, 0, 25, 720, 725, 0, 0, 0, 0, 0, 0 },
> +{ 2, 720, 1280, 1280, 720, 1650, 750, 1865, 5094, 59.939999, 74.176000, 44.955000, 59.940000, 59.939999, 59.939999, 370, 40, 110, 220, 1390, 1430, 30, 5, 5, 20, 725, 730, 0, 0, 0, 0, 0, 0 },
> +{ 2, 720, 1280, 1280, 720, 1980, 750, 2236, 6107, 50.000000, 74.250000, 37.500000, 50.000000, 50.000000, 50.000000, 700, 40, 440, 220, 1720, 1760, 30, 5, 5, 20, 725, 730, 0, 0, 0, 0, 0, 0 },
> +{ 2, 960, 1280, 1280, 960, 1800, 1000, 1863, 3817, 60.000000, 108.000000, 60.000000, 60.000000, 60.000000, 60.000000, 520, 112, 96, 312, 1376, 1488, 40, 3, 1, 36, 961, 964, 0, 0, 0, 0, 0, 0 },
> +{ 2, 960, 1280, 1280, 960, 1728, 1011, 1315, 2665, 85.000000, 148.500000, 85.938000, 85.002000, 85.000000, 85.000000, 448, 160, 64, 224, 1344, 1504, 51, 3, 1, 47, 961, 964, 0, 0, 0, 0, 0, 0 },
> +{ 2, 1024, 1280, 1280, 1024, 1688, 1066, 1863, 3579, 60.000000, 108.000000, 63.981000, 60.020000, 60.000000, 60.000000, 408, 112, 48, 248, 1328, 1440, 42, 3, 1, 38, 1025, 1028, 0, 0, 0, 0, 0, 0 },
> +{ 2, 1024, 1280, 1280, 1024, 1688, 1066, 1490, 2863, 75.000000, 135.000000, 79.976000, 75.025000, 75.000000, 75.000000, 408, 144, 16, 248, 1296, 1440, 42, 3, 1, 38, 1025, 1028, 0, 0, 0, 0, 0, 0 },
> +{ 2, 1024, 1280, 1280, 1024, 1728, 1072, 1315, 2512, 85.000000, 157.500000, 91.146000, 85.024000, 85.000000, 85.000000, 448, 160, 64, 224, 1344, 1504, 48, 3, 1, 44, 1025, 1028, 0, 0, 0, 0, 0, 0 },
> +{ 2, 1200, 1600, 1600, 1200, 2160, 1250, 1863, 3053, 60.000000, 162.000000, 75.000000, 60.000000, 60.000000, 60.000000, 560, 192, 64, 304, 1664, 1856, 50, 3, 1, 46, 1201, 1204, 0, 0, 0, 0, 0, 0 },
> +{ 2, 1200, 1600, 1600, 1200, 2160, 1250, 1725, 2827, 65.000000, 175.000000, 81.250000, 65.000000, 65.000000, 65.000000, 560, 192, 64, 304, 1664, 1856, 50, 3, 1, 46, 1201, 1204, 0, 0, 0, 0, 0, 0 },
> +{ 2, 1200, 1600, 1600, 1200, 2160, 1250, 1597, 2617, 70.000000, 189.000000, 87.500000, 70.000000, 70.000000, 70.000000, 560, 192, 64, 304, 1664, 1856, 50, 3, 1, 46, 1201, 1204, 0, 0, 0, 0, 0, 0 },
> +{ 2, 1200, 1600, 1600, 1200, 2160, 1250, 1491, 2443, 75.000000, 202.500000, 93.750000, 75.000000, 75.000000, 75.000000, 560, 192, 64, 304, 1664, 1856, 50, 3, 1, 46, 1201, 1204, 0, 0, 0, 0, 0, 0 },
> +{ 2, 1200, 1600, 1600, 1200, 2160, 1250, 1315, 2155, 85.000000, 229.500000, 106.250000, 85.000000, 85.000000, 85.000000, 560, 192, 64, 304, 1664, 1856, 50, 3, 1, 46, 1201, 1204, 0, 0, 0, 0, 0, 0 },
> +{ 2, 1050, 1680, 1680, 1050, 2240, 1089, 1865, 3508, 59.950001, 146.250000, 65.290000, 59.954000, 59.950001, 59.950001, 560, 176, 104, 280, 1784, 1960, 39, 6, 3, 30, 1053, 1059, 0, 0, 0, 0, 0, 0 },
> +{ 2, 1080, 1920, 1920, 1080, 2200, 1125, 3727, 6786, 30.000000, 74.250000, 33.750000, 30.000000, 30.000000, 30.000000, 280, 44, 88, 148, 2008, 2052, 45, 5, 3, 37, 1083, 1088, 0, 0, 0, 0, 0, 0 },
> +{ 2, 1080, 1920, 1920, 1080, 2200, 1125, 1863, 6786, 30.000000, 74.250000, 33.750000, 30.000000, 60.000000, 30.000000, 280, 88, 44, 148, 1964, 2052, 45, 5, 2, 38, 1082, 1087, 0, 0, 0, 0, 0, 1 },
> +{ 2, 1080, 1920, 1920, 1080, 2200, 1125, 3731, 6793, 29.969999, 74.176000, 33.716000, 29.970000, 29.969999, 29.969999, 280, 44, 88, 148, 2008, 2052, 45, 5, 3, 37, 1083, 1088, 0, 0, 0, 0, 0, 0 },
> +{ 2, 1080, 1920, 1920, 1080, 2640, 1125, 4473, 8143, 25.000000, 74.250000, 28.125000, 25.000000, 25.000000, 25.000000, 720, 44, 528, 148, 2448, 2492, 45, 5, 4, 36, 1084, 1089, 0, 0, 0, 0, 0, 0 },
> +{ 2, 1080, 1920, 1920, 1080, 2750, 1125, 2329, 8482, 24.000000, 74.250000, 27.000000, 24.000000, 48.000000, 24.000000, 830, 88, 594, 148, 2514, 2602, 45, 5, 2, 38, 1082, 1087, 0, 0, 0, 0, 0, 1 },
> +{ 2, 1080, 1920, 1920, 1080, 2200, 1125, 1865, 6793, 29.969999, 74.176000, 33.716000, 29.970000, 59.939999, 29.969999, 280, 44, 88, 148, 2008, 2052, 45, 5, 2, 38, 1082, 1087, 0, 0, 0, 0, 0, 1 },
> +{ 2, 1080, 1920, 1920, 1080, 2640, 1125, 2236, 8143, 25.000000, 74.250000, 28.125000, 25.000000, 50.000000, 25.000000, 720, 88, 528, 104, 2448, 2536, 45, 5, 2, 38, 1082, 1087, 0, 0, 0, 0, 0, 1 },
> +{ 2, 1080, 1920, 1920, 1080, 2750, 1125, 2332, 8491, 23.000000, 74.176000, 26.973000, 23.000000, 46.000000, 23.000000, 830, 44, 638, 148, 2558, 2602, 45, 5, 2, 38, 1082, 1087, 0, 0, 0, 0, 0, 1 },
> +};

Please, don't use floating point in Kernel space. Also, the DV API specifies frequencies
using integers.

See, for example, how the last timing line is represented:

$ git grep V4L2_DV_720P59_94 include/linux/ drivers/media/
drivers/media/platform/s5p-tv/hdmi_drv.c: { V4L2_DV_720P59_94, &hdmi_timings_720p60 },
drivers/media/platform/s5p-tv/hdmiphy_drv.c:              [V4L2_DV_720P59_94] =  74176000,
drivers/media/v4l2-core/v4l2-common.c:            { 1280, 720, "720p@59.94" },    /* V4L2_DV_720P59_94 */
include/linux/videodev2.h:#define         V4L2_DV_720P59_94       7 /* SMPTE 274M */

> +
> +static struct vga_timing_t *vc8x0_vga_lookup(int mode,
> +	u32 width, u32 height, u32 interlaced)
> +{
> +	struct vga_timing_t *vt;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(vga_timings); i++) {
> +		vt = &vga_timings[i];
> +		if (
> +			(vt->timing_mode == mode) &&
> +			(vt->spec_width == width) &&
> +			(vt->spec_height == height) &&
> +			(vt->interlaced == interlaced)
> +		) {
> +			return &vga_timings[i];
> +		}
> +	}
> +
> +	return 0;
> +}
> +#if 0
> +static void vc8x0_vga_dump(struct vga_timing_t *m)
> +{
> +	dprintk(0, "%s(%p)\n", __func__, m);
> +	dprintk(0, "timing_mode = %d\n", m->timing_mode);
> +	dprintk(0, "spec_height = %d\n", m->spec_height);
> +	dprintk(0, "spec_width = %d\n", m->spec_width);
> +	dprintk(0, "active_pixels = %d\n", m->active_pixels);
> +	dprintk(0, "active_lines = %d\n", m->active_lines);
> +	dprintk(0, "total_pixels = %d\n", m->total_pixels);
> +	dprintk(0, "total_lines = %d\n", m->total_lines);
> +	dprintk(0, "fcl = %d\n", m->fcl);
> +	dprintk(0, "bl = %d\n", m->bl);
> +	dprintk(0, "h_blanking (sav) = %d\n", m->h_blanking);
> +}
> +#endif
> +static struct vga_rate_t vga_rates[] = {
> +	/* FCL	FCL		FCL	FIELD				*/
> +	/* MIN	NOM		MAX	10M	FPS100	FPS099	RATE	*/
> +	{ 1854,	/*1866*/	1872,	166833,	6000,	5994,	ADV7441A_FRAMERATE_60, },
> +	{ 2230,	/*2237*/	2245,	200000,	5000,	5000,	ADV7441A_FRAMERATE_50, },
> +	{ 3720,	/*3732*/	3740,	333667,	3000,	2997,	ADV7441A_FRAMERATE_30, },
> +	{ 4460,	/*4474*/	4490,	400000,	2500,	2500,	ADV7441A_FRAMERATE_25, },
> +
> +	/* 23.976 */
> +	{ 4650,	/*4665*/	4680,	417083,	2400,	2398,	ADV7441A_FRAMERATE_24, },
> +};
> +
> +static struct vga_rate_t *vc8x0_vga_HdGetRate(u32 fcl28)
> +{
> +	int i;
> +	struct vga_rate_t *ret = 0;
> +
> +	for (i = 0; i < ARRAY_SIZE(vga_rates); i++) {
> +		if ((fcl28 >= vga_rates[i].fcl_min) &&
> +			(fcl28 <= vga_rates[i].fcl_max)) {
> +			ret = &vga_rates[i];
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static struct vga_size_t vga_sizes[] = {
> +	{  260,  265,  720, {  240, 240 }, 1, }, /* 525i  4x1 CP */
> +	{  310,  315,  720, {  288, 288 }, 1, }, /* 625i  4x1 CP */
> +	{  523,  527,  720, {  483,   0 }, 0, }, /* 525p  2x1 */
> +	{  623,  626,  720, {  576,   0 }, 0, }, /* 625p  2x1 */
> +	{  627,  628,  800, {  600,   0 }, 0, }, /* 800 x 600 */
> +	{  745,  752, 1280, {  720,   0 }, 0, }, /* 720p 1x1 */
> +	{  795,  800, 1400, { 1050,   0 }, 0, }, /* 1400 x 1050 */
> +	{  803,  806, 1024, {  768,   0 }, 0, }, /* 1024 x 768 */
> +	{  560,  565, 1920, {  540, 540 }, 1, }, /* 1080i 1x1 */
> +	{  925,  932, 1440, {  900,   0 }, 0, }, /* 1440 x 900p */
> +	{  990, 1005, 1280, {  960,   0 }, 0, }, /* 1280 x 960 */
> +	{ 1062, 1066, 1280, { 1024,   0 }, 0, }, /* 1280 x 1024 */
> +	{ 1084, 1087, 1400, { 1050,   0 }, 0, }, /* 1400 x 1050 */
> +	{ 1116, 1127, 1920, { 1080,   0 }, 0, }, /* 1080p 1x1 */
> +	{ 1246, 1252, 1600, { 1200,   0 }, 0, }, /* 1600 x 1200p */
> +};
> +
> +static struct vga_size_t *vc8x0_vga_HdGetSize(u32 lcf)
> +{
> +	int i;
> +	struct vga_size_t *ret = 0;
> +
> +	for (i = 0; i < ARRAY_SIZE(vga_sizes); i++) {
> +		if ((lcf >= vga_sizes[i].lcf_min) &&
> +			(lcf <= vga_sizes[i].lcf_max)) {
> +			ret = &vga_sizes[i];
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}

None of the above seems to be compliant with the timings API. Please, re-define it
according to it, in order to expose it using the right way. I won't comment more
about the timings API, but there are more related stuff below.

> +
> +/* Helpers */
> +static int adv7441a_detect(struct adv7441a_state *state);
> +
> +static inline struct adv7441a_state *to_state(struct v4l2_subdev *sd)
> +{
> +	return container_of(sd, struct adv7441a_state, sd);
> +}
> +
> +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
> +{
> +	return &container_of(ctrl->handler, struct adv7441a_state, hdl)->sd;
> +}
> +
> +static struct adv7441a_format *find_format(struct adv7441a_state *state, u32 id)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(formats); i++) {
> +		if (formats[i].id == id) {
> +			return formats + i;
> +		}
> +	}
> +	return 0;
> +}
> +
> +/* for the given input params, try to find a matching supported driver rate */
> +static struct adv7441a_format *
> +vc8x0_video_find_format(struct adv7441a_state *state,
> +	u32 pixelformat, u32 width, u32 height, u32 flags, u32 rate)
> +{
> +	unsigned int i;
> +	dprintk(1, "%s(%x, %d, %d, %d, rate=%d)\n", __func__, pixelformat,
> +		width, height, flags, rate);
> +
> +	for (i = 0; i < ARRAY_SIZE(formats); i++) {
> +#if 0
> +		if (video_1080p && (formats[i].id ==
> +			ADV7441A_FORMAT_1920x1080i60))
> +			continue;
> +		if (video_1080p && (formats[i].id ==
> +			ADV7441A_FORMAT_1920x1080i50))
> +			continue;
> +
> +		/* Skip any formats not comatible with the users selected
> +		 * cable input type. This will prevent us from selecting an
> +		 * HDMI format for 1920x1080 when the caller is selecting
> +		 * VGA for example.
> +		 */
> +		if (vc8x0_video_is_input_compatible(state->video_input_nr,
> +			&formats[i]) == 0)
> +			continue;
> +#endif
> +
> +		if ((formats[i].fourcc == pixelformat) &&
> +			(formats[i].width == width) &&
> +			(formats[i].height == height) &&
> +			(formats[i].flags == flags) &&
> +			(formats[i].frate == rate)
> +		) {
> +			return formats + i;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/* I2C Access */
> +/* 8 bit registers, 8 bit values */
> +static int i2c_write(struct adv7441a_state *state,
> +	struct i2c_client *client,
> +	u8 addr, u8 reg, u8 data)
> +{
> +	int ret;
> +	u8 buf[] = { reg, data };
> +
> +	struct i2c_msg msg = {
> +		.addr  = addr,
> +		.flags = 0,
> +		.buf   = buf,
> +		.len   = 2
> +	};
> +
> +	ret = i2c_transfer(client->adapter, &msg, 1);
> +
> +	if (ret != 1) {
> +		pr_err("%s() writereg error, ret = %d\n",
> +			__func__, ret);
> +		pr_err("%s() 0x%02x 0x%02x 0x%02x\n",
> +			__func__, addr, reg, data);
> +	}
> +
> +	return (ret != 1) ? -1 : 0;
> +}
> +
> +static u8 i2c_read(struct adv7441a_state *state,
> +	struct i2c_client *client, u8 addr, u8 reg, u8 *val)
> +{
> +	int ret;
> +	u8 b0[] = { reg };
> +	u8 b1 = 0;
> +
> +	struct i2c_msg msg[] = {
> +		{ .addr = addr, .flags = 0, .buf = b0, .len = 1 },
> +		{ .addr = addr, .flags = I2C_M_RD, .buf = &b1, .len = 1 }
> +	};
> +
> +	ret = i2c_transfer(client->adapter, msg, 2);
> +
> +	if (ret != 2)
> +		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
> +			__func__, ret);
> +
> +	*val = b1;
> +	return 1;
> +}
> +
> +static void adv7441a_unregister_clients(struct adv7441a_state *state)
> +{
> +	if (state->usermap_client) {
> +		i2c_unregister_device(state->usermap_client);
> +		state->usermap_client = 0;
> +	}
> +	if (state->user1map_client) {
> +		i2c_unregister_device(state->user1map_client);
> +		state->user1map_client = 0;
> +	}
> +	if (state->user2map_client) {
> +		i2c_unregister_device(state->user2map_client);
> +		state->user2map_client = 0;
> +	}
> +	if (state->user3map_client) {
> +		i2c_unregister_device(state->user3map_client);
> +		state->user3map_client = 0;
> +	}
> +	if (state->reservedmap_client) {
> +		i2c_unregister_device(state->reservedmap_client);
> +		state->reservedmap_client = 0;
> +	}
> +	if (state->hdmimap_client) {
> +		i2c_unregister_device(state->hdmimap_client);
> +		state->hdmimap_client = 0;
> +	}
> +	if (state->rksvmap_client) {
> +		i2c_unregister_device(state->rksvmap_client);
> +		state->rksvmap_client = 0;
> +	}
> +	if (state->edidmap_client) {
> +		i2c_unregister_device(state->edidmap_client);
> +		state->edidmap_client = 0;
> +	}
> +}
> +
> +static int adv7441a_i2c_usermap_read8(struct adv7441a_state *state,
> +	u8 reg, u8 *val)
> +{
> +	i2c_read(state, state->usermap_client,
> +		state->usermap_addr, reg, val);
> +	return 1;
> +}
> +
> +static int adv7441a_i2c_usermap_write8(struct adv7441a_state *state,
> +	u8 reg, u8 val)
> +{
> +	int ret;
> +	ret = i2c_write(state, state->usermap_client,
> +		state->usermap_addr, reg, val);
> +	return ret;
> +}
> +
> +static int adv7441a_i2c_usermap_setbit(struct adv7441a_state *state,
> +	u8 reg, u8 bitmask)
> +{
> +	unsigned char val;
> +	adv7441a_i2c_usermap_read8(state, reg, &val);
> +	val |= bitmask;
> +	return adv7441a_i2c_usermap_write8(state, reg, val);
> +}
> +
> +static int adv7441a_i2c_user1map_read8(struct adv7441a_state *state,
> +	u8 reg, u8 *val)
> +{
> +	int ret;
> +	ret = i2c_read(state, state->user1map_client,
> +		state->user1map_addr, reg, val);
> +	return ret;
> +}
> +
> +static int adv7441a_i2c_user1map_write8(struct adv7441a_state *state,
> +	u8 reg, u8 val)
> +{
> +	int ret;
> +	ret = i2c_write(state, state->user1map_client,
> +		state->user1map_addr, reg, val);
> +	return ret;
> +}
> +
> +static int adv7441a_i2c_user1map_setbit(struct adv7441a_state *state,
> +	u8 reg, u8 bitmask)
> +{
> +	unsigned char val;
> +	adv7441a_i2c_user1map_read8(state, reg, &val);
> +	val |= bitmask;
> +	return adv7441a_i2c_user1map_write8(state, reg, val);
> +}
> +
> +static int adv7441a_i2c_user2map_write8(struct adv7441a_state *state,
> +	u8 reg, u8 val)
> +{
> +	int ret;
> +	ret = i2c_write(state, state->user2map_client,
> +		state->user2map_addr, reg, val);
> +	return ret;
> +}
> +
> +static int adv7441a_i2c_hdmimap_read8(struct adv7441a_state *state,
> +	u8 reg, u8 *val)
> +{
> +	int ret;
> +	ret = i2c_read(state, state->hdmimap_client,
> +		state->hdmimap_addr, reg, val);
> +	return ret;
> +}
> +
> +static int adv7441a_i2c_hdmimap_write8(struct adv7441a_state *state,
> +	u8 reg, u8 val)
> +{
> +	int ret;
> +	ret = i2c_write(state, state->hdmimap_client,
> +		state->hdmimap_addr, reg, val);
> +	return ret;
> +}
> +
> +static int adv7441a_i2c_hdmimap_setbit(struct adv7441a_state *state,
> +	u8 reg, u8 bitmask)
> +{
> +	unsigned char val;
> +	adv7441a_i2c_usermap_read8(state, reg, &val);
> +	val |= bitmask;
> +	return adv7441a_i2c_hdmimap_write8(state, reg, val);
> +}
> +
> +static int adv7441a_i2c_edidmap_write8(struct adv7441a_state *state,
> +	u8 reg, u8 val)
> +{
> +	int ret;
> +	ret = i2c_write(state, state->edidmap_client,
> +		state->edidmap_addr, reg, val);
> +	return ret;
> +}
> +
> +static int adv7441a_i2c_rksvmap_write8(struct adv7441a_state *state,
> +	u8 reg, u8 val)
> +{
> +	int ret;
> +	ret = i2c_write(state, state->rksvmap_client,
> +		state->rksvmap_addr, reg, val);
> +	return ret;
> +}
> +
> +static int adv7441a_sw_reset(struct adv7441a_state *state)
> +{
> +	/* Put the chip into s/w reset */
> +	adv7441a_i2c_usermap_write8(state, 0x0F, 0x80);
> +	msleep(20);
> +
> +	return 0;
> +}
> +
> +/* Per resolution / format configuration settings */
> +static int adv7441a_CVBS_720x480ix60(struct adv7441a_state *state,
> +	int n)
> +{
> +	u8 reg;
> +	dprintk(1, "%s(%d)\n", __func__, n);
> +
> +	if (n == 1)
> +		reg = 0x00; /* CVBS on AIN1 (Green) */
> +	else
> +	if (n == 2)
> +		reg = 0x02; /* CVBS on AIN3 (Red) */
> +	else
> +	if (n == 3)
> +		reg = 0x01; /* CVBS on AIN2 (Blue) */
> +	else
> +		BUG();
> +
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, reg);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x01);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x5c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x17, 0x41);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x31, 0x10);
> +	adv7441a_i2c_usermap_write8(state, 0x34, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0x35, 0x22);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xf1);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0x8f, 0x50);
> +	adv7441a_i2c_usermap_write8(state, 0x90, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x00);

While it is ok to keep it as-is, I would store all those per-timings attribute into some
table, in order to simplify the code.

> +
> +	return 0;
> +}
> +
> +static int adv7441a_SVIDEO_720x480ix60(struct adv7441a_state *state)
> +{
> +	dprintk(1, "%s()\n", __func__);
> +
> +	/* Y on AIN1 (Green) */
> +	/* C on AIN3 (Red) */
> +
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc0);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x03);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x5c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x17, 0x41);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x31, 0x10);
> +	adv7441a_i2c_usermap_write8(state, 0x34, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0x35, 0x22);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xf1);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0x8f, 0x50);
> +	adv7441a_i2c_usermap_write8(state, 0x90, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x00);
> +
> +	return 0;
> +}
> +#if 0
> +static int adv7441a_UXGA_1600x1200x60(struct adv7441a_state *state,
> +	struct v4l2_dv_timings *timing)
> +{
> +	u32 ushtotal, frll, lines, sav = 488, eav = 2094;
> +	u8 reg;
> +
> +	state->vga_timing_mode = vc8x0_vga_lookup(
> +		2, /* DMT */
> +		fmt->width,
> +		fmt->height,
> +		fmt->flags == ADV7441A_FORMAT_INTERLACED ? 1 : 0);
> +	if (state->vga_timing_mode)
> +		vc8x0_vga_dump(state->vga_timing_mode);
> +
> +	if (!state->vga_timing_mode) {
> +		pr_err("%s() unable to locate fmt->id %d [%s] in the timing table\n",
> +			__func__, fmt->id, fmt->name);
> +		return -ENODEV;
> +	}
> +
> +	ushtotal = state->vga_timing_mode->total_pixels;
> +	frll = state->vga_timing_mode->bl >> 3;
> +	lines = state->vga_timing_mode->total_lines;
> +	lines--;
> +
> +	dprintk(1, "%s(ushtotal = %d, frll = %d, lines = %d, bl = %d)\n",
> +		__func__, ushtotal, frll, lines,
> +		state->vga_timing_mode->bl);
> +
> +	/* Basic input settings */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	/* Auto Mode */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x5c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xf3);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa3);
> +
> +	/* ADV7441 HW RevJ Page 190 Section 9.15 */
> +
> +	/* PLL_DIV_MAN_EN */
> +	/* PLL_DIV_RATIO */
> +	reg = 0xe0 | ((ushtotal & 0xfff) >> 8);
> +	pr_err("87 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x87, reg);
> +
> +	reg = ushtotal & 0xff;
> +	pr_err("88 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x88, reg);
> +
> +	/* FR_LL */
> +	reg = 0x70 | ((frll & 0x7ff) >> 8);
> +	pr_err("8f = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x8f, reg);
> +
> +	reg = frll & 0xff;
> +	pr_err("90 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x90, reg);
> +
> +	/* LCOUNT_MAX */
> +	reg = (lines & 0xfff) >> 4;
> +	pr_err("ab = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xab, reg);
> +	reg = (lines & 0x00f) << 4;
> +	pr_err("ac = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xac, reg);
> +
> +	/* INTERLACED */
> +	adv7441a_i2c_usermap_write8(state, 0x91, 0x10);
> +
> +	/* SAV / EAV */
> +	reg = sav >> 4;
> +	pr_err("a2 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa2, reg);
> +	reg = (eav >> 8) | (sav << 4);
> +	pr_err("a3 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa3, reg);
> +	reg = (eav & 0xff);
> +	pr_err("a4 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa4, reg);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_WXGA_1440x900x60(struct adv7441a_state *state,
> +	struct v4l2_dv_timings *timing)
> +{
> +	u32 ushtotal, frll, lines, sav = 381, eav = 1825;
> +	u8 reg;
> +
> +	state->vga_timing_mode = vc8x0_vga_lookup(
> +		1, /* GTF */
> +		fmt->width,
> +		fmt->height,
> +		fmt->flags == ADV7441A_FORMAT_INTERLACED ? 1 : 0);
> +	if (state->vga_timing_mode)
> +		vc8x0_vga_dump(state->vga_timing_mode);
> +
> +	if (!state->vga_timing_mode) {
> +		pr_err("%s() unable to locate fmt->id %d [%s] in the timing table\n",
> +			__func__, fmt->id, fmt->name);
> +		return -ENODEV;
> +	}
> +
> +	ushtotal = state->vga_timing_mode->total_pixels;
> +	frll = state->vga_timing_mode->bl >> 3;
> +	lines = state->vga_timing_mode->total_lines;
> +	lines++;
> +
> +	dprintk(1, "%s(ushtotal = %d, frll = %d, lines = %d)\n",
> +		__func__, ushtotal, frll, lines);
> +
> +	/* Basic input settings */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	/* Auto Mode */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x5c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xf3);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa3);
> +
> +	/* ADV7441 HW RevJ Page 190 Section 9.15 */
> +
> +	/* PLL_DIV_MAN_EN */
> +	/* PLL_DIV_RATIO */
> +	reg = 0xe0 | ((ushtotal & 0xfff) >> 8);
> +	pr_err("87 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x87, reg);
> +
> +	reg = ushtotal & 0xff;
> +	pr_err("88 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x88, reg);
> +
> +	/* FR_LL */
> +	reg = 0x70 | ((frll & 0x7ff) >> 8);
> +	pr_err("8f = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x8f, reg);
> +
> +	reg = frll & 0xff;
> +	pr_err("90 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x90, reg);
> +
> +	/* LCOUNT_MAX */
> +	reg = (lines & 0xfff) >> 4;
> +	pr_err("ab = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xab, reg);
> +	reg = (lines & 0x00f) << 4;
> +	pr_err("ac = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xac, reg);
> +
> +	/* INTERLACED */
> +	adv7441a_i2c_usermap_write8(state, 0x91, 0x10);
> +
> +	/* SAV / EAV */
> +	reg = sav >> 4;
> +	pr_err("a2 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa2, reg);
> +	reg = (eav >> 8) | (sav << 4);
> +	pr_err("a3 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa3, reg);
> +	reg = (eav & 0xff);
> +	pr_err("a4 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa4, reg);
> +
> +	/* VBI */
> +	reg = (lines + 1) >> 4;
> +	pr_err("a5 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa5, reg);
> +	reg = ((lines + 1) << 4) | (((lines + 1) - fmt->height) & 0xfff) >> 8;
> +	pr_err("a6 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa6, 0xd0);
> +	reg = ((lines + 1) - fmt->height) & 0xff;
> +	pr_err("a7 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa7, reg);
> +
> +
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_WSXGA_1680x1050x60(struct adv7441a_state *state,
> +	struct v4l2_dv_timings *timing)
> +{
> +	u32 ushtotal, frll, lines, sav = 357, eav = 1761;
> +	u8 reg;
> +
> +	state->vga_timing_mode = vc8x0_vga_lookup(
> +		2,
> +		fmt->width,
> +		fmt->height,
> +		fmt->flags == ADV7441A_FORMAT_INTERLACED ? 1 : 0);
> +	if (state->vga_timing_mode)
> +		vc8x0_vga_dump(state->vga_timing_mode);
> +
> +	if (!state->vga_timing_mode) {
> +		pr_err("%s() unable to locate fmt->id %d [%s] in the timing table\n",
> +			__func__, fmt->id, fmt->name);
> +		return -ENODEV;
> +	}
> +
> +	ushtotal = state->vga_timing_mode->total_pixels;
> +	frll = state->vga_timing_mode->bl >> 3;
> +	lines = state->vga_timing_mode->total_lines;
> +
> +	dprintk(1, "%s(ushtotal = %d, frll = %d, lines = %d)\n",
> +		__func__, ushtotal, frll, lines);
> +
> +	/* Basic input settings */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	/* Auto Mode */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x5c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xf3);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa3);
> +
> +	/* ADV7441 HW RevJ Page 190 Section 9.15 */
> +
> +	/* PLL_DIV_MAN_EN */
> +	/* PLL_DIV_RATIO */
> +	reg = 0xe0 | ((ushtotal & 0xfff) >> 8);
> +	pr_err("87 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x87, reg);
> +
> +	reg = ushtotal & 0xff;
> +	pr_err("88 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x88, reg);
> +
> +	/* FR_LL */
> +	reg = 0x70 | ((frll & 0x7ff) >> 8);
> +	pr_err("8f = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x8f, reg);
> +
> +	reg = frll & 0xff;
> +	pr_err("90 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x90, reg);
> +
> +	/* LCOUNT_MAX */
> +	reg = (lines & 0xfff) >> 4;
> +	pr_err("ab = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xab, reg);
> +	reg = (lines & 0x00f) << 4;
> +	pr_err("ac = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xac, reg);
> +
> +	/* INTERLACED */
> +	adv7441a_i2c_usermap_write8(state, 0x91, 0x10);
> +
> +	/* SAV / EAV */
> +	reg = sav >> 4;
> +	pr_err("a2 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa2, reg);
> +	reg = (eav >> 8) | (sav << 4);
> +	pr_err("a3 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa3, reg);
> +	reg = (eav & 0xff);
> +	pr_err("a4 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa4, reg);
> +
> +	/* VBI */
> +	reg = (lines + 1) >> 4;
> +	pr_err("a5 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa5, reg);
> +	reg = ((lines + 1) << 4) | (((lines + 1) - fmt->height) & 0xfff) >> 8;
> +	pr_err("a6 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa6, 0xd0);
> +	reg = ((lines + 1) - fmt->height) & 0xff;
> +	pr_err("a7 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa7, reg);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_VGAHD_1920x1080x60(struct adv7441a_state *state,
> +	struct v4l2_dv_timings *timing)
> +{
> +	u32 ushtotal, frll, lines, sav = 489, eav = 2413;
> +	u8 reg;
> +
> +	state->vga_timing_mode = vc8x0_vga_lookup(
> +		1, /* GTF */
> +		fmt->width,
> +		fmt->height,
> +		fmt->flags == ADV7441A_FORMAT_INTERLACED ? 1 : 0);
> +	if (state->vga_timing_mode)
> +		vc8x0_vga_dump(state->vga_timing_mode);
> +
> +	if (!state->vga_timing_mode) {
> +		pr_err("%s() unable to locate fmt->id %d [%s] in the timing table\n",
> +			__func__, fmt->id, fmt->name);
> +		return -ENODEV;
> +	}
> +
> +	ushtotal = state->vga_timing_mode->total_pixels;
> +	frll = state->vga_timing_mode->bl >> 3;
> +	lines = state->vga_timing_mode->total_lines;
> +	lines--;
> +
> +	dprintk(1, "%s(ushtotal = %d, frll = %d, lines = %d, bl = %d)\n",
> +		__func__, ushtotal, frll, lines, state->vga_timing_mode->bl);
> +
> +	/* Basic input settings */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	/* Auto Mode */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x5c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xf3);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa3);
> +
> +	/* ADV7441 HW RevJ Page 190 Section 9.15 */
> +
> +	/* PLL_DIV_MAN_EN */
> +	/* PLL_DIV_RATIO */
> +	reg = 0xe0 | ((ushtotal & 0xfff) >> 8);
> +	pr_err("87 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x87, reg);
> +
> +	reg = ushtotal & 0xff;
> +	pr_err("88 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x88, reg);
> +
> +	/* FR_LL */
> +	reg = 0x70 | ((frll & 0x7ff) >> 8);
> +	pr_err("8f = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x8f, reg);
> +
> +	reg = frll & 0xff;
> +	pr_err("90 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x90, reg);
> +
> +	/* LCOUNT_MAX */
> +	reg = (lines & 0xfff) >> 4;
> +	pr_err("ab = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xab, reg);
> +	reg = (lines & 0x00f) << 4;
> +	pr_err("ac = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xac, reg);
> +
> +	/* INTERLACED */
> +	adv7441a_i2c_usermap_write8(state, 0x91, 0x10);
> +
> +	/* SAV / EAV */
> +	reg = sav >> 4;
> +	pr_err("a2 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa2, reg);
> +	reg = (eav >> 8) | (sav << 4);
> +	pr_err("a3 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa3, reg);
> +	reg = (eav & 0xff);
> +	pr_err("a4 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa4, reg);
> +
> +	/* VBI */
> +	reg = (lines + 1) >> 4;
> +	pr_err("a5 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa5, reg);
> +	reg = ((lines + 1) << 4) | (((lines + 1) - fmt->height) & 0xfff) >> 8;
> +	pr_err("a6 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa6, 0xd0);
> +	reg = ((lines + 1) - fmt->height) & 0xff;
> +	pr_err("a7 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa7, reg);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x00);
> +
> +	return 0;
> +}
> +
> +/* Supported VGA resolutions */
> +static int adv7441a_VGA_640x480ix60(struct adv7441a_state *state,
> +	struct v4l2_dv_timings *timing)
> +{
> +	u32 ushtotal, frll, lines, sav = 160, eav = 806;
> +	u8 reg;
> +
> +	sav = 137;
> +	eav = 783;
> +
> +	state->vga_timing_mode = vc8x0_vga_lookup(
> +		2,
> +		fmt->width,
> +		fmt->height,
> +		fmt->flags == ADV7441A_FORMAT_INTERLACED ? 1 : 0);
> +	if (state->vga_timing_mode)
> +		vc8x0_vga_dump(state->vga_timing_mode);
> +
> +	if (!state->vga_timing_mode) {
> +		pr_err("%s() unable to locate fmt->id %d [%s] in the timing table\n",
> +			__func__, fmt->id, fmt->name);
> +		return -ENODEV;
> +	}
> +
> +	ushtotal = state->vga_timing_mode->total_pixels;
> +	frll = state->vga_timing_mode->bl >> 3;
> +	lines = state->vga_timing_mode->total_lines;
> +	lines--;
> +
> +	dprintk(1, "%s(ushtotal = %d, frll = %d, lines = %d)\n",
> +		__func__, ushtotal, frll, lines);
> +
> +	/* Basic input settings */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	/* Auto Mode */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x5c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xf3);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa3);
> +
> +	/* ADV7441 HW RevJ Page 190 Section 9.15 */
> +
> +	/* PLL_DIV_MAN_EN */
> +	/* PLL_DIV_RATIO */
> +	reg = 0xe0 | ((ushtotal & 0xfff) >> 8);
> +	pr_err("87 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x87, reg);
> +
> +	reg = ushtotal & 0xff;
> +	pr_err("88 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x88, reg);
> +
> +	/* FR_LL */
> +	reg = 0x70 | ((frll & 0x7ff) >> 8);
> +	pr_err("8f = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x8f, reg);
> +
> +	reg = frll & 0xff;
> +	pr_err("90 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x90, reg);
> +
> +	/* LCOUNT_MAX */
> +	reg = (lines & 0xfff) >> 4;
> +	pr_err("ab = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xab, reg);
> +	reg = (lines & 0x00f) << 4;
> +	pr_err("ac = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xac, reg);
> +
> +	/* INTERLACED */
> +	adv7441a_i2c_usermap_write8(state, 0x91, 0x10);
> +
> +	/* SAV / EAV */
> +	reg = sav >> 4;
> +	pr_err("a2 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa2, reg);
> +	reg = (eav >> 8) | (sav << 4);
> +	pr_err("a3 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa3, reg);
> +	reg = (eav & 0xff);
> +	pr_err("a4 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa4, reg);
> +
> +	/* VBI */
> +	reg = (lines + 1) >> 4;
> +	pr_err("a5 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa5, reg);
> +	reg = ((lines + 1) << 4) | (((lines + 1) - fmt->height) & 0xfff) >> 8;
> +	pr_err("a6 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa6, 0xd0);
> +	reg = ((lines + 1) - fmt->height) & 0xff;
> +	pr_err("a7 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa7, reg);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_VGA_800x600px60(struct adv7441a_state *state,
> +	struct v4l2_dv_timings *timing)
> +{
> +	u32 ushtotal, frll, lines, sav = 234, eav = 1040;
> +	u8 reg;
> +
> +	sav = 210;
> +	eav = 1016;
> +
> +	state->vga_timing_mode = vc8x0_vga_lookup(
> +		2,
> +		fmt->width,
> +		fmt->height,
> +		fmt->flags == ADV7441A_FORMAT_INTERLACED ? 1 : 0);
> +	if (state->vga_timing_mode)
> +		vc8x0_vga_dump(state->vga_timing_mode);
> +
> +	if (!state->vga_timing_mode) {
> +		pr_err("%s() unable to locate fmt->id %d [%s] in the timing table\n",
> +			__func__, fmt->id, fmt->name);
> +		return -ENODEV;
> +	}
> +
> +	ushtotal = state->vga_timing_mode->total_pixels;
> +	frll = state->vga_timing_mode->bl >> 3;
> +	lines = state->vga_timing_mode->total_lines;
> +	lines = 629;
> +
> +	dprintk(1, "%s(ushtotal = %d, frll = %d, lines = %d)\n",
> +		__func__, ushtotal, frll, lines);
> +
> +	/* Basic input settings */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	/* Auto Mode */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x5c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xf3);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa3);
> +
> +	/* ADV7441 HW RevJ Page 190 Section 9.15 */
> +
> +	/* PLL_DIV_MAN_EN */
> +	/* PLL_DIV_RATIO */
> +	reg = 0xe0 | ((ushtotal & 0xfff) >> 8);
> +	pr_err("87 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x87, reg);
> +
> +	reg = ushtotal & 0xff;
> +	pr_err("88 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x88, reg);
> +
> +	/* FR_LL */
> +	reg = 0x70 | ((frll & 0x7ff) >> 8);
> +	pr_err("8f = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x8f, reg);
> +
> +	reg = frll & 0xff;
> +	pr_err("90 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x90, reg);
> +
> +	/* LCOUNT_MAX */
> +	reg = (lines & 0xfff) >> 4;
> +	pr_err("ab = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xab, reg);
> +	reg = (lines & 0x00f) << 4;
> +	pr_err("ac = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xac, reg);
> +
> +	/* INTERLACED */
> +	adv7441a_i2c_usermap_write8(state, 0x91, 0x10);
> +
> +	/* SAV / EAV */
> +	reg = sav >> 4;
> +	pr_err("a2 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa2, reg);
> +	reg = (eav >> 8) | (sav << 4);
> +	pr_err("a3 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa3, reg);
> +	reg = (eav & 0xff);
> +	pr_err("a4 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa4, reg);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_VGA_1024x768px60(struct adv7441a_state *state,
> +	struct v4l2_dv_timings *timing)
> +{
> +	u32 ushtotal, frll, lines, sav = 290, eav = 1320;
> +	u8 reg;
> +
> +	state->vga_timing_mode = vc8x0_vga_lookup(
> +		2,
> +		fmt->width,
> +		fmt->height,
> +		fmt->flags == ADV7441A_FORMAT_INTERLACED ? 1 : 0);
> +	if (state->vga_timing_mode)
> +		vc8x0_vga_dump(state->vga_timing_mode);
> +
> +	if (!state->vga_timing_mode) {
> +		pr_err("%s() unable to locate fmt->id %d [%s] in the timing table\n",
> +			__func__, fmt->id, fmt->name);
> +		return -ENODEV;
> +	}
> +
> +	ushtotal = state->vga_timing_mode->total_pixels;
> +	frll = state->vga_timing_mode->bl >> 3;
> +	lines = state->vga_timing_mode->total_lines;
> +	lines++;
> +
> +	dprintk(1, "%s(ushtotal = %d, frll = %d, lines = %d)\n",
> +		__func__, ushtotal, frll, lines);
> +
> +	/* Basic input settings */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	/* Auto Mode */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x5c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xf3);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa3);
> +
> +	/* ADV7441 HW RevJ Page 190 Section 9.15 */
> +
> +	/* PLL_DIV_MAN_EN */
> +	/* PLL_DIV_RATIO */
> +	reg = 0xe0 | ((ushtotal & 0xfff) >> 8);
> +	pr_err("87 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x87, reg);
> +
> +	reg = ushtotal & 0xff;
> +	pr_err("88 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x88, reg);
> +
> +	/* FR_LL */
> +	reg = 0x70 | ((frll & 0x7ff) >> 8);
> +	pr_err("8f = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x8f, reg);
> +
> +	reg = frll & 0xff;
> +	pr_err("90 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x90, reg);
> +
> +	/* LCOUNT_MAX */
> +	reg = (lines & 0xfff) >> 4;
> +	pr_err("ab = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xab, reg);
> +	reg = (lines & 0x00f) << 4;
> +	pr_err("ac = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xac, reg);
> +
> +	/* INTERLACED */
> +	adv7441a_i2c_usermap_write8(state, 0x91, 0x10);
> +
> +	/* SAV / EAV */
> +	reg = sav >> 4;
> +	pr_err("a2 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa2, reg);
> +	reg = (eav >> 8) | (sav << 4);
> +	pr_err("a3 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa3, reg);
> +	reg = (eav & 0xff);
> +	pr_err("a4 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa4, reg);
> +
> +	/* VBI */
> +	reg = (lines + 1) >> 4;
> +	pr_err("a5 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa5, reg);
> +	reg = ((lines + 1) << 4) | (((lines + 1) - fmt->height) & 0xfff) >> 8;
> +	pr_err("a6 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa6, 0xd0);
> +	reg = ((lines + 1) - fmt->height) & 0xff;
> +	pr_err("a7 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa7, reg);
> +
> +
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_VGA_1280x960px60(struct adv7441a_state *state,
> +	struct v4l2_dv_timings *timing)
> +{
> +	/* 1280B@60 */
> +
> +	u32 ushtotal, frll, lines, sav = 420, eav = 1706;
> +	u8 reg;
> +
> +	state->vga_timing_mode = vc8x0_vga_lookup(
> +		2,
> +		fmt->width,
> +		fmt->height,
> +		fmt->flags == ADV7441A_FORMAT_INTERLACED ? 1 : 0);
> +	if (state->vga_timing_mode)
> +		vc8x0_vga_dump(state->vga_timing_mode);
> +
> +	if (!state->vga_timing_mode) {
> +		pr_err("%s() unable to locate fmt->id %d [%s] in the timing table\n",
> +			__func__, fmt->id, fmt->name);
> +		return -ENODEV;
> +	}
> +
> +	ushtotal = state->vga_timing_mode->total_pixels;
> +	frll = state->vga_timing_mode->bl >> 3;
> +	lines = state->vga_timing_mode->total_lines;
> +	lines++;
> +
> +	dprintk(1, "%s(ushtotal = %d, frll = %d, lines = %d)\n",
> +		__func__, ushtotal, frll, lines);
> +
> +	/* Basic input settings */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	/* Auto Mode */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x5c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xf3);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa3);
> +
> +	/* ADV7441 HW RevJ Page 190 Section 9.15 */
> +
> +	/* PLL_DIV_MAN_EN */
> +	/* PLL_DIV_RATIO */
> +	reg = 0xe0 | ((ushtotal & 0xfff) >> 8);
> +	pr_err("87 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x87, reg);
> +
> +	reg = ushtotal & 0xff;
> +	pr_err("88 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x88, reg);
> +
> +	/* FR_LL */
> +	reg = 0x70 | ((frll & 0x7ff) >> 8);
> +	pr_err("8f = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x8f, reg);
> +
> +	reg = frll & 0xff;
> +	pr_err("90 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x90, reg);
> +
> +	/* LCOUNT_MAX */
> +	reg = (lines & 0xfff) >> 4;
> +	pr_err("ab = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xab, reg);
> +	reg = (lines & 0x00f) << 4;
> +	pr_err("ac = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xac, reg);
> +
> +	/* INTERLACED */
> +	adv7441a_i2c_usermap_write8(state, 0x91, 0x10);
> +
> +	/* SAV / EAV */
> +	reg = sav >> 4;
> +	pr_err("a2 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa2, reg);
> +	reg = (eav >> 8) | (sav << 4);
> +	pr_err("a3 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa3, reg);
> +	reg = (eav & 0xff);
> +	pr_err("a4 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa4, reg);
> +
> +	/* VBI */
> +	reg = (lines + 1) >> 4;
> +	pr_err("a5 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa5, reg);
> +	reg = ((lines + 1) << 4) | (((lines + 1) - fmt->height) & 0xfff) >> 8;
> +	pr_err("a6 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa6, 0xd0);
> +	reg = ((lines + 1) - fmt->height) & 0xff;
> +	pr_err("a7 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa7, reg);
> +
> +
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_VGA_1280x720px60(struct adv7441a_state *state,
> +	struct v4l2_dv_timings *timing)
> +{
> +	u32 ushtotal, frll, lines, sav = 317, eav = 1603;
> +	u8 reg;
> +
> +	state->vga_timing_mode = vc8x0_vga_lookup(
> +		2,
> +		fmt->width,
> +		fmt->height,
> +		fmt->flags == ADV7441A_FORMAT_INTERLACED ? 1 : 0);
> +	if (state->vga_timing_mode)
> +		vc8x0_vga_dump(state->vga_timing_mode);
> +
> +	if (!state->vga_timing_mode) {
> +		pr_err("%s() unable to locate fmt->id %d [%s] in the timing table\n",
> +			__func__, fmt->id, fmt->name);
> +		return -ENODEV;
> +	}
> +
> +	ushtotal = state->vga_timing_mode->total_pixels;
> +	frll = state->vga_timing_mode->bl >> 3;
> +	lines = state->vga_timing_mode->total_lines;
> +	lines = 747;
> +
> +	dprintk(1, "%s(ushtotal = %d, frll = %d, lines = %d)\n",
> +		__func__, ushtotal, frll, lines);
> +
> +	/* Basic input settings */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	/* Auto Mode */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x5c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xf3);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa3);
> +
> +	/* ADV7441 HW RevJ Page 190 Section 9.15 */
> +
> +	/* PLL_DIV_MAN_EN */
> +	/* PLL_DIV_RATIO */
> +	reg = 0xe0 | ((ushtotal & 0xfff) >> 8);
> +	pr_err("87 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x87, reg);
> +
> +	reg = ushtotal & 0xff;
> +	pr_err("88 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x88, reg);
> +
> +	/* FR_LL */
> +	reg = 0x70 | ((frll & 0x7ff) >> 8);
> +	pr_err("8f = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x8f, reg);
> +
> +	reg = frll & 0xff;
> +	pr_err("90 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x90, reg);
> +
> +	/* LCOUNT_MAX */
> +	reg = (lines & 0xfff) >> 4;
> +	pr_err("ab = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xab, reg);
> +	reg = (lines & 0x00f) << 4;
> +	pr_err("ac = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xac, reg);
> +
> +	/* INTERLACED */
> +	adv7441a_i2c_usermap_write8(state, 0x91, 0x10);
> +
> +	/* SAV / EAV */
> +	reg = sav >> 4;
> +	pr_err("a2 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa2, reg);
> +	reg = (eav >> 8) | (sav << 4);
> +	pr_err("a3 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa3, reg);
> +	reg = (eav & 0xff);
> +	pr_err("a4 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa4, reg);
> +
> +	/* VBI */
> +	reg = (lines + 1) >> 4;
> +	pr_err("a5 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa5, reg);
> +	reg = ((lines + 1) << 4) | (((lines + 1) - fmt->height) & 0xfff) >> 8;
> +	pr_err("a6 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa6, 0xd0);
> +	reg = ((lines + 1) - fmt->height) & 0xff;
> +	pr_err("a7 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa7, reg);
> +
> +
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_VGA_1280x1024px60(struct adv7441a_state *state,
> +	struct v4l2_dv_timings *timing)
> +{
> +	/* 1280_@60 */
> +	u32 ushtotal, frll, lines, sav = 354, eav = 1640;
> +	u8 reg;
> +
> +	state->vga_timing_mode = vc8x0_vga_lookup(
> +		2,
> +		fmt->width,
> +		fmt->height,
> +		fmt->flags == ADV7441A_FORMAT_INTERLACED ? 1 : 0);
> +	if (state->vga_timing_mode)
> +		vc8x0_vga_dump(state->vga_timing_mode);
> +
> +	if (!state->vga_timing_mode) {
> +		pr_err("%s() unable to locate fmt->id %d [%s] in the timing table\n",
> +			__func__, fmt->id, fmt->name);
> +		return -ENODEV;
> +	}
> +
> +	ushtotal = state->vga_timing_mode->total_pixels;
> +	frll = state->vga_timing_mode->bl >> 3;
> +	lines = state->vga_timing_mode->total_lines;
> +	lines++;
> +
> +	dprintk(1, "%s(ushtotal = %d, frll = %d, lines = %d)\n",
> +		__func__, ushtotal, frll, lines);
> +
> +	/* Basic input settings */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	/* Auto Mode */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x5c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xf3);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa3);
> +
> +	/* ADV7441 HW RevJ Page 190 Section 9.15 */
> +
> +	/* PLL_DIV_MAN_EN */
> +	/* PLL_DIV_RATIO */
> +	reg = 0xe0 | ((ushtotal & 0xfff) >> 8);
> +	pr_err("87 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x87, reg);
> +
> +	reg = ushtotal & 0xff;
> +	pr_err("88 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x88, reg);
> +
> +	/* FR_LL */
> +	reg = 0x70 | ((frll & 0x7ff) >> 8);
> +	pr_err("8f = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x8f, reg);
> +
> +	reg = frll & 0xff;
> +	pr_err("90 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x90, reg);
> +
> +	/* LCOUNT_MAX */
> +	reg = (lines & 0xfff) >> 4;
> +	pr_err("ab = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xab, reg);
> +	reg = (lines & 0x00f) << 4;
> +	pr_err("ac = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xac, reg);
> +
> +	/* INTERLACED */
> +	adv7441a_i2c_usermap_write8(state, 0x91, 0x10);
> +
> +	/* SAV / EAV */
> +	reg = sav >> 4;
> +	pr_err("a2 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa2, reg);
> +	reg = (eav >> 8) | (sav << 4);
> +	pr_err("a3 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa3, reg);
> +	reg = (eav & 0xff);
> +	pr_err("a4 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa4, reg);
> +
> +	/* VBI */
> +	reg = (lines + 1) >> 4;
> +	pr_err("a5 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa5, reg);
> +	reg = ((lines + 1) << 4) | (((lines + 1) - fmt->height) & 0xfff) >> 8;
> +	pr_err("a6 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa6, 0xd0);
> +	reg = ((lines + 1) - fmt->height) & 0xff;
> +	pr_err("a7 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa7, reg);
> +
> +
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_VGA_1400x1050px60(struct adv7441a_state *state,
> +	struct v4l2_dv_timings *timing)
> +{
> +	u32 ushtotal, frll, lines, sav = 382, eav = 1786;
> +	u8 reg;
> +
> +	state->vga_timing_mode = vc8x0_vga_lookup(
> +		1,
> +		fmt->width,
> +		fmt->height,
> +		fmt->flags == ADV7441A_FORMAT_INTERLACED ? 1 : 0);
> +	if (state->vga_timing_mode)
> +		vc8x0_vga_dump(state->vga_timing_mode);
> +
> +	if (!state->vga_timing_mode) {
> +		pr_err("%s() unable to locate fmt->id %d [%s] in the timing table\n",
> +			__func__, fmt->id, fmt->name);
> +		return -ENODEV;
> +	}
> +
> +	ushtotal = state->vga_timing_mode->total_pixels;
> +	frll = state->vga_timing_mode->bl >> 3;
> +	lines = state->vga_timing_mode->total_lines;
> +	lines++;
> +
> +	dprintk(1, "%s(ushtotal = %d, frll = %d, lines = %d(%x))\n",
> +		__func__, ushtotal, frll, lines, lines);
> +
> +	/* Basic input settings */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	/* Auto Mode */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x5c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x02);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xf3);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa3);
> +
> +	/* ADV7441 HW RevJ Page 190 Section 9.15 */
> +
> +	/* PLL_DIV_MAN_EN */
> +	/* PLL_DIV_RATIO */
> +	reg = 0xe0 | ((ushtotal & 0xfff) >> 8);
> +	pr_err("87 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x87, reg);
> +
> +	reg = ushtotal & 0xff;
> +	pr_err("88 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x88, reg);
> +
> +	/* FR_LL */
> +	reg = 0x70 | ((frll & 0x7ff) >> 8);
> +	pr_err("8f = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x8f, reg);
> +
> +	reg = frll & 0xff;
> +	pr_err("90 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0x90, reg);
> +
> +	/* LCOUNT_MAX */
> +	reg = (lines & 0xfff) >> 4;
> +	pr_err("ab = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xab, reg);
> +	reg = (lines & 0x00f) << 4;
> +	pr_err("ac = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xac, reg);
> +
> +	/* INTERLACED */
> +	adv7441a_i2c_usermap_write8(state, 0x91, 0x10);
> +
> +	/* SAV / EAV */
> +	reg = sav >> 4;
> +	pr_err("a2 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa2, reg);
> +	reg = (eav >> 8) | (sav << 4);
> +	pr_err("a3 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa3, reg);
> +	reg = (eav & 0xff);
> +	pr_err("a4 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa4, reg);
> +
> +	/* VBI */
> +	reg = (lines + 1) >> 4;
> +	pr_err("a5 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa5, reg);
> +	reg = ((lines + 1) << 4) | (((lines + 1) - fmt->height) & 0xfff) >> 8;
> +	pr_err("a6 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa6, 0xd0);
> +	reg = ((lines + 1) - fmt->height) & 0xff;
> +	pr_err("a7 = %02x\n", reg);
> +	adv7441a_i2c_usermap_write8(state, 0xa7, reg);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x00);
> +
> +	return 0;
> +}
> +#endif
> +
> +static int adv7441a_YPRPB_720x480ix60(struct adv7441a_state *state)
> +{
> +	dprintk(1, "%s()\n", __func__);
> +
> +	/* 0820 */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x1c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xe7);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x0f);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xf4, 0x15);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_YPRPB_720x576px25(struct adv7441a_state *state)
> +{
> +	dprintk(1, "%s()\n", __func__);
> +
> +	/* 0820 */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x1c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x05);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xe7);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x0f);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xf4, 0x15);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_YPRPB_720x576ix50(struct adv7441a_state *state)
> +{
> +	dprintk(1, "%s()\n", __func__);
> +
> +	/* 0820 */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x1c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x0d);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xe7);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x0f);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xf4, 0x15);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_YPRPB_1280x720p(struct adv7441a_state *state,
> +	int rateHz)
> +{
> +	u8 reg;
> +	dprintk(1, "%s(%d)\n", __func__, rateHz);
> +
> +	switch (rateHz) {
> +	case 50:
> +		reg = 0x2a; break;
> +	case 30:
> +		reg = 0x4a; break;
> +	case 25:
> +		reg = 0x6a; break;
> +	case 24:
> +		reg = 0x8a; break;
> +	default:
> +	case 60:
> +		reg = 0x0a;
> +	}
> +
> +	/* 0820 */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x1c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0x06, reg);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xe7);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x0f);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xf4, 0x15);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_YPRPB_1920x1080px30(struct adv7441a_state *state)
> +{
> +	dprintk(1, "%s()\n", __func__);
> +
> +	/* 0820 */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x1c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xe7);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x0f);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xf4, 0x15);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_YPRPB_1920x1080i(struct adv7441a_state *state,
> +	int rateHz)
> +{
> +	u8 reg;
> +	dprintk(1, "%s(%d)\n", __func__, rateHz);
> +
> +	switch (rateHz) {
> +	case 50:
> +		reg = 0x2c; break;
> +	case 30:
> +		reg = 0x4c; break;
> +	case 25:
> +		reg = 0x6c; break;
> +	case 24:
> +		reg = 0x8c; break;
> +	default:
> +	case 60:
> +		reg = 0x0c;
> +	}
> +
> +	/* 0820 */
> +	adv7441a_i2c_usermap_write8(state, 0x69, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0x00, 0x00);
> +	adv7441a_i2c_usermap_write8(state, 0xc3, 0x31);
> +	adv7441a_i2c_usermap_write8(state, 0xc4, 0xc2);
> +	adv7441a_i2c_usermap_write8(state, 0x3a, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x00);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x1c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x01);
> +	adv7441a_i2c_usermap_write8(state, 0x06, reg);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xe7);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x0f);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xf4, 0x15);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_HDMI_720x480ix60(struct adv7441a_state *state)
> +{
> +	dprintk(1, "%s()\n", __func__);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x1c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x37);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x0a, 0xff);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xe7);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x0f);
> +	adv7441a_i2c_usermap_write8(state, 0x85, 0x19);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	/* HDMI_MODE = 1 FREE RUN */
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa0 | 1);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xc8, 0x08);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0xf4, 0x95);
> +
> +	/* VRX_USER_2_MAP_ADDR */
> +	adv7441a_i2c_user2map_write8(state, 0xf0, 0x10);
> +	adv7441a_i2c_user2map_write8(state, 0xf1, 0x0f);
> +	adv7441a_i2c_user2map_write8(state, 0xf4, 0x20);
> +
> +	/* VRX_HDMI_MAP_ADDR */
> +	/* Pixel Repetition override and 2X */
> +	adv7441a_i2c_hdmimap_write8(state, 0x41, 0x51);
> +	adv7441a_i2c_hdmimap_write8(state, 0x15, 0xec);
> +	adv7441a_i2c_hdmimap_write8(state, 0x1c, 0x4b);
> +	adv7441a_i2c_hdmimap_write8(state, 0x1d, 0x04);
> +	adv7441a_i2c_hdmimap_write8(state, 0x3c, 0x82);
> +	adv7441a_i2c_hdmimap_write8(state, 0x5a, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_HDMI_720x576px25(struct adv7441a_state *state)
> +{
> +	/* HDMI res = 625P */
> +	dprintk(1, "%s()\n", __func__);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x1c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x05);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x05);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x37);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x0a, 0xff);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xe7);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x0f);
> +	adv7441a_i2c_usermap_write8(state, 0x85, 0x19);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	/* HDMI_MODE = 1 FREE RUN */
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa0 | 1);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xc8, 0x08);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0xf4, 0x95);
> +
> +	/* VRX_USER_2_MAP_ADDR */
> +	adv7441a_i2c_user2map_write8(state, 0xf0, 0x10);
> +	adv7441a_i2c_user2map_write8(state, 0xf1, 0x0f);
> +	adv7441a_i2c_user2map_write8(state, 0xf4, 0x20);
> +
> +	/* VRX_HDMI_MAP_ADDR */
> +	adv7441a_i2c_hdmimap_write8(state, 0x15, 0xec);
> +	adv7441a_i2c_hdmimap_write8(state, 0x1c, 0x4b);
> +	adv7441a_i2c_hdmimap_write8(state, 0x1d, 0x04);
> +	adv7441a_i2c_hdmimap_write8(state, 0x3c, 0x82);
> +	adv7441a_i2c_hdmimap_write8(state, 0x5a, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_HDMI_720x576ix50(struct adv7441a_state *state)
> +{
> +	dprintk(1, "%s()\n", __func__);
> +
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x1c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x0d);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x37);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x0a, 0xff);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xe7);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x0f);
> +	adv7441a_i2c_usermap_write8(state, 0x85, 0x19);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	/* HDMI_MODE = 1 FREE RUN */
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa0 | 1);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xc8, 0x08);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0xf4, 0x95);
> +
> +	/* VRX_USER_2_MAP_ADDR */
> +	adv7441a_i2c_user2map_write8(state, 0xf0, 0x10);
> +	adv7441a_i2c_user2map_write8(state, 0xf1, 0x0f);
> +	adv7441a_i2c_user2map_write8(state, 0xf4, 0x20);
> +
> +	/* VRX_HDMI_MAP_ADDR */
> +	/* Pixel Repetition override and 2X */
> +	adv7441a_i2c_hdmimap_write8(state, 0x41, 0x51);
> +	adv7441a_i2c_hdmimap_write8(state, 0x15, 0xec);
> +	adv7441a_i2c_hdmimap_write8(state, 0x1c, 0x4b);
> +	adv7441a_i2c_hdmimap_write8(state, 0x1d, 0x04);
> +	adv7441a_i2c_hdmimap_write8(state, 0x3c, 0x82);
> +	adv7441a_i2c_hdmimap_write8(state, 0x5a, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_HDMI_1280x720px60(struct adv7441a_state *state)
> +{
> +	dprintk(1, "%s()\n", __func__);
> +
> +	/* HDMI PORT A 1280x720p 60Hz 20bit 422 */
> +	/* VC8x0 */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x1c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x05);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x37);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x0a, 0xff);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xe7);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x0f);
> +	adv7441a_i2c_usermap_write8(state, 0x85, 0x19);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	/* HDMI_MODE = 1 FREE RUN */
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa0 | 1);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xc8, 0x08);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0xf4, 0x95);
> +
> +	/* VRX_USER_2_MAP_ADDR */
> +	adv7441a_i2c_user2map_write8(state, 0xf0, 0x10);
> +	adv7441a_i2c_user2map_write8(state, 0xf1, 0x0f);
> +	adv7441a_i2c_user2map_write8(state, 0xf4, 0x20);
> +
> +	/* VRX_HDMI_MAP_ADDR */
> +	adv7441a_i2c_hdmimap_write8(state, 0x15, 0xec);
> +	adv7441a_i2c_hdmimap_write8(state, 0x1c, 0x4b);
> +	adv7441a_i2c_hdmimap_write8(state, 0x1d, 0x04);
> +	adv7441a_i2c_hdmimap_write8(state, 0x3c, 0x82);
> +	adv7441a_i2c_hdmimap_write8(state, 0x5a, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_HDMI_1920x1080ix60(struct adv7441a_state *state)
> +{
> +	dprintk(1, "%s()\n", __func__);
> +
> +	/* HDMI PORT A 1920x1080i 60Hz 20bit 422 */
> +	/* VC8x0 */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x1c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x05);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x0c);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x37);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x0a, 0xff);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xe7);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x0f);
> +	adv7441a_i2c_usermap_write8(state, 0x85, 0x19);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +
> +	/* HDMI_MODE = 1 FREE RUN */
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa0 | 1);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xc8, 0x08);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0xf4, 0x95);
> +
> +	/* VRX_USER_2_MAP_ADDR */
> +	adv7441a_i2c_user2map_write8(state, 0xf0, 0x10);
> +	adv7441a_i2c_user2map_write8(state, 0xf1, 0x0f);
> +	adv7441a_i2c_user2map_write8(state, 0xf4, 0x20);
> +
> +	/* VRX_HDMI_MAP_ADDR */
> +	adv7441a_i2c_hdmimap_write8(state, 0x15, 0xec);
> +	adv7441a_i2c_hdmimap_write8(state, 0x1c, 0x4b);
> +	adv7441a_i2c_hdmimap_write8(state, 0x1d, 0x04);
> +	adv7441a_i2c_hdmimap_write8(state, 0x3c, 0x82);
> +	adv7441a_i2c_hdmimap_write8(state, 0x5a, 0x00);
> +
> +	return 0;
> +}
> +
> +static int adv7441a_HDMI_1920x1080px60(struct adv7441a_state *state,
> +	int tdmsfix)
> +{
> +	dprintk(1, "%s(%d)\n", __func__, tdmsfix);
> +
> +	/* 1920x1080p */
> +	/* VC8x0 */
> +	adv7441a_i2c_usermap_write8(state, 0x03, 0x85);
> +	adv7441a_i2c_usermap_write8(state, 0x04, 0x1c);
> +	adv7441a_i2c_usermap_write8(state, 0x05, 0x05);
> +	adv7441a_i2c_usermap_write8(state, 0x06, 0x0b);
> +	adv7441a_i2c_usermap_write8(state, 0x0c, 0x3c);
> +	adv7441a_i2c_usermap_write8(state, 0x1d, 0x40);
> +	adv7441a_i2c_usermap_write8(state, 0x37, 0xa1);
> +	adv7441a_i2c_usermap_write8(state, 0x3c, 0xa8);
> +	adv7441a_i2c_usermap_write8(state, 0x0a, 0xff);
> +	adv7441a_i2c_usermap_write8(state, 0x47, 0x0a);
> +	adv7441a_i2c_usermap_write8(state, 0x68, 0xf0);
> +	adv7441a_i2c_usermap_write8(state, 0x6b, 0xe7);
> +	adv7441a_i2c_usermap_write8(state, 0x7b, 0x0f);
> +	adv7441a_i2c_usermap_write8(state, 0x85, 0x19);
> +	adv7441a_i2c_usermap_write8(state, 0x86, 0x0b);
> +	/* HDMI_MODE = 1 FREE RUN */
> +	adv7441a_i2c_usermap_write8(state, 0xba, 0xa0 | 1);
> +	adv7441a_i2c_usermap_write8(state, 0xc9, 0x04);
> +	adv7441a_i2c_usermap_write8(state, 0xc8, 0x08);
> +	adv7441a_i2c_usermap_write8(state, 0xf3, 0x07);
> +	adv7441a_i2c_usermap_write8(state, 0xf4, 0x95);
> +
> +	/* VRX_USER_2_MAP_ADDR */
> +	adv7441a_i2c_user2map_write8(state, 0xf0, 0x30);
> +	adv7441a_i2c_user2map_write8(state, 0xf1, 0x0f);
> +	adv7441a_i2c_user2map_write8(state, 0xf4, 0xa0);
> +
> +	/* VRX_HDMI_MAP_ADDR */
> +	/* Pixel Repetition Not set (1x) */
> +	adv7441a_i2c_hdmimap_write8(state, 0x41, 0x40);
> +	adv7441a_i2c_hdmimap_write8(state, 0x15, 0xec);
> +	adv7441a_i2c_hdmimap_write8(state, 0x1c, 0x4b);
> +	adv7441a_i2c_hdmimap_write8(state, 0x1d, 0x04);
> +	adv7441a_i2c_hdmimap_write8(state, 0x3c, 0x82);
> +
> +	if (tdmsfix)
> +		adv7441a_i2c_hdmimap_write8(state, 0x47, 0x00);
> +	else
> +		adv7441a_i2c_hdmimap_write8(state, 0x47, 0x05);
> +
> +	adv7441a_i2c_hdmimap_write8(state, 0x5a, 0x01);
> +
> +	return 0;
> +}
> +/* End - Per resolution / format configuration settings */
> +
> +static int adv7441a_set_format_DVI(struct adv7441a_state *state,
> +	struct adv7441a_format *fmt)
> +{
> +	int ret = 0;
> +
> +	dprintk(1, "%s(%p, %d) [%s]\n", __func__, state, fmt->id, fmt->name);
> +
> +	switch (fmt->id) {
> +	case ADV7441A_FORMAT_720x576p25:
> +		adv7441a_HDMI_720x576px25(state);
> +		break;
> +	case ADV7441A_FORMAT_720x576i50:
> +		adv7441a_HDMI_720x576ix50(state);
> +		break;
> +	case ADV7441A_FORMAT_720x480i59:
> +	case ADV7441A_FORMAT_720x480i60:
> +		adv7441a_HDMI_720x480ix60(state);
> +		break;
> +	case ADV7441A_FORMAT_1280x720p23:
> +	case ADV7441A_FORMAT_1280x720p24:
> +	case ADV7441A_FORMAT_1280x720p25:
> +	case ADV7441A_FORMAT_1280x720p29:
> +	case ADV7441A_FORMAT_1280x720p30:
> +	case ADV7441A_FORMAT_1280x720p50:
> +	case ADV7441A_FORMAT_1280x720p59:
> +	case ADV7441A_FORMAT_1280x720p60:
> +		adv7441a_HDMI_1280x720px60(state);
> +		break;
> +	case ADV7441A_FORMAT_1920x1080i50:
> +	case ADV7441A_FORMAT_1920x1080i59:
> +	case ADV7441A_FORMAT_1920x1080i60:
> +		adv7441a_HDMI_1920x1080ix60(state);
> +		break;
> +	case ADV7441A_FORMAT_1920x1080p23:
> +	case ADV7441A_FORMAT_1920x1080p24:
> +	case ADV7441A_FORMAT_1920x1080p25:
> +	case ADV7441A_FORMAT_1920x1080p29:
> +	case ADV7441A_FORMAT_1920x1080p30:
> +	case ADV7441A_FORMAT_1920x1080p50:
> +		adv7441a_HDMI_1920x1080px60(state, 0);
> +		break;
> +	case ADV7441A_FORMAT_1920x1080p60:
> +		adv7441a_HDMI_1920x1080px60(state, 1);
> +		break;
> +	default:
> +		pr_err("%s() huh?\n", __func__);
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
> +static int adv7441a_set_format_YPRPB(struct adv7441a_state *state,
> +	struct adv7441a_format *fmt)
> +{
> +	int ret = 0;
> +
> +	dprintk(1, "%s(%p, %d) [%s]\n", __func__, state, fmt->id, fmt->name);
> +
> +	switch (fmt->id) {
> +	case ADV7441A_FORMAT_720x480i59:
> +	case ADV7441A_FORMAT_720x480i60:
> +		adv7441a_YPRPB_720x480ix60(state);
> +		break;
> +	case ADV7441A_FORMAT_720x576p25:
> +		adv7441a_YPRPB_720x576px25(state);
> +		break;
> +	case ADV7441A_FORMAT_720x576i50:
> +		adv7441a_YPRPB_720x576ix50(state);
> +		break;
> +	case ADV7441A_FORMAT_1280x720p23:
> +	case ADV7441A_FORMAT_1280x720p24:
> +		adv7441a_YPRPB_1280x720p(state, 24);
> +		break;
> +	case ADV7441A_FORMAT_1280x720p25:
> +		adv7441a_YPRPB_1280x720p(state, 25);
> +		break;
> +	case ADV7441A_FORMAT_1280x720p29:
> +	case ADV7441A_FORMAT_1280x720p30:
> +		adv7441a_YPRPB_1280x720p(state, 30);
> +		break;
> +	case ADV7441A_FORMAT_1280x720p50:
> +		adv7441a_YPRPB_1280x720p(state, 50);
> +		break;
> +	case ADV7441A_FORMAT_1280x720p59:
> +	case ADV7441A_FORMAT_1280x720p60:
> +		adv7441a_YPRPB_1280x720p(state, 60);
> +		break;
> +	case ADV7441A_FORMAT_1920x1080p30:
> +		adv7441a_YPRPB_1920x1080px30(state);
> +		break;
> +	case ADV7441A_FORMAT_1920x1080i50:
> +		adv7441a_YPRPB_1920x1080i(state, 50);
> +		break;
> +	case ADV7441A_FORMAT_1920x1080i59:
> +	case ADV7441A_FORMAT_1920x1080i60:
> +		adv7441a_YPRPB_1920x1080i(state, 60);
> +		break;
> +	default:
> +		pr_err("%s(%p, %d) huh?\n", __func__, state, fmt->id);
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
> +static int adv7441a_set_format_COMPOSITE(struct adv7441a_state *state,
> +	struct adv7441a_format *fmt, int inputnr)
> +{
> +	int ret = 0;
> +
> +	dprintk(1, "%s(%p, %d, %d) [%s]\n", __func__, state,
> +		fmt->id, inputnr, fmt->name);
> +
> +	switch (fmt->id) {
> +	case ADV7441A_FORMAT_720x576p25:
> +	case ADV7441A_FORMAT_720x576i50:
> +		adv7441a_CVBS_720x480ix60(state, inputnr);
> +		state->vbi_enabled = 0;
> +		break;
> +	case ADV7441A_FORMAT_720x480i59:
> +	case ADV7441A_FORMAT_720x480i60:
> +		adv7441a_CVBS_720x480ix60(state, inputnr);
> +		state->vbi_enabled = 1;
> +		break;
> +	default:
> +		pr_err("%s(%p, %d, %d) huh?\n", __func__, state,
> +			fmt->id, inputnr);
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
> +static int adv7441a_set_format_SVIDEO(struct adv7441a_state *state,
> +	struct adv7441a_format *fmt)
> +{
> +	int ret = 0;
> +
> +	dprintk(1, "%s(%p, %d) [%s]\n", __func__, state, fmt->id, fmt->name);
> +
> +	switch (fmt->id) {
> +	case ADV7441A_FORMAT_720x576p25:
> +	case ADV7441A_FORMAT_720x576i50:
> +		adv7441a_SVIDEO_720x480ix60(state);
> +		state->vbi_enabled = 0;
> +		break;
> +	case ADV7441A_FORMAT_720x480i59:
> +	case ADV7441A_FORMAT_720x480i60:
> +		adv7441a_SVIDEO_720x480ix60(state);
> +		state->vbi_enabled = 1;
> +		break;
> +	default:
> +		pr_err("%s(%p, %d) huh?\n", __func__, state, fmt->id);
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +#if 0
> +static int adv7441a_set_format_VGA(struct adv7441a_state *state,
> +	struct adv7441a_format *fmt)
> +{
> +	int ret = 0;
> +
> +	dprintk(1, "%s(%p, %d) [%s]\n", __func__, state, fmt->id, fmt->name);
> +
> +	switch (fmt->id) {
> +	case ADV7441A_FORMAT_640x480p60:
> +		state->vbi_enabled = 0;
> +		adv7441a_VGA_640x480ix60(state, timing);
> +		break;
> +	case ADV7441A_FORMAT_800x600p60:
> +		state->vbi_enabled = 0;
> +		adv7441a_VGA_800x600px60(state, timing);
> +		break;
> +	case ADV7441A_FORMAT_1024x768p60:
> +		state->vbi_enabled = 0;
> +		adv7441a_VGA_1024x768px60(state, timing);
> +		break;
> +	case ADV7441A_FORMAT_1280x720p23:
> +	case ADV7441A_FORMAT_1280x720p60:
> +		state->vbi_enabled = 0;
> +		adv7441a_VGA_1280x720px60(state, timing);
> +		break;
> +	case ADV7441A_FORMAT_1280x960p60:
> +		state->vbi_enabled = 0;
> +		adv7441a_VGA_1280x960px60(state, timing);
> +		break;
> +	case ADV7441A_FORMAT_1280x1024p60:
> +		state->vbi_enabled = 0;
> +		adv7441a_VGA_1280x1024px60(state, timing);
> +		break;
> +	case ADV7441A_FORMAT_1400x1050p60:
> +		state->vbi_enabled = 0;
> +		adv7441a_VGA_1400x1050px60(state, timing);
> +		break;
> +	case ADV7441A_FORMAT_1600x1200p60:
> +	case ADV7441A_FORMAT_UXGA_1600x1200p60:
> +		adv7441a_UXGA_1600x1200x60(state, timing);
> +		state->vbi_enabled = 0;
> +		break;
> +	case ADV7441A_FORMAT_WXGA_1440x900p60:
> +		adv7441a_WXGA_1440x900x60(state, timing);
> +		state->vbi_enabled = 0;
> +		break;
> +	case ADV7441A_FORMAT_WSXGA_1680x1050p60:
> +		adv7441a_WSXGA_1680x1050x60(state, timing);
> +		state->vbi_enabled = 0;
> +		break;
> +	case ADV7441A_FORMAT_VGAHD_1920x1080p60:
> +		adv7441a_VGAHD_1920x1080x60(state, timing);
> +		state->vbi_enabled = 0;
> +		break;

Hmm... on all the above, vbi_enabled is equal to zero. Better to move it
out of the switch(), in order to simplify this function.

> +	default:
> +		pr_err("%s(%p, %d) huh?\n", __func__, state, fmt->id);
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +#endif
> +
> +static int adv7441a_set_format(struct v4l2_subdev *sd, u32 fmtid)
> +{
> +	struct adv7441a_state *state = to_state(sd);
> +	struct adv7441a_format *fmt;
> +	int ret = -ENODEV;
> +
> +	dprintk(1, "%s(%p, %d)\n", __func__, state, fmtid);
> +
> +	fmt = find_format(state, fmtid);
> +	if (!fmt) {
> +		return -EINVAL;
> +	}
> +
> +	dprintk(1, "%s(%p, %d) [%s]\n", __func__, state, fmt->id, fmt->name);
> +
> +	adv7441a_sw_reset(state);
> +
> +	switch (state->video_input_nr) {
> +	case ADV7441A_INPUT_DVI:
> +		ret = adv7441a_set_format_DVI(state, fmt);
> +		break;
> +	case ADV7441A_INPUT_YPRPB:
> +		ret = adv7441a_set_format_YPRPB(state, fmt);
> +		break;
> +	case ADV7441A_INPUT_VGA:
> +#if 0
> +		ret = adv7441a_set_format_VGA(state, fmt);
> +#endif
> +		break;
> +	case ADV7441A_INPUT_COMPOSITE1:
> +		ret = adv7441a_set_format_COMPOSITE(state, fmt, 1);
> +		break;
> +	case ADV7441A_INPUT_COMPOSITE2:
> +		ret = adv7441a_set_format_COMPOSITE(state, fmt, 2);
> +		break;
> +	case ADV7441A_INPUT_COMPOSITE3:
> +		ret = adv7441a_set_format_COMPOSITE(state, fmt, 3);
> +		break;
> +	case ADV7441A_INPUT_SVIDEO:
> +		ret = adv7441a_set_format_SVIDEO(state, fmt);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	if (ret == 0)
> +		state->fmt = fmt;
> +	else
> +		state->fmt = 0;
> +
> +	/* Free run */
> +	adv7441a_i2c_usermap_write8(state, 0xbf, 0x12);
> +
> +	return ret;
> +}
> +
> +/* Hmm: Do I extend the official list of DV presets, which
> + * are exposed to the public, or keep the format id,
> + * used to select a configuration format for the device
> + * internal to the kernel? Use s_dv_preset or s_routing?

If the DV is a standardized one, it should be at:
	include/linux/v4l2-dv-timings.h
(if you find anything missing there, feel free to add)

Are there any missing timing above?

> + * Internal by default.
> + * I'll repurpose the s_routing config field
> + * so that I pass the input and format configuration
> + * atomically.
> + */
> +static int adv7441a_s_routing(struct v4l2_subdev *sd,
> +	u32 input, u32 output, u32 config)
> +{
> +	struct adv7441a_state *state = to_state(sd);
> +
> +	int ret = 0;
> +	dprintk(1, "%s(%p, %d [%s], config = 0x%x)\n", __func__, state,
> +		input,
> +		input == ADV7441A_INPUT_DVI ? "DVI" :
> +		input == ADV7441A_INPUT_YPRPB ? "YPRPB" :
> +		input == ADV7441A_INPUT_VGA ? "VGA" :
> +		input == ADV7441A_INPUT_SVIDEO ? "SVIDEO" :
> +		input == ADV7441A_INPUT_COMPOSITE1 ? "COMPOSITE1" :
> +		input == ADV7441A_INPUT_COMPOSITE2 ? "COMPOSITE2" :
> +		input == ADV7441A_INPUT_COMPOSITE3 ? "COMPOSITE3" :
> +		"UNDEFINED",
> +		config
> +		);
> +
> +	state->video_input_nr = input;
> +	if (config) {
> +		ret = adv7441a_set_format(sd, config);
> +	}
> +
> +	return ret;
> +}
> +
> +static int adv7441a_set_edid(struct v4l2_subdev *sd,
> +	u8 *data, int len)
> +{

There is an EDID API at V4L2. Perhaps you may need to use it, if
userspace is able to control it.

> +	struct adv7441a_state *state = to_state(sd);
> +	int i;
> +
> +	dprintk(1, "%s(len=%d)\n", __func__, len);
> +
> +	if (len != 256) {
> +		pr_err("%s() edid len %d is invalid\n", __func__, len);
> +		return -EINVAL;
> +	}
> +
> +	v4l2_subdev_notify(sd, ADV7441A_HOTPLUG, (void *)0);
> +
> +	for (i = 0; i < 256; i++)
> +		adv7441a_i2c_edidmap_write8(state, i, *(data + i));
> +
> +	adv7441a_i2c_rksvmap_write8(state, 0x70, 0x02);
> +	adv7441a_i2c_rksvmap_write8(state, 0x71, 0x03);
> +	adv7441a_i2c_rksvmap_write8(state, 0x72, 0x80);
> +	adv7441a_i2c_rksvmap_write8(state, 0x73, 0x06);
> +
> +	msleep(20);
> +#if 0
> +	/* Enable our background poll worker after 250ms */
> +	queue_delayed_work(state->work_queues,
> +		&state->delayed_work_enable_hotplug, HZ / 4);
> +#endif
> +	return 0;
> +}
> +
> +void adv7441a_audio_reset_pll(struct adv7441a_state *state)
> +{
> +	/* Reset audio PLL */
> +	adv7441a_i2c_hdmimap_setbit(state, 0x5a, 0x03);
> +}
> +
> +void adv7441a_audio_configure_pll(struct adv7441a_state *state)
> +{
> +	u8 v, t[3];
> +	u32 n, cts, tdms;
> +	u32 tmp, tmp2, tmp3;
> +	u32 xtal = 28636360;
> +
> +	/* GET N */
> +	adv7441a_i2c_hdmimap_read8(state, 0x5b, &v);
> +	adv7441a_i2c_hdmimap_read8(state, 0x5d, &t[0]);
> +	adv7441a_i2c_hdmimap_read8(state, 0x5e, &t[1]);
> +	adv7441a_i2c_hdmimap_read8(state, 0x5f, &t[2]);
> +	n = ((t[0] & 0x0f) << 16) | (t[1] << 8) | t[2];
> +
> +	/* GET CTS */
> +	adv7441a_i2c_hdmimap_read8(state, 0x5b, &t[0]);
> +	adv7441a_i2c_hdmimap_read8(state, 0x5c, &t[1]);
> +	adv7441a_i2c_hdmimap_read8(state, 0x5d, &t[2]);
> +	cts = (t[0] << 12) | (t[1] << 4) | ((t[2] & 0xf0) >> 4);
> +
> +	/* GET TDMS Frequency */
> +	adv7441a_i2c_hdmimap_read8(state, 0x06, &v);
> +	tmp = xtal / 10;
> +	tmp2 = 27000000 / 10;
> +	tmp3 = tmp * v;
> +	tdms = tmp3 / tmp2;
> +
> +	/* Update the Audio PLL */
> +	if (cts) {
> +		tmp = tdms * (n / cts);
> +		tmp = (tmp * 1000) >> 7;
> +		if (tmp >= 150) {
> +			dprintk(1, "%s() Setting A\n", __func__);
> +			adv7441a_i2c_hdmimap_write8(state, 0x3d, 0x80);
> +		} else {
> +			dprintk(1, "%s() Setting B\n", __func__);
> +			adv7441a_i2c_hdmimap_write8(state, 0x3d, 0x40);
> +		}
> +	} else {
> +		dprintk(1, "%s() ELSE CTS\n", __func__);
> +		adv7441a_i2c_hdmimap_write8(state, 0x3d, 0x40);
> +	}
> +
> +	dprintk(1, "%s() Audio Frequency: %d\n", __func__, tmp);
> +}
> +
> +int adv7441a_keep_alive(struct adv7441a_state *state)
> +{
> +	u8 val, clr = 0;
> +
> +	adv7441a_i2c_hdmimap_read8(state, 0x1a, &val);
> +
> +	if (val & 0x10) {
> +		/* NEW_CTS */
> +		adv7441a_audio_reset_pll(state);
> +		clr |= 0x10;
> +	}
> +
> +	if (val & 0x08) {
> +		/* NEW_N */
> +		adv7441a_audio_configure_pll(state);
> +		clr |= 0x08;
> +	}
> +
> +	if (clr)
> +		adv7441a_i2c_user1map_write8(state, 0x6f, clr);
> +
> +	adv7441a_i2c_user1map_read8(state, 0x64, &val);
> +	if (val & 0x02) {
> +		dprintk(1, "%s() 64\n", __func__);
> +	}
> +
> +	return 0;
> +}
> +
> +static int adv7441a_is_hdmi_locked(struct adv7441a_state *state)
> +{
> +	u8 reg4, reg7;
> +
> +	/* Read the Audio/Video PLL's */
> +	adv7441a_i2c_hdmimap_read8(state, 0x04, &reg4);
> +	dprintk(2, "%s(%p) 0x04 = %02x\n", __func__,
> +		state, reg4); /* Add this */
> +
> +	/* Is Video PLL is locked, is TMDS_PORT_A is active */
> +	if ((reg4 & 0x0a) != 0x0a)
> +		return 0;
> +
> +	/* Is the vertical filter locked? */
> +	adv7441a_i2c_hdmimap_read8(state, 0x07, &reg7);
> +	dprintk(2, "%s(%p) 0x07 = %02x\n", __func__,
> +		state, reg7); /* Add this */
> +	if ((reg7 & 0x40) == 0x00)
> +		return 0;
> +
> +	/* Is the horizontal filter locked? */
> +	if ((reg7 & 0x10) == 0x00)
> +		return 0;
> +
> +	/* Locked */
> +	return 1;
> +}
> +
> +static int adv7441a_is_YPRPB_locked(struct adv7441a_state *state)
> +{
> +	u8 reg12;
> +
> +	/* Is the TLLC_PLL_LOCK bit set */
> +	adv7441a_i2c_usermap_read8(state, 0x12, &reg12);
> +	if ((reg12 & 0x80) != 0x80)
> +		return 0;
> +
> +	/* Is the CP free-running? If set then no signal */
> +	if ((reg12 & 0x40) == 0x40)
> +		return 0;
> +
> +	/* Locked */
> +	return 1;
> +}
> +
> +static int adv7441a_is_composite_locked(struct adv7441a_state *state)
> +{
> +	u8 reg10;
> +
> +	/* Is the IN_LOCK bit set */
> +	adv7441a_i2c_usermap_read8(state, 0x10, &reg10);
> +	if ((reg10 & 0x01) == 0x00)
> +		return 0;
> +
> +	/* Locked */
> +	return 1;
> +}
> +
> +/* Driver Lock detect and format recognition works in the following way.
> + * If we're using a component input then if the CP processor detects
> + * we're not locked or in free-running mode, request colorbar generation.
> + *
> + * If we're using a component input then if the CP processor detects
> + * we're correctly locked, attempt to detect the format based on the STDI
> + * setting. If the STDI setting match the user requested format or rate,
> + * disable colorbars. If the STDU setting do not match the user
> + * requested format or rate, request colorbars.
> + *
> + * If we're using a hdmi input then if the CP processor detects
> + * we're correctly locked, attempt to detect the format based on the STDI
> + * setting. If the STDI setting match the user requested format
> + * or rate, disable colorbars. If the STDU setting do not match the
> + * user requested format or rate, request colorbars.
> + */
> +/* Return 0 on not locked, 1 on locked */
> +int adv7441a_is_locked(struct adv7441a_state *state)
> +{
> +	int ret;
> +
> +	if (!time_after(jiffies,
> +		(long)state->last_locked + msecs_to_jiffies(500))) {
> +		/* Skip the detect, because it hasn't been 500ms since the
> +		 * last attempt */
> +		return 1;
> +	}
> +	state->last_locked = jiffies;
> +
> +	switch (state->video_input_nr) {
> +	case ADV7441A_INPUT_DVI:
> +		ret = adv7441a_is_hdmi_locked(state);
> +		break;
> +	case ADV7441A_INPUT_YPRPB:
> +	case ADV7441A_INPUT_VGA:
> +		ret = adv7441a_is_YPRPB_locked(state);
> +		break;
> +	case ADV7441A_INPUT_COMPOSITE1:
> +	case ADV7441A_INPUT_COMPOSITE2:
> +	case ADV7441A_INPUT_COMPOSITE3:
> +	case ADV7441A_INPUT_SVIDEO:
> +		ret = adv7441a_is_composite_locked(state);
> +		break;
> +	default:
> +		ret = 0;
> +	}
> +
> +	if (ret == 0) {
> +#if 0
> +		/* We didn't detect the video lock correctly,
> +		 * throw the colorbars up. */
> +		vc8x0_channel_loss_of_sync(state->dma_channel, 1);
> +#endif
> +	} else {
> +		adv7441a_detect(state);
> +	}
> +
> +	return ret;
> +}
> +
> +/* return 0 on format not detected or 1 on detected */
> +static int adv7441a_hdmi_detect(struct adv7441a_state *state)
> +{
> +	struct detection_t *d = &state->detection;
> +	struct adv7441a_format *f;
> +	struct vga_size_t *size;
> +	struct vga_rate_t *rate;
> +	u8 stat_10[4], stdi_b1[5], fcl[2];
> +	int i, colorbars_reqd = 1;
> +
> +	for (i = 0; i < 5; i++)
> +		adv7441a_i2c_usermap_read8(state, 0xb1 + i, &stdi_b1[i]);
> +
> +	/* See the ADV7441 HW manual section 9.10 rev J page 177 */
> +	dprintk(2, "%s(%p) STDI b1-b5: %02x %02x %02x %02x %02x\n",
> +		__func__, state,
> +		stdi_b1[0], stdi_b1[1], stdi_b1[2], stdi_b1[3], stdi_b1[4]);
> +
> +	/* if STDI_DVALID */
> +	if (stdi_b1[0] & 0x80) {
> +
> +		/* Format is detected */
> +		d->valid = 1;
> +
> +		/* if STDI_INTLCD */
> +		if (stdi_b1[0] & 0x40)
> +			d->interlaced = 1;
> +		else
> +			d->interlaced = 0;
> +
> +		/* Block length */
> +		d->bl  = ((stdi_b1[0] & 0x3f) << 8) | stdi_b1[1];
> +
> +		/* Line count in field */
> +		d->lcf = ((stdi_b1[2] & 0x07) << 8) | stdi_b1[3];
> +
> +		/* Line count in vsync */
> +		d->lcvs = stdi_b1[2] >> 3;
> +
> +		/* Read the fractional field length */
> +		adv7441a_i2c_usermap_read8(state, 0xca, &fcl[0]);
> +		adv7441a_i2c_usermap_read8(state, 0xcb, &fcl[1]);
> +		d->fcl28 = ((fcl[0] & 0x1f) << 8) | fcl[1];
> +
> +		/* if SSPD_DVALID */
> +		if (stdi_b1[4] & 0x80) {
> +			d->sync_mask = stdi_b1[4] & 0x03;
> +			d->sync_polarity = ((stdi_b1[4] & 0x08) >> 2) |
> +				((stdi_b1[4] & 0x20) >> 5);
> +		}
> +
> +		d->field_rate = 0;
> +		if (d->interlaced)
> +			d->field_rate /= 2;
> +	}
> +
> +	for (i = 0; i < 4; i++)
> +		adv7441a_i2c_usermap_read8(state, 0x10 + i, &stat_10[i]);
> +
> +	/* If CP_FREE_RUN is active then not locked to incoming video... */
> +	if (stat_10[2] & 40)
> +		d->locked = 0;
> +	else
> +		d->locked = 1;
> +
> +	/* Lookup the params in the vga table and detect whether we're locked.
> +	 * If we are, try to find the matching video format and determine
> +	 * whether we're locked to the correct format, or some other format.
> +	 * If we're locked to the incorrect format then we'll warn the user.
> +	 */
> +	if (d->valid) {
> +		dprintk(2, "%s() lcf = %d, fcl28 = %d, bl = %d\n",
> +			__func__, d->lcf, d->fcl28, d->bl);
> +		size = vc8x0_vga_HdGetSize(d->lcf);
> +		rate = vc8x0_vga_HdGetRate(d->fcl28);
> +		if (size && rate) {
> +			dprintk(2,
> +			"%s() size = %d/%d interlaced = %d rate = %d\n",
> +				__func__,
> +				size->width, size->height[0],
> +				size->interlaced,
> +				rate->rate);
> +
> +			do {
> +				if (size->interlaced) {
> +					/* Interlaced */
> +					f = vc8x0_video_find_format(
> +						state,
> +						V4L2_PIX_FMT_YUYV,
> +						size->width,
> +						size->height[0] * 2,
> +						ADV7441A_FORMAT_INTERLACED,
> +						rate->rate);
> +
> +	/* i59 to i60 is really close, rather than touch the rate table
> +	 * and risk * breaking everything so late in the project, for
> +	 * this single format I'm going to manually override the
> +	 * detected format to match the callers needs.
> +	 */
> +					if (state->video_input_nr == ADV7441A_INPUT_YPRPB) {
> +						if (f && (f->id == ADV7441A_FORMAT_1920x1080i60)) {
> +							if (state->fmt->id == ADV7441A_FORMAT_1920x1080i59) {
> +								f = state->fmt;
> +							}
> +						}
> +					}

We had lots of discussions with regards to 60.0Hz and 59.97 Hz stuff, during the
DV API proposals. It ended by being supported by two flags[1]:

	V4L2_DV_FL_CAN_REDUCE_FPS and V4L2_DV_FL_REDUCED_FPS.

[1] http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-g-dv-timings.html

> +				} else {
> +					if ((size->width == 720) &&
> +						(size->height[0] == 483) &&
> +						(state->video_input_nr == ADV7441A_INPUT_VGA)) {
> +						f = vc8x0_video_find_format(
> +							state,
> +							V4L2_PIX_FMT_YUYV,
> +							640,
> +							480,
> +							ADV7441A_FORMAT_PROGRESSIVE,
> +							60);
> +					} else
> +					if ((size->width == 720) && (size->height[0] == 576)) {
> +						f = vc8x0_video_find_format(
> +							state,
> +							V4L2_PIX_FMT_YUYV,
> +							720,
> +							576,
> +							ADV7441A_FORMAT_PROGRESSIVE,
> +							25);
> +					} else {
> +						/* Progressive */
> +						f = vc8x0_video_find_format(
> +							state,
> +							V4L2_PIX_FMT_YUYV,
> +							size->width,
> +							size->height[0],
> +							ADV7441A_FORMAT_PROGRESSIVE,
> +							rate->rate);
> +					}
> +				}
> +				state->detected_fmt = f;
> +				if (f && state->fmt) {
> +					if (f != state->fmt) {
> +						dprintk(2, "%s() Detected incorrect format->id = %d [%s], need %d\n",
> +							__func__,
> +							f->id, f->name,
> +							state->fmt->id);
> +					} else {
> +						dprintk(2, "%s() Detected format->id = %d [%s] correctly.\n",
> +						__func__, f->id, f->name);
> +						colorbars_reqd = 0;
> +					}
> +				}
> +
> +			} while (0);
> +		} else {
> +			dprintk(2, "%s() size = unknown\n", __func__);
> +		}
> +	}
> +#if 0
> +	if (colorbars_reqd == 1) {
> +		/* We didn't detect the video format correctly,
> +		 * throw the colorbars up. */
> +		vc8x0_channel_loss_of_sync(state->dma_channel, 1);
> +	} else {
> +		/* format is good. Remove colorbars if they were present. */
> +		vc8x0_channel_loss_of_sync(state->dma_channel, 0);
> +	}
> +#endif
> +	return 0;
> +}
> +
> +/* return 0 on format not detected or 1 on detected */
> +static int adv7441a_composite_detect(struct adv7441a_state *state)
> +{
> +	int colorbars_reqd = 1;
> +	u8 ret, reg10;
> +
> +	if (!state->fmt)
> +		return 0;
> +
> +	/* Read the standard auto-detect bits */
> +	adv7441a_i2c_usermap_read8(state, 0x10, &reg10);
> +	switch ((reg10 & 0x70) >> 4) {
> +	case 0x00: /* NTSC-MJ */
> +	case 0x01: /* NTSC-443 */
> +	case 0x02: /* PAL-M */
> +	case 0x03: /* PAL-60 */
> +		if (state->fmt->height == 480)
> +			colorbars_reqd = 0;
> +		break;
> +	case 0x04: /* PAL-BGHID */
> +	case 0x06: /* PAL-N */
> +		if (state->fmt->height == 576)
> +			colorbars_reqd = 0;
> +		break;
> +	case 0x05: /* SECAM */
> +	case 0x07: /* SECAM 525 */
> +	default:
> +		break;
> +	}
> +#if 0
> +	if (colorbars_reqd == 1) {
> +		/* We didn't detect the video format correctly
> +		 * throw the colorbars up. */
> +		vc8x0_channel_loss_of_sync(state->dma_channel, 1);
> +		ret = 0;
> +	} else {
> +		/* format is good. Remove colorbars if they were present. */
> +		vc8x0_channel_loss_of_sync(state->dma_channel, 0);
> +		ret = 1;
> +	}
> +#endif
> +	return ret;
> +}
> +
> +/* return 0 on format not detected or 1 on detected */
> +static int adv7441a_vga_detect(struct adv7441a_state *state)
> +{
> +	if (!state->fmt)
> +		return 0;
> +
> +	return 1;
> +}
> +
> +/* Detect the video format and rate based on each different input type */
> +/* return 0 on format not detected or 1 on detected */
> +static int adv7441a_detect(struct adv7441a_state *state)
> +{
> +	int ret;
> +	dprintk(1, "%s()\n", __func__);
> +
> +	if (!time_after(jiffies, (long)state->last_detected +
> +		msecs_to_jiffies(500))) {
> +		/* Skip the detect, because it hasn't been 500ms since
> +		 * the last attempt */
> +		return 1;
> +	}
> +	state->last_detected = jiffies;
> +
> +	switch (state->video_input_nr) {
> +	case ADV7441A_INPUT_YPRPB:
> +	case ADV7441A_INPUT_DVI:
> +		ret = adv7441a_hdmi_detect(state);
> +		break;
> +	case ADV7441A_INPUT_VGA:
> +		ret = adv7441a_vga_detect(state);
> +		ret = adv7441a_hdmi_detect(state);
> +		break;
> +	case ADV7441A_INPUT_COMPOSITE1:
> +	case ADV7441A_INPUT_COMPOSITE2:
> +	case ADV7441A_INPUT_COMPOSITE3:
> +	case ADV7441A_INPUT_SVIDEO:
> +		ret = adv7441a_composite_detect(state);
> +		break;
> +	default:
> +		ret = 0;
> +	}
> +
> +	return ret;
> +}
> +
> +static void adv7441a_log_status_detection(struct v4l2_subdev *sd)
> +{
> +	struct adv7441a_state *state = to_state(sd);
> +	struct detection_t *d = &state->detection;
> +
> +	v4l2_info(sd, "Detected settings:\n");
> +	v4l2_info(sd, " ->locked = %d\n", d->locked);
> +	v4l2_info(sd, " ->interlaced = %d\n", d->interlaced);
> +	v4l2_info(sd, " ->sync_mask = %d\n", d->sync_mask);
> +	v4l2_info(sd, " ->sync_polarity = 0x%02x\n", d->sync_polarity);
> +	v4l2_info(sd, " ->lcf = %d\n", d->lcf);
> +	v4l2_info(sd, " ->lcvs = %d\n", d->lcvs);
> +	v4l2_info(sd, " ->fcl28 = %d\n", d->fcl28);
> +	v4l2_info(sd, " ->bl = %d\n", d->bl);
> +}
> +
> +static void adv7441a_log_status_debug(struct v4l2_subdev *sd)
> +{
> +	struct adv7441a_state *state = to_state(sd);
> +	int i, c = 0, rate = 0;
> +	unsigned char buf[0x100];
> +	v4l2_info(sd, "AD7441:\n");
> +
> +	for (i = 0; i < sizeof(buf); i++)
> +		adv7441a_i2c_hdmimap_read8(state, i, &buf[i]);
> +
> +	v4l2_info(sd, "HDMI 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
> +	for (i = 0; i < sizeof(buf); i++) {
> +		if (c == 0)
> +			v4l2_info(sd, " %02x:", i);
> +
> +		v4l2_info(sd, " %02x", buf[i]);
> +
> +		if (++c == 16) {
> +			v4l2_info(sd, "\n");
> +			c = 0;
> +		}
> +	}
> +
> +	v4l2_info(sd, "->Audio PLL Locked = %d\n", (buf[0x04] >> 0) & 0x01);
> +	v4l2_info(sd, "->Video PLL Locked = %d\n", (buf[0x04] >> 1) & 0x01);
> +	v4l2_info(sd, "->TMDS Port B Active = %d\n", (buf[0x04] >> 2) & 0x01);
> +	v4l2_info(sd, "->TMDS Port A Active = %d\n", (buf[0x04] >> 3) & 0x01);
> +	v4l2_info(sd, "->AV Muted = %d\n", (buf[0x04] >> 6) & 0x01);
> +	v4l2_info(sd, "->Video Width Detected = %d\n",
> +		((buf[0x07] << 8) | buf[0x08]) & 0xfff);
> +	v4l2_info(sd, "->Video Height Detected = %d\n",
> +		((buf[0x09] << 8) | buf[0x0a]) & 0xfff);
> +
> +	for (i = 0; i < sizeof(buf); i++)
> +		adv7441a_i2c_usermap_read8(state, i, &buf[i]);
> +
> +	v4l2_info(sd, "USR  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
> +	c = 0;
> +	for (i = 0; i < sizeof(buf); i++) {
> +		if (c == 0)
> +			v4l2_info(sd, " %02x:", i);
> +
> +		v4l2_info(sd, " %02x", buf[i]);
> +
> +		if (++c == 16) {
> +			v4l2_info(sd, "\n");
> +			c = 0;
> +		}
> +	}
> +#if 0
> +	for (i = 0; i < sizeof(buf); i++)
> +		adv7441a_i2c_edidmap_read8(state, i, &buf[i]);
> +
> +	v4l2_info(sd, "EDID 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
> +	c = 0;
> +	for (i = 0; i < sizeof(buf); i++) {
> +		if (c == 0)
> +			v4l2_info(sd, " %02x:", i);
> +
> +		seq_printf(m, " %02x", buf[i]);
> +
> +		if (++c == 16) {
> +			v4l2_info(sd, "\n");
> +			c = 0;
> +		}
> +	}

Instead, use the existing function for doing memory dumps:
	print_hex_dump()

> +	if (memcmp(edid_data, buf, sizeof(edid_data)) != 0)
> +		v4l2_info(sd, "Edid corrupt?\n");
> +#endif
> +	memset(buf, 0, sizeof(buf));
> +	for (i = 0x60; i < 0x70; i++)
> +		adv7441a_i2c_user1map_read8(state, i, &buf[i]);
> +
> +	v4l2_info(sd, "USR1 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
> +	c = 0;
> +	for (i = 0; i < sizeof(buf); i++) {
> +		if (c == 0)
> +			v4l2_info(sd, " %02x:", i);
> +
> +		v4l2_info(sd, " %02x", buf[i]);
> +
> +		if (++c == 16) {
> +			v4l2_info(sd, "\n");
> +			c = 0;
> +		}
> +	}

Again, print_hex_dump()

> +
> +	switch (buf[6] & 0x0f) {
> +	case 0x0a:
> +		v4l2_info(sd, "->Resolution Requested = 1280x720p\n");
> +		break;
> +	case 0x0c:
> +	case 0x0e:
> +		v4l2_info(sd, "->Resolution Requested = 1920x1080i\n");
> +		break;
> +	}
> +
> +	switch ((buf[6] & 0xe0) >> 5) {
> +	case 0x00:
> +		rate = 60;
> +		break;
> +	case 0x01:
> +		rate = 50;
> +		break;
> +	case 0x02:
> +		rate = 30;
> +		break;
> +	case 0x03:
> +		rate = 25;
> +		break;
> +	case 0x04:
> +		rate = 24;
> +		break;
> +	}
> +	v4l2_info(sd, "->Rate Requested = %dHz\n", rate);
> +	v4l2_info(sd, "->Format Requested = %d [%s]\n",
> +		state->fmt ? state->fmt->id : -1,
> +		state->fmt ? state->fmt->name : "undefined");
> +}
> +
> +static int adv7441a_log_status(struct v4l2_subdev *sd)
> +{
> +	adv7441a_log_status_detection(sd);
> +	adv7441a_log_status_debug(sd);
> +
> +	return 0;
> +}

Hmm... I think you need to do some #if testing here, to avoid producing warnings or
errors if advanced debug is disabled.

> +
> +static int adv7441a_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +	struct v4l2_subdev *sd = to_sd(ctrl);
> +	struct adv7441a_state *state = to_state(sd);
> +
> +	dprintk(1, "%s(0x%x = 0x%x)\n", __func__, ctrl->id, ctrl->val);
> +
> +	switch (ctrl->id) {
> +	case V4L2_CID_BRIGHTNESS:
> +		/* Enable the Video Adjustment and CSC block */
> +		state->brightness = ctrl->val;
> +		adv7441a_i2c_user1map_setbit(state, 0x9e, 0x80);
> +		adv7441a_i2c_usermap_setbit(state, 0x69, 0x18);
> +		adv7441a_i2c_user1map_write8(state, 0x9c,
> +			state->brightness - 128);
> +		break;
> +	case V4L2_CID_HUE:
> +		/* Enable the Video Adjustment and CSC block */
> +		state->hue = ctrl->val;
> +		adv7441a_i2c_user1map_setbit(state, 0x9e, 0x80);
> +		adv7441a_i2c_usermap_setbit(state, 0x69, 0x18);
> +		adv7441a_i2c_user1map_write8(state, 0x9d, state->hue);
> +		break;
> +	case V4L2_CID_CONTRAST:
> +		/* Enable the Video Adjustment and CSC block */
> +		state->contrast = ctrl->val;
> +		adv7441a_i2c_user1map_setbit(state, 0x9e, 0x80);
> +		adv7441a_i2c_usermap_setbit(state, 0x69, 0x18);
> +		adv7441a_i2c_user1map_write8(state, 0x9a, state->contrast);
> +		break;
> +	case V4L2_CID_SATURATION:
> +		/* Enable the Video Adjustment and CSC block */
> +		state->saturation = ctrl->val;
> +		adv7441a_i2c_user1map_setbit(state, 0x9e, 0x80);
> +		adv7441a_i2c_usermap_setbit(state, 0x69, 0x18);
> +		adv7441a_i2c_user1map_write8(state, 0x9b, state->saturation);
> +		break;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int adv7441a_g_chip_ident(struct v4l2_subdev *sd,
> +	struct v4l2_dbg_chip_ident *chip)
> +{
> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
> +
> +	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7441A, 0);
> +}
> +
> +static const struct v4l2_ctrl_ops adv7441a_ctrl_ops = {
> +	.s_ctrl = adv7441a_s_ctrl,
> +};
> +
> +static const struct v4l2_subdev_core_ops adv7441a_core_ops = {
> +	.log_status	= adv7441a_log_status,
> +	.g_chip_ident	= adv7441a_g_chip_ident,
> +	.g_ext_ctrls	= v4l2_subdev_g_ext_ctrls,
> +	.try_ext_ctrls	= v4l2_subdev_try_ext_ctrls,
> +	.s_ext_ctrls	= v4l2_subdev_s_ext_ctrls,
> +	.g_ctrl		= v4l2_subdev_g_ctrl,
> +	.s_ctrl		= v4l2_subdev_s_ctrl,
> +	.queryctrl	= v4l2_subdev_queryctrl,
> +	.querymenu	= v4l2_subdev_querymenu,
> +};
> +
> +static const struct v4l2_subdev_video_ops adv7441a_video_ops = {
> +	.s_routing	= adv7441a_s_routing,
> +};
> +
> +static const struct v4l2_subdev_ops adv7441a_ops = {
> +	.core	= &adv7441a_core_ops,
> +	.video	= &adv7441a_video_ops,
> +};
> +
> +#if 0
> +static void adv7441a_delayed_work_enable_hotplug(struct work_struct *work)
> +{
> +	struct delayed_work *dwork = to_delayed_work(work);
> +	struct adv7441a_state *state = container_of(dwork,
> +		struct adv7441a_state,
> +		delayed_work_enable_hotplug);
> +
> +	struct v4l2_subdev *sd = &state->sd;
> +
> +	dprintk(0, "%s() enable hotplug\n", __func__);
> +
> +	v4l2_subdev_notify(sd, ADV7441A_HOTPLUG, (void *)1);
> +}
> +#endif
> +
> +static int adv7441a_probe(struct i2c_client *client,
> +	const struct i2c_device_id *id)
> +{
> +	struct adv7441a_state *state;
> +	int ret;
> +
> +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
> +		return -ENODEV;
> +
> +	dprintk(1, "chip found @ 0x%x (%s)\n",
> +		client->addr << 1, client->adapter->name);
> +
> +	state = kzalloc(sizeof(struct adv7441a_state), GFP_KERNEL);
> +	if (state == NULL)
> +		return -ENOMEM;
> +
> +	state->usermap_addr = client->addr << 1;
> +
> +	if (state->usermap_addr == 0x42) {
> +		state->user1map_addr	= 0x46;
> +		state->user2map_addr	= 0x62;
> +		state->user3map_addr	= 0x4a;
> +		state->reservedmap_addr	= 0x4e;
> +		state->hdmimap_addr	= 0x6a;
> +		state->rksvmap_addr	= 0x66;
> +		state->edidmap_addr	= 0x6e;
> +	} else
> +	if (state->usermap_addr == 0x40) {
> +		state->user1map_addr	= 0x44;
> +		state->user2map_addr	= 0x60;
> +		state->user3map_addr	= 0x48;
> +		state->reservedmap_addr	= 0x4c;
> +		state->hdmimap_addr	= 0x68;
> +		state->rksvmap_addr	= 0x64;
> +		state->edidmap_addr	= 0x6c;
> +	}
> +
> +	state->brightness = 128;
> +	state->contrast = 0x80;
> +	state->hue = 0;
> +	state->saturation = 0x80;
> +
> +	state->usermap_client =
> +		i2c_new_dummy(client->adapter, state->usermap_addr);
> +	state->user1map_client =
> +		i2c_new_dummy(client->adapter, state->user1map_addr);
> +	state->user2map_client =
> +		i2c_new_dummy(client->adapter, state->user2map_addr);
> +	state->user3map_client =
> +		i2c_new_dummy(client->adapter, state->user3map_addr);
> +	state->reservedmap_client =
> +		i2c_new_dummy(client->adapter, state->reservedmap_addr);
> +	state->hdmimap_client =
> +		i2c_new_dummy(client->adapter, state->hdmimap_addr);
> +	state->rksvmap_client =
> +		i2c_new_dummy(client->adapter, state->rksvmap_addr);
> +	state->edidmap_client =
> +		i2c_new_dummy(client->adapter, state->edidmap_addr);

The above thing looks very confusing to me. Does this device have all those
addresses? What's the difference between them?

> +
> +	v4l2_i2c_subdev_init(&state->sd, client, &adv7441a_ops);
> +
> +	v4l2_ctrl_handler_init(&state->hdl, 4);
> +
> +	v4l2_ctrl_new_std(&state->hdl, &adv7441a_ctrl_ops,
> +			V4L2_CID_BRIGHTNESS, -127, 128, 1, 128);
> +
> +	v4l2_ctrl_new_std(&state->hdl, &adv7441a_ctrl_ops,
> +			V4L2_CID_HUE, 0, 255, 1, 0);
> +
> +	v4l2_ctrl_new_std(&state->hdl, &adv7441a_ctrl_ops,
> +			V4L2_CID_CONTRAST, 0, 255, 1, 128);
> +
> +	v4l2_ctrl_new_std(&state->hdl, &adv7441a_ctrl_ops,
> +			V4L2_CID_SATURATION, 0, 255, 1, 128);
> +
> +	state->sd.ctrl_handler = &state->hdl;
> +	if (state->hdl.error) {
> +		int err = state->hdl.error;
> +
> +		v4l2_ctrl_handler_free(&state->hdl);
> +		adv7441a_unregister_clients(state);
> +		kfree(state);
> +		return err;
> +	}
> +	v4l2_ctrl_handler_setup(&state->hdl);
> +
> +	adv7441a_set_edid(&state->sd, &edid_data[0], sizeof(edid_data));
> +	adv7441a_s_routing(&state->sd, ADV7441A_INPUT_DVI, 0, 0);
> +	state->vga_timing_mode = vc8x0_vga_lookup(2, 640, 480, 1);
> +
> +	/* Establish a default */
> +	adv7441a_HDMI_1920x1080px60(state, 0);
> +
> +	ret = 0;
> +	if (ret) {
> +		v4l2_ctrl_handler_free(&state->hdl);
> +		adv7441a_unregister_clients(state);
> +		kfree(state);
> +	}
> +#if 0
> +	/* Hotplug and background work queueing */
> +	state->work_queues = create_singlethread_workqueue(client->name);
> +	if (state->work_queues) {
> +		INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug,
> +			adv7441a_delayed_work_enable_hotplug);
> +	} else {
> +		pr_err("Could not create work queue\n");
> +		ret = -ENOMEM;
> +	}
> +#endif
> +	dprintk(1, "ADV7441A Loaded and attached\n");
> +	return ret;
> +}
> +
> +static int adv7441a_remove(struct i2c_client *client)
> +{
> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
> +	struct adv7441a_state *state = to_state(sd);
> +#if 0
> +	cancel_delayed_work(&state->delayed_work_enable_hotplug);
> +	destroy_workqueue(state->work_queues);
> +#endif
> +	v4l2_device_unregister_subdev(sd);
> +	adv7441a_unregister_clients(to_state(sd));
> +	v4l2_ctrl_handler_free(&state->hdl);
> +	kfree(state);
> +
> +	dprintk(1, "ADV7441A Unloaded\n");
> +	return 0;
> +}
> +
> +static const struct i2c_device_id adv7441a_id[] = {
> +	{"adv7441a", 0},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(i2c, adv7441a_id);
> +
> +static struct i2c_driver adv7441a_driver = {
> +	.driver = {
> +		.owner	= THIS_MODULE,
> +		.name	= "adv7441a",
> +	},
> +	.probe		= adv7441a_probe,
> +	.remove		= adv7441a_remove,
> +	.id_table	= adv7441a_id,
> +};
> +module_i2c_driver(adv7441a_driver);
> diff --git a/include/media/adv7441a.h b/include/media/adv7441a.h
> new file mode 100644
> index 0000000..b1538fe
> --- /dev/null
> +++ b/include/media/adv7441a.h
> @@ -0,0 +1,88 @@
> +/*
> + *  Driver for the Analog Devices ADV7441A Video Decoder.
> + *
> + *  Copyright 2011/2012, Kernel Labs Inc. www.kernellabs.com.
> + *   - Steven Toth <stoth@kernellabs.com>
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, write to the Free Software
> + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + */
> +#ifndef ADV7441A_H
> +#define ADV7441A_H
> +
> +#define ADV7441A_INPUT_DVI		(0)
> +#define ADV7441A_INPUT_YPRPB		(1)
> +#define ADV7441A_INPUT_VGA		(2)
> +#define ADV7441A_INPUT_SVIDEO		(3)
> +#define ADV7441A_INPUT_COMPOSITE1	(4)
> +#define ADV7441A_INPUT_COMPOSITE2	(5)
> +#define ADV7441A_INPUT_COMPOSITE3	(6)
> +
> +#define ADV7441A_FORMAT_UNKNOWN          0x00
> +#define ADV7441A_FORMAT_INTERLACED       0x01
> +#define ADV7441A_FORMAT_PROGRESSIVE      0x02
> +#define ADV7441A_FORMAT_720x480i59       0x02
> +#define ADV7441A_FORMAT_720x480i60       0x03
> +#define ADV7441A_FORMAT_720x576i50       0x04
> +#define ADV7441A_FORMAT_720x576p25       0x05
> +#define ADV7441A_FORMAT_1280x720p23      0x06
> +#define ADV7441A_FORMAT_1280x720p24      0x07
> +#define ADV7441A_FORMAT_1280x720p25      0x08
> +#define ADV7441A_FORMAT_1280x720p29      0x09
> +#define ADV7441A_FORMAT_1280x720p30      0x0A
> +#define ADV7441A_FORMAT_1280x720p50      0x0B
> +#define ADV7441A_FORMAT_1280x720p59      0x0C
> +#define ADV7441A_FORMAT_1280x720p60      0x0D
> +#define ADV7441A_FORMAT_1920x1080i50     0x0E
> +#define ADV7441A_FORMAT_1920x1080i59     0x0F
> +#define ADV7441A_FORMAT_1920x1080i60     0x10
> +#define ADV7441A_FORMAT_1920x1080p23     0x11
> +#define ADV7441A_FORMAT_1920x1080p24     0x12
> +#define ADV7441A_FORMAT_1920x1080p25     0x13
> +#define ADV7441A_FORMAT_1920x1080p29     0x14
> +#define ADV7441A_FORMAT_1920x1080p30     0x15
> +#define ADV7441A_FORMAT_1920x1080p50     0x16
> +#define ADV7441A_FORMAT_1920x1080p59     0x17
> +#define ADV7441A_FORMAT_1920x1080p60     0x18
> +
> +/* VGA */
> +#define ADV7441A_FORMAT_640x480p60       0x30
> +#define ADV7441A_FORMAT_800x600p60       0x31
> +#define ADV7441A_FORMAT_1024x768p60      0x32
> +#define ADV7441A_FORMAT_1280x960p60      0x33
> +#define ADV7441A_FORMAT_1280x1024p60     0x34
> +#define ADV7441A_FORMAT_1400x1050p60     0x35
> +#define ADV7441A_FORMAT_1600x1200p60     0x36
> +#define ADV7441A_FORMAT_UXGA_1600x1200p60	0x43
> +#define ADV7441A_FORMAT_WXGA_1440x900p60		0x46
> +#define ADV7441A_FORMAT_WSXGA_1680x1050p60	0x48
> +#define ADV7441A_FORMAT_VGAHD_1920x1080p60	0x49
> +
> +#define ADV7441A_FRAMERATE_UNKNOWN	(0)
> +#define ADV7441A_FRAMERATE_23		(23)
> +#define ADV7441A_FRAMERATE_24		(24)
> +#define ADV7441A_FRAMERATE_25		(25)
> +#define ADV7441A_FRAMERATE_29		(29)
> +#define ADV7441A_FRAMERATE_30		(30)
> +#define ADV7441A_FRAMERATE_50		(50)
> +#define ADV7441A_FRAMERATE_59		(59)
> +#define ADV7441A_FRAMERATE_60		(60)
> +
> +/* Asynchronous Driver Events */
> +#define ADV7441A_HOTPLUG         (1)
> +#define ADV7441A_FMT_CHANGE      (2)
> +
> +#endif
> diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
> index 58f914a..07e2513 100644
> --- a/include/media/v4l2-chip-ident.h
> +++ b/include/media/v4l2-chip-ident.h
> @@ -183,6 +183,9 @@ enum {
>  	/* module adv7393: just ident 7393 */
>  	V4L2_IDENT_ADV7393 = 7393,
>  
> +	/* module adv7441a: just ident 7441 */
> +	V4L2_IDENT_ADV7441A = 7441,
> +
>  	/* module saa7706h: just ident 7706 */
>  	V4L2_IDENT_SAA7706H = 7706,
>  
> -- 
> 1.7.11.4
> 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-09-13 23:19                       ` Mauro Carvalho Chehab
@ 2012-09-13 23:23                         ` Mauro Carvalho Chehab
  2012-09-14  0:59                           ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 18+ messages in thread
From: Mauro Carvalho Chehab @ 2012-09-13 23:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Steven Toth, Hans Verkuil, Linux-Media

Em 13-09-2012 20:19, Mauro Carvalho Chehab escreveu:
> Em Sat, 18 Aug 2012 11:48:52 -0400
> Steven Toth <stoth@kernellabs.com> escreveu:
> 
>> Mauro, please read below, a new set of patches I'm submitting for merge.
>>
>> On Thu, Aug 16, 2012 at 2:49 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>> On Thu August 16 2012 19:39:51 Steven Toth wrote:
>>>>>> So, I've ran v4l2-compliance and it pointed out a few things that I've
>>>>>> fixed, but it also does a few things that (for some reason) I can't
>>>>>> seem to catch. One particular test is on (iirc) s_fmt. It attempts to
>>>>>> set ATSC but by ioctl callback never receives ATSC in the norm/id arg,
>>>>>> it actually receives 0x0. This feels more like a bug in the test.
>>>>>> Either way, I have some if (std & ATSC) return -EINVAL, but it still
>>>>>> appears to fail the test.
>>>>
>>>> Oddly enough. If I set tvnorms to something valid, then compliance
>>>> passes but gstreamer
>>>> fails to run, looks like some kind of confusion about either the
>>>> current established
>>>> norm, or a failure to establish a norm.
>>>>
>>>> For the time being I've set tvnorms to 0 (with a comment) and removed
>>>> current_norm.
>>>
>>> Well, this needs to be sorted, because something is clearly amiss.
>>
>> Agreed. I just can't see what's wrong. I may need your advise /
>> eyeballs on this. I'd be willing to provide logs that show gstreamer
>> accessing the driver and exiting. It needs fixed, I've tried, I just
>> can't see why gstreamer fails.
>>
>> On the main topic of merge.... As promised, I spent quite a bit of
>> time this week reworking the code based on the feedback. I also
>> flattened all of these patches into a single patchset and upgraded to
>> the latest re-org tree.
>>
>> The source notes describe in a little more detail the major changes:
>> http://git.kernellabs.com/?p=stoth/media_tree.git;a=commit;h=f295dd63e2f7027e327daad730eb86f2c17e3b2c
>>
>> Mauro, so, I hereby submit for your review/merge again, the updated
>> patchset. *** Please comment. ***
> 
> I'll comment patch by patch. Let's hope the ML will get this email. Not sure,
> as it tends to discard big emails like that.
> 
> This is the comment of patch 1/4.
> 

Patch 2 is trivial. It is obviously OK.

Patch 3 also looked OK on my eyes.

Regards,
Mauro


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-09-13 23:23                         ` Mauro Carvalho Chehab
@ 2012-09-14  0:59                           ` Mauro Carvalho Chehab
  2012-09-14  2:09                             ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 18+ messages in thread
From: Mauro Carvalho Chehab @ 2012-09-14  0:59 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Steven Toth, Hans Verkuil, Linux-Media

Em Thu, 13 Sep 2012 20:23:42 -0300
Mauro Carvalho Chehab <mchehab@redhat.com> escreveu:

> Em 13-09-2012 20:19, Mauro Carvalho Chehab escreveu:
> > Em Sat, 18 Aug 2012 11:48:52 -0400
> > Steven Toth <stoth@kernellabs.com> escreveu:
> > 
> >> Mauro, please read below, a new set of patches I'm submitting for merge.
> >>
> >> On Thu, Aug 16, 2012 at 2:49 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> >>> On Thu August 16 2012 19:39:51 Steven Toth wrote:
> >>>>>> So, I've ran v4l2-compliance and it pointed out a few things that I've
> >>>>>> fixed, but it also does a few things that (for some reason) I can't
> >>>>>> seem to catch. One particular test is on (iirc) s_fmt. It attempts to
> >>>>>> set ATSC but by ioctl callback never receives ATSC in the norm/id arg,
> >>>>>> it actually receives 0x0. This feels more like a bug in the test.
> >>>>>> Either way, I have some if (std & ATSC) return -EINVAL, but it still
> >>>>>> appears to fail the test.
> >>>>
> >>>> Oddly enough. If I set tvnorms to something valid, then compliance
> >>>> passes but gstreamer
> >>>> fails to run, looks like some kind of confusion about either the
> >>>> current established
> >>>> norm, or a failure to establish a norm.
> >>>>
> >>>> For the time being I've set tvnorms to 0 (with a comment) and removed
> >>>> current_norm.
> >>>
> >>> Well, this needs to be sorted, because something is clearly amiss.
> >>
> >> Agreed. I just can't see what's wrong. I may need your advise /
> >> eyeballs on this. I'd be willing to provide logs that show gstreamer
> >> accessing the driver and exiting. It needs fixed, I've tried, I just
> >> can't see why gstreamer fails.
> >>
> >> On the main topic of merge.... As promised, I spent quite a bit of
> >> time this week reworking the code based on the feedback. I also
> >> flattened all of these patches into a single patchset and upgraded to
> >> the latest re-org tree.
> >>
> >> The source notes describe in a little more detail the major changes:
> >> http://git.kernellabs.com/?p=stoth/media_tree.git;a=commit;h=f295dd63e2f7027e327daad730eb86f2c17e3b2c
> >>
> >> Mauro, so, I hereby submit for your review/merge again, the updated
> >> patchset. *** Please comment. ***
> > 
> > I'll comment patch by patch. Let's hope the ML will get this email. Not sure,
> > as it tends to discard big emails like that.
> > 
> > This is the comment of patch 1/4.
> > 
> 
> Patch 2 is trivial. It is obviously OK.
> 
> Patch 3 also looked OK on my eyes.

Patch 4 will very likely be discarded by vger server, if everything is
added there. So, I'll drop the parts that weren't commented.

Anyway:

> Subject: [media] vc8x0: Adding support for the ViewCast O820E Capture Card.
> Cc: Linux Media Mailing List <linux-media@vger.kernel.org>
> 
> A dual channel 1920x1080p60 PCIe x4 capture card, two DVI
> inputs capable of capturing DVI/HDMI, Component, Svideo, Composite
> and some VGA resolutions.
...

> +#include "vc8x0.h"
> +
> +static unsigned int audio_debug;
> +module_param(audio_debug, int, 0644);
> +MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]");
> +
> +static unsigned int audio_alsa_during_irq = 1;
> +module_param(audio_alsa_during_irq, int, 0644);
> +MODULE_PARM_DESC(audio_alsa_during_irq, "feed alsa during the irq handler, not via a dpc [audio]");
> +
> +#define dprintk(level, fmt, arg...)\
> +	do {\
> +		if (audio_debug >= level)\
> +			pr_err("%s/0: " fmt, \
> +				channel->dev->name, ## arg);\
> +	} while (0)
> +
> +#define MIXER_RCA_JACKS 1
> +
> +/* Repack 24 bit audio samples (in 32bit alignment)
> + * into 16bit samples within the same buffer, and
> + * return the new buffer length in bytes.
> + *
> + * Input Sample:
> + * LEFT         RIGHT
> + * 00 B0 B1 B2  00 B1 B1 B2
> +
> + * Output Sample:
> + * LEFT   RIGHT
> + * B1 B2  B1 B2
> + */
> +static int repack_24_to_16(u8 *buf, int len)
> +{
> +	int i;
> +	u8 *dst = buf;
> +	u8 *src = buf + 2;
> +
> +	/* For each 24 bit sample */
> +	for (i = 0; i < (len / 4); i++) {
> +		*(dst) = *(src);
> +		*(dst + 1) = *(src + 1);
> +		dst += 2;
> +		src += 4;
> +	}
> +
> +	return (len / 4) * 2;
> +}

Why is it needed? It would be better to let ALSA userspace to handle
it.

> +	dprintk(3,
> +		"%s() %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
> +		__func__, *(buf->cpu + 0), *(buf->cpu + 1), *(buf->cpu + 2),
> +		*(buf->cpu + 3), *(buf->cpu + 4), *(buf->cpu + 5),
> +		*(buf->cpu + 6), *(buf->cpu + 7), *(buf->cpu + 8),
> +		*(buf->cpu + 9), *(buf->cpu + 10), *(buf->cpu + 11),
> +		*(buf->cpu + 12), *(buf->cpu + 13), *(buf->cpu + 14),
> +		*(buf->cpu + 15)
> +	    );

FYI, there's now a new printk syntax to print buffer dumps like
that, where you pass the buffer and the length, and printk does the
rest.

> +	spin_unlock(&channel->dma_buffers_full_lock);
> +	spin_unlock_irqrestore(&channel->dma_buffers_dpc_lock, flags);
> +
> +	/* BAM! The interrupt handler is now free to move on */
> +	/* BAM! The interrupt handler is now free to move on */
> +	/* BAM! The interrupt handler is now free to move on */
> +	/* BAM! The interrupt handler is now free to move on */

Wow! the above 4 lines won the prize of the weirdest comment I ever seen ;)
Why you need to say the above 4 times? :)

Even saying it once seems overkill to me, as it just repeats what the
 spin_unlock() just said ;)

> +
> +	/* Now let's dequeue the full buffers */
> +	/* For each full buffer, send it to user space */
> +	spin_lock(&channel->dma_buffers_full_lock);

Huh? You just unlocked it... Also, it looks weird that you're using two spin
locks on the above code, and just one here. Using more than one spin lock
like that could cause dead locks.

Btw, this patch is too big! You should break it into some smaller
pieces (one patch per file, for example) making life easier for reviewers and
allowing people at the ML to see/comment the full code, as one of the requirements
is that, before sending a pull request, you should be sending the patches to
the ML.

In the specific case of the -alsa driver, it is mandatory to have it on a
separate patch, as it should be copied also to the alsa ML, to allow alsa
people to comment/review.

So, please split patch 4 into separate patches, doing the Kconfig/Makefile
integration at the end of your series.

> +	buf->used_len = 3840;
> +	buf->used_len = repack_24_to_16(buf->cpu, buf->used_len);

This repack thing looks weird on my eyes.

> +	spin_lock_irqsave(&channel->dma_buffers_busy_lock, flags);
> +
> +	/* Last, put the buffer on the DPC list for our deferred worker
> +	 * to process */
> +	spin_lock_irqsave(&channel->dma_buffers_dpc_lock, flags);

Again, double-locking.

> +static inline void handle_audio_data(struct vc8x0_dma_buffer *buf,
> +	int *period_elapsed)
> +{
> +	struct vc8x0_dma_channel *channel = buf->channel;
> +	struct vc8x0_audio_dev *chip = channel->audio_dev;
> +	struct snd_pcm_runtime *runtime = chip->capture_pcm_substream->runtime;
> +	int stride;
> +	int len, rdb, cpsafe[3];
> +	unsigned char *cp;
> +	unsigned int oldptr;
> +
> +	stride = runtime->frame_bits >> 3;
> +	if (stride == 0) {
> +		pr_err("%s() divbyzero BUG\n", __func__);
> +		stride = 4;
> +	}
> +
> +	len = buf->used_len / stride;

Hmm... that looks weird on my eyes, as other drivers don't have
such check. Why such logic is needed? Rounding it to 4 won't cause
buffer overflows? Maybe a BUG_ON would apply better here.

> +#if ENABLE_ALSA_MIXER

Please use CONFIG_foo instead, it the user may opt to have it or not.

> diff --git a/drivers/media/pci/vc8x0/vc8x0-buffer.c b/drivers/media/pci/vc8x0/vc8x0-buffer.c


> +DMA buffers per channel must be contigious, reside only in 32bit

typo: contiguous.

> +memory.
> +
> +The PCIe bridge (GN4124) supports up to 18 'fifos', essentially
> +discrete DMA channels. The GN4124 uses a DMA Sequencer architecture
> +to control which dma buffers are targets for which channel. The sequencer
> +is a list of program instructions that effictivel handle the data modement

typo: effective

> +
> +void vc8x0_buffer_analyze(u8 *buf, int len)
> +{
> +	int i;
> +	u32 data[256];
> +	memset(data, 0, sizeof(data));
> +
> +	for (i = 0; i < len; i++) {
> +		data[*(buf + i)]++;
> +	}
> +
> +	for (i = 0; i < 256; i++) {
> +		if (data[i]) {
> +			pr_err("%02x %x\n", i, data[i]);
> +		}
> +	}

use print_hex_dump() instead of the loop.

On a big driver, like that, it is hard to see how each module
interacts with the others. Yet, it seemed, on my eyes, that
vc8x0-buffer is doing something close to what vb2-contig is
already doing.

If you need to use contiguous buffer memories for DMA transfers,
I strongly suggest you to use vb2, as vb1 is known to have some
serious issues with contiguous memories.

> diff --git a/drivers/media/pci/vc8x0/vc8x0-channel.c b/drivers/media/pci/vc8x0/vc8x0-channel.c

Again, it is hard to understand what is there at *-channel, in the context
of the entire driver, but it seems part of a videobuf handling code.

> diff --git a/drivers/media/pci/vc8x0/vc8x0-core.c b/drivers/media/pci/vc8x0/vc8x0-core.c

> +
> +/* 1 = Basic device statistics
> + * 2 = PCIe register dump for entire device
> + * 4 = AD9985 register dump
> + * 8 = SIL9013 register dump
> + */
> +unsigned int vc8x0_thread_active = 1;
> +module_param(vc8x0_thread_active, int, 0644);
> +MODULE_PARM_DESC(vc8x0_thread_active, "should keep alive thread run");

Is it really needed? If so, I think you should better describe it as, the
above description doesn't mean anything for me... What Thread? What happens
if the thread doesn't run?

> +static int vc8x0_dev_setup(struct vc8x0_dev *dev)
> +{
> +	int i;
> +
> +	mutex_init(&dev->lock);
> +
> +	atomic_inc(&dev->refcount);
> +
> +	dev->nr = vc8x0_devcount++;
> +	sprintf(dev->name, "vc8x0[%d]", dev->nr);
> +
> +	/* board config */
> +	dev->board = UNSET;
> +	if (card[dev->nr] < vc8x0_bcount)
> +		dev->board = card[dev->nr];
> +	for (i = 0; UNSET == dev->board  &&  i < vc8x0_idcount; i++)
> +		if (dev->pci->subsystem_vendor == vc8x0_subids[i].subvendor &&
> +		    dev->pci->subsystem_device == vc8x0_subids[i].subdevice)
> +			dev->board = vc8x0_subids[i].card;
> +	if (UNSET == dev->board) {
> +		dev->board = VC8X0_BOARD_UNKNOWN;
> +		vc8x0_card_list(dev);
> +	}
> +
> +	/* The keepalive thread needs a mutex */
> +	mutex_init(&dev->kthread_lock);
> +
> +	/* Main Master 0 Bus incl. eeprom */
> +	mutex_init(&dev->i2c_bus.lock);
> +	dev->i2c_bus.nr = 0;
> +	dev->i2c_bus.dev = dev;
> +	dev->i2c_bus.reg_base = 0xd80;
> +
> +	if (get_resources(dev) < 0) {
> +		pr_err(
> +		"CORE %s No more PCIe resources for subsystem: %04x:%04x\n",
> +		       dev->name, dev->pci->subsystem_vendor,
> +		       dev->pci->subsystem_device);
> +
> +		vc8x0_devcount--;
> +		return -ENODEV;
> +	}
> +
> +	/* PCIe stuff */
> +	dev->lmmio032 = ioremap(pci_resource_start(dev->pci, BAR0),
> +			     pci_resource_len(dev->pci, BAR0));
> +	dev->lmmio064 = (u64 *)dev->lmmio032;
> +	dev->bmmio = (u8 *)dev->lmmio032;
> +	dev->lmmio4 = ioremap(pci_resource_start(dev->pci, BAR4),
> +			     pci_resource_len(dev->pci, BAR4));
> +
> +	dev->m_nInterruptMask1 = 0;
> +	dev->m_nInterruptMask2 = 0;
> +
> +	pr_info("CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
> +	       dev->name, dev->pci->subsystem_vendor,
> +	       dev->pci->subsystem_device, vc8x0_boards[dev->board].name,
> +	       dev->board, card[dev->nr] == dev->board ?
> +	       "insmod option" : "autodetected");
> +
> +	return 0;
> +}

This is driver's author choice, but I would move driver init, register, unregister
logic to be at *-cards.c. That balances a little more the code size on each
.c file. We successfully did it on several drivers, and the end result reduced
the number of exported functions.

> +#if ENABLE_ALSA
...

> +#if ENABLE_MONITOR_REGISTERS
...
> +#if ENABLE_AUDIO_KEEPALIVE && ENABLE_ALSA
...

Why do you need those defines? If they're needed, please use CONFIG_foo.

If they're for debug purposes, please convert them on if (debug == FOO).

> +#if ENABLE_ALSA && ENABLE_AUDIO_KEEPALIVE
> +		/* The PCM audio subsystem throws this messages:
> +		 * ALSA sound/core/pcm_lib.c:1765: capture write error
> +		 * (DMA or IRQ trouble?) when no audio is delivered for 10
> +		 * seconds. It basically means it's worker thread didn't
> +		 * receive a notification with 10 seconds. The message is poor.
> +		 * In terms of the vc8x0 driver this message will appear by
> +		 * default if the HDMI cable is disconnected for > 10 seconds,
> +		 * and it will appear every 10 seconds. If you don't want
> +		 * this IRQ message to appear then set ENABLE_AUDIO_KEEPLIVE=1

How to set it? It is not on Kconfig, nor it is a modprobe option.

> +		/* Other parts of the driver need to guarantee that
> +		 * various 'keep alives' aren't happening. We'll
> +		 * prevent race conditions by allowing the
> +		 * rest of the driver to dictate when
> +		 * this keepalives can occur.
> +		 */
> +		mutex_lock(&dev->kthread_lock);
> +
> +		mutex_unlock(&dev->kthread_lock);

Huh???? Lock/unlock here, without any code inside? That looks odd.

> +#if ENABLE_BAD_READS

Yet another define stuff, without a Kconfig item.

> diff --git a/drivers/media/pci/vc8x0/vc8x0-display.c b/drivers/media/pci/vc8x0/vc8x0-display.c

> +struct letter_t {
> +	u8 *ptr;
> +	u8 data[8];
> +} charset[] = {
> + /* ' ' */ [0x20] = { 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, },
> + /* 00000000 */
> + /* 00000000 */
> + /* 00000000 */
> + /* 00000000 */
> + /* 00000000 */
> + /* 00000000 */
> + /* 00000000 */
> + /* 00000000 */
> + /* '!' */ [0x21] = { 0, { 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x04, 0x00 }, },
> + /* 00000100 */
> + /* 00000100 */
> + /* 00000100 */
> + /* 00000100 */
> + /* 00000000 */
> + /* 00000000 */
> + /* 00000100 */
> + /* 00000000 */

Charset???? No, please! If you really need a charset, take a look at the
vivi driver. It uses an already-existent Kernel charset. See:

	static int __init vivi_init(void)
	{
		const struct font_desc *font = find_font("VGA8x16");

Not sure about the rest of the code here at vc8x0-display.c, but maybe you'll
find a similar code to it already coded. Where do you use it?

> diff --git a/drivers/media/pci/vc8x0/vc8x0-dma.c b/drivers/media/pci/vc8x0/vc8x0-dma.c

> +/* DMA SEQUENCER PROGRAM */
> +
> +static u32 vc8x0_FlexDMAProgram[] = {
> +/*	0x0000	*/	VDMA_LOAD_RA(VD_1_STREAM_DISABLED),
...
> +/*	0x02DA	*/	VDMA_JMP(VDMA_ALWAYS, 0, MAIN),
> +};
> +

Firmware? It is likely better to put it elsewhere, maybe at linux-firmware.
There are some GPL'd firmwares there.

I'll comment the remaining files of patch 4 on a separate email
(editing a 11.000 lines email is very hard... my emailer crashed a few
 times).

Regards,
Mauro



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-09-14  0:59                           ` Mauro Carvalho Chehab
@ 2012-09-14  2:09                             ` Mauro Carvalho Chehab
  2012-09-14  7:27                               ` Hans Verkuil
  0 siblings, 1 reply; 18+ messages in thread
From: Mauro Carvalho Chehab @ 2012-09-14  2:09 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Steven Toth, Hans Verkuil, Linux-Media

Em 13-09-2012 21:59, Mauro Carvalho Chehab escreveu:
> Em Thu, 13 Sep 2012 20:23:42 -0300
> Mauro Carvalho Chehab <mchehab@redhat.com> escreveu:
> 
>> Em 13-09-2012 20:19, Mauro Carvalho Chehab escreveu:
>>> Em Sat, 18 Aug 2012 11:48:52 -0400
>>> Steven Toth <stoth@kernellabs.com> escreveu:
>>>
>>>> Mauro, please read below, a new set of patches I'm submitting for merge.
>>>>
>>>> On Thu, Aug 16, 2012 at 2:49 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>>>> On Thu August 16 2012 19:39:51 Steven Toth wrote:
>>>>>>>> So, I've ran v4l2-compliance and it pointed out a few things that I've
>>>>>>>> fixed, but it also does a few things that (for some reason) I can't
>>>>>>>> seem to catch. One particular test is on (iirc) s_fmt. It attempts to
>>>>>>>> set ATSC but by ioctl callback never receives ATSC in the norm/id arg,
>>>>>>>> it actually receives 0x0. This feels more like a bug in the test.
>>>>>>>> Either way, I have some if (std & ATSC) return -EINVAL, but it still
>>>>>>>> appears to fail the test.
>>>>>>
>>>>>> Oddly enough. If I set tvnorms to something valid, then compliance
>>>>>> passes but gstreamer
>>>>>> fails to run, looks like some kind of confusion about either the
>>>>>> current established
>>>>>> norm, or a failure to establish a norm.
>>>>>>
>>>>>> For the time being I've set tvnorms to 0 (with a comment) and removed
>>>>>> current_norm.
>>>>>
>>>>> Well, this needs to be sorted, because something is clearly amiss.
>>>>
>>>> Agreed. I just can't see what's wrong. I may need your advise /
>>>> eyeballs on this. I'd be willing to provide logs that show gstreamer
>>>> accessing the driver and exiting. It needs fixed, I've tried, I just
>>>> can't see why gstreamer fails.
>>>>
>>>> On the main topic of merge.... As promised, I spent quite a bit of
>>>> time this week reworking the code based on the feedback. I also
>>>> flattened all of these patches into a single patchset and upgraded to
>>>> the latest re-org tree.
>>>>
>>>> The source notes describe in a little more detail the major changes:
>>>> http://git.kernellabs.com/?p=stoth/media_tree.git;a=commit;h=f295dd63e2f7027e327daad730eb86f2c17e3b2c
>>>>
>>>> Mauro, so, I hereby submit for your review/merge again, the updated
>>>> patchset. *** Please comment. ***
>>>
>>> I'll comment patch by patch. Let's hope the ML will get this email. Not sure,
>>> as it tends to discard big emails like that.
>>>
>>> This is the comment of patch 1/4.
>>>
>>
>> Patch 2 is trivial. It is obviously OK.
>>
>> Patch 3 also looked OK on my eyes.
> 
> Patch 4 will very likely be discarded by vger server, if everything is
> added there. So, I'll drop the parts that weren't commented.
> 
> Anyway:
> 
>> Subject: [media] vc8x0: Adding support for the ViewCast O820E Capture Card.
>> Cc: Linux Media Mailing List <linux-media@vger.kernel.org>
>>
>> A dual channel 1920x1080p60 PCIe x4 capture card, two DVI
>> inputs capable of capturing DVI/HDMI, Component, Svideo, Composite
>> and some VGA resolutions.
> ...
> 
>> +#include "vc8x0.h"
>> +
>> +static unsigned int audio_debug;
>> +module_param(audio_debug, int, 0644);
>> +MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]");
>> +
>> +static unsigned int audio_alsa_during_irq = 1;
>> +module_param(audio_alsa_during_irq, int, 0644);
>> +MODULE_PARM_DESC(audio_alsa_during_irq, "feed alsa during the irq handler, not via a dpc [audio]");
>> +
>> +#define dprintk(level, fmt, arg...)\
>> +	do {\
>> +		if (audio_debug >= level)\
>> +			pr_err("%s/0: " fmt, \
>> +				channel->dev->name, ## arg);\
>> +	} while (0)
>> +
>> +#define MIXER_RCA_JACKS 1
>> +
>> +/* Repack 24 bit audio samples (in 32bit alignment)
>> + * into 16bit samples within the same buffer, and
>> + * return the new buffer length in bytes.
>> + *
>> + * Input Sample:
>> + * LEFT         RIGHT
>> + * 00 B0 B1 B2  00 B1 B1 B2
>> +
>> + * Output Sample:
>> + * LEFT   RIGHT
>> + * B1 B2  B1 B2
>> + */
>> +static int repack_24_to_16(u8 *buf, int len)
>> +{
>> +	int i;
>> +	u8 *dst = buf;
>> +	u8 *src = buf + 2;
>> +
>> +	/* For each 24 bit sample */
>> +	for (i = 0; i < (len / 4); i++) {
>> +		*(dst) = *(src);
>> +		*(dst + 1) = *(src + 1);
>> +		dst += 2;
>> +		src += 4;
>> +	}
>> +
>> +	return (len / 4) * 2;
>> +}
> 
> Why is it needed? It would be better to let ALSA userspace to handle
> it.
> 
>> +	dprintk(3,
>> +		"%s() %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
>> +		__func__, *(buf->cpu + 0), *(buf->cpu + 1), *(buf->cpu + 2),
>> +		*(buf->cpu + 3), *(buf->cpu + 4), *(buf->cpu + 5),
>> +		*(buf->cpu + 6), *(buf->cpu + 7), *(buf->cpu + 8),
>> +		*(buf->cpu + 9), *(buf->cpu + 10), *(buf->cpu + 11),
>> +		*(buf->cpu + 12), *(buf->cpu + 13), *(buf->cpu + 14),
>> +		*(buf->cpu + 15)
>> +	    );
> 
> FYI, there's now a new printk syntax to print buffer dumps like
> that, where you pass the buffer and the length, and printk does the
> rest.
> 
>> +	spin_unlock(&channel->dma_buffers_full_lock);
>> +	spin_unlock_irqrestore(&channel->dma_buffers_dpc_lock, flags);
>> +
>> +	/* BAM! The interrupt handler is now free to move on */
>> +	/* BAM! The interrupt handler is now free to move on */
>> +	/* BAM! The interrupt handler is now free to move on */
>> +	/* BAM! The interrupt handler is now free to move on */
> 
> Wow! the above 4 lines won the prize of the weirdest comment I ever seen ;)
> Why you need to say the above 4 times? :)
> 
> Even saying it once seems overkill to me, as it just repeats what the
>  spin_unlock() just said ;)
> 
>> +
>> +	/* Now let's dequeue the full buffers */
>> +	/* For each full buffer, send it to user space */
>> +	spin_lock(&channel->dma_buffers_full_lock);
> 
> Huh? You just unlocked it... Also, it looks weird that you're using two spin
> locks on the above code, and just one here. Using more than one spin lock
> like that could cause dead locks.
> 
> Btw, this patch is too big! You should break it into some smaller
> pieces (one patch per file, for example) making life easier for reviewers and
> allowing people at the ML to see/comment the full code, as one of the requirements
> is that, before sending a pull request, you should be sending the patches to
> the ML.
> 
> In the specific case of the -alsa driver, it is mandatory to have it on a
> separate patch, as it should be copied also to the alsa ML, to allow alsa
> people to comment/review.
> 
> So, please split patch 4 into separate patches, doing the Kconfig/Makefile
> integration at the end of your series.
> 
>> +	buf->used_len = 3840;
>> +	buf->used_len = repack_24_to_16(buf->cpu, buf->used_len);
> 
> This repack thing looks weird on my eyes.
> 
>> +	spin_lock_irqsave(&channel->dma_buffers_busy_lock, flags);
>> +
>> +	/* Last, put the buffer on the DPC list for our deferred worker
>> +	 * to process */
>> +	spin_lock_irqsave(&channel->dma_buffers_dpc_lock, flags);
> 
> Again, double-locking.
> 
>> +static inline void handle_audio_data(struct vc8x0_dma_buffer *buf,
>> +	int *period_elapsed)
>> +{
>> +	struct vc8x0_dma_channel *channel = buf->channel;
>> +	struct vc8x0_audio_dev *chip = channel->audio_dev;
>> +	struct snd_pcm_runtime *runtime = chip->capture_pcm_substream->runtime;
>> +	int stride;
>> +	int len, rdb, cpsafe[3];
>> +	unsigned char *cp;
>> +	unsigned int oldptr;
>> +
>> +	stride = runtime->frame_bits >> 3;
>> +	if (stride == 0) {
>> +		pr_err("%s() divbyzero BUG\n", __func__);
>> +		stride = 4;
>> +	}
>> +
>> +	len = buf->used_len / stride;
> 
> Hmm... that looks weird on my eyes, as other drivers don't have
> such check. Why such logic is needed? Rounding it to 4 won't cause
> buffer overflows? Maybe a BUG_ON would apply better here.
> 
>> +#if ENABLE_ALSA_MIXER
> 
> Please use CONFIG_foo instead, it the user may opt to have it or not.
> 
>> diff --git a/drivers/media/pci/vc8x0/vc8x0-buffer.c b/drivers/media/pci/vc8x0/vc8x0-buffer.c
> 
> 
>> +DMA buffers per channel must be contigious, reside only in 32bit
> 
> typo: contiguous.
> 
>> +memory.
>> +
>> +The PCIe bridge (GN4124) supports up to 18 'fifos', essentially
>> +discrete DMA channels. The GN4124 uses a DMA Sequencer architecture
>> +to control which dma buffers are targets for which channel. The sequencer
>> +is a list of program instructions that effictivel handle the data modement
> 
> typo: effective
> 
>> +
>> +void vc8x0_buffer_analyze(u8 *buf, int len)
>> +{
>> +	int i;
>> +	u32 data[256];
>> +	memset(data, 0, sizeof(data));
>> +
>> +	for (i = 0; i < len; i++) {
>> +		data[*(buf + i)]++;
>> +	}
>> +
>> +	for (i = 0; i < 256; i++) {
>> +		if (data[i]) {
>> +			pr_err("%02x %x\n", i, data[i]);
>> +		}
>> +	}
> 
> use print_hex_dump() instead of the loop.
> 
> On a big driver, like that, it is hard to see how each module
> interacts with the others. Yet, it seemed, on my eyes, that
> vc8x0-buffer is doing something close to what vb2-contig is
> already doing.
> 
> If you need to use contiguous buffer memories for DMA transfers,
> I strongly suggest you to use vb2, as vb1 is known to have some
> serious issues with contiguous memories.
> 
>> diff --git a/drivers/media/pci/vc8x0/vc8x0-channel.c b/drivers/media/pci/vc8x0/vc8x0-channel.c
> 
> Again, it is hard to understand what is there at *-channel, in the context
> of the entire driver, but it seems part of a videobuf handling code.
> 
>> diff --git a/drivers/media/pci/vc8x0/vc8x0-core.c b/drivers/media/pci/vc8x0/vc8x0-core.c
> 
>> +
>> +/* 1 = Basic device statistics
>> + * 2 = PCIe register dump for entire device
>> + * 4 = AD9985 register dump
>> + * 8 = SIL9013 register dump
>> + */
>> +unsigned int vc8x0_thread_active = 1;
>> +module_param(vc8x0_thread_active, int, 0644);
>> +MODULE_PARM_DESC(vc8x0_thread_active, "should keep alive thread run");
> 
> Is it really needed? If so, I think you should better describe it as, the
> above description doesn't mean anything for me... What Thread? What happens
> if the thread doesn't run?
> 
>> +static int vc8x0_dev_setup(struct vc8x0_dev *dev)
>> +{
>> +	int i;
>> +
>> +	mutex_init(&dev->lock);
>> +
>> +	atomic_inc(&dev->refcount);
>> +
>> +	dev->nr = vc8x0_devcount++;
>> +	sprintf(dev->name, "vc8x0[%d]", dev->nr);
>> +
>> +	/* board config */
>> +	dev->board = UNSET;
>> +	if (card[dev->nr] < vc8x0_bcount)
>> +		dev->board = card[dev->nr];
>> +	for (i = 0; UNSET == dev->board  &&  i < vc8x0_idcount; i++)
>> +		if (dev->pci->subsystem_vendor == vc8x0_subids[i].subvendor &&
>> +		    dev->pci->subsystem_device == vc8x0_subids[i].subdevice)
>> +			dev->board = vc8x0_subids[i].card;
>> +	if (UNSET == dev->board) {
>> +		dev->board = VC8X0_BOARD_UNKNOWN;
>> +		vc8x0_card_list(dev);
>> +	}
>> +
>> +	/* The keepalive thread needs a mutex */
>> +	mutex_init(&dev->kthread_lock);
>> +
>> +	/* Main Master 0 Bus incl. eeprom */
>> +	mutex_init(&dev->i2c_bus.lock);
>> +	dev->i2c_bus.nr = 0;
>> +	dev->i2c_bus.dev = dev;
>> +	dev->i2c_bus.reg_base = 0xd80;
>> +
>> +	if (get_resources(dev) < 0) {
>> +		pr_err(
>> +		"CORE %s No more PCIe resources for subsystem: %04x:%04x\n",
>> +		       dev->name, dev->pci->subsystem_vendor,
>> +		       dev->pci->subsystem_device);
>> +
>> +		vc8x0_devcount--;
>> +		return -ENODEV;
>> +	}
>> +
>> +	/* PCIe stuff */
>> +	dev->lmmio032 = ioremap(pci_resource_start(dev->pci, BAR0),
>> +			     pci_resource_len(dev->pci, BAR0));
>> +	dev->lmmio064 = (u64 *)dev->lmmio032;
>> +	dev->bmmio = (u8 *)dev->lmmio032;
>> +	dev->lmmio4 = ioremap(pci_resource_start(dev->pci, BAR4),
>> +			     pci_resource_len(dev->pci, BAR4));
>> +
>> +	dev->m_nInterruptMask1 = 0;
>> +	dev->m_nInterruptMask2 = 0;
>> +
>> +	pr_info("CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
>> +	       dev->name, dev->pci->subsystem_vendor,
>> +	       dev->pci->subsystem_device, vc8x0_boards[dev->board].name,
>> +	       dev->board, card[dev->nr] == dev->board ?
>> +	       "insmod option" : "autodetected");
>> +
>> +	return 0;
>> +}
> 
> This is driver's author choice, but I would move driver init, register, unregister
> logic to be at *-cards.c. That balances a little more the code size on each
> .c file. We successfully did it on several drivers, and the end result reduced
> the number of exported functions.
> 
>> +#if ENABLE_ALSA
> ...
> 
>> +#if ENABLE_MONITOR_REGISTERS
> ...
>> +#if ENABLE_AUDIO_KEEPALIVE && ENABLE_ALSA
> ...
> 
> Why do you need those defines? If they're needed, please use CONFIG_foo.
> 
> If they're for debug purposes, please convert them on if (debug == FOO).
> 
>> +#if ENABLE_ALSA && ENABLE_AUDIO_KEEPALIVE
>> +		/* The PCM audio subsystem throws this messages:
>> +		 * ALSA sound/core/pcm_lib.c:1765: capture write error
>> +		 * (DMA or IRQ trouble?) when no audio is delivered for 10
>> +		 * seconds. It basically means it's worker thread didn't
>> +		 * receive a notification with 10 seconds. The message is poor.
>> +		 * In terms of the vc8x0 driver this message will appear by
>> +		 * default if the HDMI cable is disconnected for > 10 seconds,
>> +		 * and it will appear every 10 seconds. If you don't want
>> +		 * this IRQ message to appear then set ENABLE_AUDIO_KEEPLIVE=1
> 
> How to set it? It is not on Kconfig, nor it is a modprobe option.
> 
>> +		/* Other parts of the driver need to guarantee that
>> +		 * various 'keep alives' aren't happening. We'll
>> +		 * prevent race conditions by allowing the
>> +		 * rest of the driver to dictate when
>> +		 * this keepalives can occur.
>> +		 */
>> +		mutex_lock(&dev->kthread_lock);
>> +
>> +		mutex_unlock(&dev->kthread_lock);
> 
> Huh???? Lock/unlock here, without any code inside? That looks odd.
> 
>> +#if ENABLE_BAD_READS
> 
> Yet another define stuff, without a Kconfig item.
> 
>> diff --git a/drivers/media/pci/vc8x0/vc8x0-display.c b/drivers/media/pci/vc8x0/vc8x0-display.c
> 
>> +struct letter_t {
>> +	u8 *ptr;
>> +	u8 data[8];
>> +} charset[] = {
>> + /* ' ' */ [0x20] = { 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, },
>> + /* 00000000 */
>> + /* 00000000 */
>> + /* 00000000 */
>> + /* 00000000 */
>> + /* 00000000 */
>> + /* 00000000 */
>> + /* 00000000 */
>> + /* 00000000 */
>> + /* '!' */ [0x21] = { 0, { 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x04, 0x00 }, },
>> + /* 00000100 */
>> + /* 00000100 */
>> + /* 00000100 */
>> + /* 00000100 */
>> + /* 00000000 */
>> + /* 00000000 */
>> + /* 00000100 */
>> + /* 00000000 */
> 
> Charset???? No, please! If you really need a charset, take a look at the
> vivi driver. It uses an already-existent Kernel charset. See:
> 
> 	static int __init vivi_init(void)
> 	{
> 		const struct font_desc *font = find_font("VGA8x16");
> 
> Not sure about the rest of the code here at vc8x0-display.c, but maybe you'll
> find a similar code to it already coded. Where do you use it?
> 
>> diff --git a/drivers/media/pci/vc8x0/vc8x0-dma.c b/drivers/media/pci/vc8x0/vc8x0-dma.c
> 
>> +/* DMA SEQUENCER PROGRAM */
>> +
>> +static u32 vc8x0_FlexDMAProgram[] = {
>> +/*	0x0000	*/	VDMA_LOAD_RA(VD_1_STREAM_DISABLED),
> ...
>> +/*	0x02DA	*/	VDMA_JMP(VDMA_ALWAYS, 0, MAIN),
>> +};
>> +
> 
> Firmware? It is likely better to put it elsewhere, maybe at linux-firmware.
> There are some GPL'd firmwares there.
> 
> I'll comment the remaining files of patch 4 on a separate email
> (editing a 11.000 lines email is very hard... my emailer crashed a few
>  times).

> diff --git a/drivers/media/pci/vc8x0/vc8x0-video.c b/drivers/media/pci/vc8x0/vc8x0-video.c

> +static unsigned int video_1080p = 1;
> +module_param(video_1080p, int, 0644);
> +MODULE_PARM_DESC(video_1080p, "enable 1080i50/60 (0) or 1080p50/60 (1) handling [default 1, 1080p]");

DV timings API allows selecting each time. No need for modprobe
parameters.

> +
> +static struct vc8x0_format formats[] = {
> +	{
> +		.name     = "422packed,YUYV,640x480p60",
> +		.fourcc   = V4L2_PIX_FMT_YUYV,
> +		.width    = 640,
> +		.height   = 480,
> +		.depth    = 16,
> +		.flags    = ADV7441A_FORMAT_PROGRESSIVE,
> +		.id       = ADV7441A_FORMAT_640x480p60,

Again, please use the public standards at DV API. You'll only
need adv7441a-specific ID's it it supports non-standard timings.

> +static int vc8x0_video_generate_osd(struct vc8x0_dma_channel *channel, u8 *dst)
> +{
> +#if 1
> +	return 0;
> +#else
> +	/* Do some text rendering */
> +	struct vc8x0_format *fmt = channel->ad7441_ctx.detected_fmt;
> +	unsigned char tmp[256];
> +	int ret;
> +
> +	ret = vc8x0_display_render_reset(&channel->display_ctx, dst,
> +		channel->fmt->width);
> +	if (ret < 0)
> +		return ret;

Hmm... Are you using the *-display.c code for OSD? Not sure if it is
a good idea to handle it like that.

Hans,

What do you think?

Yet, the code here is commented, but there's a hole driver there in order
to implement OSD display, just bloating the driver's code... 
...

> +void vc8x0_video_timeout(unsigned long data)
> +{
> +	struct vc8x0_dma_channel *channel = (struct vc8x0_dma_channel *)data;
> +	struct vc8x0_buffer *buf;
> +	u8 *dst;
> +	unsigned long flags;
> +
> +	dprintk(1, "%s()\n", __func__);
> +
> +	if (channel->state != STATE_RUNNING) {
> +		/* Return without processing the buffer or restarting
> +		 * the timer
> +		 */
> +		pr_err("%s() channel stopped, aborting\n", __func__);
> +		return;
> +	}
> +
> +	/* Return all of the buffers in error state, so the vbi/vid inode
> +	 * can return from blocking.
> +	 */
> +	spin_lock_irqsave(&channel->v4l2_capture_lock, flags);
> +	while (!list_empty(&channel->v4l2_capture)) {
> +		buf = list_entry(channel->v4l2_capture.next,
> +			struct vc8x0_buffer, vb.queue);
> +
> +		/* See the notes in the video dequeue section related to
> +		 * generating colorbars */
> +		dst = videobuf_to_vmalloc(&buf->vb);

Double-buffering? Doesn't it be giving you some performance issues?

I suspect that converting it to VB2 will allow you to avoid the
memcpy you're likely doing with VB1.

> +
> +/* Linux VBI handling wants lines 5-21 in a single videobuf buffer in YUY2
> + * format. We'll skip the first 4 lines of the FPGA buffer, convert to 422
> + * and place the resulting pixeldata into a short VBI buffer. Unlikely
> + * video, once the single field of VBI data is processed, we'll hand it off
> + * to the user sometime after this function has created the content.
> + */

Hmm... doesn't it support sliced VBI? If so, I think the implementation will
be cleaner... there are lots of "magic stuff" on the code below.

> +void vc8x0_process_vbi_field(u8 *py, struct vc8x0_buffer *vb_buf, int nr,
> +	struct vc8x0_format *fmt)
> +{
> +	u8 *dst = 0;
> +	u8 *y;
> +	int i;
> +
> +	dst = videobuf_to_vmalloc(&vb_buf->vb);
> +
> +	/* VBI collected buy the PGA starts at line 2, so we need to put
> +	 * this in line 2 in the dest buffer.
> +	 */
> +	if (nr == 1) {
> +		dst += (vb_buf->vb.width);
> +		dst += (vb_buf->vb.width) * 21;
> +	}
> +
> +	y  = (py + ((fmt->width * (fmt->height / 2)) * nr));
> +	if (nr == 1)
> +		y += (fmt->width * fmt->vbi_field0_lines);
> +
> +	/* We're going to deinterlace in dwords */
> +	/* We're going to deinterlace 4 dwords at a time, 8 pixels per cycle */
> +
> +	/* Process a single field of vbi data, 17 lines max */
> +	for (i = 0; i < 22; i++)
> +		memcpy(dst + (i * 1440), y + (i * fmt->width), 720);
> +}
> +
> +void vc8x0_process_video_field(u8 *py, u8 *pu, u8 *pv,
> +	struct vc8x0_buffer *vb_buf, int nr,
> +	u32 vbi_enabled, struct vc8x0_format *fmt)
> +{
> +	u32 px[4];
> +	u32 yp, up, vp;
> +	u8 *dst = 0;
> +	u32 *ddst = 0;
> +	u32 *y, *u, *v;
> +	u32 ymax;
> +	int i, pixelcount;
> +
> +	dst = videobuf_to_vmalloc(&vb_buf->vb);
> +	dst += ((vb_buf->vb.width * 2) * nr);
> +	ddst = (u32 *)dst;
> +
> +	y  = (u32 *)(py + ((vb_buf->vb.width * (vb_buf->vb.height / 2)) * nr));
> +	u  = (u32 *)(pu + (((vb_buf->vb.width / 2) *
> +		(vb_buf->vb.height / 2)) * nr));
> +	v  = (u32 *)(pv + (((vb_buf->vb.width / 2) *
> +		(vb_buf->vb.height / 2)) * nr));
> +
> +	if (vbi_enabled) {
> +		/* VBI */
> +		if (nr == 0) {
> +			y += ((fmt->width * fmt->vbi_field0_lines) /
> +				sizeof(u32));
> +			u += (((fmt->width / 2) * fmt->vbi_field0_lines) /
> +				sizeof(u32));
> +			v += (((fmt->width / 2) * fmt->vbi_field0_lines) /
> +				sizeof(u32));
> +		} else {
> +			y += ((fmt->width * fmt->vbi_field0_lines) /
> +				sizeof(u32));
> +			u += (((fmt->width / 2) * fmt->vbi_field0_lines) /
> +				sizeof(u32));
> +			v += (((fmt->width / 2) * fmt->vbi_field0_lines) /
> +				sizeof(u32));
> +
> +			y += ((fmt->width * fmt->vbi_field1_lines) /
> +				sizeof(u32));
> +			u += (((fmt->width / 2) * fmt->vbi_field1_lines) /
> +				sizeof(u32));
> +			v += (((fmt->width / 2) * fmt->vbi_field1_lines) /
> +				sizeof(u32));
> +		}
> +	}
> +
> +	/* We're going to deinterlace in dwords */
> +	/* We're going to deinterlace 4 dwords at a time, 8 pixels per cycle */
> +
> +	/* Process a single field (height / 2) of width ant 8 pixels per time */
> +	ymax = ((vb_buf->vb.height / 2) * vb_buf->vb.width) / 8;
> +	for (i = 0, pixelcount = 0; i < ymax; i++, pixelcount += 8) {
> +
> +		if (pixelcount == (vb_buf->vb.width)) {
> +			ddst += (vb_buf->vb.width / 2);
> +			pixelcount = 0;
> +		}
> +
> +		/* highly optimized for intel i686 little endian, which is
> +		 * what the SOW calls for. */
> +		/* Input data in ram looks like:
> +		 * y_plane: Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8
> +		 * u_plane: U0 U1 U2 U3
> +		 * v_plane: V0 V1 V2 V3
> +		 *
> +		 * We shuffle these bytes into dwords ...
> +		 * px[0] = 0xV0Y1U0Y0
> +		 * px[1] = 0xV1Y3U1Y2
> +		 * px[2] = 0xV2Y5U2Y4
> +		 * px[3] = 0xV3Y7U3Y6
> +		 *
> +		 * and the dwords in little ending are stored back into a
> +		 * byte buffer,
> +		 * which then looks like:
> +		 * bytes 0 - 15 ->
> +		 * Y0 U0 Y1 V0  Y2 U1 Y3 V1  Y3 U2 Y4 V2  Y5 U3 Y6 V3
> +		 *
> +		 */
> +
> +		yp = *(y++);
> +		up = *(u++);
> +		vp = *(v++);
> +
> +		/* Pixels 1, 2 */
> +		/* Y0 xx Y1 xx */
> +		px[0] = (yp & 0x000000ff) | ((yp & 0x0000ff00) << 8);
> +
> +		/* xx U0 xx xx */
> +		px[0] |= ((up & 0x000000ff) << 8);
> +
> +		/* xx xx xx V0 */
> +		px[0] |= ((vp & 0x000000ff) << 24);
> +
> +		/* Pixels 3, 4 */
> +		/* Y0 xx Y1 xx */
> +		px[1] = ((yp & 0x00ff0000) >> 16) | ((yp & 0xff000000) >> 8);
> +
> +		/* xx U0 xx xx */
> +		px[1] |= (up & 0x0000ff00);
> +
> +		/* xx xx xx V0 */
> +		px[1] |= ((vp & 0x0000ff00) << 16);
> +
> +
> +		yp = *(y++);
> +
> +		/* Pixels 5, 6 */
> +		/* Y0 xx Y1 xx */
> +		px[2] = (yp & 0x000000ff) | ((yp & 0x0000ff00) << 8);
> +
> +		/* xx U0 xx xx */
> +		px[2] |= ((up & 0x00ff0000) >> 8);
> +
> +		/* xx xx xx V0 */
> +		px[2] |= ((vp & 0x00ff0000) << 8);
> +
> +
> +		/* Pixels 7, 8 */
> +		/* Y0 xx Y1 xx */
> +		px[3] = ((yp & 0x00ff0000) >> 16) | ((yp & 0xff000000) >> 8);
> +
> +		/* xx U0 xx xx */
> +		px[3] |= ((up & 0xff000000) >> 16);
> +
> +		/* xx xx xx V0 */
> +		px[3] |= (vp & 0xff000000);
> +
> +		/* clk the 8 pixels (4 dwords) into the videobuf image, now
> +		 * as YUYV422 */
> +
> +		*(ddst++) = px[0];
> +		*(ddst++) = px[1];
> +		*(ddst++) = px[2];
> +		*(ddst++) = px[3];
> +	}
> +}
> +

The above are format conversions!!! It should be at libv4l, and not on
Kernelspace.

> +			if (fmt->flags == ADV7441A_FORMAT_INTERLACED) {
> +
> +				vc8x0_process_video_field(
> +					buf->cpu_y_plane,
> +					buf->cpu_u_plane,
> +					buf->cpu_v_plane,
> +					vb_buf,
> +					0,
> +					channel->vbi_enabled,
> +					fmt);
> +				vc8x0_process_video_field(
> +					buf->cpu_y_plane,
> +					buf->cpu_u_plane,
> +					buf->cpu_v_plane,
> +					vb_buf,
> +					1,
> +					channel->vbi_enabled,
> +					fmt);

Those in-kernel software format changing logic is not allowed.
Instead, add it video formats parsing into libv4l and output 
the format here as provided by the hardware.

> +
> +				if (channel->vbi_enabled) {
> +					spin_lock(&channel->vbi_capture_lock);
> +					do {
> +						if (list_empty(&channel->vbi_capture)) {
> +							break;
> +						}
> +
> +						vbi_buf = list_entry(channel->vbi_capture.next,
> +							struct vc8x0_buffer, vb.queue);
> +						dst = videobuf_to_vmalloc(&vbi_buf->vb);
> +						if (!dst)
> +							break;
> +						vc8x0_process_vbi_field(buf->cpu_y_plane, vbi_buf, 0, fmt);
> +						vc8x0_process_vbi_field(buf->cpu_y_plane, vbi_buf, 1, fmt);

libv4l doesn't handle weird vbi formats, so, while this is ugly,
we might accept it if there isn't any other clean way of doing it.

> +
> +						do_gettimeofday(&vbi_buf->vb.ts);

We're not using gettimeofday() anymore, as the time is not
monotonic (e. g. it is affected by TZ). See the KS/2012 notes.

> +						list_del(&vbi_buf->vb.queue);
> +
> +						vbi_buf->vb.state = VIDEOBUF_DONE;
> +						wake_up(&vbi_buf->vb.done);
> +
> +						/* re-set the buffer timeout */
> +						mod_timer(&channel->vbi_timeout,
> +							jiffies + (HZ / 2));
> +
> +					} while (0);
> +					spin_unlock(&channel->vbi_capture_lock);
> +				}
> +
> +			} else
> +			if (fmt->flags == ADV7441A_FORMAT_PROGRESSIVE) {
> +				for (i = 0, j = 0; i < (vb_buf->vb.height *
> +					vb_buf->vb.width); i++, j += 2) {
> +					crc += *(buf->cpu_y_plane + i);
> +					*(pdst + j + 0) =
> +						*(buf->cpu_y_plane + i);
> +				}
> +				for (i = 0, j = 1; i < ((vb_buf->vb.height *
> +					vb_buf->vb.width) / 2); i++, j += 4) {
> +					*(pdst + j + 0) =
> +						*(buf->cpu_u_plane + i);
> +					*(pdst + j + 2) =
> +						*(buf->cpu_v_plane + i);
> +				}

> +	spin_unlock_irqrestore(&channel->dma_buffers_dpc_lock, flags);
> +
> +	/* BAM! The interrupt handler is now free to move on */
> +	/* BAM! The interrupt handler is now free to move on */
> +	/* BAM! The interrupt handler is now free to move on */
> +	/* BAM! The interrupt handler is now free to move on */
> +
> +	/* Now let's dequeue the full buffers */
> +	/* For each full buffer, send it to user space */
> +	spin_lock(&channel->dma_buffers_full_lock);

Oh: That bambambambam comments again.... Looks weird, and I bet it will
cause dead locks as well.

> +	list_for_each_safe(p, q, &channel->dma_buffers_full) {
> +
> +		buf = list_entry(p, struct vc8x0_dma_buffer, list);
> +
> +		vc8x0_video_buffer_dequeue(buf);
> +
> +		spin_lock_irqsave(&channel->dma_buffers_busy_lock, flags);
> +		buf->state = STATE_BUSY;
> +		list_move_tail(&buf->list, &channel->dma_buffers_busy);
> +		spin_unlock_irqrestore(&channel->dma_buffers_busy_lock, flags);
> +
> +	}
> +	spin_unlock(&channel->dma_buffers_full_lock);
> +}
> +
> +int vc8x0_video_irqhandler(struct vc8x0_dma_channel *channel)
> +{
> +	struct vc8x0_dev *dev = channel->dev;
> +	struct vc8x0_dma_buffer *buf, *ts_buf;
> +	int handled = 0;
> +
> +	u32 lastidx = 0, vid_pciaddr = 0, ts_pciaddr = 0;
> +	u32 buflen, reg;
> +	unsigned long flags;
> +
> +	/* Process the interrupt */
> +
> +	channel->buffers_processed++;
> +	buflen = channel->fmt->width * channel->fmt->height * 2;
> +	if (buflen > MAX_USER_VIDEO_BUFFER_SIZE) {
> +		pr_err("%s() buffer length is corrupt (%x).\n",
> +			__func__, buflen);
> +		goto badaddr;
> +	}
> +
> +	/* Find the finished frame and locate it's pci address */
> +	lastidx = vc_read32(channel->regs.m_nLastFrameIndex);
> +	if ((lastidx < 1) || (lastidx > MAX_USER_VIDEO_BUFFERS)) {
> +		pr_err("%s() lastidx out of range, critical (%x).\n",
> +			__func__, lastidx);
> +		goto badaddr;
> +	}
> +
> +	if (channel->lastidx == lastidx) {
> +		/* We've already processed this frame, skip it,
> +		 * duplicate interrupt.
> +		 */
> +		goto out;
> +	}
> +	channel->lastidx = lastidx;
> +
> +	if (lastidx == 9)
> +		lastidx = 1;
> +	else
> +		lastidx++;
> +
> +	lastidx--;
> +
> +	reg = channel->regs.m_nYDmaAddrL + (lastidx * 6 * sizeof(u32));
> +	vid_pciaddr = vc_read32(reg);
> +
> +	reg = channel->regs.m_nYTSDmaAddrL + (lastidx * 2 * sizeof(u32));
> +	ts_pciaddr = vc_read32(reg);
> +
> +	dprintk(2, "%s() buf completed, reg=%x, vid_physical 0x%x\n",
> +		__func__, reg, vid_pciaddr);
> +	dprintk(2, "%s() ts_physical 0x%x, lastidx=%d\n",
> +		__func__, ts_pciaddr, lastidx);
> +
> +	/* Find the video buffer by address */
> +	buf = vc8x0_buffer_busy_get_by_address(channel,
> +		vid_pciaddr, TYPE_VIDEO);
> +	if (buf == 0) {
> +		dprintk(1, "%s() No busy video dma buffer for address 0x%x\n",
> +			__func__, vid_pciaddr);
> +		channel->buffers_bad_address++;
> +		goto badaddr;
> +	}
> +	buf->used_len = buflen;
> +
> +	/* Find the timestamp buffer by address */
> +	ts_buf = vc8x0_buffer_busy_get_by_address(channel,
> +		ts_pciaddr, TYPE_TIMESTAMP);
> +	if (ts_buf == 0) {
> +		dprintk(1,
> +		"%s() No busy timestamp dma buffer for address 0x%x\n",
> +			__func__, ts_pciaddr);
> +		channel->buffers_bad_address++;
> +		goto badaddr;
> +	}
> +	ts_buf->used_len = 0;
> +	dprintk(2, "%s() bufs completed vid %p nr=%d, ts %p nr=%d\n",
> +		__func__, buf, buf->nr, ts_buf, ts_buf->nr);
> +
> +	vc8x0_timestamp_validate(ts_buf, lastidx);
> +
> +	/* Put the buffer on the DPC list. This list is spinlock held very
> +	 * briefly so we're not going to be held up.
> +	 * The only person that holds the DPC spinlock is the deferred work
> +	 * queue. The only person that holds the busy spinlock is the
> +	 * interrupt handler.
> +	 * These spinlocks are also held briefly for reporting purposes in other
> +	 * parts of the driver but they are very timely.
> +	 */
> +	spin_lock_irqsave(&channel->dma_buffers_busy_lock, flags);
> +
> +	/* Last, put the buffer on the DPC list for our deferred
> +	 * worker to process */
> +	spin_lock_irqsave(&channel->dma_buffers_dpc_lock, flags);

How many locks are you using on those IRQ code? 3 locks? more?

I would try to rewrite the entire code to use just one, as otherwise,
you'll get dead locks.

> +	buf->state = STATE_DPC;
> +	list_move_tail(&buf->list, &channel->dma_buffers_dpc);
> +	spin_unlock_irqrestore(&channel->dma_buffers_dpc_lock, flags);
> +
> +	spin_unlock_irqrestore(&channel->dma_buffers_busy_lock, flags);
> +
> +	handled++;
> +badaddr:
> +	if (handled) {
> +		if (video_during_irq == 1) {
> +			/* Process video now, zero latency */
> +			vc8x0_video_work_handler(&channel->workhandler);
> +		} else {
> +			/* Process video via a deferred queue, with
> +			 * possible latencies */
> +			schedule_work(&channel->workhandler);
> +		}
> +	}
> +out:
> +	return handled;
> +}
> +


> +
> +static const struct v4l2_queryctrl no_ctl = {
> +	.name  = "42",
> +	.flags = V4L2_CTRL_FLAG_DISABLED,
> +};
> +
> +static struct vc8x0_ctrl vc8x0_ctls[] = {
> +	{
> +		.v = {
> +			.id            = V4L2_CID_BRIGHTNESS,
> +			.name          = "Brightness",
> +			.minimum       = -127,
> +			.maximum       = 128,
> +			.step          = 1,
> +			.default_value = 128,
> +			.type          = V4L2_CTRL_TYPE_INTEGER,
> +		},
> +	}, {
> +		.v = {
> +			.id            = V4L2_CID_CONTRAST,
> +			.name          = "Contrast",
> +			.minimum       = 0,
> +			.maximum       = 255,
> +			.step          = 1,
> +			.default_value = 128,
> +			.type          = V4L2_CTRL_TYPE_INTEGER,
> +		},
> +	}, {
> +		.v = {
> +			.id            = V4L2_CID_SATURATION,
> +			.name          = "Saturation",
> +			.minimum       = 0,
> +			.maximum       = 255,
> +			.step          = 1,
> +			.default_value = 128,
> +			.type          = V4L2_CTRL_TYPE_INTEGER,
> +		},
> +	}, {
> +		.v = {
> +			.id            = V4L2_CID_HUE,
> +			.name          = "Hue",
> +			.minimum       = 0,
> +			.maximum       = 255,
> +			.step          = 1,
> +			.default_value = 0,
> +			.type          = V4L2_CTRL_TYPE_INTEGER,
> +		},
> +	}, {
> +		.v = {
> +			.id            = V4L2_CID_AUDIO_MUTE,
> +			.name          = "Mute",
> +			.minimum       = 0,
> +			.maximum       = 1,
> +			.step          = 1,
> +			.default_value = 0,
> +			.type          = V4L2_CTRL_TYPE_BOOLEAN,
> +		},
> +	}, {
> +		.v = {
> +			.id            = V4L2_CID_AUDIO_VOLUME,
> +			.name          = "Volume",
> +			.minimum       = -4,
> +			.maximum       = 20,
> +			.step          = 1,
> +			.default_value = 5,
> +			.type          = V4L2_CTRL_TYPE_INTEGER,
> +		},
> +	}
> +};
> +static const int VC8X0_CTLS = ARRAY_SIZE(vc8x0_ctls);
> +
> +/* Must be sorted from low to high control ID! */
> +static const u32 vc8x0_user_ctrls[] = {
> +	V4L2_CID_USER_CLASS,
> +	V4L2_CID_BRIGHTNESS,
> +	V4L2_CID_CONTRAST,
> +	V4L2_CID_SATURATION,
> +	V4L2_CID_HUE,
> +	V4L2_CID_AUDIO_VOLUME,
> +	V4L2_CID_AUDIO_MUTE,
> +	0
> +};
> +
> +static const u32 *ctrl_classes[] = {
> +	vc8x0_user_ctrls,
> +	NULL
> +};
> +
> +static int vc8x0_set_tvnorm(struct vc8x0_dma_channel *channel, v4l2_std_id norm)
> +{
> +	dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
> +		__func__,
> +		(unsigned int)norm,
> +		v4l2_norm_to_name(norm));
> +
> +	if (norm & V4L2_STD_ATSC)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +

> +static int vc8x0_ctrl_query(struct v4l2_queryctrl *qctrl)
> +{
> +	int i;
> +
> +	if (qctrl->id < V4L2_CID_BASE ||
> +	    qctrl->id >= V4L2_CID_LASTP1)
> +		return -EINVAL;
> +	for (i = 0; i < VC8X0_CTLS; i++)
> +		if (vc8x0_ctls[i].v.id == qctrl->id)
> +			break;
> +	if (i == VC8X0_CTLS) {
> +		*qctrl = no_ctl;
> +		return 0;
> +	}
> +	*qctrl = vc8x0_ctls[i].v;
> +	return 0;
> +}
> +




> +static int vidioc_enum_frameintervals(struct file *file, void *priv,
> +	struct v4l2_frmivalenum *f)
> +{
> +	struct vc8x0_fh *fh = priv;
> +	struct vc8x0_dma_channel *channel  = fh->channel;
> +	int framerates[4] = { 25, 30, 50, 60 };

You'll need to add some logic here to handle 60Hz and 59.97Hz difference.

> +
> +	dprintk(1, "%s(index=%d)\n", __func__, f->index);
> +
> +	if ((f->index < 0) || (f->index >= 4))
> +		return -EINVAL;
> +
> +	f->type = V4L2_FRMSIZE_TYPE_DISCRETE;
> +	f->discrete.numerator = 1;
> +	f->discrete.denominator = framerates[f->index];
> +
> +	dprintk(1, "%s(index=%d) rate = %d/%d\n", __func__, f->index,
> +		f->discrete.numerator, f->discrete.denominator);
> +
> +	return 0;
> +}
> +


> +
> +static int vc8x0_querymenu(struct file *file, void *priv,
> +	struct v4l2_querymenu *m)
> +{
> +	return -EINVAL;

I think v4l2-compliance will not like it. Had you validate this driver
with the compliance tool? Could you please post the results?

> +}
> +
> +static int vc8x0_g_priority(struct file *file, void *priv,
> +	enum v4l2_priority *p)
> +{
> +	return -EINVAL;

Priority is handled by the V4L framework. Please implement it.

> +}
> +
> +static int vc8x0_log_status(struct file *file, void *priv)
> +{
> +	struct vc8x0_dma_channel *channel = ((struct vc8x0_fh *)priv)->channel;
> +	struct vc8x0_dev *dev = channel->dev;
> +
> +	v4l2_subdev_call(channel->sd_adv7441a, core, log_status);
> +	v4l2_subdev_call(dev->dma_channel[DMA_CHANNEL9].sd_pcm3052,
> +		core, log_status);
> +
> +	return 0;
> +}

I think this is only available with advanced debug.

> +
> +static const struct v4l2_file_operations video_fops = {
> +	.owner	       = THIS_MODULE,
> +	.open	       = vc8x0_video_open,
> +	.release       = vc8x0_video_close,
> +	.read	       = vc8x0_video_read,
> +	.poll          = vc8x0_video_poll,
> +	.mmap	       = vc8x0_video_mmap,
> +	.unlocked_ioctl = video_ioctl2,
> +};
> +
> +static const struct v4l2_ioctl_ops video_ioctl_ops = {
> +	.vidioc_querycap      = vidioc_querycap,
> +	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
> +	.vidioc_enum_frameintervals  = vidioc_enum_frameintervals,
> +	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
> +	.vidioc_try_fmt_vid_cap   = vc8x0_try_fmt_vid_cap,
> +	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
> +	.vidioc_reqbufs       = vidioc_reqbufs,
> +	.vidioc_querybuf      = vidioc_querybuf,
> +	.vidioc_qbuf          = vidioc_qbuf,
> +	.vidioc_dqbuf         = vidioc_dqbuf,
> +	.vidioc_s_std         = vc8x0_s_std,
> +	.vidioc_enum_input    = vidioc_enum_input,
> +	.vidioc_g_input       = vidioc_g_input,
> +	.vidioc_s_input       = vidioc_s_input,
> +	.vidioc_queryctrl     = vidioc_queryctrl,
> +	.vidioc_g_ctrl        = vidioc_g_ctrl,
> +	.vidioc_s_ctrl        = vidioc_s_ctrl,
> +	.vidioc_streamon      = vidioc_streamon,
> +	.vidioc_streamoff     = vidioc_streamoff,
> +	.vidioc_s_parm        = vc8x0_video_s_parm,
> +	.vidioc_g_parm        = vc8x0_video_g_parm,
> +/* Need this for VBI */
> +	.vidioc_g_fmt_vbi_cap   = vidioc_g_fmt_vbi_cap,
> +	.vidioc_g_std           = vc8x0_g_std,
> +	.vidioc_enumaudio	= vc8x0_g_audio,
> +	.vidioc_g_audio		= vc8x0_g_audio,
> +	.vidioc_s_audio		= vc8x0_s_audio,
> +	.vidioc_querymenu	= vc8x0_querymenu,
> +	.vidioc_g_priority	= vc8x0_g_priority,
> +	.vidioc_log_status	= vc8x0_log_status,

DV timings ioctl's are missing.

> +};
> +
> +static struct video_device vc8x0_vbi_template;
> +static struct video_device vc8x0_video_template = {
> +	.name		= "vc8x0-video",
> +	.fops		= &video_fops,
> +	.ioctl_ops	= &video_ioctl_ops,
> +#if 0
> +	/* If I set this to something valid then gstreamer fails
> +	 * to negotiate a reasonable std/fmt, but it fixes
> +	 * the v4l2 ATSC compliance test.
> +	 */
> +	.tvnorms	= V4L2_STD_NTSC_M,
> +#else
> +	/* We'll fail the ATSC compliance test but gstreamer will work. */
> +	.tvnorms	= 0,
> +#endif

That looks really weird. Ok, when HDMI is used, "NTSC" doesn't
make sense, but for the other inputs, it should be accepting it.


> +/* Enable this to enable bad register reads and verification */
> +#define ENABLE_BAD_READS 0
> +
> +/* Read 12 registers from the FPGA during interrupt handling */
> +#define ENABLE_MONITOR_REGISTERS 1
> +
> +/* ALSA adjustments */
> +#define ENABLE_ALSA 1
> +#define ENABLE_AUDIO_KEEPALIVE 1
> +#define ENABLE_AUDIO_DMA 1
> +#define ENABLE_ALSA_MIXER 1
> +#define ENABLE_ALSA_WORKAROUNDS 1

Oh... that defines appeared, finally! The best is to convert the
ones that actually make sense into CONFIG_foo, and maybe discarding
the others or convert them into debug stuff.

With that, I finished the review.

Please, next time you submit it, make sure to break the patch series
into something that makes easier for us to review. A big patch like
that is _really_ hard for review as, on the next step, I'll need to
re-read everything.

Thanks,
Mauro

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [GIT PULL] ViewCast O820E capture support added
  2012-09-14  2:09                             ` Mauro Carvalho Chehab
@ 2012-09-14  7:27                               ` Hans Verkuil
  0 siblings, 0 replies; 18+ messages in thread
From: Hans Verkuil @ 2012-09-14  7:27 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Mauro Carvalho Chehab, Steven Toth, Linux-Media

On Fri September 14 2012 04:09:42 Mauro Carvalho Chehab wrote:
> Em 13-09-2012 21:59, Mauro Carvalho Chehab escreveu:
> > Em Thu, 13 Sep 2012 20:23:42 -0300
> > Mauro Carvalho Chehab <mchehab@redhat.com> escreveu:
> > 
> >> Em 13-09-2012 20:19, Mauro Carvalho Chehab escreveu:
> >>> Em Sat, 18 Aug 2012 11:48:52 -0400
> >>> Steven Toth <stoth@kernellabs.com> escreveu:
> >>>
> >>>> Mauro, please read below, a new set of patches I'm submitting for merge.
> >>>>
> >>>> On Thu, Aug 16, 2012 at 2:49 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> >>>>> On Thu August 16 2012 19:39:51 Steven Toth wrote:
> >>>>>>>> So, I've ran v4l2-compliance and it pointed out a few things that I've
> >>>>>>>> fixed, but it also does a few things that (for some reason) I can't
> >>>>>>>> seem to catch. One particular test is on (iirc) s_fmt. It attempts to
> >>>>>>>> set ATSC but by ioctl callback never receives ATSC in the norm/id arg,
> >>>>>>>> it actually receives 0x0. This feels more like a bug in the test.
> >>>>>>>> Either way, I have some if (std & ATSC) return -EINVAL, but it still
> >>>>>>>> appears to fail the test.
> >>>>>>
> >>>>>> Oddly enough. If I set tvnorms to something valid, then compliance
> >>>>>> passes but gstreamer
> >>>>>> fails to run, looks like some kind of confusion about either the
> >>>>>> current established
> >>>>>> norm, or a failure to establish a norm.
> >>>>>>
> >>>>>> For the time being I've set tvnorms to 0 (with a comment) and removed
> >>>>>> current_norm.
> >>>>>
> >>>>> Well, this needs to be sorted, because something is clearly amiss.
> >>>>
> >>>> Agreed. I just can't see what's wrong. I may need your advise /
> >>>> eyeballs on this. I'd be willing to provide logs that show gstreamer
> >>>> accessing the driver and exiting. It needs fixed, I've tried, I just
> >>>> can't see why gstreamer fails.
> >>>>
> >>>> On the main topic of merge.... As promised, I spent quite a bit of
> >>>> time this week reworking the code based on the feedback. I also
> >>>> flattened all of these patches into a single patchset and upgraded to
> >>>> the latest re-org tree.
> >>>>
> >>>> The source notes describe in a little more detail the major changes:
> >>>> http://git.kernellabs.com/?p=stoth/media_tree.git;a=commit;h=f295dd63e2f7027e327daad730eb86f2c17e3b2c
> >>>>
> >>>> Mauro, so, I hereby submit for your review/merge again, the updated
> >>>> patchset. *** Please comment. ***
> >>>
> >>> I'll comment patch by patch. Let's hope the ML will get this email. Not sure,
> >>> as it tends to discard big emails like that.
> >>>
> >>> This is the comment of patch 1/4.
> >>>
> >>
> >> Patch 2 is trivial. It is obviously OK.
> >>
> >> Patch 3 also looked OK on my eyes.
> > 
> > Patch 4 will very likely be discarded by vger server, if everything is
> > added there. So, I'll drop the parts that weren't commented.
> > 
> > Anyway:
> > 
> >> Subject: [media] vc8x0: Adding support for the ViewCast O820E Capture Card.
> >> Cc: Linux Media Mailing List <linux-media@vger.kernel.org>
> >>
> >> A dual channel 1920x1080p60 PCIe x4 capture card, two DVI
> >> inputs capable of capturing DVI/HDMI, Component, Svideo, Composite
> >> and some VGA resolutions.
> > ...
> > 


> >> diff --git a/drivers/media/pci/vc8x0/vc8x0-display.c b/drivers/media/pci/vc8x0/vc8x0-display.c
> > 
> >> +struct letter_t {
> >> +	u8 *ptr;
> >> +	u8 data[8];
> >> +} charset[] = {
> >> + /* ' ' */ [0x20] = { 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, },
> >> + /* 00000000 */
> >> + /* 00000000 */
> >> + /* 00000000 */
> >> + /* 00000000 */
> >> + /* 00000000 */
> >> + /* 00000000 */
> >> + /* 00000000 */
> >> + /* 00000000 */
> >> + /* '!' */ [0x21] = { 0, { 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x04, 0x00 }, },
> >> + /* 00000100 */
> >> + /* 00000100 */
> >> + /* 00000100 */
> >> + /* 00000100 */
> >> + /* 00000000 */
> >> + /* 00000000 */
> >> + /* 00000100 */
> >> + /* 00000000 */
> > 
> > Charset???? No, please! If you really need a charset, take a look at the
> > vivi driver. It uses an already-existent Kernel charset. See:
> > 
> > 	static int __init vivi_init(void)
> > 	{
> > 		const struct font_desc *font = find_font("VGA8x16");
> > 
> > Not sure about the rest of the code here at vc8x0-display.c, but maybe you'll
> > find a similar code to it already coded. Where do you use it?

I think all this is just for debugging and should just be removed. It renders
debugging text in the frame.

> > diff --git a/drivers/media/pci/vc8x0/vc8x0-video.c b/drivers/media/pci/vc8x0/vc8x0-video.c
> 

> > +static int vc8x0_video_generate_osd(struct vc8x0_dma_channel *channel, u8 *dst)
> > +{
> > +#if 1
> > +	return 0;
> > +#else
> > +	/* Do some text rendering */
> > +	struct vc8x0_format *fmt = channel->ad7441_ctx.detected_fmt;
> > +	unsigned char tmp[256];
> > +	int ret;
> > +
> > +	ret = vc8x0_display_render_reset(&channel->display_ctx, dst,
> > +		channel->fmt->width);
> > +	if (ret < 0)
> > +		return ret;
> 
> Hmm... Are you using the *-display.c code for OSD? Not sure if it is
> a good idea to handle it like that.
> 
> Hans,
> 
> What do you think?
> 
> Yet, the code here is commented, but there's a hole driver there in order
> to implement OSD display, just bloating the driver's code... 

I think it can all be removed completely. It's not a real OSD, it just
renders text in a captured frame.

> > +static int vc8x0_log_status(struct file *file, void *priv)
> > +{
> > +	struct vc8x0_dma_channel *channel = ((struct vc8x0_fh *)priv)->channel;
> > +	struct vc8x0_dev *dev = channel->dev;
> > +
> > +	v4l2_subdev_call(channel->sd_adv7441a, core, log_status);
> > +	v4l2_subdev_call(dev->dma_channel[DMA_CHANNEL9].sd_pcm3052,
> > +		core, log_status);
> > +
> > +	return 0;
> > +}
> 
> I think this is only available with advanced debug.

No, this is always available. Only g/s_dbg_register are under advanced debug.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2012-09-14  7:28 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-12 23:16 [GIT PULL] ViewCast O820E capture support added Steven Toth
2012-08-13 14:04 ` Hans Verkuil
2012-08-13 14:46   ` Steven Toth
2012-08-13 15:49     ` Hans Verkuil
2012-08-13 17:36       ` Mauro Carvalho Chehab
2012-08-14 15:07         ` Steven Toth
2012-08-15 11:14           ` Hans Verkuil
2012-08-16 13:27             ` Steven Toth
2012-08-16 14:49               ` Hans Verkuil
2012-08-16 17:39                 ` Steven Toth
2012-08-16 18:49                   ` Hans Verkuil
2012-08-18 15:48                     ` Steven Toth
2012-08-18 18:56                       ` Hans Verkuil
2012-09-13 23:19                       ` Mauro Carvalho Chehab
2012-09-13 23:23                         ` Mauro Carvalho Chehab
2012-09-14  0:59                           ` Mauro Carvalho Chehab
2012-09-14  2:09                             ` Mauro Carvalho Chehab
2012-09-14  7:27                               ` Hans Verkuil

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.