]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] Big zoran driver update
authorRonald Bultje <rbultje@ronald.bitfreak.net>
Wed, 20 Aug 2003 07:30:34 +0000 (00:30 -0700)
committerLinus Torvalds <torvalds@home.osdl.org>
Wed, 20 Aug 2003 07:30:34 +0000 (00:30 -0700)
This is a patch for the video4linux unified zoran driver that has been
in the kernel since 2.4.5 or so.

It fixes the compile issues in the current 2.6.0-test3 unified zoran
driver (current one doesn't compile at all), and also updates its
version to what we have in CVS.  This adds support for new cards (e.g.
LML33R10 from LinuxMediaLabs and DC30+ from Pinnacle), fixes bugs in
cards that were already supported and generally improves capture
reliability.  Changes per file (in detail) are given below.

i2c-id.h:
  add some new IDs for new i2c drivers

pci_ids.h:
  add PCI IDs for each of the supported cards if it has any

saa7111.c, saa7110.c, adv7175.c, bt819.c, saa7185.c, bt856.c:
  update to whatever we've got in our CVS. For most, these are just
  "easiness" fixes that either add some better debug output, or that make
  maintainance for both 2.6.x and 2.4.x simpler for me. There's also some
  specific changes. E.g., in saa7110.c, we enable the VCR mode bits so we
  get a better image from VCR input. In all of them, we make debugging an
  insmod option rather than a compile-time option (this makes debugging
  for users a *lot* easier). Point is that I just want our latest CVS in
  here. Maintainance is going to be a personal horror-story if it's not.

vpx3220.c, saa7114.c, adv7170.c:
  new i2c ones (for respectively DC10/DC30, LML33R10 and again LML33R10)

zr36067.c:
  removed, the driver is now spread over multiple source files.

zoran*.[ch], zr36057.h
  spread-out source files. Also fixes lots of bugs, can't even start
  naming them all, you don't want that, neither do I. Just assume that it
  works better than it used to - it does.

  Nice things that aren't in the old driver: much more stable, supports
  DC30+, supports LML33R10, has proper locking/semaphores, supports
  multiple opens without races now, adapted to new i2c subsystem, v4l2
  support, Xv (hardware-scaled) overlay support, and a lot more.

  Oh, and this one actually compiles.

videocodec.[ch], zr360{16,50,60}.[ch]:
  new sublayer for the driver to unify how we handle the zr36060 chip
  (DC10(+)/LML33/LML33R10/Buz) and the zr36050/zr36016 (DC30(+)).

MAINTAINERS:
  add me as maintainer (I am).

Kconfig:
  add new cards, plus improve the descriptions.

Makefile:
  d'oh.

Zoran:
  documentation update.

Others:
  I don't think there are any.

Greg has gone over the i2c changes a long time ago, he agreed on all of
them. Gerd is supposed to take care of the v4l part, he has never
complained about any of them. Stability is good, we've fixed most issues
(there's still some out there, but nothing serious), lots better than in
the old driver. Also, the cards work much better than with the old
driver.

33 files changed:
Documentation/video4linux/Zoran
MAINTAINERS
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7170.c [new file with mode: 0644]
drivers/media/video/adv7175.c
drivers/media/video/bt819.c
drivers/media/video/bt856.c
drivers/media/video/saa7110.c
drivers/media/video/saa7111.c
drivers/media/video/saa7114.c [new file with mode: 0644]
drivers/media/video/saa7185.c
drivers/media/video/videocodec.c [new file with mode: 0644]
drivers/media/video/videocodec.h [new file with mode: 0644]
drivers/media/video/vpx3220.c [new file with mode: 0644]
drivers/media/video/zoran.h
drivers/media/video/zoran_card.c [new file with mode: 0644]
drivers/media/video/zoran_card.h [new file with mode: 0644]
drivers/media/video/zoran_device.c [new file with mode: 0644]
drivers/media/video/zoran_device.h [new file with mode: 0644]
drivers/media/video/zoran_driver.c [new file with mode: 0644]
drivers/media/video/zoran_procfs.c
drivers/media/video/zoran_procfs.h [new file with mode: 0644]
drivers/media/video/zr36016.c [new file with mode: 0644]
drivers/media/video/zr36016.h [new file with mode: 0644]
drivers/media/video/zr36050.c [new file with mode: 0644]
drivers/media/video/zr36050.h [new file with mode: 0644]
drivers/media/video/zr36057.h
drivers/media/video/zr36060.c [new file with mode: 0644]
drivers/media/video/zr36060.h
drivers/media/video/zr36067.c [deleted file]
include/linux/i2c-id.h
include/linux/pci_ids.h

index e1dda3e4ab14352376d25d47b125b4dca935786b..089143f5c4a135c4ca3699a968177328a66d0b58 100644 (file)
-DC10/DC10plus/LML33/Buz  Driver for Linux
-=========================================
+Frequently Asked Questions:
+===========================
+subject: unified zoran driver (zr360x7, zoran, buz, dc10(+), dc30(+), lml33)
+website: http://mjpeg.sourceforge.net/driver-zoran/
+
+1. What cards are supported
+1.1 What the TV decoder can do an what not
+1.2 What the TV encoder can do an what not
+2. How do I get this damn thing to work
+3. What mainboard should I use (or why doesn't my card work)
+4. Programming interface
+5. Applications
+6. Concerning buffer sizes, quality, output size etc.
+7. It hangs/crashes/fails/whatevers! Help!
+8. Maintainers/Contacting
+9. License
+
+===========================
+
+1. What cards are supported
+
+Iomega Buz, Linux Media Labs LML33/LML33R10, Pinnacle/Miro
+DC10/DC10+/DC30/DC30+ and related boards (available under various names).
+
+Iomega Buz:
+* Zoran zr36067 PCI controller
+* Zoran zr36060 MJPEG codec
+* Philips saa7111 TV decoder
+* Philips saa7185 TV encoder
+Drivers to use: videodev, i2c-core, i2c-algo-bit,
+                videocodec, saa7111, saa7185, zr36060, zoran
+Inputs/outputs: Composite and S-video
+Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
+Card number: 7
+
+Linux Media Labs LML33:
+* Zoran zr36067 PCI controller
+* Zoran zr36060 MJPEG codec
+* Brooktree bt819 TV decoder
+* Brooktree bt856 TV encoder
+Drivers to use: videodev, i2c-core, i2c-algo-bit,
+                videocodec, bt819, bt856, zr36060, zoran
+Inputs/outputs: Composite and S-video
+Norms: PAL (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
+Card number: 5
+
+Linux Media Labs LML33R10:
+* Zoran zr36067 PCI controller
+* Zoran zr36060 MJPEG codec
+* Philips saa7114 TV decoder
+* Analog Devices adv7170 TV encoder
+Drivers to use: videodev, i2c-core, i2c-algo-bit,
+                videocodec, saa7114, adv7170, zr36060, zoran
+Inputs/outputs: Composite and S-video
+Norms: PAL (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
+Card number: 6
+
+Pinnacle/Miro DC10(new):
+* Zoran zr36057 PCI controller
+* Zoran zr36060 MJPEG codec
+* Philips saa7110a TV decoder
+* Analog Devices adv7176 TV encoder
+Drivers to use: videodev, i2c-core, i2c-algo-bit,
+                videocodec, saa7110, adv7175, zr36060, zoran
+Inputs/outputs: Composite, S-video and Internal
+Norms: PAL, SECAM (768x576 @ 25 fps), NTSC (640x480 @ 29.97 fps)
+Card number: 1
+
+Pinnacle/Miro DC10+:
+* Zoran zr36067 PCI controller
+* Zoran zr36060 MJPEG codec
+* Philips saa7110a TV decoder
+* Analog Devices adv7176 TV encoder
+Drivers to use: videodev, i2c-core, i2c-algo-bit,
+               videocodec, sa7110, adv7175, zr36060, zoran
+Inputs/outputs: Composite, S-video and Internal
+Norms: PAL, SECAM (768x576 @ 25 fps), NTSC (640x480 @ 29.97 fps)
+Card number: 2
+
+Pinnacle/Miro DC10(old): *
+* Zoran zr36057 PCI controller
+* Zoran zr36050 MJPEG codec
+* Zoran zr36016 Video Front End or Fuji md0211 Video Front End (clone?)
+* Micronas vpx3220a TV decoder
+* mse3000 TV encoder or Analog Devices adv7176 TV encoder *
+Drivers to use: videodev, i2c-core, i2c-algo-bit,
+                videocodec, vpx3220, mse3000/adv7175, zr36050, zr36016, zoran
+Inputs/outputs: Composite, S-video and Internal
+Norms: PAL, SECAM (768x576 @ 25 fps), NTSC (640x480 @ 29.97 fps)
+Card number: 0
+
+Pinnacle/Miro DC30: *
+* Zoran zr36057 PCI controller
+* Zoran zr36050 MJPEG codec
+* Zoran zr36016 Video Front End
+* Micronas vpx3225d/vpx3220a/vpx3216b TV decoder
+* Analog Devices adv7176 TV encoder
+Drivers to use: videodev, i2c-core, i2c-algo-bit,
+                videocodec, vpx3220/vpx3224, adv7175, zr36050, zr36016, zoran
+Inputs/outputs: Composite, S-video and Internal
+Norms: PAL, SECAM (768x576 @ 25 fps), NTSC (640x480 @ 29.97 fps)
+Card number: 3
+
+Pinnacle/Miro DC30+: *
+* Zoran zr36067 PCI controller
+* Zoran zr36050 MJPEG codec
+* Zoran zr36016 Video Front End
+* Micronas vpx3225d/vpx3220a/vpx3216b TV decoder
+* Analog Devices adv7176 TV encoder
+Drivers to use: videodev, i2c-core, i2c-algo-bit,
+               videocodec, vpx3220/vpx3224, adv7175, zr36050, zr36015, zoran
+Inputs/outputs: Composite, S-video and Internal
+Norms: PAL, SECAM (768x576 @ 25 fps), NTSC (640x480 @ 29.97 fps)
+Card number: 4
+
+Note: No module for the mse3000 is available yet
+Note: No module for the vpx3224 is available yet
+Note: use encoder=X or decoder=X for non-default i2c chips (see i2c-id.h)
+
+===========================
+
+1.1 What the TV decoder can do an what not
+
+The best know TV standards are NTSC/PAL/SECAM. but for decoding a frame that
+information is not enough. There are several formats of the TV standards.
+And not every TV decoder is able to handle every format. Also the every 
+combination is supported by the driver. There are currently 11 different 
+tv broadcast formats all aver the world. 
+
+The CCIR defines parameters needed for broadcasting the signal. 
+The CCIR has defined different standards: A,B,D,E,F,G,D,H,I,K,K1,L,M,N,...
+The CCIR says not much about about the colorsystem used !!!
+And talking about a colorsystem says not to much about how it is broadcast.
+
+The CCIR standards A,E,F are not used any more.
+
+When you speak about NTSC, you usually mean the standard: CCIR - M using
+the NTSC colorsystem which is used in the USA, Japan, Mexico, Canada
+and a few others. 
+
+When you talk about PAL, you usually mean: CCIR - B/G using the PAL
+colorsystem which is used in many Countries. 
+
+When you talk about SECAM, you mean: CCIR - L using the SECAM Colorsystem 
+which is used in France, and a few others.
+
+There the other version of SECAM, CCIR - D/K is used in Bulgaria, China,
+Slovakai, Hungary, Korea (Rep.), Poland, Rumania and a others. 
+
+The CCIR - H uses the PAL colorsystem (sometimes SECAM) and is used in 
+Egypt, Libya, Sri Lanka, Syrain Arab. Rep.
+
+The CCIR - I uses the PAL colorsystem, and is used in Great Britain, Hong Kong,
+Ireland, Nigeria, South Africa.
+
+The CCIR - N uses the PAL colorsystem and PAL frame size but the NTSC framerate,
+and is used in Argentinia, Uruguay, an a few others
+
+We do not talk about how the audio is broadcast !
+
+A rather good sites about the TV standards are: 
+http://www.sony.jp/ServiceArea/Voltage_map/
+http://info.electronicwerkstatt.de/bereiche/fernsehtechnik/frequenzen_und_normen/Fernsehnormen/
+and http://www.cabl.com/restaurant/channel.html
+
+Other weird things around: NTSC 4.43 is a modificated NTSC, which is mainly
+used in PAL VCR's that are able to play back NTSC. PAL 60 seems to be the same
+as NTSC 4.43 . The Datasheets also talk about NTSC 44, It seems as if it would 
+be the same as NTSC 4.43. 
+NTSC Combs seems to be a decoder mode where the decoder uses a comb filter
+to split coma and luma instead of a Delay line.
+
+But I did not defiantly find out what NTSC Comb is.
+
+Philips saa7111 TV decoder
+was introduced in 1997, is used in the BUZ and 
+can handle: PAL B/G/H/I, PAL N, PAL M, NTSC M, NTSC N, NTSC 4.43 and SECAM 
+
+Philips saa7110a TV decoder
+was introduced in 1995, is used in the Pinnacle/Miro DC10(new), DC10+ and
+can handle: PAL B/G, NTSC M and SECAM 
+
+Philips saa7114 TV decoder
+was introduced in 2000, is used in the LML33R10 and  
+can handle: PAL B/G/D/H/I/N, PAL N, PAL M, NTSC M, NTSC 4.43 and SECAM
+
+Brooktree bt819 TV decoder
+was introduced in 1996, and is used in the LML33 and
+can handle: PAL B/D/G/H/I, NTSC M
+
+Micronas vpx3220a TV decoder
+was introduced in 1996, is used in the DC30 and DC30+ and
+can handle: PAL B/G/H/I, PAL N, PAL M, NTSC M, NTSC 44, PAL 60, SECAM,NTSC Comb
+
+===========================
+
+1.2 What the TV encoder can do an what not
+
+The TV encoder are doing the "same" as the decoder, but in the oder direction.
+You feed them digital data and the generate a Composite or SVHS signal.
+For information about the colorsystems and TV norm take a look in the
+TV decoder section.
+
+Philips saa7185 TV Encoder
+was introduced in 1996, is used in the BUZ
+can generate: PAL B/G, NTSC M
+
+Brooktree bt856 TV Encoder
+was introduced in 1994, is used in the LML33 
+can generate: PAL B/D/G/H/I/N, PAL M, NTSC M, PAL-N (Argentina)
+
+Analog Devices adv7170 TV Encoder
+was introduced in 2000, is used in the LML300R10
+can generate: PAL B/D/G/H/I/N, PAL M, NTSC M, PAL 60
 
-by Rainer Johanni <Rainer@Johanni.de> (for Iomega Buz Driver)
+Analog Devices adv7175 TV Encoder
+was introduced in 1996, is used in the DC10, DC10+, DC10 old, DC30, DC30+
+can generate: PAL B/D/G/H/I/N, PAL M, NTSC M
 
-Adapted for DC10/DC10plus by Wolfgang Scherr <scherr@net4you.net>
-
-Further changes for DC10/DC10plus and LML33 cards by
-Serguei Miridonov <mirsev@cicese.mx>
-
-Current homepage: http://www.cicese.mx/~mirsev/Linux/DC10plus/
-Current maintainer: Serguei Miridonov <mirsev@cicese.mx>
-
-  This is a driver for DC10plus capture cards from Pinnacle Systems
-  Inc., LML33 cards from Linux Media Labs and Buz from Iomega.
-  It also works with many old Miro DC10 cards with SAA7110A TV decoder
-  and ADV7176 TV encoder (please, make sure that your card has these
-  chips, otherwise the driver will not work).
-
-  The driver is Video4Linux compliant and contains extensions to
-  provide hardware support for full motion MJPEG compression and
-  decompression. Since this driver is a derivative from the driver for
-  Buz Iomega cards written by Dr. Rainer Johanni,
-  http://www.johanni.de/munich-vision/buz/ they both have compatible
-  API. I hope that this API will become a part of V4L standard.
-
-Copyright: This driver is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License. Please,
-check http://www.gnu.org/ for details.
-
-No warranty: This software is provided on AN "AS-IS" basis WITHOUT
-WARRANTY OF ANY KIND. YOU USE IT AT YOUR OWN RISK.
-
-
-
-CONTENTS
-~~~~~~~~
-
-Supported Formats
-Hardware compression
-Compiling and Loading the Driver
-Driver Options
-Tested applications
-Programming interface
-Features for testing
-Mailing lists
-Bug Reports
-
-
-Supported Formats
-=================
-
-Card:              DC10/DC10plus             LML33/Buz
-
-TV standard:       NTSC/PAL/SECAM(*)         NTSC/PAL
-
-Format:            Square pixel              CCIR.601
-                   640x480 NTSC              720x480 NTSC
-                   768x576 PAL/SECAM(*)      720x576 PAL
-
-Frame rates: 30 frames/60 fields per second NTSC
-             25 frames/50 fields per second PAL/SECAM(*)
-
-(*) - SECAM is supported for input only in DC10/DC10plus cards. The
-output of the recorded SECAM video stream will be in PAL standard.
-Also, please, note that monitoring of the SECAM input signal at the
-DC10/DC10plus analog output may not be available. Please, use
-appropriate application like XawTV to watch full color SECAM video at
-the card input.
-
-Hardware compression
-====================
-
-Since the card provides hardware compression, even low end machines can
-be successfully used for movie capture and playback. I'm testing the
-driver with with 2.2.16 kernel running on 233 MHz Pentium MMX with 64M
-RAM on 430TX motherboard and with 10GB IDE drive from Western Digital
-Corp.
-
-On one test run with DC10plus card I've got 0 frames dropped during
-about 20 minutes of full motion NTSC (I live in Mexico) video capture
-with fully synchronized audio. The command was
-
-  lavrec -fa -in -d1 -l -1 -q30 -w /dos/g/capture/Linux/test%03d.avi
-
-for recording, and
-
-  lavplay -n128 /dos/g/capture/Linux/test*.avi
-
-for playback. (See lavtools distribution for more information).
-
-Typical run of similar test can provide as few as 6-8 dropped frames per
-half of an hour. You mileage may vary, though.
-
-Compiling and Loading the Driver
-================================
-
-You should run a 2.2.x kernel in order to use this driver. The driver
-was also tested with 2.4-test6 kernel, so hopefully it will work
-with 2.4 kernels too.
-
-I would recommend to use only official kernels from www.kernel.org and
-its mirrors. Kernels supplied with some Linux distributions may be
-patched in some way to meet specific needs of particular Linux
-distributor and could be incompatible with this driver. As a driver
-maintainer, I am not able to follow every unofficial kernel release,
-and no unofficial kernels will be supported.
-
-Besides the files in this directory, the driver needs the 'videodev'
-and the 'i2c' module from the Linux kernel (i2c-old for 2.4 kernels).
-In order to get these modules available, enable module support for
-VIDEODEV and BTTV (which implies i2c) in your 2.2.x kernel
-configuration. You will find these devices in the menu "Character
-Devices" in your Kernel Configuration.
-
-In newer kernels (2.4) instead of BTTV you should enable support for
-Iomega Buz cards and for Zoran 36060/36067 chipset. This will include
-i2c or i2c-old modules and Buz/LML33 driver. However, instead of
-modules for Buz/LML33 driver from the kernel, use modules from _this_
-driver.
-
-To compile the driver, just type make.
-
-Before you load the driver you must have a video device at major device
-node 81. If you don't have it yet, do the following (as root!):
-
-cd /dev
-mknod video0 c 81 0
-ln -s video0 video
-
-If you have more than one card, add more nodes in /dev directory:
-
-mknod video1 c 81 1
-mknod video2 c 81 2
-...
-
-The driver should operate properly with several cards. It was tested
-with one DC10plus and one LML33 cards installed together and the driver
-correctly identifies both cards and works with both of them.
-
-Currently the driver does not support LML33 and Buz cards installed
-together in the same system. This will be fixed in future versions.
-
-Edit the 'update' script if you want to give the driver special options
-(see below for options descriptions) and then type (as root)
-
-./update <card_list>
-
-to insert all necessary modules into the kernel. <card_list> is a list of
-cards installed in your system separated by white space. Supported cards 
-are dc10, dc10plus, lml33, and buz. For example, if you have both dc10plus
-and lml33 cards, please type
-
-./update dc10 lml33
-
-If you want to make full use of the Video for Linux _uncompressed_
-grabbing facilities, you must either
-
-- obtain and install the "big_physarea patch" for your kernel and
-  set aside the necessary memory during boot time. There seem to be
-  several versions of this patch against various kernel versions
-  floating around in the net, you may obtain one e.g. from:
-  http://www.polyware.nl/~middelin/hob-v4l.html#bigphysarea
-  You also have to compile your driver AFTER installing that patch in
-  order to get it working
-
-  or
-
-- start your kernel with the mem=xxx option, where xxx is your
-  real memory minus the memory needed for the buffers.
-  For doing this add an entry in lilo.conf (if you use lilo):
-    append "mem=xxxM"
-  or add a line in your linux.par file (if you use loadlin):
-    mem=xxxM
-
-The second method is by far easier, however it is dangerous if more
-than one driver at a time has the idea to use the memory leftover by
-setting the mem=xxx parameter below the actual memory size.
-
-Read also below how to use this memory!
-
-
-  If you use only MJPEG compressed capture provided by the driver, you
-  should not need large memory areas for DMA. In this case, you will be
-  able to capture and playback movies with lavtools, however you will
-  not be able to use capture features of XawTV and other similar
-  programs (you can still watch video on the screen).
-
-
-
-Driver Options
-==============
-
-You are able to customize the behavior of the driver by giving
-it some options at start time.
-
-default_input, default_norm
----------------------------
-
-As soon as the driver is loaded, the Buz samples video signals
-from one of its input ports and displays it on its output.
-The driver uses the Composite Input and the video norm PAL for this.
-If you want to change this default behavior, set default_input=1
-(for S-VHS input) or default_norm=1 for NTSC or default_norm=2
-for SECAM (DC10/DC10plus only).
-
-lock_norm
----------
-
-This option was introduced to disable norm (TV standard) change by some
-not well behaving programs. For example, if you have some application
-which was written by somebody who lives in a country with PAL standard,
-this program may not have NTSC option and may always try to set the
-driver to PAL. In this case, you may load the driver with
-default_norm=1 and lock_norm=1 and the card will be forced to work in
-NTSC standard only.
-
-  Options:
-  
-  lock_norm=0   default, TV standard change is enabled;
-  lock_norm=1   TV standard change is disabled but the driver
-                will not notify the application about any error;
-  lock_norm=2   TV standard change is disabled and the driver
-                will notify the program that TV standards other
-                than set by default_norm=X option are not 
-                supported.
-
-pass_through
-------------
-
-When the driver is not in use (device is not opened by any program) and
-pass_through=0 (default) the driver will set the TV encoder to produce
-color bar signal at the output. If the driver was loaded with
-pass_through=1, the color bar will be disabled and input signal will be
-sent to the output even if the driver not in use. If you have LML33 card
-and wish the color bar signal at the output, you will also need to set
-lml33dpath=1 (please, see next section).
-
-lml33dpath
-----------
-
-LML33 card normally (lml33dpath=0) connects its output to the input
-using analog switch. Additionally, it also allows real-time monitoring
-of digitized video using TV monitor connected to the output. This
-"digital path" option can be enabled setting lml33dpath=1. In this
-mode, the input is connected only to the TV decoder, digital video data
-is sent via internal video bus to the TV encoder and resulting analog
-signal is sent to the output. This mode could be very useful for testing and
-picture adjustment while watching video at the TV monitor connected to
-the output. However, because of lack of 75 ohm terminating resistors at
-TV decoder input, the signal will suffer serious distortions.
-
-# These distortions could be eliminated by soldering two 75 ohm resistors
-# in LML33 card: in parallel to capacitors C73 and C82 (see schematics of
-# H33 board available at www.linuxmedialabs.com and www.zoran.com). Be
-# aware, however, that doing so will void card warranty and the card,
-# after this change, must always be used with loading option lml33dpath=1.
-# 
-# WARNING: I DID NOT TRY THIS CARD CHANGE YET, THIS IS JUST AN ASSUMPTION
-# AND I WILL NOT BE RESPONSIBLE FOR ANY DAMAGE ASSOCIATED WITH THIS
-# CHANGE. IF YOU WISH TO TRY IT, DO IT AT YOUR OWN RISK.
-
-Please, note that DC10/DC10plus cards always use "digital path" for
-signal monitoring. Its input and output are both properly terminated
-and the digitized signal quality does not depend on the connection of
-the output load.
-
-
-v4l_nbufs, v4l_bufsize
-----------------------
-
-In order to make to make full use of the Video for Linux uncompressed
-picture grabbing facilities of the driver (which are needed by many
-Video for Linux applications), the driver needs a set of physically
-contiguous buffers for grabbing. These parameters determine how many
-buffers of which size the driver will allocate at open (the open will
-fail if it is unable to do so!).
-
-These values do not affect the MJPEG grabbing facilities of the driver,
-they are needed for uncompressed image grabbing only!!!
-
-v4l_nbufs is the number of buffers to allocate, a value of 2 (the default)
-should be sufficient in almost all cases. Only special applications
-(streaming captures) will need more buffers and then mostly the
-MJPEG capturing features of the Buz will be more appropriate.
-So leave this parameter at it's default unless you know what you do.
-
-The things for v4l_bufsize are more complicated: v4l_bufsize is set by
-default to 128 [KB] which is the maximum amount of physically
-contiguous memory Linux is able to allocate without kernel changes.
-This is sufficient for grabbing 24 bit color images up to sizes of
-approx. 240x180 pixels (240*180*3 = 129600, 128 KB = 131072).
-
-In order to be able to capture bigger images you have either to
-- obtain and install the "big_physarea patch" and set aside
-  the necessary memory during boot time or
-- start your kernel with the mem=xxx option, where xxx is your
-  real memory minus the memory needed for the buffers.
-In that case, useful settings for v4l_bufsize are
-- 1296 [Kb] for grabbing 24 bit images of max size 768*576
-- 1728 [Kb] for 32bit images of same size (4*768*576 = 1728 Kb!)
-You may reduce these numbers accordingly if you know you are only
-grabbing 720 pixels wide images or NTSC images (max height 480).
-
-In some cases it may happen that Linux isn't even able to obtain
-the default 128 KB buffers. If you don't need uncompressed image
-grabbing at all, set v4l_bufsize to an arbitrary small value (e.g. 4)
-in order to be able to open the video device.
-
-triton, natoma
---------------
-
-The driver tries to detect if you have a triton or natoma chipset
-in order to take special measures for these chipsets.
-If this detection fails but you are sure you have such a chipset,
-set the corresponding variable to 1.
-This is a very special option and may go away in the future.
-
-
-Tested applications
-===================
-
-  XawTV         to watch video on your computer monitor.
-
-  kwintv        the same (you might need to use option lock_norm=1).
-  
-  lavtools      To record and playback AVI or Quicktime files. Note: you
-                will need patched version, lavtools-1.2p2 to support new
-                features of this driver. Please visit driver homepage for
-                more info.
-
-  Broadcast2000 reportedly (I didn't try that) can accept movies recorded
-                by lavrec in Quicktime format for editing and then edited
-                movie can be played back by lavplay program.
-
-  MainActor 3.5x also can accept movies recorded by lavrec for editing.
-
-
-The driver can to be used by two programs at the same time
-(please, see warning note below regarding this feature). Using XawTV
-you can watch what you are recording or playing back with lavtools.
-I've tested the following sequence and it worked for me:
-
-* start xawtv and switch inputs, TV standards, and adjust video
-  (contrast, saturation, etc.). You may also run your favorite
-  audio mixer application to adjust audio inputs.
-
-* run lavrec with options: 
-
-    -i<set your input and norm here> (to choose proper input
-                                      and TV standard)
-
-    -l -1  (to use audio mixer settings)
-
-    Other lavrec option can be added at your choice.
-
-* watch the movie in xawtv window while recording it as AVI or
-  Quicktime file.
-
-* when recording is finished, run lavplay or xlav and watch your
-  clip in xawtv window.
-
-* Note: you should not quit xawtv during recording or playing back.
-  If you quit xawtv during recording or playback, another lavtools
-  program will stop and may even crash.
-
-I'm not sure that the same will work for you. You can try but,
-please, be careful.
-
-WARNING! This is an experimental feature and I'm not sure if it will be
-supported in the future. The original driver was not designed to be
-used like this and it has no protection against any interference
-between two running programs. THEREFORE, IT IS POTENTIALLY DANGEROUS
-AND SINCE THE DRIVER OPERATES IN KERNEL SPACE, USING THIS FEATURE MAY
-CRASH YOUR ENTIRE SYSTEM.
-
-
-Programming interface
-=====================
-
-This driver should be fully compliant to Video for Linux, so all
-tools working with Video for Linux should work with (hopefully)
-no problems.
-
-A description of the Video for Linux programming interface can be found at:
+ITT mse3000 TV encoder
+was introduced in 1991, is used in the DC10 old
+can generate: PAL , NTSC , SECAM
+
+The adv717x, should be able to produce PAL N. But you find nothing PAL N 
+specific in the the registers. Seem that you have to reuse a other standard
+to generate PAL N, maybe it would work if you use the PAL M settings. 
+
+==========================
+
+2. How do I get this damn thing to work
+
+Load zoran.o. If it can't autodetect your card, use the card=X insmod
+option with X being the card number as given in the previous section.
+To have more than one card, use card=X1[,X2[,X3,[X4[..]]]]
+
+To automate this, add the following to your /etc/modules.conf:
+
+options zoran card=X1[,X2[,X3[,X4[..]]]]
+alias char-major-81-0 zoran
+
+One thing to keep in mind is that this doesn't load zoran.o itself yet. It
+just automates loading. If you start using xawtv, the device won't load on
+some systems, since you're trying to load modules as a user, which is not
+allowed ("permission denied"). A quick workaround is to add 'Load "v4l"' to
+XF86Config-4 when you use X by default, or to run 'v4l-conf -c <device>' in
+one of your startup scripts (normally rc.local) if you don't use X. Both
+make sure that the modules are loaded on startup, under the root account.
+
+===========================
+
+3. What mainboard should I use (or why doesn't my card work)
+
+<insert lousy disclaimer here>. In short: good=SiS/Intel, bad=VIA.
+
+Experience tells us that people with a Buz, on average, have more problems
+than users with a DC10+/LML33. Also, it tells us that people owning a VIA-
+based mainboard (ktXXX, MVP3) have more problems than users with a mainboard
+based on a different chipset. Here's some notes from Andrew Stevens:
+--
+Here's my experience of using LML33 and Buz on various motherboards:
+
+VIA MVP3
+       Forget it. Pointless. Doesn't work.
+Intel 430FX (Pentium 200) 
+       LML33 perfect, Buz tolerable (3 or 4 frames dropped per movie)
+Intel 440BX (early stepping)
+       LML33 tolerable. Buz starting to get annoying (6-10 frames/hour)
+Intel 440BX (late stepping)
+       Buz tolerable, LML3 almost perfect (occasional single frame drops)
+SiS735
+       LML33 perfect, Buz tolerable.
+VIA KT133(*)
+       LML33 starting to get annoying, Buz poor enough that I have up.
+
+Both 440BX boards were dual CPU versions.
+--
+Bernhard Praschinger later added:
+--
+AMD 751
+       Buz perfect-tolerable
+AMD 760
+       Buz perfect-tolerable
+--
+In general, people on the user mailinglist won't give you much of a chance
+if you have a VIA-based motherboard. They may be cheap, but sometimes, you'd
+rather want to spend some more money on better boards. In general, VIA
+mainboard's IDE/PCI performance will also suck badly compared to others.
+You'll noticed the DC10+/DC30+ aren't mentioned anywhere in the overview.
+Basically, you can assume that if the Buz works, the LML33 will work too. If
+the LML33 works, the DC10+/DC30+ will work too. They're most tolerant to
+different mainboard chipsets from all of the supported cards.
+
+If you experience timeouts during capture, buy a better mainboard or lower
+the quality/buffersize during capture (see 'Concerning buffer sizes, quality,
+output size etc.'). If it hangs, there's little we can do as of now. Check
+your IRQs and make sure the card has its own interrupts.
+
+===========================
+
+4. Programming interface
+
+This driver conforms to video4linux and video4linux2, both can be used to
+use the driver. Since video4linux didn't provide adequate calls to fully
+use the cards' features, we've introduced several programming extensions,
+which are currently officially accepted in the 2.4.x branch of the kernel.
+These extensions are known as the v4l/mjpeg extensions. See zoran.h for
+details (structs/ioctls).
+
+Information - video4linux:
 http://roadrunner.swansea.linux.org.uk/v4lapi.shtml
+/usr/src/linux/Documentation/video4linux/API.html
+/usr/include/linux/videodev.h
 
-Besides the Video for Linux interface, the driver has a "proprietary"
-interface for accessing the Buz's MJPEG capture and playback facilities.
+Information - video4linux/mjpeg extensions:
+./zoran.h
+(also see below)
 
-For a full description of all members and ioctls see "zoran.h" (used to
-be buz.h or dc10.h in previous versions, so, please, update your
-programs accordingly).
+Information - video4linux2:
+http://www.thedirks.org/v4l2/
+/usr/include/linux/videodev2.h
+http://www.bytesex.org/v4l/
 
+More information on the video4linux/mjpeg extensions, by Serguei
+Miridonovi and Rainer Johanni:
+--
 The ioctls for that interface are as follows:
 
 BUZIOC_G_PARAMS
@@ -434,7 +365,6 @@ data to disk (after BUZIOC_QBUF_CAPT) or for reuse (after BUZIOC_QBUF_PLAY).
 BUZIOC_G_STATUS
 
 Get the status of the input lines (video source connected/norm).
-This ioctl may be subject to change.
 
 For programming example, please, look at lavrec.c and lavplay.c code in
 lavtools-1.2p2 package (URL: http://www.cicese.mx/~mirsev/DC10plus/)
@@ -450,68 +380,178 @@ Additional notes for software developers:
    settings of a variety of TV capture cards which may work in ITU or
    square pixel format. Remember that users now can lock the norm to
    avoid any ambiguity.
-
-Features for testing
-====================
-
-When loaded, the driver creates a /proc/zoranX entry for each card:
-using 'cat /proc/zoran0' for your first card you can see the contents
-of ZR36057/67 chip registers. It is also possible to modify the
-contents of some registers directly. WARNING: modified contents is not
-stored in the driver memory, if you restart any program which uses this
-driver or even change position or cause redraw of a window of xawtv or
-other program, the original registers contents will be restored by the
-driver. However, it can be used to change ZR36067 registers on the fly
-for fine tuning and then to include these changes into driver code.
-This feature is very limited and still requires some documentation.
-However, if you are impatient, look at zoran_procfs.c code and
-(IMPORTANT!) read ZR36057/67 manual. To set TopField bit, for example,
-you need to type as root:
-
-echo TopField=1 > /proc/zoranX # change X to 0 for your first card,
-                               # 1 for second and so on...
-
-If you use this feature and have found some interesting result, please, let
-me know.
-
-Mailing lists
-=============
-
-There are two mailing lists available to discuss application issues and
-suggest driver improvements:
-
-1. A mailing list buz-linux was set up to discuss Iomega Buz driver.
-Since this driver is derivative of that driver, you can also post your
-questions and suggestions there. Subscribe with a message (with
-"subscribe" in the subject) to  buz-linux-subscribe@webmages.com.
-Unsubscribe with a message (with "unsubscribe" in the subject) to
-buz-linux-unsubscribe@webmages.com. The mailing list archive can be
-found at http://buz.webmages.com/list/. 
-
-2. Video4Linux mailing list is set for more general discussions related
-to uncompressed video capture, V4L and V4L2 API, many Video4Linux
-applications, etc. to subscribe to this mailing list, please, visit
-https://listman.redhat.com/mailman/listinfo/video4linux-list
-
-Bug Reports
-===========
-
-If you have found a bug, please, do the following:
-
-1. Edit first line of zoran.c file and set DEBUGLEVEL to 3;
-2. Recompile the driver and install it running update script
-   in the driver directory;
-3. Run the application(s) which you used when you had found a
-   suspisious behavior;
-4. When application stops, look at you /var/log/messages file
-   (or whatever file you use to log kernel messages) and copy
-   all lines related to the driver activity to a separate file
-   in the same order of their appearence in your log file.
-5. Mail a message to <mirsev@cicese.mx> with a subject
-   "Linux DC10(plus)/LML33/Buz driver bug report" with a detailed
-   description of your problem, kernel version, application name and
-   attach that file with kernel messages as plain text (please, don't
-   attach it using base64, uuencode, or any other encoding).
-   
-   If you have a Buz card, please, also mail the same message to
-   Wolfgang Scherr <scherr@net4you.net>
+--
+Please note that lavplay/lavrec are also included in the MJPEG-tools
+(http://mjpeg.sf.net/).
+
+===========================
+
+5. Applications
+
+Applications known to work with this driver:
+
+TV viewing:
+* xawtv
+* kwintv
+* probably any TV application that supports video4linux or video4linux2.
+
+MJPEG capture/playback:
+* mjpegtools/lavtools (or Linux Video Studio)
+* gstreamer
+* mplayer
+
+General raw capture:
+* xawtv
+* gstreamer
+* probably any application that supports video4linux or video4linux2
+
+Video editing:
+* Cinelerra
+* MainActor
+* mjpegtools (or Linux Video Studio)
+
+===========================
+
+6. Concerning buffer sizes, quality, output size etc.
+
+The zr36060 can do 1:2 JPEG compression. This is really the theoretical
+maximum that the chipset can reach. The driver can, however, limit compression
+to a maximum (size) of 1:4. The reason for this is that some cards (e.g. Buz)
+can't handle 1:2 compression without stopping capture after only a few minutes.
+With 1:4, it'll mostly work. If you have a Buz, use 'low_bitrate=1' to go into
+1:4 max. compression mode.
+
+100% JPEG quality is thus 1:2 compression in practice. So for a full PAL frame
+(size 720x576). The JPEG fields are stored in YUY2 format, so the size of the
+fields are 720x288x16/2 bits/field (2 fields/frame) = 207360 bytes/field x 2 =
+414720 bytes/frame (add some more bytes for headers and DHT (huffman)/DQT
+(quantization) tables, and you'll get to something like 512kB per frame for
+1:2 compression. For 1:4 compression, you'd have frames of half this size.
+
+Some additional explanation by Martin Samuelsson, which also explains the
+importance of buffer sizes:
+--
+> Hmm, I do not think it is really that way. With the current (downloaded
+> at 18:00 Monday) driver I get that output sizes for 10 sec:
+> -q 50 -b 128 : 24.283.332 Bytes
+> -q 50 -b 256 : 48.442.368
+> -q 25 -b 128 : 24.655.992
+> -q 25 -b 256 : 25.859.820
+
+I woke up, and can't go to sleep again. I'll kill some time explaining why 
+this doesn't look strange to me.
+
+Let's do some math using a width of 704 pixels. I'm not sure whether the Buz 
+actually use that number or not, but that's not too important right now.
+
+704x288 pixels, one field, is 202752 pixels. Divided by 64 pixels per block; 
+3168 blocks per field. Each pixel consist of two bytes; 128 bytes per block; 
+1024 bits per block. 100% in the new driver mean 1:2 compression; the maximum 
+output becomes 512 bits per block. Actually 510, but 512 is simpler to use 
+for calculations.
+
+Let's say that we specify d1q50. We thus want 256 bits per block; times 3168 
+becomes 811008 bits; 101376 bytes per field. We're talking raw bits and bytes 
+here, so we don't need to do any fancy corrections for bits-per-pixel or such 
+things. 101376 bytes per field.
+
+d1 video contains two fields per frame. Those sum up to 202752 bytes per 
+frame, and one of those frames goes into each buffer.
+
+But wait a second! -b128 gives 128kB buffers! It's not possible to cram 
+202752 bytes of JPEG data into 128kB!
+
+This is what the driver notice and automatically compensate for in your 
+examples. Let's do some math using this information:
+
+128kB is 131072 bytes. In this buffer, we want to store two fields, which 
+leaves 65536 bytes for each field. Using 3168 blocks per field, we get 
+20.68686868... available bytes per block; 165 bits. We can't allow the 
+request for 256 bits per block when there's only 165 bits available! The -q50 
+option is silently overridden, and the -b128 option takes precedence, leaving 
+us with the equivalence of -q32.
+
+This gives us a data rate of 165 bits per block, which, times 3168, sums up 
+to 65340 bytes per field, out of the allowed 65536. The current driver has 
+another level of rate limiting; it won't accept -q values that fill more than 
+6/8 of the specified buffers. (I'm not sure why. "Playing it safe" seem to be 
+a safe bet. Personally, I think I would have lowered requested-bits-per-block 
+by one, or something like that.) We can't use 165 bits per block, but have to 
+lower it again, to 6/8 of the available buffer space: We end up with 124 bits 
+per block, the equivalence of -q24. With 128kB buffers, you can't use greater 
+than -q24 at -d1. (And PAL, and 704 pixels width...)
+
+The third example is limited to -q24 through the same process. The second 
+example, using very similar calculations, is limited to -q48. The only 
+example that actually grab at the specified -q value is the last one, which 
+is clearly visible, looking at the file size.
+--
+
+Conclusion: the quality of the resulting movie depends on buffer size, quality,
+whether or not you use 'low_bitrate=1' as insmod option for the zr36060.c
+module to do 1:4 instead of 1:2 compression, etc.
+
+If you experience timeouts, lowering the quality/buffersize or using
+'low_bitrate=1 as insmod option for zr36060.o might actually help, as is
+proven by the Buz.
+
+===========================
+
+7. It hangs/crashes/fails/whatevers! Help!
+
+Make sure that the card has its own interrupts (see /proc/interrupts), check
+the output of dmesg at high verbosity (load zoran.o/zr36067.o with debug=2,
+load all other modules with debug=1). Check that your mainboard is favorable
+(see question 2) and if not, test the card in another computer. Also see the
+notes given in question 3 and try lowering quality/buffersize/capturesize
+if recording fails after a period of time.
+
+If all this doesn't help, give a clear description of the problem including
+detailed hardware information (memory+brand, mainboard+chipset+brand, which
+MJPEG card, processor, other PCI cards that might be of interest), give the
+system PnP information (/proc/interrupts, /proc/dma, /proc/devices), and give
+the kernel version, driver version, glibc version, gcc version and any other
+information that might possibly be of interest. Also provide the dmesg output
+at high verbosity. See 'Contacting' on how to contact the developers.
+
+===========================
+
+8. Maintainers/Contacting
+
+The driver is currently maintained by Laurent Pinchart and Ronald Bultje
+(<laurent.pinchart@skynet.be> and <rbultje@ronald.bitfreak.net>). For bug
+reports or questions, please contact the mailinglist instead of the developers
+individually. For user questions (i.e. bug reports or how-to questions), send
+an email to <mjpeg-users@lists.sf.net>, for developers (i.e. if you want to
+help programming), send an email to <mjpeg-developer@lists.sf.net>. See
+http://www.sf.net/projects/mjpeg/ for subscription information.
+
+For bug reports, be sure to include all the information as described in
+the section 'It hangs/crashes/fails/whatevers! Help!'. Please make sure
+you're using the latest version (http://mjpeg.sf.net/driver-zoran/).
+
+Previous maintainers/developers of this driver include Serguei Miridonov
+<mirsev@cicese.mx>, Wolfgang Scherr <scherr@net4you.net>, Dave Perks
+<dperks@ibm.net> and Rainer Johanni <Rainer@Johanni.de>.
+
+===========================
+
+9. License
+
+This driver is distributed under the terms of the General Public License.
+
+    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.
+
+See http://www.gnu.org/ for more information.
index 7e98b242ae60d377e6b9401d5bd9d0fa0bfe1582..63e80a34b5696fd0f43a6114bb6dc305fb62adad 100644 (file)
@@ -2249,6 +2249,13 @@ M:       fuganti@netbank.com.br
 W:     http://cvs.conectiva.com.br/drivers/ZFL-watchdog/
 S:     Maintained
 
+ZR36067 VIDEO FOR LINUX DRIVER
+P:     Ronald Bultje
+M:     R.S.Bultje@pharm.uu.nl
+L:     mjpeg-users@lists.sourceforge.net
+W:     http://mjpeg.sourceforge.net/driver-zoran/
+S:     Maintained
+
 ZR36120 VIDEO FOR LINUX DRIVER
 P:     Pauline Middelink
 M:     middelin@polyware.nl
index 54aef443539cdc97b326d84b311969465800450d..50e706e6a0e81be0b24f29ad4a2bf8d241e7ea15 100644 (file)
@@ -160,33 +160,54 @@ config VIDEO_STRADIS
          <http://www.stradis.com/decoder.html>.
 
 config VIDEO_ZORAN
-       tristate "Zoran ZR36057/36060 Video For Linux"
+       tristate "Zoran ZR36057/36067 Video For Linux"
        depends on VIDEO_DEV && PCI && I2C
        help
-         Say Y here to include support for video cards based on the Zoran
-         ZR36057/36060 encoder/decoder chip (including the Iomega Buz and the
-         Miro DC10 and DC30 video capture cards).
+         Say Y for support for MJPEG capture cards based on the Zoran
+         36057/36067 PCI controller chipset. This includes the Iomega
+         Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is
+         a driver homepage at <http://mjpeg.sf.net/driver-zoran/>. For
+         more information, check <file:Documentation/video4linux/Zoran>.
 
+         This driver is available as a module called zr36067 ( = code
+         which can be inserted in and removed from the running kernel
+         whenever you want). If you want to compile it as a module, say M
+         here and read <file:Documentation/modules.txt>.
 config VIDEO_ZORAN_BUZ
        tristate "Iomega Buz support"
        depends on VIDEO_ZORAN
        help
-         Say Y here to include support for the Iomega Buz video card.  There
-         is a Buz/Linux homepage at <http://www.lysator.liu.se/~gz/buz/>.
+         Support for the Iomega Buz MJPEG capture/playback card.
 
 config VIDEO_ZORAN_DC10
-       tristate "Miro DC10(+) support"
+       tristate "Pinnacle/Miro DC10(+) support"
        depends on VIDEO_ZORAN
        help
-         Say Y to support the Pinnacle Systems Studio DC10 plus TV/Video
-         card.  Vendor page at <http://www.pinnaclesys.com/>.
+         Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
+         card.
+
+config VIDEO_ZORAN_DC30
+       tristate "Pinnacle/Miro DC30(+) support"
+       depends on VIDEO_ZORAN
+       help
+         Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
+         card. This also supports really old DC10 cards based on the
+         zr36050 MJPEG codec and zr36016 VFE.
 
 config VIDEO_ZORAN_LML33
        tristate "Linux Media Labs LML33 support"
        depends on VIDEO_ZORAN
        help
-         Say Y here to support the Linux Media Labs LML33 TV/Video card.
-         Resources page is at <http://www.linuxmedialabs.com/lml33doc.html>.
+         Support for the Linux Media Labs LML33 MJPEG capture/playback
+         card.
+
+config VIDEO_ZORAN_LML33R10
+       tristate "Linux Media Labs LML33R10 support"
+       depends on VIDEO_ZORAN
+       help
+         support for the Linux Media Labs LML33R10 MJPEG capture/playback
+         card.
 
 config VIDEO_ZR36120
        tristate "Zoran ZR36120/36125 Video For Linux"
index 4b853d292d055b0fbfba56bb6abb4f84cbc33e70..0ccad83079171794b8e3a1de4645b6ea78496f4a 100644 (file)
@@ -5,6 +5,8 @@
 bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
                        bttv-risc.o bttv-vbi.o
 zoran-objs      :=     zr36120.o zr36120_i2c.o zr36120_mem.o
+zr36067-objs   :=      zoran_procfs.o zoran_device.o \
+                       zoran_driver.o zoran_card.o
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o
 
@@ -17,10 +19,13 @@ obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
 obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
 obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
 obj-$(CONFIG_VIDEO_W9966) += w9966.o
-obj-$(CONFIG_VIDEO_ZORAN_BUZ) += saa7111.o saa7185.o
-obj-$(CONFIG_VIDEO_ZORAN_DC10) += saa7110.o adv7175.o
-obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o
-obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o
+obj-$(CONFIG_VIDEO_ZORAN_BUZ) += saa7111.o saa7185.o zr36060.o
+obj-$(CONFIG_VIDEO_ZORAN_DC10) += saa7110.o adv7175.o zr36060.o
+obj-$(CONFIG_VIDEO_ZORAN_DC30) += adv7175.o vpx3220.o zr36050.o \
+       zr36016.o
+obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o zr36060.o
+obj-$(CONFIG_VIDEO_ZORAN_LML33R10) += saa7114.o adv7170.o zr36060.o
+obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
 obj-$(CONFIG_VIDEO_PMS) += pms.o
 obj-$(CONFIG_VIDEO_PLANB) += planb.o
 obj-$(CONFIG_VIDEO_VINO) += vino.o
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
new file mode 100644 (file)
index 0000000..fabd43b
--- /dev/null
@@ -0,0 +1,537 @@
+/* 
+ * adv7170 - adv7170, adv7171 video encoder driver version 0.0.1
+ *
+ * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
+ *
+ * Based on adv7176 driver by:    
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *    - some corrections for Pinnacle Systems Inc. DC10plus card.
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
+ *
+ * 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/version.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+
+#include <linux/videodev.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
+MODULE_AUTHOR("Maxim Yevtyushkin");
+MODULE_LICENSE("GPL");
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define I2C_NAME(x) (x)->dev.name
+
+#include <linux/video_encoder.h>
+
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
+
+/* ----------------------------------------------------------------------- */
+
+struct adv7170 {
+       unsigned char reg[128];
+
+       int norm;
+       int input;
+       int enable;
+       int bright;
+       int contrast;
+       int hue;
+       int sat;
+};
+
+#define   I2C_ADV7170        0xd4
+#define   I2C_ADV7171        0x54
+
+static char adv7170_name[] = "adv7170";
+static char adv7171_name[] = "adv7171";
+
+static char *inputs[] = { "pass_through", "play_back" };
+static char *norms[] = { "PAL", "NTSC" };
+
+/* ----------------------------------------------------------------------- */
+
+static inline int
+adv7170_write (struct i2c_client *client,
+              u8                 reg,
+              u8                 value)
+{
+       struct adv7170 *encoder = i2c_get_clientdata(client);
+       encoder->reg[reg] = value;
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int
+adv7170_read (struct i2c_client *client,
+             u8                 reg)
+{
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int
+adv7170_write_block (struct i2c_client *client,
+                    const u8          *data,
+                    unsigned int       len)
+{
+       int ret = -1;
+       u8 reg;
+
+       /* the adv7170 has an autoincrement function, use it if
+        * the adapter understands raw I2C */
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               /* do raw I2C, not smbus compatible */
+               struct adv7170 *encoder = i2c_get_clientdata(client);
+               struct i2c_msg msg;
+               u8 block_data[32];
+               msg.addr = client->addr;
+               msg.flags = client->flags;
+               while (len >= 2) {
+                       msg.buf = (char *) block_data;
+                       msg.len = 0;
+                       block_data[msg.len++] = reg = data[0];
+                       do {
+                               block_data[msg.len++] =
+                                   encoder->reg[reg++] = data[1];
+                               len -= 2;
+                               data += 2;
+                       } while (len >= 2 && data[0] == reg &&
+                                msg.len < 32);
+                       if ((ret =
+                            i2c_transfer(client->adapter, &msg, 1)) < 0)
+                               break;
+               }
+       } else {
+               /* do some slow I2C emulation kind of thing */
+               while (len >= 2) {
+                       reg = *data++;
+                       if ((ret =
+                            adv7170_write(client, reg, *data++)) < 0)
+                               break;
+                       len -= 2;
+               }
+       }
+
+       return ret;
+}
+
+/* ----------------------------------------------------------------------- */
+// Output filter:  S-Video  Composite
+
+#define MR050       0x11       //0x09
+#define MR060       0x14       //0x0c
+
+//---------------------------------------------------------------------------
+
+#define TR0MODE     0x4c
+#define TR0RST     0x80
+
+#define TR1CAPT            0x00
+#define TR1PLAY            0x00
+
+
+static const unsigned char init_NTSC[] = {
+       0x00, 0x10,             // MR0
+       0x01, 0x20,             // MR1
+       0x02, 0x0e,             // MR2 RTC control: bits 2 and 1 
+       0x03, 0x80,             // MR3
+       0x04, 0x30,             // MR4
+       0x05, 0x00,             // Reserved
+       0x06, 0x00,             // Reserved
+       0x07, TR0MODE,          // TM0
+       0x08, TR1CAPT,          // TM1
+       0x09, 0x16,             // Fsc0
+       0x0a, 0x7c,             // Fsc1
+       0x0b, 0xf0,             // Fsc2
+       0x0c, 0x21,             // Fsc3
+       0x0d, 0x00,             // Subcarrier Phase
+       0x0e, 0x00,             // Closed Capt. Ext 0
+       0x0f, 0x00,             // Closed Capt. Ext 1
+       0x10, 0x00,             // Closed Capt. 0
+       0x11, 0x00,             // Closed Capt. 1
+       0x12, 0x00,             // Pedestal Ctl 0
+       0x13, 0x00,             // Pedestal Ctl 1
+       0x14, 0x00,             // Pedestal Ctl 2
+       0x15, 0x00,             // Pedestal Ctl 3
+       0x16, 0x00,             // CGMS_WSS_0
+       0x17, 0x00,             // CGMS_WSS_1
+       0x18, 0x00,             // CGMS_WSS_2
+       0x19, 0x00,             // Teletext Ctl 
+};
+
+static const unsigned char init_PAL[] = {
+       0x00, 0x71,             // MR0
+       0x01, 0x20,             // MR1
+       0x02, 0x0e,             // MR2 RTC control: bits 2 and 1
+       0x03, 0x80,             // MR3
+       0x04, 0x30,             // MR4
+       0x05, 0x00,             // Reserved
+       0x06, 0x00,             // Reserved
+       0x07, TR0MODE,          // TM0
+       0x08, TR1CAPT,          // TM1
+       0x09, 0xcb,             // Fsc0
+       0x0a, 0x8a,             // Fsc1
+       0x0b, 0x09,             // Fsc2
+       0x0c, 0x2a,             // Fsc3
+       0x0d, 0x00,             // Subcarrier Phase
+       0x0e, 0x00,             // Closed Capt. Ext 0
+       0x0f, 0x00,             // Closed Capt. Ext 1
+       0x10, 0x00,             // Closed Capt. 0
+       0x11, 0x00,             // Closed Capt. 1
+       0x12, 0x00,             // Pedestal Ctl 0
+       0x13, 0x00,             // Pedestal Ctl 1
+       0x14, 0x00,             // Pedestal Ctl 2
+       0x15, 0x00,             // Pedestal Ctl 3
+       0x16, 0x00,             // CGMS_WSS_0
+       0x17, 0x00,             // CGMS_WSS_1
+       0x18, 0x00,             // CGMS_WSS_2
+       0x19, 0x00,             // Teletext Ctl
+};
+
+
+static int
+adv7170_command (struct i2c_client *client,
+                unsigned int       cmd,
+                void *             arg)
+{
+       struct adv7170 *encoder = i2c_get_clientdata(client);
+
+       switch (cmd) {
+
+       case 0:
+#if 0
+               /* This is just for testing!!! */
+               adv7170_write_block(client, init_common,
+                                   sizeof(init_common));
+               adv7170_write(client, 0x07, TR0MODE | TR0RST);
+               adv7170_write(client, 0x07, TR0MODE);
+#endif
+               break;
+
+       case ENCODER_GET_CAPABILITIES:
+       {
+               struct video_encoder_capability *cap = arg;
+
+               cap->flags = VIDEO_ENCODER_PAL |
+                            VIDEO_ENCODER_NTSC;
+               cap->inputs = 2;
+               cap->outputs = 1;
+       }
+               break;
+
+       case ENCODER_SET_NORM:
+       {
+               int iarg = *(int *) arg;
+
+               dprintk(1, KERN_DEBUG "%s_command: set norm %d",
+                       I2C_NAME(client), iarg);
+
+               switch (iarg) {
+
+               case VIDEO_MODE_NTSC:
+                       adv7170_write_block(client, init_NTSC,
+                                           sizeof(init_NTSC));
+                       if (encoder->input == 0)
+                               adv7170_write(client, 0x02, 0x0e);      // Enable genlock
+                       adv7170_write(client, 0x07, TR0MODE | TR0RST);
+                       adv7170_write(client, 0x07, TR0MODE);
+                       break;
+
+               case VIDEO_MODE_PAL:
+                       adv7170_write_block(client, init_PAL,
+                                           sizeof(init_PAL));
+                       if (encoder->input == 0)
+                               adv7170_write(client, 0x02, 0x0e);      // Enable genlock
+                       adv7170_write(client, 0x07, TR0MODE | TR0RST);
+                       adv7170_write(client, 0x07, TR0MODE);
+                       break;
+
+               default:
+                       dprintk(1, KERN_ERR "%s: illegal norm: %d\n",
+                              I2C_NAME(client), iarg);
+                       return -EINVAL;
+
+               }
+               dprintk(1, KERN_DEBUG "%s: switched to %s\n", I2C_NAME(client),
+                       norms[iarg]);
+               encoder->norm = iarg;
+       }
+               break;
+
+       case ENCODER_SET_INPUT:
+       {
+               int iarg = *(int *) arg;
+
+               /* RJ: *iarg = 0: input is from decoder
+                *iarg = 1: input is from ZR36060
+                *iarg = 2: color bar */
+
+               dprintk(1, KERN_DEBUG "%s_command: set input from %s\n",
+                       I2C_NAME(client),
+                       iarg == 0 ? "decoder" : "ZR36060");
+
+               switch (iarg) {
+
+               case 0:
+                       adv7170_write(client, 0x01, 0x20);
+                       adv7170_write(client, 0x08, TR1CAPT);   /* TR1 */
+                       adv7170_write(client, 0x02, 0x0e);      // Enable genlock
+                       adv7170_write(client, 0x07, TR0MODE | TR0RST);
+                       adv7170_write(client, 0x07, TR0MODE);
+                       //udelay(10);
+                       break;
+
+               case 1:
+                       adv7170_write(client, 0x01, 0x00);
+                       adv7170_write(client, 0x08, TR1PLAY);   /* TR1 */
+                       adv7170_write(client, 0x02, 0x08);
+                       adv7170_write(client, 0x07, TR0MODE | TR0RST);
+                       adv7170_write(client, 0x07, TR0MODE);
+                       //udelay(10);
+                       break;
+
+               default:
+                       dprintk(1, KERN_ERR "%s: illegal input: %d\n",
+                               I2C_NAME(client), iarg);
+                       return -EINVAL;
+
+               }
+               dprintk(1, KERN_DEBUG "%s: switched to %s\n", I2C_NAME(client),
+                       inputs[iarg]);
+               encoder->input = iarg;
+       }
+               break;
+
+       case ENCODER_SET_OUTPUT:
+       {
+               int *iarg = arg;
+
+               /* not much choice of outputs */
+               if (*iarg != 0) {
+                       return -EINVAL;
+               }
+       }
+               break;
+
+       case ENCODER_ENABLE_OUTPUT:
+       {
+               int *iarg = arg;
+
+               encoder->enable = !!*iarg;
+       }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+static unsigned short normal_i2c[] =
+    { I2C_ADV7170 >> 1, (I2C_ADV7170 >> 1) + 1,
+       I2C_ADV7171 >> 1, (I2C_ADV7171 >> 1) + 1,
+       I2C_CLIENT_END
+};
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+                                                                                
+static struct i2c_client_address_data addr_data = {
+       .normal_i2c             = normal_i2c,
+       .normal_i2c_range       = normal_i2c_range,
+       .probe                  = probe,
+       .probe_range            = probe_range,
+       .ignore                 = ignore,
+       .ignore_range           = ignore_range,
+       .force                  = force
+};
+
+static int adv7170_i2c_id = 0;
+static struct i2c_driver i2c_driver_adv7170;
+
+static int
+adv7170_detect_client (struct i2c_adapter *adapter,
+                      int                 address,
+                      int                 kind)
+{
+       int i;
+       struct i2c_client *client;
+       struct adv7170 *encoder;
+       char *dname;
+
+       dprintk(1,
+               KERN_INFO
+               "adv7170.c: detecting adv7170 client on address 0x%x\n",
+               address << 1);
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return 0;
+
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+       memset(client, 0, sizeof(struct i2c_client));
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &i2c_driver_adv7170;
+       client->flags = I2C_CLIENT_ALLOW_USE;
+       client->id = adv7170_i2c_id++;
+       if ((client->addr == I2C_ADV7170 >> 1) ||
+           (client->addr == (I2C_ADV7170 >> 1) + 1)) {
+               dname = adv7170_name;
+       } else if ((client->addr == I2C_ADV7171 >> 1) ||
+                  (client->addr == (I2C_ADV7171 >> 1) + 1)) {
+               dname = adv7171_name;
+       } else {
+               /* We should never get here!!! */
+               return 0;
+       }
+       snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+               "%s[%d]", dname, client->id);
+
+       encoder = kmalloc(sizeof(struct adv7170), GFP_KERNEL);
+       if (encoder == NULL) {
+               return -ENOMEM;
+       }
+       memset(encoder, 0, sizeof(struct adv7170));
+       encoder->norm = VIDEO_MODE_NTSC;
+       encoder->input = 0;
+       encoder->enable = 1;
+       i2c_set_clientdata(client, encoder);
+
+       i = i2c_attach_client(client);
+       if (i) {
+               kfree(client);
+               kfree(encoder);
+               return i;
+       }
+
+       i = adv7170_write_block(client, init_NTSC, sizeof(init_NTSC));
+       if (i >= 0) {
+               i = adv7170_write(client, 0x07, TR0MODE | TR0RST);
+               i = adv7170_write(client, 0x07, TR0MODE);
+               i = adv7170_read(client, 0x12);
+               dprintk(1, KERN_INFO "%s_attach: rev. %d at 0x%02x\n",
+                       I2C_NAME(client), i & 1, client->addr << 1);
+       }
+       if (i < 0) {
+               dprintk(1, KERN_ERR "%s_attach: init error 0x%x\n",
+                      I2C_NAME(client), i);
+       }
+
+       return 0;
+}
+
+static int
+adv7170_attach_adapter (struct i2c_adapter *adapter)
+{
+       dprintk(1,
+               KERN_INFO
+               "adv7170.c: starting probe for adapter %s (0x%x)\n",
+               I2C_NAME(adapter), adapter->id);
+       return i2c_probe(adapter, &addr_data, &adv7170_detect_client);
+}
+
+static int
+adv7170_detach_client (struct i2c_client *client)
+{
+       struct adv7170 *encoder = i2c_get_clientdata(client);
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+
+       kfree(encoder);
+       kfree(client);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_adv7170 = {
+       .owner = THIS_MODULE,
+       .name = "adv7170",      /* name */
+
+       .id = I2C_DRIVERID_ADV7170,
+       .flags = I2C_DF_NOTIFY,
+
+       .attach_adapter = adv7170_attach_adapter,
+       .detach_client = adv7170_detach_client,
+       .command = adv7170_command,
+};
+
+static int __init
+adv7170_init (void)
+{
+       return i2c_add_driver(&i2c_driver_adv7170);
+}
+
+static void __exit
+adv7170_exit (void)
+{
+       i2c_del_driver(&i2c_driver_adv7170);
+}
+
+module_init(adv7170_init);
+module_exit(adv7170_exit);
index 3f3adcca4ba1516f803ec192b768d32bf62f3f8f..fd807e0e78d4017894de1d8e1d80c35722ef3d8e 100644 (file)
@@ -1,27 +1,30 @@
-#define DEBUGLEVEL 0
 /* 
-    adv7175 - adv7175a video encoder driver version 0.0.3
+ *  adv7175 - adv7175a video encoder driver version 0.0.3
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *    - some corrections for Pinnacle Systems Inc. DC10plus card.
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *    - moved over to linux>=2.4.x i2c protocol (9/9/2002)
+ *
+ * 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.
+ */
 
-    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
-
-    Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
-    Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
-       - some corrections for Pinnacle Systems Inc. DC10plus card.
-
-    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/version.h>
 
 #include <linux/module.h>
 #include <linux/init.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
+#include <asm/segment.h>
 #include <linux/types.h>
 
 #include <linux/videodev.h>
 #include <linux/version.h>
 #include <asm/uaccess.h>
 
+MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
+MODULE_AUTHOR("Dave Perks");
+MODULE_LICENSE("GPL");
+
 #include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define I2C_NAME(s) (s)->dev.name
 
 #include <linux/video_encoder.h>
 
-#if (DEBUGLEVEL > 0)
-#define DEBUG(x...)  x         /* Debug driver */
-#else
-#define DEBUG(x...)
-#endif
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define I2C_ADV7175    0xd4
-#define I2C_ADV7176    0x54
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
 
-#define IF_NAME                "adv7175"
+/* ----------------------------------------------------------------------- */
+
+struct adv7175 {
+       unsigned char reg[128];
+
+       int norm;
+       int input;
+       int enable;
+       int bright;
+       int contrast;
+       int hue;
+       int sat;
+};
+
+#define   I2C_ADV7175        0xd4
+#define   I2C_ADV7176        0x54
 
 static char adv7175_name[] = "adv7175";
 static char adv7176_name[] = "adv7176";
-static char unknown_name[] = "UNKNOWN";
-char *dname;
 
-#if (DEBUGLEVEL > 0)
 static char *inputs[] = { "pass_through", "play_back", "color_bar" };
 static char *norms[] = { "PAL", "NTSC", "SECAM->PAL (may not work!)" };
-#endif
 
-#define I2C_DELAY   10
+/* ----------------------------------------------------------------------- */
 
-static unsigned short normal_i2c[] = {I2C_ADV7175, I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
-static unsigned short probe[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
-static unsigned short probe_range[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
-static unsigned short ignore[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
-static unsigned short ignore_range[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
-static unsigned short force[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
+static inline int
+adv7175_write (struct i2c_client *client,
+              u8                 reg,
+              u8                 value)
+{
+       struct adv7175 *encoder = i2c_get_clientdata(client);
+       encoder->reg[reg] = value;
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
 
-static struct i2c_client_address_data addr_data = {
-                                               normal_i2c, normal_i2c_range,
-                                               probe, probe_range,
-                                               ignore, ignore_range,
-                                               force};
-static struct i2c_client client_template;
+static inline int
+adv7175_read (struct i2c_client *client,
+             u8                 reg)
+{
+       return i2c_smbus_read_byte_data(client, reg);
+}
 
-struct adv7175 {
-       struct i2c_client       *client;
-       int                     addr;
-       unsigned char           reg[128];
-       struct semaphore        lock;
-       int                     norm;
-       int                     input;
-       int                     enable;
-       int                     bright;
-       int                     contrast;
-       int                     hue;
-       int                     sat;
-};
+static int
+adv7175_write_block (struct i2c_client *client,
+                    const u8          *data,
+                    unsigned int       len)
+{
+       int ret = -1;
+       u8 reg;
+
+       /* the adv7175 has an autoincrement function, use it if
+        * the adapter understands raw I2C */
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               /* do raw I2C, not smbus compatible */
+               struct adv7175 *encoder = i2c_get_clientdata(client);
+               struct i2c_msg msg;
+               u8 block_data[32];
+               msg.addr = client->addr;
+               msg.flags = client->flags;
+               while (len >= 2) {
+                       msg.buf = (char *) block_data;
+                       msg.len = 0;
+                       block_data[msg.len++] = reg = data[0];
+                       do {
+                               block_data[msg.len++] =
+                                   encoder->reg[reg++] = data[1];
+                               len -= 2;
+                               data += 2;
+                       } while (len >= 2 && data[0] == reg &&
+                                msg.len < 32);
+                       if ((ret =
+                            i2c_transfer(client->adapter, &msg, 1)) < 0)
+                               break;
+               }
+       } else {
+               /* do some slow I2C emulation kind of thing */
+               while (len >= 2) {
+                       reg = *data++;
+                       if ((ret =
+                            adv7175_write(client, reg, *data++)) < 0)
+                               break;
+                       len -= 2;
+               }
+       }
+
+       return ret;
+}
+
+#ifdef ENCODER_DUMP
+static void
+dump (struct i2c_client *client)
+{
+       struct adv7175 *encoder = i2c_get_clientdata(client);
+       int i, j;
+       printk(KERN_INFO "%s: registry dump\n", I2C_NAME(client));
+       for (i = 0; i < 182 / 8; i++) {
+               printk("%s: 0x%02x -", I2C_NAME(client), i * 8);
+               for (j = 0; j < 8; j++) {
+                       printk(" 0x%02x", encoder->reg[i * 8 + j]);
+               }
+               printk("\n");
+       }
+}
+#endif
 
 /* ----------------------------------------------------------------------- */
 // Output filter:  S-Video  Composite
@@ -135,8 +209,6 @@ static const unsigned char init_common[] = {
        0x0f, 0x00,             /*  */
        0x10, 0x00,             /*  */
        0x11, 0x00,             /*  */
-       0x12, 0x00,             /* MR3 */
-       0x24, 0x00,             /*  */
 };
 
 static const unsigned char init_pal[] = {
@@ -159,284 +231,328 @@ static const unsigned char init_ntsc[] = {
        0x06, 0x1a,             /* subc. phase */
 };
 
-static int adv717x_attach(struct i2c_adapter *adap, int addr, int kind)
+static int
+adv7175_command (struct i2c_client *client,
+                unsigned int       cmd,
+                void              *arg)
 {
-       struct adv7175 *encoder;
-       struct  i2c_client      *client;
-       int rv = 0;
-       int i, x_common=39; /* x is number entries init_common - 1 */
+       struct adv7175 *encoder = i2c_get_clientdata(client);
 
-       printk(KERN_INFO "adv717x: video chip found.\n");
-       client=kmalloc(sizeof(*client), GFP_KERNEL);
-       if(client == NULL)
-               return -ENOMEM;
-       memset(client, 0, sizeof(*client));
+       switch (cmd) {
 
-       client_template.adapter = adap;
-       client_template.addr = addr;
-       memcpy(client, &client_template, sizeof(*client));
+       case 0:
+               /* This is just for testing!!! */
+               adv7175_write_block(client, init_common,
+                                   sizeof(init_common));
+               adv7175_write(client, 0x07, TR0MODE | TR0RST);
+               adv7175_write(client, 0x07, TR0MODE);
+               break;
 
-       encoder = kmalloc(sizeof(*encoder), GFP_KERNEL);
-       if (encoder == NULL) {
-               kfree(client);
-               return -ENOMEM;
+       case ENCODER_GET_CAPABILITIES:
+       {
+               struct video_encoder_capability *cap = arg;
+
+               cap->flags = VIDEO_ENCODER_PAL |
+                            VIDEO_ENCODER_NTSC |
+                            VIDEO_ENCODER_SECAM; /* well, hacky */
+               cap->inputs = 2;
+               cap->outputs = 1;
        }
+               break;
 
-       memset(encoder, 0, sizeof(*encoder));
-       if ((encoder->addr == I2C_ADV7175) || (encoder->addr == (I2C_ADV7175 + 2))) {
-               dname = adv7175_name;
-       } else if ((encoder->addr == I2C_ADV7176) || (encoder->addr == (I2C_ADV7176 + 2))) {
-               dname = adv7176_name;
-       } else {
-               // We should never get here!!!
-               dname = unknown_name;
+       case ENCODER_SET_NORM:
+       {
+               int iarg = *(int *) arg;
+
+               switch (iarg) {
+
+               case VIDEO_MODE_NTSC:
+                       adv7175_write_block(client, init_ntsc,
+                                           sizeof(init_ntsc));
+                       if (encoder->input == 0)
+                               adv7175_write(client, 0x0d, 0x4f);      // Enable genlock
+                       adv7175_write(client, 0x07, TR0MODE | TR0RST);
+                       adv7175_write(client, 0x07, TR0MODE);
+                       break;
+
+               case VIDEO_MODE_PAL:
+                       adv7175_write_block(client, init_pal,
+                                           sizeof(init_pal));
+                       if (encoder->input == 0)
+                               adv7175_write(client, 0x0d, 0x4f);      // Enable genlock
+                       adv7175_write(client, 0x07, TR0MODE | TR0RST);
+                       adv7175_write(client, 0x07, TR0MODE);
+                       break;
+
+               case VIDEO_MODE_SECAM:  // WARNING! ADV7176 does not support SECAM.
+                       /* This is an attempt to convert
+                        * SECAM->PAL (typically it does not work
+                        * due to genlock: when decoder is in SECAM
+                        * and encoder in in PAL the subcarrier can
+                        * not be syncronized with horizontal
+                        * quency) */
+                       adv7175_write_block(client, init_pal,
+                                           sizeof(init_pal));
+                       if (encoder->input == 0)
+                               adv7175_write(client, 0x0d, 0x49);      // Disable genlock
+                       adv7175_write(client, 0x07, TR0MODE | TR0RST);
+                       adv7175_write(client, 0x07, TR0MODE);
+                       break;
+               default:
+                       dprintk(1, KERN_ERR "%s: illegal norm: %d\n",
+                               I2C_NAME(client), iarg);
+                       return -EINVAL;
+
+               }
+               dprintk(1, KERN_INFO "%s: switched to %s\n", I2C_NAME(client),
+                       norms[iarg]);
+               encoder->norm = iarg;
        }
-       strlcpy(client->name, dname, DEVICE_NAME_SIZE);
-       init_MUTEX(&encoder->lock);
-       encoder->client = client;
-       i2c_set_clientdata(client, encoder);
-       encoder->addr = addr;
-       encoder->norm = VIDEO_MODE_PAL;
-       encoder->input = 0;
-       encoder->enable = 1;
+               break;
+
+       case ENCODER_SET_INPUT:
+       {
+               int iarg = *(int *) arg;
+
+               /* RJ: *iarg = 0: input is from SAA7110
+                *iarg = 1: input is from ZR36060
+                *iarg = 2: color bar */
+
+               switch (iarg) {
+
+               case 0:
+                       adv7175_write(client, 0x01, 0x00);
+                       adv7175_write(client, 0x0c, TR1CAPT);   /* TR1 */
+                       if (encoder->norm == VIDEO_MODE_SECAM)
+                               adv7175_write(client, 0x0d, 0x49);      // Disable genlock
+                       else
+                               adv7175_write(client, 0x0d, 0x4f);      // Enable genlock
+                       adv7175_write(client, 0x07, TR0MODE | TR0RST);
+                       adv7175_write(client, 0x07, TR0MODE);
+                       //udelay(10);
+                       break;
 
-       for (i=1; i<x_common; i++) {
-               rv = i2c_smbus_write_byte(client,init_common[i]);
-               if (rv < 0) {
-                       printk(KERN_ERR "%s_attach: init error %d\n", client->name, rv);
+               case 1:
+                       adv7175_write(client, 0x01, 0x00);
+                       adv7175_write(client, 0x0c, TR1PLAY);   /* TR1 */
+                       adv7175_write(client, 0x0d, 0x49);
+                       adv7175_write(client, 0x07, TR0MODE | TR0RST);
+                       adv7175_write(client, 0x07, TR0MODE);
+                       //udelay(10);
                        break;
+
+               case 2:
+                       adv7175_write(client, 0x01, 0x80);
+                       adv7175_write(client, 0x0d, 0x49);
+                       adv7175_write(client, 0x07, TR0MODE | TR0RST);
+                       adv7175_write(client, 0x07, TR0MODE);
+                       //udelay(10);
+                       break;
+
+               default:
+                       dprintk(1, KERN_ERR "%s: illegal input: %d\n",
+                               I2C_NAME(client), iarg);
+                       return -EINVAL;
+
+               }
+               dprintk(1, KERN_INFO "%s: switched to %s\n", I2C_NAME(client),
+                       inputs[iarg]);
+               encoder->input = iarg;
+       }
+               break;
+
+       case ENCODER_SET_OUTPUT:
+       {
+               int *iarg = arg;
+
+               /* not much choice of outputs */
+               if (*iarg != 0) {
+                       return -EINVAL;
                }
        }
+               break;
+
+       case ENCODER_ENABLE_OUTPUT:
+       {
+               int *iarg = arg;
 
-       if (rv >= 0) {
-               i2c_smbus_write_byte_data(client,0x07, TR0MODE | TR0RST);
-               i2c_smbus_write_byte_data(client,0x07, TR0MODE);
-               i2c_smbus_read_byte_data(client,0x12);
-               printk(KERN_INFO "%s_attach: %s rev. %d at 0x%02x\n",
-                      client->name, dname, rv & 1, client->addr);
+               encoder->enable = !!*iarg;
        }
+               break;
 
-       i2c_attach_client(client);
+#ifdef ENCODER_DUMP
+       case ENCODER_DUMP:
+       {
+               dump(client);
+       }
+               break;
+#endif
+
+       default:
+               return -EINVAL;
+       }
 
        return 0;
 }
 
-static
-int adv717x_probe(struct i2c_adapter *adap)
-{
-       return i2c_probe(adap, &addr_data, adv717x_attach);
-}
+/* ----------------------------------------------------------------------- */
 
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+static unsigned short normal_i2c[] =
+    { I2C_ADV7175 >> 1, (I2C_ADV7175 >> 1) + 1,
+       I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1,
+       I2C_CLIENT_END
+};
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+                                                                                
+static struct i2c_client_address_data addr_data = {
+       .normal_i2c             = normal_i2c,
+       .normal_i2c_range       = normal_i2c_range,
+       .probe                  = probe,
+       .probe_range            = probe_range,
+       .ignore                 = ignore,
+       .ignore_range           = ignore_range,
+       .force                  = force
+};
 
-static int adv717x_detach(struct i2c_client *client)
-{
-       i2c_detach_client(client);
-       kfree(i2c_get_clientdata(client));
-       kfree(client);
-       return 0;
-}
+static int adv7175_i2c_id = 0;
+static struct i2c_driver i2c_driver_adv7175;
 
-static int adv717x_command(struct i2c_client *client, unsigned int cmd,
-                          void *arg)
+static int
+adv7175_detect_client (struct i2c_adapter *adapter,
+                      int                 address,
+                      int                 kind)
 {
-       struct adv7175 *encoder = i2c_get_clientdata(client);
-       int i, x_ntsc=13, x_pal=13; 
-               /* x_ntsc is number of entries in init_ntsc -1 */
-               /* x_pal is number of entries in init_pal -1 */
+       int i;
+       struct i2c_client *client;
+       struct adv7175 *encoder;
+       char *dname;
 
-       switch (cmd) {
+       dprintk(1,
+               KERN_INFO
+               "adv7175.c: detecting adv7175 client on address 0x%x\n",
+               address << 1);
 
-       case ENCODER_GET_CAPABILITIES:
-               {
-                       struct video_encoder_capability *cap = arg;
-
-                       cap->flags = VIDEO_ENCODER_PAL | VIDEO_ENCODER_NTSC
-                           // | VIDEO_ENCODER_SECAM
-                           // | VIDEO_ENCODER_CCIR
-                           ;
-                       cap->inputs = 2;
-                       cap->outputs = 1;
-               }
-               break;
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return 0;
 
-       case ENCODER_SET_NORM:
-               {
-                       int iarg = *(int *) arg;
-
-                       if (encoder->norm != iarg) {
-                               switch (iarg) {
-
-                               case VIDEO_MODE_NTSC:
-                                       for (i=1; i< x_ntsc; i++)
-                                               i2c_smbus_write_byte(client, init_ntsc[i]);
-                                       if (encoder->input == 0)
-                                               i2c_smbus_write_byte_data(client,0x0d, 0x4f); // Enable genlock
-                                       i2c_smbus_write_byte_data(client,0x07, TR0MODE | TR0RST);
-                                       i2c_smbus_write_byte_data(client,0x07, TR0MODE);
-                                       break;
-
-                               case VIDEO_MODE_PAL:
-                                       for (i=1; i< x_pal; i++)
-                                               i2c_smbus_write_byte(client, init_pal[i]);
-                                       if (encoder->input == 0)
-                                               i2c_smbus_write_byte_data(client,0x0d, 0x4f); // Enable genlock
-                                       i2c_smbus_write_byte_data(client,0x07, TR0MODE | TR0RST);
-                                       i2c_smbus_write_byte_data(client,0x07, TR0MODE);
-                                       break;
-
-                               case VIDEO_MODE_SECAM:  // WARNING! ADV7176 does not support SECAM.
-                                       // This is an attempt to convert SECAM->PAL (typically
-                                       // it does not work due to genlock: when decoder
-                                       // is in SECAM and encoder in in PAL the subcarrier
-                                       // can not be syncronized with horizontal frequency)
-                                       for (i=1; i< x_pal; i++)
-                                               i2c_smbus_write_byte(client, init_pal[i]);
-                                       if (encoder->input == 0)
-                                               i2c_smbus_write_byte_data(client,0x0d, 0x49); // Disable genlock
-                                       i2c_smbus_write_byte_data(client,0x07, TR0MODE | TR0RST);
-                                       i2c_smbus_write_byte_data(client,0x07, TR0MODE);
-                                       break;
-                               default:
-                                       printk(KERN_ERR "%s: illegal norm: %d\n",
-                                              client->name, iarg);
-                                       return -EINVAL;
-
-                               }
-                               DEBUG(printk
-                                     (KERN_INFO "%s: switched to %s\n",
-                                      client->name, norms[iarg]));
-                               encoder->norm = iarg;
-                       }
-               }
-               break;
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+       memset(client, 0, sizeof(struct i2c_client));
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &i2c_driver_adv7175;
+       client->flags = I2C_CLIENT_ALLOW_USE;
+       client->id = adv7175_i2c_id++;
+       if ((client->addr == I2C_ADV7175 >> 1) ||
+           (client->addr == (I2C_ADV7175 >> 1) + 1)) {
+               dname = adv7175_name;
+       } else if ((client->addr == I2C_ADV7176 >> 1) ||
+                  (client->addr == (I2C_ADV7176 >> 1) + 1)) {
+               dname = adv7176_name;
+       } else {
+               /* We should never get here!!! */
+               return 0;
+       }
+       snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+               "%s[%d]", dname, client->id);
 
-       case ENCODER_SET_INPUT:
-               {
-                       int iarg = *(int *) arg;
-
-                       /* RJ: *iarg = 0: input is from SAA7110
-                          *iarg = 1: input is from ZR36060
-                          *iarg = 2: color bar */
-
-                       if (encoder->input != iarg) {
-                               switch (iarg) {
-
-                               case 0:
-                                       i2c_smbus_write_byte_data(client, 0x01, 0x00);
-                                       i2c_smbus_write_byte_data(client, 0x0c, TR1CAPT);       /* TR1 */
-                                       if (encoder->norm ==
-                                           VIDEO_MODE_SECAM)
-                                               i2c_smbus_write_byte_data(client, 0x0d, 0x49);  // Disable genlock
-                                       else
-                                               i2c_smbus_write_byte_data(client, 0x0d, 0x4f);  // Enable genlock
-                                       i2c_smbus_write_byte_data(client, 0x07, TR0MODE | TR0RST);
-                                       i2c_smbus_write_byte_data(client, 0x07, TR0MODE);
-                                       //udelay(10);
-                                       break;
-
-                               case 1:
-                                       i2c_smbus_write_byte_data(client, 0x01, 0x00);
-                                       i2c_smbus_write_byte_data(client, 0x0c, TR1PLAY);       /* TR1 */
-                                       i2c_smbus_write_byte_data(client, 0x0d, 0x49);
-                                       i2c_smbus_write_byte_data(client, 0x07, TR0MODE | TR0RST);
-                                       i2c_smbus_write_byte_data(client, 0x07, TR0MODE);
-                                       //udelay(10);
-                                       break;
-
-                               case 2:
-                                       i2c_smbus_write_byte_data(client, 0x01, 0x80);
-                                       i2c_smbus_write_byte_data(client, 0x0d, 0x49);
-                                       i2c_smbus_write_byte_data(client, 0x07, TR0MODE | TR0RST);
-                                       i2c_smbus_write_byte_data(client, 0x07, TR0MODE);
-                                       //udelay(10);
-                                       break;
-
-                               default:
-                                       printk(KERN_ERR "%s: illegal input: %d\n",
-                                              client->name, iarg);
-                                       return -EINVAL;
-
-                               }
-                               DEBUG(printk
-                                     (KERN_INFO "%s: switched to %s\n",
-                                      client->name, inputs[iarg]));
-                               encoder->input = iarg;
-                       }
-               }
-               break;
+       encoder = kmalloc(sizeof(struct adv7175), GFP_KERNEL);
+       if (encoder == NULL) {
+               return -ENOMEM;
+       }
+       memset(encoder, 0, sizeof(struct adv7175));
+       encoder->norm = VIDEO_MODE_PAL;
+       encoder->input = 0;
+       encoder->enable = 1;
+       i2c_set_clientdata(client, encoder);
 
-       case ENCODER_SET_OUTPUT:
-               {
-                       int *iarg = arg;
+       i = i2c_attach_client(client);
+       if (i) {
+               kfree(client);
+               kfree(encoder);
+               return i;
+       }
 
-                       /* not much choice of outputs */
-                       if (*iarg != 0) {
-                               return -EINVAL;
-                       }
-               }
-               break;
+       i = adv7175_write_block(client, init_common, sizeof(init_common));
+       if (i >= 0) {
+               i = adv7175_write(client, 0x07, TR0MODE | TR0RST);
+               i = adv7175_write(client, 0x07, TR0MODE);
+               i = adv7175_read(client, 0x12);
+               dprintk(1, KERN_INFO "%s_attach: rev. %d at 0x%x\n",
+                       I2C_NAME(client), i & 1, client->addr << 1);
+       }
+       if (i < 0) {
+               dprintk(1, KERN_ERR "%s_attach: init error 0x%x\n",
+                       I2C_NAME(client), i);
+       }
 
-       case ENCODER_ENABLE_OUTPUT:
-               {
-                       int *iarg = arg;
-
-                       encoder->enable = !!*iarg;
-                       i2c_smbus_write_byte_data(client, 0x61,
-                                     (encoder->
-                                      reg[0x61] & 0xbf) | (encoder->
-                                                           enable ? 0x00 :
-                                                           0x40));
-               }
-               break;
+       return 0;
+}
 
-       default:
-               return -EINVAL;
+static int
+adv7175_attach_adapter (struct i2c_adapter *adapter)
+{
+       dprintk(1,
+               KERN_INFO
+               "adv7175.c: starting probe for adapter %s (0x%x)\n",
+               I2C_NAME(adapter), adapter->id);
+       return i2c_probe(adapter, &addr_data, &adv7175_detect_client);
+}
+
+static int
+adv7175_detach_client (struct i2c_client *client)
+{
+       struct adv7175 *encoder = i2c_get_clientdata(client);
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
        }
 
+       kfree(encoder);
+       kfree(client);
+
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
 static struct i2c_driver i2c_driver_adv7175 = {
-       .owner          = THIS_MODULE,
-       .name           = "adv7175",            /* name */
-       .id             = I2C_DRIVERID_ADV717x, /* ID */
-       .flags          = I2C_DF_NOTIFY, //I2C_ADV7175, I2C_ADV7175 + 3,
-       .attach_adapter = adv717x_probe,
-       .detach_client  = adv717x_detach,
-       .command        = adv717x_command,
-};
+       .owner = THIS_MODULE,
+       .name = "adv7175",      /* name */
 
-static struct i2c_driver i2c_driver_adv7176 = {
-       .owner          = THIS_MODULE,
-       .name           = "adv7176",            /* name */
-       .id             = I2C_DRIVERID_ADV717x, /* ID */
-       .flags          = I2C_DF_NOTIFY, //I2C_ADV7176, I2C_ADV7176 + 3,
-       .attach_adapter = adv717x_probe,
-       .detach_client  = adv717x_detach,
-       .command        = adv717x_command,
-};
+       .id = I2C_DRIVERID_ADV7175,
+       .flags = I2C_DF_NOTIFY,
 
-static struct i2c_client client_template = {
-       .driver         = &i2c_driver_adv7175,
-       .name           = "adv7175_client",
+       .attach_adapter = adv7175_attach_adapter,
+       .detach_client = adv7175_detach_client,
+       .command = adv7175_command,
 };
 
-static int adv717x_init(void)
+static int __init
+adv7175_init (void)
 {
-       int res_adv7175 = 0, res_adv7176 = 0;
-       res_adv7175 = i2c_add_driver(&i2c_driver_adv7175);
-       res_adv7176 = i2c_add_driver(&i2c_driver_adv7176);
-       return (res_adv7175 | res_adv7176);     // Any idea how to make it better?
+       return i2c_add_driver(&i2c_driver_adv7175);
 }
 
-static void adv717x_exit(void)
+static void __exit
+adv7175_exit (void)
 {
-       i2c_del_driver(&i2c_driver_adv7176);
        i2c_del_driver(&i2c_driver_adv7175);
 }
 
-module_init(adv717x_init);
-module_exit(adv717x_exit);
-MODULE_LICENSE("GPL");
+module_init(adv7175_init);
+module_exit(adv7175_exit);
index 9cb5152e010f833949b572a405c272df8b276a8d..3f95d3e50a6c90ad815a99a39fb708cacdcd3c64 100644 (file)
@@ -1,29 +1,34 @@
 /* 
-    bt819 - BT819A VideoStream Decoder (Rockwell Part)
-
-    Copyright (C) 1999 Mike Bernson <mike@mlb.org>
-    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
-
-    Modifications for LML33/DC10plus unified driver
-    Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
-    
-    This code was modify/ported from the saa7111 driver written
-    by Dave Perks.
-
-    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.
-*/
+ *  bt819 - BT819A VideoStream Decoder (Rockwell Part)
+ *
+ * Copyright (C) 1999 Mike Bernson <mike@mlb.org>
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * Modifications for LML33/DC10plus unified driver
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *  
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *    - moved over to linux>=2.4.x i2c protocol (9/9/2002)
+ *
+ * This code was modify/ported from the saa7111 driver written
+ * by Dave Perks.
+ *
+ * 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/version.h>
 
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
+#include <linux/major.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
 #include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
 
 #include <linux/videodev.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
+MODULE_AUTHOR("Mike Bernson & Dave Perks");
+MODULE_LICENSE("GPL");
 
 #include <linux/i2c.h>
-#include <linux/video_decoder.h>
+#include <linux/i2c-dev.h>
 
-#define DEBUG(x)       x       /* Debug driver */
+#define I2C_NAME(s) (s)->dev.name
 
-/* ----------------------------------------------------------------------- */
+#include <linux/video_decoder.h>
 
-static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-I2C_CLIENT_INSMOD;
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
 
-static struct i2c_client client_template;
+/* ----------------------------------------------------------------------- */
 
 struct bt819 {
-       struct i2c_client *client;
-       int addr;
        unsigned char reg[32];
 
        int initialized;
@@ -66,7 +86,6 @@ struct bt819 {
        int contrast;
        int hue;
        int sat;
-       struct semaphore lock;
 };
 
 struct timing {
@@ -78,27 +97,95 @@ struct timing {
        int vscale;
 };
 
+/* for values, see the bt819 datasheet */
 struct timing timing_data[] = {
-       {864 - 24, 2, 623, 1, 0x0504, 0x0000},
-       {858 - 24, 2, 523, 1, 0x00f8, 0x0000},
-//      { 858-68, 64, 523, 1, 0x00f8, 0x0000 },
+       {864 - 24, 20, 625 - 2, 1, 0x0504, 0x0000},
+       {858 - 24, 20, 525 - 2, 1, 0x00f8, 0x0000},
 };
 
 #define   I2C_BT819        0x8a
 
-#define   I2C_DELAY   10
-
 /* ----------------------------------------------------------------------- */
 
+static inline int
+bt819_write (struct i2c_client *client,
+            u8                 reg,
+            u8                 value)
+{
+       struct bt819 *decoder = i2c_get_clientdata(client);
+       decoder->reg[reg] = value;
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
 
-static int bt819_setbit(struct bt819 *dev, int subaddr, int bit, int data)
+static inline int
+bt819_setbit (struct i2c_client *client,
+             u8                 reg,
+             u8                 bit,
+             u8                 value)
 {
-       return i2c_smbus_write_byte_data(dev->client, subaddr, (dev->reg[subaddr] & ~(1 << bit)) | (data ? (1 << bit) : 0));
+       struct bt819 *decoder = i2c_get_clientdata(client);
+       return bt819_write(client, reg,
+                          (decoder->
+                           reg[reg] & ~(1 << bit)) |
+                           (value ? (1 << bit) : 0));
 }
 
-static int bt819_init(struct i2c_client *client)
+static int
+bt819_write_block (struct i2c_client *client,
+                  const u8          *data,
+                  unsigned int       len)
 {
-       struct bt819 *decoder;
+       int ret = -1;
+       u8 reg;
+
+       /* the bt819 has an autoincrement function, use it if
+        * the adapter understands raw I2C */
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               /* do raw I2C, not smbus compatible */
+               struct bt819 *decoder = i2c_get_clientdata(client);
+               struct i2c_msg msg;
+               u8 block_data[32];
+               msg.addr = client->addr;
+               msg.flags = client->flags;
+               while (len >= 2) {
+                       msg.buf = (char *) block_data;
+                       msg.len = 0;
+                       block_data[msg.len++] = reg = data[0];
+                       do {
+                               block_data[msg.len++] =
+                                   decoder->reg[reg++] = data[1];
+                               len -= 2;
+                               data += 2;
+                       } while (len >= 2 && data[0] == reg &&
+                                msg.len < 32);
+                       if ((ret =
+                            i2c_transfer(client->adapter, &msg, 1)) < 0)
+                               break;
+               }
+       } else {
+               /* do some slow I2C emulation kind of thing */
+               while (len >= 2) {
+                       reg = *data++;
+                       if ((ret = bt819_write(client, reg, *data++)) < 0)
+                               break;
+                       len -= 2;
+               }
+       }
+
+       return ret;
+}
+
+static inline int
+bt819_read (struct i2c_client *client,
+           u8                 reg)
+{
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int
+bt819_init (struct i2c_client *client)
+{
+       struct bt819 *decoder = i2c_get_clientdata(client);
 
        static unsigned char init[] = {
                //0x1f, 0x00,     /* Reset */
@@ -118,107 +205,57 @@ static int bt819_init(struct i2c_client *client)
                0x0e, 0xb4,     /* 0x0e Chroma Gain (V) msb */
                0x0f, 0x00,     /* 0x0f Hue control */
                0x12, 0x04,     /* 0x12 Output Format */
-               0x13, 0x20,     /* 0x13 Vertial Scaling msb 0x60, */
+               0x13, 0x20,     /* 0x13 Vertial Scaling msb 0x00
+                                          chroma comb OFF, line drop scaling, interlace scaling
+                                          BUG? Why does turning the chroma comb on fuck up color?
+                                          Bug in the bt819 stepping on my board?
+                                       */
                0x14, 0x00,     /* 0x14 Vertial Scaling lsb */
-               0x16, 0x04,     /* 0x16 Video Timing Polarity 0x02, */
+               0x16, 0x07,     /* 0x16 Video Timing Polarity 
+                                          ACTIVE=active low
+                                          FIELD: high=odd, 
+                                          vreset=active high,
+                                          hreset=active high */
                0x18, 0x68,     /* 0x18 AGC Delay */
                0x19, 0x5d,     /* 0x19 Burst Gate Delay */
                0x1a, 0x80,     /* 0x1a ADC Interface */
        };
 
-       struct timing *timing;
-
-       decoder = i2c_get_clientdata(client);
-       timing = &timing_data[decoder->norm];
-
-       init[3 * 2 - 1] = (((timing->vdelay >> 8) & 0x03) << 6) |
-           (((timing->vactive >> 8) & 0x03) << 4) |
-           (((timing->hdelay >> 8) & 0x03) << 2) |
-           ((timing->hactive >> 8) & 0x03);
-       init[4 * 2 - 1] = timing->vdelay & 0xff;
-       init[5 * 2 - 1] = timing->vactive & 0xff;
-       init[6 * 2 - 1] = timing->hdelay & 0xff;
-       init[7 * 2 - 1] = timing->hactive & 0xff;
-       init[8 * 2 - 1] = timing->hscale >> 8;
-       init[9 * 2 - 1] = timing->hscale & 0xff;
-
-       i2c_smbus_write_byte_data(client, 0x1f, 0x00);
+       struct timing *timing = &timing_data[decoder->norm];
+
+       init[0x03 * 2 - 1] =
+           (((timing->vdelay >> 8) & 0x03) << 6) | (((timing->
+                                                      vactive >> 8) &
+                                                     0x03) << 4) |
+           (((timing->hdelay >> 8) & 0x03) << 2) | ((timing->
+                                                     hactive >> 8) &
+                                                    0x03);
+       init[0x04 * 2 - 1] = timing->vdelay & 0xff;
+       init[0x05 * 2 - 1] = timing->vactive & 0xff;
+       init[0x06 * 2 - 1] = timing->hdelay & 0xff;
+       init[0x07 * 2 - 1] = timing->hactive & 0xff;
+       init[0x08 * 2 - 1] = timing->hscale >> 8;
+       init[0x09 * 2 - 1] = timing->hscale & 0xff;
+       init[0x19*2-1] = decoder->norm == 0 ? 115 : 93; /* Chroma burst delay */
+       /* reset */
+       bt819_write(client, 0x1f, 0x00);
        mdelay(1);
-       return i2c_master_send(client, init, sizeof(init));
-
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int bt819_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-       int i;
-       struct bt819 *decoder;
-       struct i2c_client *client;
-
-       client = kmalloc(sizeof(*client), GFP_KERNEL);
-       if(client == NULL)
-               return -ENOMEM;
-       memset(client, 0, sizeof(*client));
-       client_template.adapter = adap;
-       client_template.addr = addr;
-       memcpy(client, &client_template, sizeof(*client));
-       
-       decoder = kmalloc(sizeof(struct bt819), GFP_KERNEL);
-       if (decoder == NULL) {
-               MOD_DEC_USE_COUNT;
-               kfree(client);
-               return -ENOMEM;
-       }
 
-       memset(decoder, 0, sizeof(struct bt819));
-       strlcpy(client->name, "bt819", DEVICE_NAME_SIZE);
-       i2c_set_clientdata(client, decoder);
-       decoder->client = client;
-       decoder->addr = addr;
-       decoder->norm = VIDEO_MODE_NTSC;
-       decoder->input = 0;
-       decoder->enable = 1;
-       decoder->bright = 32768;
-       decoder->contrast = 32768;
-       decoder->hue = 32768;
-       decoder->sat = 32768;
-       decoder->initialized = 0;
+       /* init */
+       return bt819_write_block(client, init, sizeof(init));
 
-       i = bt819_init(client);
-       if (i < 0) {
-               printk(KERN_ERR "%s: bt819_attach: init status %d\n",
-                      decoder->client->name, i);
-       } else {
-               printk(KERN_INFO "%s: bt819_attach: chip version %x\n",
-                      decoder->client->name, i2c_smbus_read_byte_data(client,
-                                                     0x17) & 0x0f);
-       }
-       init_MUTEX(&decoder->lock);
-       i2c_attach_client(client);
-       MOD_INC_USE_COUNT;
-       return 0;
-}
-static int bt819_probe(struct i2c_adapter *adap)
-{
-       return i2c_probe(adap, &addr_data, bt819_attach);
 }
 
-static int bt819_detach(struct i2c_client *client)
-{
-       i2c_detach_client(client);
-       i2c_get_clientdata(client);
-       kfree(client);
-       MOD_DEC_USE_COUNT;
-       return 0;
-}
+/* ----------------------------------------------------------------------- */
 
-static int bt819_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int
+bt819_command (struct i2c_client *client,
+              unsigned int       cmd,
+              void              *arg)
 {
        int temp;
 
        struct bt819 *decoder = i2c_get_clientdata(client);
-       //return 0;
 
        if (!decoder->initialized) {    // First call to bt819_init could be
                bt819_init(client);     // without #FRST = 0
@@ -227,207 +264,222 @@ static int bt819_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
        switch (cmd) {
 
+       case 0:
+               /* This is just for testing!!! */
+               bt819_init(client);
+               break;
+
        case DECODER_GET_CAPABILITIES:
-               {
-                       struct video_decoder_capability *cap = arg;
-
-                       cap->flags
-                           = VIDEO_DECODER_PAL
-                           | VIDEO_DECODER_NTSC | VIDEO_DECODER_CCIR;
-                       cap->inputs = 8;
-                       cap->outputs = 1;
-               }
+       {
+               struct video_decoder_capability *cap = arg;
+
+               cap->flags = VIDEO_DECODER_PAL |
+                            VIDEO_DECODER_NTSC |
+                            VIDEO_DECODER_AUTO |
+                            VIDEO_DECODER_CCIR;
+               cap->inputs = 8;
+               cap->outputs = 1;
+       }
                break;
 
        case DECODER_GET_STATUS:
-               {
-                       int *iarg = arg;
-                       int status;
-                       int res;
-
-                       status = i2c_smbus_read_byte_data(client, 0x00);
-                       res = 0;
-                       if ((status & 0x80)) {
-                               res |= DECODER_STATUS_GOOD;
-                       }
-                       switch (decoder->norm) {
-                       case VIDEO_MODE_NTSC:
-                               res |= DECODER_STATUS_NTSC;
-                               break;
-                       case VIDEO_MODE_PAL:
+       {
+               int *iarg = arg;
+               int status;
+               int res;
+
+               status = bt819_read(client, 0x00);
+               res = 0;
+               if ((status & 0x80)) {
+                       res |= DECODER_STATUS_GOOD;
+               }
+               switch (decoder->norm) {
+               case VIDEO_MODE_NTSC:
+                       res |= DECODER_STATUS_NTSC;
+                       break;
+               case VIDEO_MODE_PAL:
+                       res |= DECODER_STATUS_PAL;
+                       break;
+               default:
+               case VIDEO_MODE_AUTO:
+                       if ((status & 0x10)) {
                                res |= DECODER_STATUS_PAL;
-                               break;
-                       default:
-                       case VIDEO_MODE_AUTO:
-                               if ((status & 0x10)) {
-                                       res |= DECODER_STATUS_PAL;
-                               } else {
-                                       res |= DECODER_STATUS_NTSC;
-                               }
-                               break;
+                       } else {
+                               res |= DECODER_STATUS_NTSC;
                        }
-                       res |= DECODER_STATUS_COLOR;
-                       *iarg = res;
-
-                       DEBUG(printk(KERN_INFO "%s-bt819: get status %x\n",
-                                    decoder->client->name, *iarg));
+                       break;
                }
+               res |= DECODER_STATUS_COLOR;
+               *iarg = res;
+
+               dprintk(1, KERN_INFO "%s: get status %x\n", I2C_NAME(client),
+                       *iarg);
+       }
                break;
 
        case DECODER_SET_NORM:
-               {
-                       int *iarg = arg;
-                       struct timing *timing;
-
-                       DEBUG(printk(KERN_INFO "%s-bt819: set norm %x\n",
-                                    decoder->client->name, *iarg));
-
-                       if (*iarg == VIDEO_MODE_NTSC) {
-                               bt819_setbit(decoder, 0x01, 0, 1);
-                               bt819_setbit(decoder, 0x01, 1, 0);
-                               i2c_smbus_write_byte_data(client, 0x18, 0x68);
-                               i2c_smbus_write_byte_data(client, 0x19, 0x5d);
-                               //bt819_setbit(decoder, 0x1a,  5, 1);
-                               timing = &timing_data[VIDEO_MODE_NTSC];
-                       } else {
-                               bt819_setbit(decoder, 0x01, 0, 1);
-                               bt819_setbit(decoder, 0x01, 1, 1);
-                               i2c_smbus_write_byte_data(client, 0x18, 0x7f);
-                               i2c_smbus_write_byte_data(client, 0x19, 0x72);
-                               //bt819_setbit(decoder, 0x1a,  5, 0);
-                               timing = &timing_data[VIDEO_MODE_PAL];
-                       }
+       {
+               int *iarg = arg;
+               struct timing *timing = NULL;
+
+               dprintk(1, KERN_INFO "%s: set norm %x\n", I2C_NAME(client),
+                       *iarg);
+
+               switch (*iarg) {
+               case VIDEO_MODE_NTSC:
+                       bt819_setbit(client, 0x01, 0, 1);
+                       bt819_setbit(client, 0x01, 1, 0);
+                       bt819_setbit(client, 0x01, 5, 0);
+                       bt819_write(client, 0x18, 0x68);
+                       bt819_write(client, 0x19, 0x5d);
+                       //bt819_setbit(client, 0x1a,  5, 1);
+                       timing = &timing_data[VIDEO_MODE_NTSC];
+                       break;
+               case VIDEO_MODE_PAL:
+                       bt819_setbit(client, 0x01, 0, 1);
+                       bt819_setbit(client, 0x01, 1, 1);
+                       bt819_setbit(client, 0x01, 5, 1);
+                       bt819_write(client, 0x18, 0x7f);
+                       bt819_write(client, 0x19, 0x72);
+                       //bt819_setbit(client, 0x1a,  5, 0);
+                       timing = &timing_data[VIDEO_MODE_PAL];
+                       break;
+               case VIDEO_MODE_AUTO:
+                       bt819_setbit(client, 0x01, 0, 0);
+                       bt819_setbit(client, 0x01, 1, 0);
+                       break;
+               default:
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: unsupported norm %d\n",
+                               I2C_NAME(client), *iarg);
+                       return -EINVAL;
+               }
 
-                       i2c_smbus_write_byte_data(client, 0x03,
+               if (timing) {
+                       bt819_write(client, 0x03,
                                    (((timing->vdelay >> 8) & 0x03) << 6) |
-                                   (((timing->
-                                      vactive >> 8) & 0x03) << 4) |
-                                   (((timing->
-                                      hdelay >> 8) & 0x03) << 2) |
-                                   ((timing->hactive >> 8) & 0x03));
-
-                       i2c_smbus_write_byte_data(client, 0x04, timing->vdelay & 0xff);
-                       i2c_smbus_write_byte_data(client, 0x05, timing->vactive & 0xff);
-                       i2c_smbus_write_byte_data(client, 0x06, timing->hdelay & 0xff);
-                       i2c_smbus_write_byte_data(client, 0x07, timing->hactive & 0xff);
-                       i2c_smbus_write_byte_data(client, 0x08, timing->hscale >> 8);
-                       i2c_smbus_write_byte_data(client, 0x09, timing->hscale & 0xff);
-                       decoder->norm = *iarg;
+                                   (((timing->vactive >> 8) & 0x03) << 4) |
+                                   (((timing->hdelay >> 8) & 0x03) << 2) |
+                                    ((timing->hactive >> 8) & 0x03) );
+                       bt819_write(client, 0x04, timing->vdelay & 0xff);
+                       bt819_write(client, 0x05, timing->vactive & 0xff);
+                       bt819_write(client, 0x06, timing->hdelay & 0xff);
+                       bt819_write(client, 0x07, timing->hactive & 0xff);
+                       bt819_write(client, 0x08, (timing->hscale >> 8) & 0xff);
+                       bt819_write(client, 0x09, timing->hscale & 0xff);
                }
+
+               decoder->norm = *iarg;
+       }
                break;
 
        case DECODER_SET_INPUT:
-               {
-                       int *iarg = arg;
+       {
+               int *iarg = arg;
 
-                       DEBUG(printk(KERN_INFO "%s-bt819: set input %x\n",
-                                    decoder->client->name, *iarg));
+               dprintk(1, KERN_INFO "%s: set input %x\n", I2C_NAME(client),
+                       *iarg);
 
-                       if (*iarg < 0 || *iarg > 7) {
-                               return -EINVAL;
-                       }
+               if (*iarg < 0 || *iarg > 7) {
+                       return -EINVAL;
+               }
 
-                       if (decoder->input != *iarg) {
-                               decoder->input = *iarg;
-                               /* select mode */
-                               if (decoder->input == 0) {
-                                       bt819_setbit(decoder, 0x0b, 6, 0);
-                                       bt819_setbit(decoder, 0x1a, 1, 1);
-                               } else {
-                                       bt819_setbit(decoder, 0x0b, 6, 1);
-                                       bt819_setbit(decoder, 0x1a, 1, 0);
-                               }
+               if (decoder->input != *iarg) {
+                       decoder->input = *iarg;
+                       /* select mode */
+                       if (decoder->input == 0) {
+                               bt819_setbit(client, 0x0b, 6, 0);
+                               bt819_setbit(client, 0x1a, 1, 1);
+                       } else {
+                               bt819_setbit(client, 0x0b, 6, 1);
+                               bt819_setbit(client, 0x1a, 1, 0);
                        }
                }
+       }
                break;
 
        case DECODER_SET_OUTPUT:
-               {
-                       int *iarg = arg;
+       {
+               int *iarg = arg;
 
-                       DEBUG(printk(KERN_INFO "%s-bt819: set output %x\n",
-                                    decoder->client->name, *iarg));
+               dprintk(1, KERN_INFO "%s: set output %x\n", I2C_NAME(client),
+                       *iarg);
 
-                       /* not much choice of outputs */
-                       if (*iarg != 0) {
-                               return -EINVAL;
-                       }
+               /* not much choice of outputs */
+               if (*iarg != 0) {
+                       return -EINVAL;
                }
+       }
                break;
 
        case DECODER_ENABLE_OUTPUT:
-               {
-                       int *iarg = arg;
-                       int enable = (*iarg != 0);
-
-                       DEBUG(printk
-                             (KERN_INFO "%s-bt819: enable output %x\n",
-                              decoder->client->name, *iarg));
-
-                       if (decoder->enable != enable) {
-                               decoder->enable = enable;
-
-                               if (decoder->enable) {
-                                       bt819_setbit(decoder, 0x16, 7, 0);
-                               } else {
-                                       bt819_setbit(decoder, 0x16, 7, 1);
-                               }
+       {
+               int *iarg = arg;
+               int enable = (*iarg != 0);
+
+               dprintk(1, KERN_INFO "%s: enable output %x\n",
+                       I2C_NAME(client), *iarg);
+
+               if (decoder->enable != enable) {
+                       decoder->enable = enable;
+
+                       if (decoder->enable) {
+                               bt819_setbit(client, 0x16, 7, 0);
+                       } else {
+                               bt819_setbit(client, 0x16, 7, 1);
                        }
                }
+       }
                break;
 
        case DECODER_SET_PICTURE:
-               {
-                       struct video_picture *pic = arg;
+       {
+               struct video_picture *pic = arg;
 
-                       DEBUG(printk
-                             (KERN_INFO
-                              "%s-bt819: set picture brightness %d contrast %d colour %d\n",
-                              decoder->client->name, pic->brightness,
-                              pic->contrast, pic->colour));
+               dprintk(1,
+                       KERN_INFO
+                       "%s: set picture brightness %d contrast %d colour %d\n",
+                       I2C_NAME(client), pic->brightness, pic->contrast,
+                       pic->colour);
 
 
-                       if (decoder->bright != pic->brightness) {
-                               /* We want -128 to 127 we get 0-65535 */
-                               decoder->bright = pic->brightness;
-                               i2c_smbus_write_byte_data(client, 0x0a,
-                                           (decoder->bright >> 8) - 128);
-                       }
+               if (decoder->bright != pic->brightness) {
+                       /* We want -128 to 127 we get 0-65535 */
+                       decoder->bright = pic->brightness;
+                       bt819_write(client, 0x0a,
+                                   (decoder->bright >> 8) - 128);
+               }
 
-                       if (decoder->contrast != pic->contrast) {
-                               /* We want 0 to 511 we get 0-65535 */
-                               decoder->contrast = pic->contrast;
-                               i2c_smbus_write_byte_data(client, 0x0c,
-                                           (decoder->
-                                            contrast >> 7) & 0xff);
-                               bt819_setbit(decoder, 0x0b, 2,
-                                            ((decoder->
-                                              contrast >> 15) & 0x01));
-                       }
+               if (decoder->contrast != pic->contrast) {
+                       /* We want 0 to 511 we get 0-65535 */
+                       decoder->contrast = pic->contrast;
+                       bt819_write(client, 0x0c,
+                                   (decoder->contrast >> 7) & 0xff);
+                       bt819_setbit(client, 0x0b, 2,
+                                    ((decoder->contrast >> 15) & 0x01));
+               }
 
-                       if (decoder->sat != pic->colour) {
-                               /* We want 0 to 511 we get 0-65535 */
-                               decoder->sat = pic->colour;
-                               i2c_smbus_write_byte_data(client, 0x0d,
-                                           (decoder->sat >> 7) & 0xff);
-                               bt819_setbit(decoder, 0x0b, 1,
-                                            ((decoder->
-                                              sat >> 15) & 0x01));
-
-                               temp = (decoder->sat * 201) / 237;
-                               i2c_smbus_write_byte_data(client, 0x0e,
-                                           (temp >> 7) & 0xff);
-                               bt819_setbit(decoder, 0x0b, 0,
-                                            (temp >> 15) & 0x01);
-                       }
+               if (decoder->sat != pic->colour) {
+                       /* We want 0 to 511 we get 0-65535 */
+                       decoder->sat = pic->colour;
+                       bt819_write(client, 0x0d,
+                                   (decoder->sat >> 7) & 0xff);
+                       bt819_setbit(client, 0x0b, 1,
+                                    ((decoder->sat >> 15) & 0x01));
+
+                       temp = (decoder->sat * 201) / 237;
+                       bt819_write(client, 0x0e, (temp >> 7) & 0xff);
+                       bt819_setbit(client, 0x0b, 0, (temp >> 15) & 0x01);
+               }
 
-                       if (decoder->hue != pic->hue) {
-                               /* We want -128 to 127 we get 0-65535 */
-                               decoder->hue = pic->hue;
-                               i2c_smbus_write_byte_data(client, 0x0f,
-                                           128 - (decoder->hue >> 8));
-                       }
+               if (decoder->hue != pic->hue) {
+                       /* We want -128 to 127 we get 0-65535 */
+                       decoder->hue = pic->hue;
+                       bt819_write(client, 0x0f,
+                                   128 - (decoder->hue >> 8));
                }
+       }
                break;
 
        default:
@@ -439,32 +491,174 @@ static int bt819_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_bt819 = {
-        .name = "bt819",               /* name */
-       .id = I2C_DRIVERID_BT819,       /* ID */
-       .flags = I2C_DF_NOTIFY,
-       .attach_adapter = bt819_probe,
-       .detach_client = bt819_detach,
-       .command = bt819_command
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+static unsigned short normal_i2c[] = {
+       I2C_BT819 >> 1,
+       I2C_CLIENT_END,
+};
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
 
+static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+                                                                                
+static struct i2c_client_address_data addr_data = {
+       .normal_i2c             = normal_i2c,
+       .normal_i2c_range       = normal_i2c_range,
+       .probe                  = probe,
+       .probe_range            = probe_range,
+       .ignore                 = ignore,
+       .ignore_range           = ignore_range,
+       .force                  = force
 };
 
-static struct i2c_client client_template = {
-       .id = -1,
-       .driver = &i2c_driver_bt819,
-       .name = "bt819_client",
+static int bt819_i2c_id = 0;
+static struct i2c_driver i2c_driver_bt819;
+
+static int
+bt819_detect_client (struct i2c_adapter *adapter,
+                    int                 address,
+                    int                 kind)
+{
+       int i, id;
+       struct bt819 *decoder;
+       struct i2c_client *client;
+
+       dprintk(1,
+               KERN_INFO
+               "saa7111.c: detecting bt819 client on address 0x%x\n",
+               address << 1);
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return 0;
+
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+       memset(client, 0, sizeof(struct i2c_client));
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &i2c_driver_bt819;
+       client->flags = I2C_CLIENT_ALLOW_USE;
+       client->id = bt819_i2c_id++;
+
+       decoder = kmalloc(sizeof(struct bt819), GFP_KERNEL);
+       if (decoder == NULL) {
+               kfree(client);
+               return -ENOMEM;
+       }
+
+       memset(decoder, 0, sizeof(struct bt819));
+       decoder->norm = VIDEO_MODE_NTSC;
+       decoder->input = 0;
+       decoder->enable = 1;
+       decoder->bright = 32768;
+       decoder->contrast = 32768;
+       decoder->hue = 32768;
+       decoder->sat = 32768;
+       decoder->initialized = 0;
+       i2c_set_clientdata(client, decoder);
+
+       id = bt819_read(client, 0x17);
+       switch (id & 0xf0) {
+       case 0x70:
+               snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+                        "bt819a[%d]", client->id);
+               break;
+       case 0x60:
+               snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+                        "bt817a[%d]", client->id);
+               break;
+       case 0x20:
+               snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+                        "bt815a[%d]", client->id);
+               break;
+       default:
+               dprintk(1,
+                       KERN_ERR
+                       "bt819: unknown chip version 0x%x (ver 0x%x)\n",
+                       id & 0xf0, id & 0x0f);
+               kfree(decoder);
+               kfree(client);
+               return 0;
+       }
+
+       i = i2c_attach_client(client);
+       if (i) {
+               kfree(client);
+               kfree(decoder);
+               return i;
+       }
+
+       i = bt819_init(client);
+       if (i < 0) {
+               dprintk(1, KERN_ERR "%s_attach: init status %d\n",
+                       I2C_NAME(client), i);
+       } else {
+               dprintk(1,
+                       KERN_INFO
+                       "%s_attach: chip version 0x%x at address 0x%x\n",
+                       I2C_NAME(client), id & 0x0f,
+                       client->addr << 1);
+       }
+
+       return 0;
+}
+
+static int
+bt819_attach_adapter (struct i2c_adapter *adapter)
+{
+       return i2c_probe(adapter, &addr_data, &bt819_detect_client);
+}
+
+static int
+bt819_detach_client (struct i2c_client *client)
+{
+       struct bt819 *decoder = i2c_get_clientdata(client);
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+
+       kfree(decoder);
+       kfree(client);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_bt819 = {
+       .owner = THIS_MODULE,
+       .name = "bt819",
+
+       .id = I2C_DRIVERID_BT819,
+       .flags = I2C_DF_NOTIFY,
+
+       .attach_adapter = bt819_attach_adapter,
+       .detach_client = bt819_detach_client,
+       .command = bt819_command,
 };
 
-static int bt819_setup(void)
+static int __init
+bt819_init_module (void)
 {
        return i2c_add_driver(&i2c_driver_bt819);
 }
 
-static void bt819_exit(void)
+static void __exit
+bt819_exit (void)
 {
        i2c_del_driver(&i2c_driver_bt819);
 }
 
-module_init(bt819_setup);
+module_init(bt819_init_module);
 module_exit(bt819_exit);
-MODULE_LICENSE("GPL");
index 0888febb383107faa7b227365b0462143b431d29..a19a5aa1986f056d5147d1b00e09ffbbe623f0e6 100644 (file)
@@ -1,29 +1,34 @@
 /* 
-    bt856 - BT856A Digital Video Encoder (Rockwell Part)
+ * bt856 - BT856A Digital Video Encoder (Rockwell Part)
+ *
+ * Copyright (C) 1999 Mike Bernson <mike@mlb.org>
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * Modifications for LML33/DC10plus unified driver
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * This code was modify/ported from the saa7111 driver written
+ * by Dave Perks.
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *   - moved over to linux>=2.4.x i2c protocol (9/9/2002)
+ *
+ * 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.
+ */
 
-    Copyright (C) 1999 Mike Bernson <mike@mlb.org>
-    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
-
-    Modifications for LML33/DC10plus unified driver
-    Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
-    
-    This code was modify/ported from the saa7111 driver written
-    by Dave Perks.
-
-    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/version.h>
 
 #include <linux/module.h>
 #include <linux/init.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
+#include <asm/segment.h>
 #include <linux/types.h>
 
 #include <linux/videodev.h>
 #include <linux/version.h>
 #include <asm/uaccess.h>
 
+MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
+MODULE_AUTHOR("Mike Bernson & Dave Perks");
+MODULE_LICENSE("GPL");
+
 #include <linux/i2c.h>
-#include <linux/video_encoder.h>
+#include <linux/i2c-dev.h>
 
-#define DEBUG(x)   x           /* Debug driver */
+#define I2C_NAME(s) (s)->dev.name
 
-/* ----------------------------------------------------------------------- */
+#include <linux/video_encoder.h>
 
-static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-static struct i2c_client_address_data addr_data = {
-       normal_i2c , normal_i2c_range,
-       probe , probe_range,
-       ignore , ignore_range,
-       force
-};
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
+
+/* ----------------------------------------------------------------------- */
 
-static struct i2c_client client_template;
+#define REG_OFFSET  0xCE
 
 struct bt856 {
-       struct i2c_client *client;
-       int addr;
-       unsigned char reg[128];
+       unsigned char reg[32];
 
        int norm;
        int enable;
@@ -81,212 +86,192 @@ struct bt856 {
        int contrast;
        int hue;
        int sat;
-       struct semaphore lock;
 };
 
 #define   I2C_BT856        0x88
 
-#define I2C_DELAY   10
-
 /* ----------------------------------------------------------------------- */
 
-static int bt856_setbit(struct bt856 *dev, int subaddr, int bit, int data)
+static inline int
+bt856_write (struct i2c_client *client,
+            u8                 reg,
+            u8                 value)
 {
-       return i2c_smbus_write_byte_data(dev->client, subaddr,(dev->reg[subaddr] & ~(1 << bit)) | (data ? (1 << bit) : 0));
+       struct bt856 *encoder = i2c_get_clientdata(client);
+       encoder->reg[reg - REG_OFFSET] = value;
+       return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-/* ----------------------------------------------------------------------- */
-
-static int bt856_attach(struct i2c_adapter *adap, int addr, int kind)
+static inline int
+bt856_setbit (struct i2c_client *client,
+             u8                 reg,
+             u8                 bit,
+             u8                 value)
 {
-       struct bt856 *encoder;
-       struct i2c_client *client;
-       
-       client = kmalloc(sizeof(*client), GFP_KERNEL);
-       if(client == NULL)
-               return -ENOMEM;
-       memset(client, 0, sizeof(*client));
-       client_template.adapter = adap;
-       client_template.addr = addr;
-       memcpy(client, &client_template, sizeof(*client));      
-       
-       /* This chip is not on the buz card but at the same address saa7185 */
-       //if (memcmp(device->bus->name, "buz", 3) == 0 || memcmp(device->bus->name, "zr36057", 6) == 0)
-       //   return 1;
+       struct bt856 *encoder = i2c_get_clientdata(client);
+       return bt856_write(client, reg,
+                          (encoder->
+                           reg[reg - REG_OFFSET] & ~(1 << bit)) |
+                           (value ? (1 << bit) : 0));
+}
 
-       encoder = kmalloc(sizeof(struct bt856), GFP_KERNEL);
+static void
+bt856_dump (struct i2c_client *client)
+{
+       int i;
+       struct bt856 *encoder = i2c_get_clientdata(client);
+       printk(KERN_INFO "%s: register dump:", I2C_NAME(client));
+       for (i = 0xd6; i <= 0xde; i += 2)
+               printk(" %02x", encoder->reg[i - REG_OFFSET]);
+       printk("\n");
+}
 
-       if (encoder == NULL) {
-               MOD_DEC_USE_COUNT;
-               return -ENOMEM;
-       }
+/* ----------------------------------------------------------------------- */
 
+static int
+bt856_command (struct i2c_client *client,
+              unsigned int       cmd,
+              void              *arg)
+{
+       struct bt856 *encoder = i2c_get_clientdata(client);
 
-       memset(encoder, 0, sizeof(struct bt856));
-       strlcpy(client->name, "bt856", DEVICE_NAME_SIZE);
-       encoder->client = client;
-       i2c_set_clientdata(client, encoder);
-       encoder->addr = client->addr;
-       encoder->norm = VIDEO_MODE_NTSC;
-       encoder->enable = 1;
+       switch (cmd) {
 
-       DEBUG(printk(KERN_INFO "%s-bt856: attach\n", encoder->client->name));
+       case 0:
+               /* This is just for testing!!! */
+               dprintk(1, KERN_INFO "bt856: init\n");
+               bt856_write(client, 0xdc, 0x18);
+               bt856_write(client, 0xda, 0);
+               bt856_write(client, 0xde, 0);
 
-       i2c_smbus_write_byte_data(client, 0xdc, 0x18);
-       encoder->reg[0xdc] = 0x18;
-       i2c_smbus_write_byte_data(client, 0xda, 0);
-       encoder->reg[0xda] = 0;
-       i2c_smbus_write_byte_data(client, 0xde, 0);
-       encoder->reg[0xde] = 0;
+               bt856_setbit(client, 0xdc, 3, 1);
+               //bt856_setbit(client, 0xdc, 6, 0);
+               bt856_setbit(client, 0xdc, 4, 1);
 
-       bt856_setbit(encoder, 0xdc, 3, 1);
-       //bt856_setbit(encoder, 0xdc, 6, 0);
-       bt856_setbit(encoder, 0xdc, 4, 1);
+               switch (encoder->norm) {
 
-       switch (encoder->norm) {
+               case VIDEO_MODE_NTSC:
+                       bt856_setbit(client, 0xdc, 2, 0);
+                       break;
 
-       case VIDEO_MODE_NTSC:
-               bt856_setbit(encoder, 0xdc, 2, 0);
-               break;
+               case VIDEO_MODE_PAL:
+                       bt856_setbit(client, 0xdc, 2, 1);
+                       break;
+               }
 
-       case VIDEO_MODE_PAL:
-               bt856_setbit(encoder, 0xdc, 2, 1);
+               bt856_setbit(client, 0xdc, 1, 1);
+               bt856_setbit(client, 0xde, 4, 0);
+               bt856_setbit(client, 0xde, 3, 1);
+               if (debug != 0)
+                       bt856_dump(client);
                break;
-       }
-
-       bt856_setbit(encoder, 0xdc, 1, 1);
-       bt856_setbit(encoder, 0xde, 4, 0);
-       bt856_setbit(encoder, 0xde, 3, 1);
-       init_MUTEX(&encoder->lock);
-       i2c_attach_client(client);
-       MOD_INC_USE_COUNT;
-       return 0;
-}
 
-static int bt856_probe(struct i2c_adapter *adap)
-{
-       return i2c_probe(adap, &addr_data , bt856_attach);
-}
-
-static int bt856_detach(struct i2c_client *client)
-{
-       i2c_detach_client(client);
-       i2c_get_clientdata(client);
-       kfree(client);
-       MOD_DEC_USE_COUNT;
-       return 0;
-}
-
-static int bt856_command(struct i2c_client *client, unsigned int cmd,
-                        void *arg)
-{
-       struct bt856 *encoder = i2c_get_clientdata(client);
+       case ENCODER_GET_CAPABILITIES:
+       {
+               struct video_encoder_capability *cap = arg;
 
-       switch (cmd) {
+               dprintk(1, KERN_INFO "%s: get capabilities\n",
+                       I2C_NAME(client));
 
-       case ENCODER_GET_CAPABILITIES:
-               {
-                       struct video_encoder_capability *cap = arg;
-
-                       DEBUG(printk
-                             (KERN_INFO "%s-bt856: get capabilities\n",
-                              encoder->client->name));
-
-                       cap->flags
-                           = VIDEO_ENCODER_PAL
-                           | VIDEO_ENCODER_NTSC | VIDEO_ENCODER_CCIR;
-                       cap->inputs = 2;
-                       cap->outputs = 1;
-               }
+               cap->flags = VIDEO_ENCODER_PAL |
+                            VIDEO_ENCODER_NTSC |
+                            VIDEO_ENCODER_CCIR;
+               cap->inputs = 2;
+               cap->outputs = 1;
+       }
                break;
 
        case ENCODER_SET_NORM:
-               {
-                       int *iarg = arg;
+       {
+               int *iarg = arg;
 
-                       DEBUG(printk(KERN_INFO "%s-bt856: set norm %d\n",
-                                    encoder->client->name, *iarg));
+               dprintk(1, KERN_INFO "%s: set norm %d\n", I2C_NAME(client),
+                       *iarg);
 
-                       switch (*iarg) {
+               switch (*iarg) {
 
-                       case VIDEO_MODE_NTSC:
-                               bt856_setbit(encoder, 0xdc, 2, 0);
-                               break;
+               case VIDEO_MODE_NTSC:
+                       bt856_setbit(client, 0xdc, 2, 0);
+                       break;
 
-                       case VIDEO_MODE_PAL:
-                               bt856_setbit(encoder, 0xdc, 2, 1);
-                               bt856_setbit(encoder, 0xda, 0, 0);
-                               //bt856_setbit(encoder, 0xda, 0, 1);
-                               break;
+               case VIDEO_MODE_PAL:
+                       bt856_setbit(client, 0xdc, 2, 1);
+                       bt856_setbit(client, 0xda, 0, 0);
+                       //bt856_setbit(client, 0xda, 0, 1);
+                       break;
 
-                       default:
-                               return -EINVAL;
+               default:
+                       return -EINVAL;
 
-                       }
-                       encoder->norm = *iarg;
                }
+               encoder->norm = *iarg;
+               if (debug != 0)
+                       bt856_dump(client);
+       }
                break;
 
        case ENCODER_SET_INPUT:
-               {
-                       int *iarg = arg;
-
-                       DEBUG(printk(KERN_INFO "%s-bt856: set input %d\n",
-                                    encoder->client->name, *iarg));
-
-                       /*     We only have video bus.
-                          *iarg = 0: input is from bt819
-                          *iarg = 1: input is from ZR36060 */
-
-                       switch (*iarg) {
-
-                       case 0:
-                               bt856_setbit(encoder, 0xde, 4, 0);
-                               bt856_setbit(encoder, 0xde, 3, 1);
-                               bt856_setbit(encoder, 0xdc, 3, 1);
-                               bt856_setbit(encoder, 0xdc, 6, 0);
-                               break;
-                       case 1:
-                               bt856_setbit(encoder, 0xde, 4, 0);
-                               bt856_setbit(encoder, 0xde, 3, 1);
-                               bt856_setbit(encoder, 0xdc, 3, 1);
-                               bt856_setbit(encoder, 0xdc, 6, 1);
-                               break;
-                       case 2: // Color bar
-                               bt856_setbit(encoder, 0xdc, 3, 0);
-                               bt856_setbit(encoder, 0xde, 4, 1);
-                               break;
-                       default:
-                               return -EINVAL;
-
-                       }
+       {
+               int *iarg = arg;
+
+               dprintk(1, KERN_INFO "%s: set input %d\n", I2C_NAME(client),
+                       *iarg);
+
+               /* We only have video bus.
+                * iarg = 0: input is from bt819
+                * iarg = 1: input is from ZR36060 */
+
+               switch (*iarg) {
+
+               case 0:
+                       bt856_setbit(client, 0xde, 4, 0);
+                       bt856_setbit(client, 0xde, 3, 1);
+                       bt856_setbit(client, 0xdc, 3, 1);
+                       bt856_setbit(client, 0xdc, 6, 0);
+                       break;
+               case 1:
+                       bt856_setbit(client, 0xde, 4, 0);
+                       bt856_setbit(client, 0xde, 3, 1);
+                       bt856_setbit(client, 0xdc, 3, 1);
+                       bt856_setbit(client, 0xdc, 6, 1);
+                       break;
+               case 2: // Color bar
+                       bt856_setbit(client, 0xdc, 3, 0);
+                       bt856_setbit(client, 0xde, 4, 1);
+                       break;
+               default:
+                       return -EINVAL;
+
                }
+
+               if (debug != 0)
+                       bt856_dump(client);
+       }
                break;
 
        case ENCODER_SET_OUTPUT:
-               {
-                       int *iarg = arg;
+       {
+               int *iarg = arg;
 
-                       DEBUG(printk(KERN_INFO "%s-bt856: set output %d\n",
-                                    encoder->client->name, *iarg));
+               dprintk(1, KERN_INFO "%s: set output %d\n", I2C_NAME(client),
+                       *iarg);
 
-                       /* not much choice of outputs */
-                       if (*iarg != 0) {
-                               return -EINVAL;
-                       }
+               /* not much choice of outputs */
+               if (*iarg != 0) {
+                       return -EINVAL;
                }
+       }
                break;
 
        case ENCODER_ENABLE_OUTPUT:
-               {
-                       int *iarg = arg;
+       {
+               int *iarg = arg;
 
-                       encoder->enable = !!*iarg;
+               encoder->enable = !!*iarg;
 
-                       DEBUG(printk
-                             (KERN_INFO "%s-bt856: enable output %d\n",
-                              encoder->client->name, encoder->enable));
-               }
+               dprintk(1, KERN_INFO "%s: enable output %d\n",
+                       I2C_NAME(client), encoder->enable);
+       }
                break;
 
        default:
@@ -298,32 +283,162 @@ static int bt856_command(struct i2c_client *client, unsigned int cmd,
 
 /* ----------------------------------------------------------------------- */
 
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+static unsigned short normal_i2c[] = { I2C_BT856 >> 1, I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+                                                                                
+static struct i2c_client_address_data addr_data = {
+       .normal_i2c             = normal_i2c,
+       .normal_i2c_range       = normal_i2c_range,
+       .probe                  = probe,
+       .probe_range            = probe_range,
+       .ignore                 = ignore,
+       .ignore_range           = ignore_range,
+       .force                  = force
+};
+
+static int bt856_i2c_id = 0;
+static struct i2c_driver i2c_driver_bt856;
+
+static int
+bt856_detect_client (struct i2c_adapter *adapter,
+                    int                 address,
+                    int                 kind)
+{
+       int i;
+       struct i2c_client *client;
+       struct bt856 *encoder;
+
+       dprintk(1,
+               KERN_INFO
+               "bt856.c: detecting bt856 client on address 0x%x\n",
+               address << 1);
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return 0;
+
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+       memset(client, 0, sizeof(struct i2c_client));
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &i2c_driver_bt856;
+       client->flags = I2C_CLIENT_ALLOW_USE;
+       client->id = bt856_i2c_id++;
+       snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+               "bt856[%d]", client->id);
+
+       encoder = kmalloc(sizeof(struct bt856), GFP_KERNEL);
+       if (encoder == NULL) {
+               return -ENOMEM;
+       }
+       memset(encoder, 0, sizeof(struct bt856));
+       encoder->norm = VIDEO_MODE_NTSC;
+       encoder->enable = 1;
+       i2c_set_clientdata(client, encoder);
+
+       i = i2c_attach_client(client);
+       if (i) {
+               kfree(client);
+               kfree(encoder);
+               return i;
+       }
+
+       bt856_write(client, 0xdc, 0x18);
+       bt856_write(client, 0xda, 0);
+       bt856_write(client, 0xde, 0);
+
+       bt856_setbit(client, 0xdc, 3, 1);
+       //bt856_setbit(client, 0xdc, 6, 0);
+       bt856_setbit(client, 0xdc, 4, 1);
+
+       switch (encoder->norm) {
+
+       case VIDEO_MODE_NTSC:
+               bt856_setbit(client, 0xdc, 2, 0);
+               break;
+
+       case VIDEO_MODE_PAL:
+               bt856_setbit(client, 0xdc, 2, 1);
+               break;
+       }
+
+       bt856_setbit(client, 0xdc, 1, 1);
+       bt856_setbit(client, 0xde, 4, 0);
+       bt856_setbit(client, 0xde, 3, 1);
+
+       if (debug != 0)
+               bt856_dump(client);
+
+       dprintk(1, KERN_INFO "%s_attach: at address 0x%x\n", I2C_NAME(client),
+               client->addr << 1);
+
+       return 0;
+}
+
+static int
+bt856_attach_adapter (struct i2c_adapter *adapter)
+{
+       dprintk(1,
+               KERN_INFO
+               "bt856.c: starting probe for adapter %s (0x%x)\n",
+               I2C_NAME(adapter), adapter->id);
+       return i2c_probe(adapter, &addr_data, &bt856_detect_client);
+}
+
+static int
+bt856_detach_client (struct i2c_client *client)
+{
+       struct bt856 *encoder = i2c_get_clientdata(client);
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+
+       kfree(encoder);
+       kfree(client);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
 static struct i2c_driver i2c_driver_bt856 = {
        .owner = THIS_MODULE,
-       .name = "bt856",                /* name */
-       .id = I2C_DRIVERID_BT856,       /* ID */
+       .name = "bt856",
+
+       .id = I2C_DRIVERID_BT856,
        .flags = I2C_DF_NOTIFY,
-       .attach_adapter = bt856_probe,
-       .detach_client = bt856_detach,
-       .command = bt856_command
-};
 
-static struct i2c_client client_template = {
-       .id = -1,
-       .driver = &i2c_driver_bt856,
-       .name = "bt856_client",
+       .attach_adapter = bt856_attach_adapter,
+       .detach_client = bt856_detach_client,
+       .command = bt856_command,
 };
 
-static int bt856_init(void)
+static int __init
+bt856_init (void)
 {
        return i2c_add_driver(&i2c_driver_bt856);
 }
 
-static void bt856_exit(void)
+static void __exit
+bt856_exit (void)
 {
        i2c_del_driver(&i2c_driver_bt856);
 }
 
 module_init(bt856_init);
 module_exit(bt856_exit);
-MODULE_LICENSE("GPL");
index c1cb663c6749306d12d650f4187aa367045a07f8..99aaad69dc066b61b9f17c08a95f8cc5a34f8377 100644 (file)
@@ -1,22 +1,31 @@
 /*
-    saa7110 - Philips SAA7110(A) video decoder driver
-
-    Copyright (C) 1998 Pauline Middelink <middelin@polyware.nl>
-
-    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.
-*/
+ * saa7110 - Philips SAA7110(A) video decoder driver
+ *
+ * Copyright (C) 1998 Pauline Middelink <middelin@polyware.nl>
+ *
+ * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *    - some corrections for Pinnacle Systems Inc. DC10plus card.
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
+ *
+ * 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/version.h>
 
 #include <linux/module.h>
 #include <linux/init.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
+MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
+MODULE_AUTHOR("Pauline Middelink");
+MODULE_LICENSE("GPL");
+
 #include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define I2C_NAME(s) (s)->dev.name
+
 #include <linux/videodev.h>
-#include "linux/video_decoder.h"
+#include <linux/video_decoder.h>
 
-#define DEBUG(x...)                    /* remove when no long debugging */
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
 
 #define SAA7110_MAX_INPUT      9       /* 6 CVBS, 3 SVHS */
-#define SAA7110_MAX_OUTPUT     0       /* it's a decoder only */
+#define SAA7110_MAX_OUTPUT     0       /* its a decoder only */
 
 #define        I2C_SAA7110             0x9C    /* or 0x9E */
 
-#define IF_NAME        "saa7110"
-#define        I2C_DELAY               10      /* 10 us or 100khz */
+struct saa7110 {
+       unsigned char reg[54];
 
-static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+       int norm;
+       int input;
+       int enable;
+       int bright;
+       int contrast;
+       int hue;
+       int sat;
 
-static struct i2c_client_address_data addr_data = {
-       normal_i2c, normal_i2c_range,
-       probe, probe_range,
-       ignore, ignore_range,
-       force
+       wait_queue_head_t wq;
 };
 
-static struct i2c_client client_template;
+/* ----------------------------------------------------------------------- */
+/* I2C support functions                                                  */
+/* ----------------------------------------------------------------------- */
 
-struct saa7110 {
-       struct i2c_client *client;
-       int             addr;
-       unsigned char   reg[36];
-       struct semaphore lock;
-       int             norm;
-       int             input;
-       int             enable;
-       int             bright;
-       int             contrast;
-       int             hue;
-       int             sat;
-};
+static int
+saa7110_write (struct i2c_client *client,
+              u8                 reg,
+              u8                 value)
+{
+       struct saa7110 *decoder = i2c_get_clientdata(client);
+       decoder->reg[reg] = value;
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int
+saa7110_write_block (struct i2c_client *client,
+                    const u8          *data,
+                    unsigned int       len)
+{
+       int ret = -1;
+       u8 reg = *data++;
+       len--;
+
+       /* the saa7110 has an autoincrement function, use it if
+        * the adapter understands raw I2C */
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               struct saa7110 *decoder = i2c_get_clientdata(client);
+               struct i2c_msg msg;
+               u8 block_data[54];
+               msg.len = 0;
+               msg.buf = (char *) block_data;
+               msg.addr = client->addr;
+               msg.flags = client->flags;
+               while (len >= 1) {
+                       msg.len = 0;
+                       block_data[msg.len++] = reg;
+                       while (len-- >= 1 && msg.len < 54)
+                               block_data[msg.len++] =
+                                   decoder->reg[reg++] = *data++;
+                       ret = i2c_transfer(client->adapter, &msg, 1);
+               }
+       } else {
+               while (len-- >= 1) {
+                       if ((ret =
+                            saa7110_write(client, reg++, *data++)) < 0)
+                               break;
+               }
+       }
+
+       return ret;
+}
+
+static inline int
+saa7110_read (struct i2c_client *client)
+{
+       return i2c_smbus_read_byte(client);
+}
 
 /* ----------------------------------------------------------------------- */
 /* SAA7110 functions                                                      */
 /* ----------------------------------------------------------------------- */
-static
-int saa7110_selmux(struct i2c_client *client, int chan)
+
+#define FRESP_06H_COMPST 0x03  //0x13
+#define FRESP_06H_SVIDEO 0x83  //0xC0
+
+
+static int
+saa7110_selmux (struct i2c_client *client,
+               int                chan)
 {
-static const unsigned char modes[9][8] = {
-/* mode 0 */   { 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },
-/* mode 1 */   { 0x00, 0xD8, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },
-/* mode 2 */   { 0x00, 0xBA, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 },
-/* mode 3 */   { 0x00, 0xB8, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 },
-/* mode 4 */   { 0x00, 0x7C, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 },
-/* mode 5 */   { 0x00, 0x78, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 },
-/* mode 6 */   { 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 },
-/* mode 7 */   { 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 },
-/* mode 8 */   { 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } };
-       const unsigned char* ptr = modes[chan];
-
-       i2c_smbus_write_byte_data(client,0x06,ptr[0]);  /* Luminance control    */
-       i2c_smbus_write_byte_data(client,0x20,ptr[1]);  /* Analog Control #1    */
-       i2c_smbus_write_byte_data(client,0x21,ptr[2]);  /* Analog Control #2    */
-       i2c_smbus_write_byte_data(client,0x22,ptr[3]);  /* Mixer Control #1     */
-       i2c_smbus_write_byte_data(client,0x2C,ptr[4]);  /* Mixer Control #2     */
-       i2c_smbus_write_byte_data(client,0x30,ptr[5]);  /* ADCs gain control    */
-       i2c_smbus_write_byte_data(client,0x31,ptr[6]);  /* Mixer Control #3     */
-       i2c_smbus_write_byte_data(client,0x21,ptr[7]);  /* Analog Control #2    */
+       static const unsigned char modes[9][8] = {
+               /* mode 0 */
+               {FRESP_06H_COMPST, 0xD9, 0x17, 0x40, 0x03,
+                             0x44, 0x75, 0x16},
+               /* mode 1 */
+               {FRESP_06H_COMPST, 0xD8, 0x17, 0x40, 0x03,
+                             0x44, 0x75, 0x16},
+               /* mode 2 */
+               {FRESP_06H_COMPST, 0xBA, 0x07, 0x91, 0x03,
+                             0x60, 0xB5, 0x05},
+               /* mode 3 */
+               {FRESP_06H_COMPST, 0xB8, 0x07, 0x91, 0x03,
+                             0x60, 0xB5, 0x05},
+               /* mode 4 */
+               {FRESP_06H_COMPST, 0x7C, 0x07, 0xD2, 0x83,
+                             0x60, 0xB5, 0x03},
+               /* mode 5 */
+               {FRESP_06H_COMPST, 0x78, 0x07, 0xD2, 0x83,
+                             0x60, 0xB5, 0x03},
+               /* mode 6 */
+               {FRESP_06H_SVIDEO, 0x59, 0x17, 0x42, 0xA3,
+                             0x44, 0x75, 0x12},
+               /* mode 7 */
+               {FRESP_06H_SVIDEO, 0x9A, 0x17, 0xB1, 0x13,
+                             0x60, 0xB5, 0x14},
+               /* mode 8 */
+               {FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23,
+                             0x44, 0x75, 0x21}
+       };
+       struct saa7110 *decoder = i2c_get_clientdata(client);
+       const unsigned char *ptr = modes[chan];
+
+       saa7110_write(client, 0x06, ptr[0]);    /* Luminance control    */
+       saa7110_write(client, 0x20, ptr[1]);    /* Analog Control #1    */
+       saa7110_write(client, 0x21, ptr[2]);    /* Analog Control #2    */
+       saa7110_write(client, 0x22, ptr[3]);    /* Mixer Control #1     */
+       saa7110_write(client, 0x2C, ptr[4]);    /* Mixer Control #2     */
+       saa7110_write(client, 0x30, ptr[5]);    /* ADCs gain control    */
+       saa7110_write(client, 0x31, ptr[6]);    /* Mixer Control #3     */
+       saa7110_write(client, 0x21, ptr[7]);    /* Analog Control #2    */
+       decoder->input = chan;
 
        return 0;
 }
 
-static
-int determine_norm(struct i2c_client* client)
+static const unsigned char initseq[] = {
+       0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF2, 0x03, 0x00,
+       /* 0x08 */ 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x86, 0x18, 0x90,
+       /* 0x10 */ 0x00, 0x59, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
+       /* 0x18 */ 0xF2, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* 0x20 */ 0xD9, 0x16, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
+       /* 0x28 */ 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x03, 0x0C,
+       /* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02
+};
+
+static int
+determine_norm (struct i2c_client *client)
 {
-       int     status;
+       struct saa7110 *decoder = i2c_get_clientdata(client);
+       int status;
 
        /* mode changed, start automatic detection */
-       status = i2c_smbus_read_byte(client);
+       saa7110_write_block(client, initseq, sizeof(initseq));
+       saa7110_selmux(client, decoder->input);
+       sleep_on_timeout(&decoder->wq, HZ / 4);
+       status = saa7110_read(client);
+       if (status & 0x40) {
+               dprintk(1, KERN_INFO "%s: status=0x%02x (no signal)\n",
+                       I2C_NAME(client), status);
+               return decoder->norm;   // no change
+       }
        if ((status & 3) == 0) {
-               i2c_smbus_write_byte_data(client,0x06,0x80);
+               saa7110_write(client, 0x06, 0x83);
                if (status & 0x20) {
-                       DEBUG(printk(KERN_INFO "%s: norm=bw60\n",adp->name));
-                       i2c_smbus_write_byte_data(client,0x2E,0x81);
+                       dprintk(1,
+                               KERN_INFO
+                               "%s: status=0x%02x (NTSC/no color)\n",
+                               I2C_NAME(client), status);
+                       //saa7110_write(client,0x2E,0x81);
                        return VIDEO_MODE_NTSC;
                }
-               DEBUG(printk(KERN_INFO "%s: norm=bw50\n",adp->name));
-               i2c_smbus_write_byte_data(client,0x2E,0x9A);
+               dprintk(1, KERN_INFO "%s: status=0x%02x (PAL/no color)\n",
+                       I2C_NAME(client), status);
+               //saa7110_write(client,0x2E,0x9A);
                return VIDEO_MODE_PAL;
        }
-
-       i2c_smbus_write_byte_data(client,0x06,0x00);
+       //saa7110_write(client,0x06,0x03);
        if (status & 0x20) {    /* 60Hz */
-               DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",adp->name));
-               i2c_smbus_write_byte_data(client,0x0D,0x06);
-               i2c_smbus_write_byte_data(client,0x11,0x2C);
-               i2c_smbus_write_byte_data(client,0x2E,0x81);
+               dprintk(1, KERN_INFO "%s: status=0x%02x (NTSC)\n",
+                       I2C_NAME(client), status);
+               saa7110_write(client, 0x0D, 0x86);
+               saa7110_write(client, 0x0F, 0x50);
+               saa7110_write(client, 0x11, 0x2C);
+               //saa7110_write(client,0x2E,0x81);
                return VIDEO_MODE_NTSC;
        }
 
        /* 50Hz -> PAL/SECAM */
-       i2c_smbus_write_byte_data(client,0x0D,0x06);
-       i2c_smbus_write_byte_data(client,0x11,0x59);
-       i2c_smbus_write_byte_data(client,0x2E,0x9A);
+       saa7110_write(client, 0x0D, 0x86);
+       saa7110_write(client, 0x0F, 0x10);
+       saa7110_write(client, 0x11, 0x59);
+       //saa7110_write(client,0x2E,0x9A);
 
-       mdelay(150);    /* pause 150 ms */
+       sleep_on_timeout(&decoder->wq, HZ / 4);
 
-       status = i2c_smbus_read_byte(client);
+       status = saa7110_read(client);
        if ((status & 0x03) == 0x01) {
-               DEBUG(printk(KERN_INFO "%s: norm=secam\n",dev->name));
-               i2c_smbus_write_byte_data(client,0x0D,0x07);
+               dprintk(1, KERN_INFO "%s: status=0x%02x (SECAM)\n",
+                       I2C_NAME(client), status);
+               saa7110_write(client, 0x0D, 0x87);
                return VIDEO_MODE_SECAM;
        }
-       DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name));
+       dprintk(1, KERN_INFO "%s: status=0x%02x (PAL)\n", I2C_NAME(client),
+               status);
        return VIDEO_MODE_PAL;
 }
 
-static
-int saa7110_attach(struct i2c_adapter *adap, int  addr, int kind)
+static int
+saa7110_command (struct i2c_client *client,
+                unsigned int       cmd,
+                void              *arg)
 {
-static const unsigned char initseq[] = {
-            0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00,
-               0xF8, 0xF8, 0x60, 0x60, 0x00, 0x06, 0x18, 0x90,
-               0x00, 0x2C, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
-               0xF0, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
-               0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03,
-               0x40, 0x75, 0x01, 0x8C, 0x03};
-       struct  saa7110 *decoder;
-       struct i2c_client *client;
-       int                     rv;
-       client=kmalloc(sizeof(*client), GFP_KERNEL);
-       if(client == NULL) 
-               return -ENOMEM;
-       memset(client, 0, sizeof(*client));
-       client_template.adapter = adap;
-       client_template.addr = addr;
-       memcpy(client, &client_template, sizeof(*client));
-
-       decoder = kmalloc(sizeof(*decoder), GFP_KERNEL);
-       if (decoder == NULL) {
-               kfree(client);
-               return -ENOMEM;
-               }
+       struct saa7110 *decoder = i2c_get_clientdata(client);
+       int v;
 
-       /* clear our private data */
-       memset(decoder, 0, sizeof(*decoder));
-       strlcpy(client->name, IF_NAME, DEVICE_NAME_SIZE);
-       decoder->client = client;
-       i2c_set_clientdata(client, decoder);
-       decoder->addr = addr;
-       decoder->norm = VIDEO_MODE_PAL;
-       decoder->input = 0;
-       decoder->enable = 1;
-       decoder->bright = 32768;
-       decoder->contrast = 32768;
-       decoder->hue = 32768;
-       decoder->sat = 32768;
+       switch (cmd) {
+       case 0:
+               //saa7110_write_block(client, initseq, sizeof(initseq));
+               break;
 
-       rv = i2c_master_send(client, initseq, sizeof(initseq));
-       if (rv < 0)
-               printk(KERN_ERR "%s_attach: init status %d\n", client->name, rv);
-       else {
-               i2c_smbus_write_byte_data(client,0x21,0x16);
-               i2c_smbus_write_byte_data(client,0x0D,0x04);
-               DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", client->name, i2c_smbus_read_byte(client)));
-               i2c_smbus_write_byte_data(client,0x0D,0x06);
+       case DECODER_GET_CAPABILITIES:
+       {
+               struct video_decoder_capability *dc = arg;
+               dc->flags =
+                   VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
+                   VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
+               dc->inputs = SAA7110_MAX_INPUT;
+               dc->outputs = SAA7110_MAX_OUTPUT;
        }
-
-       init_MUTEX(&decoder->lock);
-       i2c_attach_client(client);
-       MOD_INC_USE_COUNT;
-       /* setup and implicit mode 0 select has been performed */
-       return 0;
-}
-
-static 
-int saa7110_probe(struct i2c_adapter *adap) 
-{
-       return i2c_probe(adap, &addr_data, saa7110_attach);
-}
-
-static
-int saa7110_detach(struct i2c_client *client)
-{
-       struct saa7110* decoder = i2c_get_clientdata(client);
-
-       i2c_detach_client(client);
-
-       DEBUG(printk(KERN_INFO "%s_detach\n",client->name));
-
-       /* stop further output */
-       i2c_smbus_write_byte_data(client,0x0E,0x00);
-
-       kfree(decoder);
-       kfree(client);
-
-       MOD_DEC_USE_COUNT;
-       return 0;
-}
-
-static
-int saa7110_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-       struct saa7110* decoder = i2c_get_clientdata(client);
-       int     v;
-
-       switch (cmd) {
-        case DECODER_GET_CAPABILITIES:
-               {
-                       struct video_decoder_capability *dc = arg;
-                       dc->flags = VIDEO_DECODER_PAL
-                                 | VIDEO_DECODER_NTSC
-                                 | VIDEO_DECODER_SECAM
-                                 | VIDEO_DECODER_AUTO
-                                 | VIDEO_DECODER_CCIR;
-                       dc->inputs = SAA7110_MAX_INPUT;
-                       dc->outputs = SAA7110_MAX_OUTPUT;
-               }
                break;
 
-        case DECODER_GET_STATUS:
-               {
-                       struct saa7110* decoder = i2c_get_clientdata(client);
-                       int status;
-                       int res = 0;
-
-                       status = i2c_smbus_read_byte(client);
-                       if (status & 0x40)
-                               res |= DECODER_STATUS_GOOD;
-                       if (status & 0x03)
-                               res |= DECODER_STATUS_COLOR;
-
-                       switch (decoder->norm) {
-                        case VIDEO_MODE_NTSC:
-                               res |= DECODER_STATUS_NTSC;
-                               break;
-                        case VIDEO_MODE_PAL:
-                               res |= DECODER_STATUS_PAL;
-                               break;
-                        case VIDEO_MODE_SECAM:
-                               res |= DECODER_STATUS_SECAM;
-                               break;
-                       }
-                       *(int*)arg = res;
+       case DECODER_GET_STATUS:
+       {
+               int status;
+               int res = 0;
+
+               status = saa7110_read(client);
+               dprintk(1, KERN_INFO "%s: status=0x%02x norm=%d\n",
+                       I2C_NAME(client), status, decoder->norm);
+               if (!(status & 0x40))
+                       res |= DECODER_STATUS_GOOD;
+               if (status & 0x03)
+                       res |= DECODER_STATUS_COLOR;
+
+               switch (decoder->norm) {
+               case VIDEO_MODE_NTSC:
+                       res |= DECODER_STATUS_NTSC;
+                       break;
+               case VIDEO_MODE_PAL:
+                       res |= DECODER_STATUS_PAL;
+                       break;
+               case VIDEO_MODE_SECAM:
+                       res |= DECODER_STATUS_SECAM;
+                       break;
                }
+               *(int *) arg = res;
+       }
                break;
 
-        case DECODER_SET_NORM:
-               v = *(int*)arg;
+       case DECODER_SET_NORM:
+               v = *(int *) arg;
                if (decoder->norm != v) {
                        decoder->norm = v;
-                       i2c_smbus_write_byte_data(client, 0x06, 0x00);
+                       //saa7110_write(client, 0x06, 0x03);
                        switch (v) {
-                        case VIDEO_MODE_NTSC:
-                               i2c_smbus_write_byte_data(client, 0x0D, 0x06);
-                               i2c_smbus_write_byte_data(client, 0x11, 0x2C);
-                               i2c_smbus_write_byte_data(client, 0x30, 0x81);
-                               i2c_smbus_write_byte_data(client, 0x2A, 0xDF);
+                       case VIDEO_MODE_NTSC:
+                               saa7110_write(client, 0x0D, 0x86);
+                               saa7110_write(client, 0x0F, 0x50);
+                               saa7110_write(client, 0x11, 0x2C);
+                               //saa7110_write(client, 0x2E, 0x81);
+                               dprintk(1,
+                                       KERN_INFO "%s: switched to NTSC\n",
+                                       I2C_NAME(client));
                                break;
-                        case VIDEO_MODE_PAL:
-                               i2c_smbus_write_byte_data(client, 0x0D, 0x06);
-                               i2c_smbus_write_byte_data(client, 0x11, 0x59);
-                               i2c_smbus_write_byte_data(client, 0x2E, 0x9A);
+                       case VIDEO_MODE_PAL:
+                               saa7110_write(client, 0x0D, 0x86);
+                               saa7110_write(client, 0x0F, 0x10);
+                               saa7110_write(client, 0x11, 0x59);
+                               //saa7110_write(client, 0x2E, 0x9A);
+                               dprintk(1,
+                                       KERN_INFO "%s: switched to PAL\n",
+                                       I2C_NAME(client));
                                break;
-                        case VIDEO_MODE_SECAM:
-                               i2c_smbus_write_byte_data(client, 0x0D, 0x07);
-                               i2c_smbus_write_byte_data(client, 0x11, 0x59);
-                               i2c_smbus_write_byte_data(client, 0x2E, 0x9A);
+                       case VIDEO_MODE_SECAM:
+                               saa7110_write(client, 0x0D, 0x87);
+                               saa7110_write(client, 0x0F, 0x10);
+                               saa7110_write(client, 0x11, 0x59);
+                               //saa7110_write(client, 0x2E, 0x9A);
+                               dprintk(1,
+                                       KERN_INFO
+                                       "%s: switched to SECAM\n",
+                                       I2C_NAME(client));
                                break;
-                        case VIDEO_MODE_AUTO:
-                               *(int*)arg = determine_norm(client);
+                       case VIDEO_MODE_AUTO:
+                               dprintk(1,
+                                       KERN_INFO
+                                       "%s: TV standard detection...\n",
+                                       I2C_NAME(client));
+                               decoder->norm = determine_norm(client);
+                               *(int *) arg = decoder->norm;
                                break;
-                        default:
+                       default:
                                return -EPERM;
                        }
                }
                break;
 
-        case DECODER_SET_INPUT:
-               v = *(int*)arg;
-               if (v<0 || v>SAA7110_MAX_INPUT)
+       case DECODER_SET_INPUT:
+               v = *(int *) arg;
+               if (v < 0 || v > SAA7110_MAX_INPUT) {
+                       dprintk(1,
+                               KERN_INFO "%s: input=%d not available\n",
+                               I2C_NAME(client), v);
                        return -EINVAL;
+               }
                if (decoder->input != v) {
-                       decoder->input = v;
                        saa7110_selmux(client, v);
+                       dprintk(1, KERN_INFO "%s: switched to input=%d\n",
+                               I2C_NAME(client), v);
                }
                break;
 
-        case DECODER_SET_OUTPUT:
-               v = *(int*)arg;
+       case DECODER_SET_OUTPUT:
+               v = *(int *) arg;
                /* not much choice of outputs */
                if (v != 0)
                        return -EINVAL;
                break;
 
-        case DECODER_ENABLE_OUTPUT:
-               v = *(int*)arg;
+       case DECODER_ENABLE_OUTPUT:
+               v = *(int *) arg;
                if (decoder->enable != v) {
                        decoder->enable = v;
-                       i2c_smbus_write_byte_data(client,0x0E, v ? 0x18 : 0x00);
+                       saa7110_write(client, 0x0E, v ? 0x18 : 0x80);
+                       dprintk(1, KERN_INFO "%s: YUV %s\n", I2C_NAME(client),
+                               v ? "on" : "off");
                }
                break;
 
-        case DECODER_SET_PICTURE:
-               {
-                       struct video_picture *pic = arg;
+       case DECODER_SET_PICTURE:
+       {
+               struct video_picture *pic = arg;
 
-                       if (decoder->bright != pic->brightness) {
-                               /* We want 0 to 255 we get 0-65535 */
-                               decoder->bright = pic->brightness;
-                               i2c_smbus_write_byte_data(client, 0x19, decoder->bright >> 8);
-                       }
-                       if (decoder->contrast != pic->contrast) {
-                               /* We want 0 to 127 we get 0-65535 */
-                               decoder->contrast = pic->contrast;
-                               i2c_smbus_write_byte_data(client, 0x13, decoder->contrast >> 9);
-                       }
-                       if (decoder->sat != pic->colour) {
-                               /* We want 0 to 127 we get 0-65535 */
-                               decoder->sat = pic->colour;
-                               i2c_smbus_write_byte_data(client, 0x12, decoder->sat >> 9);
-                       }
-                       if (decoder->hue != pic->hue) {
-                               /* We want -128 to 127 we get 0-65535 */
-                               decoder->hue = pic->hue;
-                               i2c_smbus_write_byte_data(client, 0x07, (decoder->hue>>8)-128);
-                       }
+               if (decoder->bright != pic->brightness) {
+                       /* We want 0 to 255 we get 0-65535 */
+                       decoder->bright = pic->brightness;
+                       saa7110_write(client, 0x19, decoder->bright >> 8);
                }
+               if (decoder->contrast != pic->contrast) {
+                       /* We want 0 to 127 we get 0-65535 */
+                       decoder->contrast = pic->contrast;
+                       saa7110_write(client, 0x13,
+                                     decoder->contrast >> 9);
+               }
+               if (decoder->sat != pic->colour) {
+                       /* We want 0 to 127 we get 0-65535 */
+                       decoder->sat = pic->colour;
+                       saa7110_write(client, 0x12, decoder->sat >> 9);
+               }
+               if (decoder->hue != pic->hue) {
+                       /* We want -128 to 127 we get 0-65535 */
+                       decoder->hue = pic->hue;
+                       saa7110_write(client, 0x07,
+                                     (decoder->hue >> 8) - 128);
+               }
+       }
                break;
 
-        case DECODER_DUMP:
-               for (v=0; v<34; v+=16) {
+       case DECODER_DUMP:
+               for (v = 0; v < 0x34; v += 16) {
                        int j;
-                       DEBUG(printk(KERN_INFO "%s: %03x\n",client->name,v));
-                       for (j=0; j<16; j++) {
-                               DEBUG(printk(KERN_INFO " %02x",decoder->reg[v+j]));
+                       dprintk(1, KERN_INFO "%s: %03x\n", I2C_NAME(client),
+                               v);
+                       for (j = 0; j < 16; j++) {
+                               dprintk(1, KERN_INFO " %02x",
+                                       decoder->reg[v + j]);
                        }
-                       DEBUG(printk(KERN_INFO "\n"));
+                       dprintk(1, KERN_INFO "\n");
                }
                break;
 
-        default:
-               DEBUG(printk(KERN_INFO "unknown saa7110_command??(%d)\n",cmd));
+       default:
+               dprintk(1, KERN_INFO "unknown saa7110_command??(%d)\n",
+                       cmd);
                return -EINVAL;
        }
        return 0;
@@ -380,33 +447,173 @@ int saa7110_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa7110 =
-{
-       .owner          = THIS_MODULE,
-       .name           = IF_NAME,                      /* name */
-       .id             = I2C_DRIVERID_SAA7110, /* in i2c.h */
-       .flags          = I2C_DF_NOTIFY,        /* Addr range */
-       .attach_adapter = saa7110_probe,
-       .detach_client  = saa7110_detach,
-       .command        = saa7110_command
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+static unsigned short normal_i2c[] = {
+       I2C_SAA7110 >> 1,
+       (I2C_SAA7110 >> 1) + 1,
+       I2C_CLIENT_END
 };
-static struct i2c_client client_template = {
-       .id             = -1,
-       .driver         = &i2c_driver_saa7110,
-       .name           = "saa7110_client",
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+                                                                                
+static struct i2c_client_address_data addr_data = {
+       .normal_i2c             = normal_i2c,
+       .normal_i2c_range       = normal_i2c_range,
+       .probe                  = probe,
+       .probe_range            = probe_range,
+       .ignore                 = ignore,
+       .ignore_range           = ignore_range,
+       .force                  = force
 };
 
-static int saa7110_init(void)
+static int saa7110_i2c_id = 0;
+static struct i2c_driver i2c_driver_saa7110;
+
+static int
+saa7110_detect_client (struct i2c_adapter *adapter,
+                      int                 address,
+                      int                 kind)
+{
+       struct i2c_client *client;
+       struct saa7110 *decoder;
+       int rv;
+
+       dprintk(1,
+               KERN_INFO
+               "saa7110.c: detecting saa7110 client on address 0x%x\n",
+               address << 1);
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality
+           (adapter,
+            I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+               return 0;
+
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+       memset(client, 0, sizeof(struct i2c_client));
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &i2c_driver_saa7110;
+       client->flags = I2C_CLIENT_ALLOW_USE;
+       client->id = saa7110_i2c_id++;
+       snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+               "saa7110[%d]", client->id);
+
+       decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL);
+       if (decoder == 0) {
+               kfree(client);
+               return -ENOMEM;
+       }
+       memset(decoder, 0, sizeof(struct saa7110));
+       decoder->norm = VIDEO_MODE_PAL;
+       decoder->input = 0;
+       decoder->enable = 1;
+       decoder->bright = 32768;
+       decoder->contrast = 32768;
+       decoder->hue = 32768;
+       decoder->sat = 32768;
+       init_waitqueue_head(&decoder->wq);
+       i2c_set_clientdata(client, decoder);
+
+       rv = i2c_attach_client(client);
+       if (rv) {
+               kfree(client);
+               kfree(decoder);
+               return rv;
+       }
+
+       rv = saa7110_write_block(client, initseq, sizeof(initseq));
+       if (rv < 0)
+               dprintk(1, KERN_ERR "%s_attach: init status %d\n",
+                       I2C_NAME(client), rv);
+       else {
+               int ver, status;
+               saa7110_write(client, 0x21, 0x10);
+               saa7110_write(client, 0x0e, 0x18);
+               saa7110_write(client, 0x0D, 0x04);
+               ver = saa7110_read(client);
+               saa7110_write(client, 0x0D, 0x06);
+               //mdelay(150);
+               status = saa7110_read(client);
+               dprintk(1,
+                       KERN_INFO
+                       "%s_attach: SAA7110A version %x at 0x%02x, status=0x%02x\n",
+                       I2C_NAME(client), ver, client->addr << 1, status);
+               saa7110_write(client, 0x0D, 0x86);
+               saa7110_write(client, 0x0F, 0x10);
+               saa7110_write(client, 0x11, 0x59);
+               //saa7110_write(client, 0x2E, 0x9A);
+       }
+
+       //saa7110_selmux(client,0);
+       //determine_norm(client);
+       /* setup and implicit mode 0 select has been performed */
+
+       return 0;
+}
+
+static int
+saa7110_attach_adapter (struct i2c_adapter *adapter)
+{
+       dprintk(1,
+               KERN_INFO
+               "saa7110.c: starting probe for adapter %s (0x%x)\n",
+               I2C_NAME(adapter), adapter->id);
+       return i2c_probe(adapter, &addr_data, &saa7110_detect_client);
+}
+
+static int
+saa7110_detach_client (struct i2c_client *client)
+{
+       struct saa7110 *decoder = i2c_get_clientdata(client);
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+
+       kfree(decoder);
+       kfree(client);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_saa7110 = {
+       .owner = THIS_MODULE,
+       .name = "saa7110",
+
+       .id = I2C_DRIVERID_SAA7110,
+       .flags = I2C_DF_NOTIFY,
+
+       .attach_adapter = saa7110_attach_adapter,
+       .detach_client = saa7110_detach_client,
+       .command = saa7110_command,
+};
+
+static int __init
+saa7110_init (void)
 {
        return i2c_add_driver(&i2c_driver_saa7110);
 }
 
-static void saa7110_exit(void)
+static void __exit
+saa7110_exit (void)
 {
        i2c_del_driver(&i2c_driver_saa7110);
 }
 
-
 module_init(saa7110_init);
 module_exit(saa7110_exit);
-MODULE_LICENSE("GPL");
index 2868285b8a9048c8fb1a1a2c46fa9fa0f4830804..1fd2bb5297914e6c5c1e6a29664d6a75fe2e427a 100644 (file)
@@ -1,25 +1,30 @@
 /* 
-    saa7111 - Philips SAA7111A video decoder driver version 0.0.3
+ * saa7111 - Philips SAA7111A video decoder driver version 0.0.3
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * Slight changes for video timing and attachment output by
+ * Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
+ *
+ * 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.
+ */
 
-    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
-
-    Slight changes for video timing and attachment output by
-    Wolfgang Scherr <scherr@net4you.net>
-    
-    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/version.h>
 
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/major.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
 #include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
 
 #include <linux/videodev.h>
 #include <linux/version.h>
+#include <asm/uaccess.h>
+
+MODULE_DESCRIPTION("Philips SAA7111 video decoder driver");
+MODULE_AUTHOR("Dave Perks");
+MODULE_LICENSE("GPL");
+
 #include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define I2C_NAME(s) (s)->dev.name
 
 #include <linux/video_decoder.h>
 
-#define DEBUG(x)               /* Debug driver */
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
 
 /* ----------------------------------------------------------------------- */
 
 struct saa7111 {
-       struct i2c_client *client;
-       int addr;
-       struct semaphore lock;
        unsigned char reg[32];
 
        int norm;
@@ -57,335 +83,344 @@ struct saa7111 {
        int sat;
 };
 
-static unsigned short normal_i2c[] = { 0x24, 0x25, I2C_CLIENT_END };   
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; 
-
-I2C_CLIENT_INSMOD;
-
-static struct i2c_client client_template;
+#define   I2C_SAA7111        0x48
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7111_attach(struct i2c_adapter *adap, int addr, int kind)
+static inline int
+saa7111_write (struct i2c_client *client,
+              u8                 reg,
+              u8                 value)
 {
-       int i;
-       struct saa7111 *decoder;
-       struct i2c_client *client;
-
-       /* who wrote this? init[] is used for i2c_master_send() which expects an array that
-          will be used for the 'buf' part of an i2c message unchanged. so, the first byte
-          needs to be the subaddress to start with, then follow the data bytes... */
-       static const unsigned char init[] = {
-               0x00,     /* start address */
-       
-               0x00,     /* 00 - ID byte */
-               0x00,     /* 01 - reserved */
-
-               /*front end */
-               0xd0,     /* 02 - FUSE=3, GUDL=2, MODE=0 */
-               0x23,     /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
-               0x00,     /* 04 - GAI1=256 */
-               0x00,     /* 05 - GAI2=256 */
-
-               /* decoder */
-               0xf3,     /* 06 - HSB at  13(50Hz) /  17(60Hz) pixels after end of last line */
-               0x13,     /* 07 - HSS at 113(50Hz) / 117(60Hz) pixels after end of last line */
-               0xc8,     /* 08 - AUFD=1, FSEL=1, EXFIL=0, VTRC=1, HPLL=0, VNOI=0 */
-               0x01,     /* 09 - BYPS=0, PREF=0, BPSS=0, VBLB=0, UPTCV=0, APER=1 */
-               0x80,     /* 0a - BRIG=128 */
-               0x47,     /* 0b - CONT=1.109 */
-               0x40,     /* 0c - SATN=1.0 */
-               0x00,     /* 0d - HUE=0 */
-               0x01,     /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
-               0x00,     /* 0f - reserved */
-               0x48,     /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
-               0x1c,     /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
-               0x00,     /* 12 - output control 2 */
-               0x00,     /* 13 - output control 3 */
-               0x00,     /* 14 - reserved */
-               0x00,     /* 15 - VBI */
-               0x00,     /* 16 - VBI */
-               0x00,     /* 17 - VBI */
-       };
-       client = kmalloc(sizeof(*client), GFP_KERNEL);
-       if(client == NULL) 
-               return -ENOMEM;
-       client_template.adapter = adap;
-       client_template.addr = addr;
-       memcpy(client, &client_template, sizeof(*client));
-
-       decoder = kmalloc(sizeof(*decoder), GFP_KERNEL);
-       if (decoder == NULL)
-       {
-               kfree(client);
-               return -ENOMEM;
-       }
-
-       memset(decoder, 0, sizeof(*decoder));
-       strlcpy(client->name, "saa7111", DEVICE_NAME_SIZE);
-       decoder->client = client;
-       i2c_set_clientdata(client, decoder);
-       decoder->addr = addr;
-       decoder->norm = VIDEO_MODE_NTSC;
-       decoder->input = 0;
-       decoder->enable = 1;
-       decoder->bright = 32768;
-       decoder->contrast = 32768;
-       decoder->hue = 32768;
-       decoder->sat = 32768;
+       struct saa7111 *decoder = i2c_get_clientdata(client);
+       decoder->reg[reg] = value;
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
 
-       i = i2c_master_send(client, init, sizeof(init));
-       if (i < 0) {
-               printk(KERN_ERR "%s_attach: init status %d\n",
-                      client->name, i);
+static int
+saa7111_write_block (struct i2c_client *client,
+                    const u8          *data,
+                    unsigned int       len)
+{
+       int ret = -1;
+       u8 reg;
+
+       /* the saa7111 has an autoincrement function, use it if
+        * the adapter understands raw I2C */
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               /* do raw I2C, not smbus compatible */
+               struct saa7111 *decoder = i2c_get_clientdata(client);
+               struct i2c_msg msg;
+               u8 block_data[32];
+               msg.addr = client->addr;
+               msg.flags = client->flags;
+               while (len >= 2) {
+                       msg.buf = (char *) block_data;
+                       msg.len = 0;
+                       block_data[msg.len++] = reg = data[0];
+                       do {
+                               block_data[msg.len++] =
+                                   decoder->reg[reg++] = data[1];
+                               len -= 2;
+                               data += 2;
+                       } while (len >= 2 && data[0] == reg &&
+                                msg.len < 32);
+                       if ((ret =
+                            i2c_transfer(client->adapter, &msg, 1)) < 0)
+                               break;
+               }
        } else {
-               printk(KERN_INFO "%s_attach: chip version %x @ 0x%08x\n",
-                      client->name, i2c_smbus_read_byte_data(client, 0x00) >> 4,addr);
+               /* do some slow I2C emulation kind of thing */
+               while (len >= 2) {
+                       reg = *data++;
+                       if ((ret =
+                            saa7111_write(client, reg, *data++)) < 0)
+                               break;
+                       len -= 2;
+               }
        }
 
-       init_MUTEX(&decoder->lock);
-       i2c_attach_client(client);
-       MOD_INC_USE_COUNT;
-       return 0;
-}
-static int saa7111_probe(struct i2c_adapter *adap)
-{
-       /* probing unknown devices on any Matrox i2c-bus takes ages due to the
-          slow bit banging algorithm used. because of the fact a saa7111(a)
-          is *never* present on a Matrox gfx card, we can skip such adapters
-          here */
-       if( 0 != (adap->id & I2C_HW_B_G400)) {
-               return -ENODEV;
-       }
-       
-       printk("saa7111: probing %s i2c adapter [id=0x%x]\n",
-                       adap->name,adap->id);
-       return i2c_probe(adap, &addr_data, saa7111_attach);
+       return ret;
 }
 
-static int saa7111_detach(struct i2c_client *client)
+static inline int
+saa7111_read (struct i2c_client *client,
+             u8                 reg)
 {
-       struct saa7111 *decoder = i2c_get_clientdata(client);
-       i2c_detach_client(client);
-       kfree(decoder);
-       kfree(client);
-       MOD_DEC_USE_COUNT;
-       return 0;
+       return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int saa7111_command(struct i2c_client *client, unsigned int cmd,
-                          void *arg)
+/* ----------------------------------------------------------------------- */
+
+static const unsigned char init[] = {
+       0x00, 0x00,             /* 00 - ID byte */
+       0x01, 0x00,             /* 01 - reserved */
+
+       /*front end */
+       0x02, 0xd0,             /* 02 - FUSE=3, GUDL=2, MODE=0 */
+       0x03, 0x23,             /* 03 - HLNRS=0, VBSL=1, WPOFF=0,
+                                * HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
+       0x04, 0x00,             /* 04 - GAI1=256 */
+       0x05, 0x00,             /* 05 - GAI2=256 */
+
+       /* decoder */
+       0x06, 0xf3,             /* 06 - HSB at  13(50Hz) /  17(60Hz)
+                                * pixels after end of last line */
+       /*0x07, 0x13,     * 07 - HSS at 113(50Hz) / 117(60Hz) pixels
+                                * after end of last line */
+       0x07, 0xe8,             /* 07 - HSS seems to be needed to
+                                * work with NTSC, too */
+       0x08, 0xc8,             /* 08 - AUFD=1, FSEL=1, EXFIL=0,
+                                * VTRC=1, HPLL=0, VNOI=0 */
+       0x09, 0x01,             /* 09 - BYPS=0, PREF=0, BPSS=0,
+                                * VBLB=0, UPTCV=0, APER=1 */
+       0x0a, 0x80,             /* 0a - BRIG=128 */
+       0x0b, 0x47,             /* 0b - CONT=1.109 */
+       0x0c, 0x40,             /* 0c - SATN=1.0 */
+       0x0d, 0x00,             /* 0d - HUE=0 */
+       0x0e, 0x01,             /* 0e - CDTO=0, CSTD=0, DCCF=0,
+                                * FCTC=0, CHBW=1 */
+       0x0f, 0x00,             /* 0f - reserved */
+       0x10, 0x48,             /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
+       0x11, 0x1c,             /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
+                                * OEYC=1, OEHV=1, VIPB=0, COLO=0 */
+       0x12, 0x00,             /* 12 - output control 2 */
+       0x13, 0x00,             /* 13 - output control 3 */
+       0x14, 0x00,             /* 14 - reserved */
+       0x15, 0x00,             /* 15 - VBI */
+       0x16, 0x00,             /* 16 - VBI */
+       0x17, 0x00,             /* 17 - VBI */
+};
+
+static int
+saa7111_command (struct i2c_client *client,
+                unsigned int       cmd,
+                void              *arg)
 {
        struct saa7111 *decoder = i2c_get_clientdata(client);
 
        switch (cmd) {
 
-#if defined(DECODER_DUMP)
+       case 0:
+               //saa7111_write_block(client, init, sizeof(init));
+               break;
+
        case DECODER_DUMP:
-               {
-                       int i;
-
-                       for (i = 0; i < 32; i += 16) {
-                               int j;
-
-                               printk("KERN_DEBUG %s: %03x", client->name, i);
-                               for (j = 0; j < 16; ++j) {
-                                       printk(" %02x",
-                                              i2c_smbus_read_byte_data(client,
-                                                           i + j));
-                               }
-                               printk("\n");
+       {
+               int i;
+
+               for (i = 0; i < 32; i += 16) {
+                       int j;
+
+                       printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
+                       for (j = 0; j < 16; ++j) {
+                               printk(" %02x",
+                                      saa7111_read(client, i + j));
                        }
+                       printk("\n");
                }
+       }
                break;
-#endif                         /* defined(DECODER_DUMP) */
 
        case DECODER_GET_CAPABILITIES:
-               {
-                       struct video_decoder_capability *cap = arg;
-
-                       cap->flags
-                           = VIDEO_DECODER_PAL
-                           | VIDEO_DECODER_NTSC
-                           | VIDEO_DECODER_AUTO | VIDEO_DECODER_CCIR;
-                       cap->inputs = 8;
-                       cap->outputs = 1;
-               }
+       {
+               struct video_decoder_capability *cap = arg;
+
+               cap->flags = VIDEO_DECODER_PAL |
+                            VIDEO_DECODER_NTSC |
+                            VIDEO_DECODER_SECAM |
+                            VIDEO_DECODER_AUTO |
+                            VIDEO_DECODER_CCIR;
+               cap->inputs = 8;
+               cap->outputs = 1;
+       }
                break;
 
        case DECODER_GET_STATUS:
-               {
-                       int *iarg = arg;
-                       int status;
-                       int res;
-
-                       status = i2c_smbus_read_byte_data(client, 0x1f);
-                       res = 0;
-                       if ((status & (1 << 6)) == 0) {
-                               res |= DECODER_STATUS_GOOD;
-                       }
-                       switch (decoder->norm) {
-                       case VIDEO_MODE_NTSC:
+       {
+               int *iarg = arg;
+               int status;
+               int res;
+
+               status = saa7111_read(client, 0x1f);
+               dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
+                       status);
+               res = 0;
+               if ((status & (1 << 6)) == 0) {
+                       res |= DECODER_STATUS_GOOD;
+               }
+               switch (decoder->norm) {
+               case VIDEO_MODE_NTSC:
+                       res |= DECODER_STATUS_NTSC;
+                       break;
+               case VIDEO_MODE_PAL:
+                       res |= DECODER_STATUS_PAL;
+                       break;
+               case VIDEO_MODE_SECAM:
+                       res |= DECODER_STATUS_SECAM;
+                       break;
+               default:
+               case VIDEO_MODE_AUTO:
+                       if ((status & (1 << 5)) != 0) {
                                res |= DECODER_STATUS_NTSC;
-                               break;
-                       case VIDEO_MODE_PAL:
+                       } else {
                                res |= DECODER_STATUS_PAL;
-                               break;
-                       default:
-                       case VIDEO_MODE_AUTO:
-                               if ((status & (1 << 5)) != 0) {
-                                       res |= DECODER_STATUS_NTSC;
-                               } else {
-                                       res |= DECODER_STATUS_PAL;
-                               }
-                               break;
-                       }
-                       if ((status & (1 << 0)) != 0) {
-                               res |= DECODER_STATUS_COLOR;
                        }
-                       *iarg = res;
+                       break;
                }
+               if ((status & (1 << 0)) != 0) {
+                       res |= DECODER_STATUS_COLOR;
+               }
+               *iarg = res;
+       }
                break;
 
        case DECODER_SET_NORM:
-               {
-                       int *iarg = arg;
-
-                       switch (*iarg) {
-
-                       case VIDEO_MODE_NTSC:
-                               i2c_smbus_write_byte_data(client, 0x08,
-                                             (decoder->
-                                              reg[0x08] & 0x3f) | 0x40);
-                               break;
-
-                       case VIDEO_MODE_PAL:
-                               i2c_smbus_write_byte_data(client, 0x08,
-                                             (decoder->
-                                              reg[0x08] & 0x3f) | 0x00);
-                               break;
-
-                       case VIDEO_MODE_AUTO:
-                               i2c_smbus_write_byte_data(client, 0x08,
-                                             (decoder->
-                                              reg[0x08] & 0x3f) | 0x80);
-                               break;
-
-                       default:
-                               return -EINVAL;
+       {
+               int *iarg = arg;
+
+               switch (*iarg) {
+
+               case VIDEO_MODE_NTSC:
+                       saa7111_write(client, 0x08,
+                                     (decoder->reg[0x08] & 0x3f) | 0x40);
+                       saa7111_write(client, 0x0e,
+                                     (decoder->reg[0x0e] & 0x8f));
+                       break;
+
+               case VIDEO_MODE_PAL:
+                       saa7111_write(client, 0x08,
+                                     (decoder->reg[0x08] & 0x3f) | 0x00);
+                       saa7111_write(client, 0x0e,
+                                     (decoder->reg[0x0e] & 0x8f));
+                       break;
+
+               case VIDEO_MODE_SECAM:
+                       saa7111_write(client, 0x08,
+                                     (decoder->reg[0x0e] & 0x3f) | 0x00);
+                       saa7111_write(client, 0x0e,
+                                     (decoder->reg[0x0e] & 0x8f) | 0x50);
+                       break;
+
+               case VIDEO_MODE_AUTO:
+                       saa7111_write(client, 0x08,
+                                     (decoder->reg[0x08] & 0x3f) | 0x80);
+                       saa7111_write(client, 0x0e,
+                                     (decoder->reg[0x0e] & 0x8f));
+                       break;
+
+               default:
+                       return -EINVAL;
 
-                       }
-                       decoder->norm = *iarg;
                }
+               decoder->norm = *iarg;
+       }
                break;
 
        case DECODER_SET_INPUT:
-               {
-                       int *iarg = arg;
+       {
+               int *iarg = arg;
 
-                       if (*iarg < 0 || *iarg > 7) {
-                               return -EINVAL;
-                       }
+               if (*iarg < 0 || *iarg > 7) {
+                       return -EINVAL;
+               }
 
-                       if (decoder->input != *iarg) {
-                               decoder->input = *iarg;
-                               /* select mode */
-                               i2c_smbus_write_byte_data(client, 0x02,
-                                             (decoder->
-                                              reg[0x02] & 0xf8) |
-                                             decoder->input);
-                               /* bypass chrominance trap for modes 4..7 */
-                               i2c_smbus_write_byte_data(client, 0x09,
-                                             (decoder->
-                                              reg[0x09] & 0x7f) |
-                                             ((decoder->input >
-                                               3) ? 0x80 : 0));
-                       }
+               if (decoder->input != *iarg) {
+                       decoder->input = *iarg;
+                       /* select mode */
+                       saa7111_write(client, 0x02,
+                                     (decoder->
+                                      reg[0x02] & 0xf8) | decoder->input);
+                       /* bypass chrominance trap for modes 4..7 */
+                       saa7111_write(client, 0x09,
+                                     (decoder->
+                                      reg[0x09] & 0x7f) | ((decoder->
+                                                            input >
+                                                            3) ? 0x80 :
+                                                           0));
                }
+       }
                break;
 
        case DECODER_SET_OUTPUT:
-               {
-                       int *iarg = arg;
+       {
+               int *iarg = arg;
 
-                       /* not much choice of outputs */
-                       if (*iarg != 0) {
-                               return -EINVAL;
-                       }
+               /* not much choice of outputs */
+               if (*iarg != 0) {
+                       return -EINVAL;
                }
+       }
                break;
 
        case DECODER_ENABLE_OUTPUT:
-               {
-                       int *iarg = arg;
-                       int enable = (*iarg != 0);
-
-                       if (decoder->enable != enable) {
-                               decoder->enable = enable;
-
-// RJ: If output should be disabled (for playing videos), we also need a open PLL.
-//     The input is set to 0 (where no input source is connected), although this
-//     is not necessary.
-//
-//     If output should be enabled, we have to reverse the above.
-
-                               if (decoder->enable) {
-                                       i2c_smbus_write_byte_data(client, 0x02,
-                                                     (decoder->
-                                                      reg[0x02] & 0xf8) |
-                                                     decoder->input);
-                                       i2c_smbus_write_byte_data(client, 0x08,
-                                                     (decoder->
-                                                      reg[0x08] & 0xfb));
-                                       i2c_smbus_write_byte_data(client, 0x11,
-                                                     (decoder->
-                                                      reg[0x11] & 0xf3) |
-                                                     0x0c);
-                               } else {
-                                       i2c_smbus_write_byte_data(client, 0x02,
-                                                     (decoder->
-                                                      reg[0x02] & 0xf8));
-                                       i2c_smbus_write_byte_data(client, 0x08,
-                                                     (decoder->
-                                                      reg[0x08] & 0xfb) |
-                                                     0x04);
-                                       i2c_smbus_write_byte_data(client, 0x11,
-                                                     (decoder->
-                                                      reg[0x11] & 0xf3));
-                               }
+       {
+               int *iarg = arg;
+               int enable = (*iarg != 0);
+
+               if (decoder->enable != enable) {
+                       decoder->enable = enable;
+
+                       /* RJ: If output should be disabled (for
+                        * playing videos), we also need a open PLL.
+                        * The input is set to 0 (where no input
+                        * source is connected), although this
+                        * is not necessary.
+                        *
+                        * If output should be enabled, we have to
+                        * reverse the above.
+                        */
+
+                       if (decoder->enable) {
+                               saa7111_write(client, 0x02,
+                                             (decoder->
+                                              reg[0x02] & 0xf8) |
+                                             decoder->input);
+                               saa7111_write(client, 0x08,
+                                             (decoder->reg[0x08] & 0xfb));
+                               saa7111_write(client, 0x11,
+                                             (decoder->
+                                              reg[0x11] & 0xf3) | 0x0c);
+                       } else {
+                               saa7111_write(client, 0x02,
+                                             (decoder->reg[0x02] & 0xf8));
+                               saa7111_write(client, 0x08,
+                                             (decoder->
+                                              reg[0x08] & 0xfb) | 0x04);
+                               saa7111_write(client, 0x11,
+                                             (decoder->reg[0x11] & 0xf3));
                        }
                }
+       }
                break;
 
        case DECODER_SET_PICTURE:
-               {
-                       struct video_picture *pic = arg;
-
-                       if (decoder->bright != pic->brightness) {
-                               /* We want 0 to 255 we get 0-65535 */
-                               decoder->bright = pic->brightness;
-                               i2c_smbus_write_byte_data(client, 0x0a,
-                                             decoder->bright >> 8);
-                       }
-                       if (decoder->contrast != pic->contrast) {
-                               /* We want 0 to 127 we get 0-65535 */
-                               decoder->contrast = pic->contrast;
-                               i2c_smbus_write_byte_data(client, 0x0b,
-                                             decoder->contrast >> 9);
-                       }
-                       if (decoder->sat != pic->colour) {
-                               /* We want 0 to 127 we get 0-65535 */
-                               decoder->sat = pic->colour;
-                               i2c_smbus_write_byte_data(client, 0x0c,
-                                             decoder->sat >> 9);
-                       }
-                       if (decoder->hue != pic->hue) {
-                               /* We want -128 to 127 we get 0-65535 */
-                               decoder->hue = pic->hue;
-                               i2c_smbus_write_byte_data(client, 0x0d,
-                                             (decoder->hue - 32768) >> 8);
-                       }
+       {
+               struct video_picture *pic = arg;
+
+               if (decoder->bright != pic->brightness) {
+                       /* We want 0 to 255 we get 0-65535 */
+                       decoder->bright = pic->brightness;
+                       saa7111_write(client, 0x0a, decoder->bright >> 8);
                }
+               if (decoder->contrast != pic->contrast) {
+                       /* We want 0 to 127 we get 0-65535 */
+                       decoder->contrast = pic->contrast;
+                       saa7111_write(client, 0x0b,
+                                     decoder->contrast >> 9);
+               }
+               if (decoder->sat != pic->colour) {
+                       /* We want 0 to 127 we get 0-65535 */
+                       decoder->sat = pic->colour;
+                       saa7111_write(client, 0x0c, decoder->sat >> 9);
+               }
+               if (decoder->hue != pic->hue) {
+                       /* We want -128 to 127 we get 0-65535 */
+                       decoder->hue = pic->hue;
+                       saa7111_write(client, 0x0d,
+                                     (decoder->hue - 32768) >> 8);
+               }
+       }
                break;
 
        default:
@@ -397,34 +432,151 @@ static int saa7111_command(struct i2c_client *client, unsigned int cmd,
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa7111 = {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,54)
-       .owner          = THIS_MODULE,
-#endif
-       .name           = "saa7111",             /* name */
-       .id             = I2C_DRIVERID_SAA7111A, /* ID */
-       .flags          = I2C_DF_NOTIFY,
-       .attach_adapter = saa7111_probe,
-       .detach_client  = saa7111_detach,
-       .command        = saa7111_command
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+static unsigned short normal_i2c[] = { I2C_SAA7111 >> 1, I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+                                                                                
+static struct i2c_client_address_data addr_data = {
+       .normal_i2c             = normal_i2c,
+       .normal_i2c_range       = normal_i2c_range,
+       .probe                  = probe,
+       .probe_range            = probe_range,
+       .ignore                 = ignore,
+       .ignore_range           = ignore_range,
+       .force                  = force
 };
 
-static struct i2c_client client_template = {
-       .id     = -1,
-       .driver = &i2c_driver_saa7111,
-       .name   = "saa7111_client",
+static int saa7111_i2c_id = 0;
+static struct i2c_driver i2c_driver_saa7111;
+
+static int
+saa7111_detect_client (struct i2c_adapter *adapter,
+                      int                 address,
+                      int                 kind)
+{
+       int i;
+       struct i2c_client *client;
+       struct saa7111 *decoder;
+
+       dprintk(1,
+               KERN_INFO
+               "saa7111.c: detecting saa7111 client on address 0x%x\n",
+               address << 1);
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return 0;
+
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+       memset(client, 0, sizeof(struct i2c_client));
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &i2c_driver_saa7111;
+       client->flags = I2C_CLIENT_ALLOW_USE;
+       client->id = saa7111_i2c_id++;
+       snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+               "saa7111[%d]", client->id);
+
+       decoder = kmalloc(sizeof(struct saa7111), GFP_KERNEL);
+       if (decoder == NULL) {
+               kfree(client);
+               return -ENOMEM;
+       }
+       memset(decoder, 0, sizeof(struct saa7111));
+       decoder->norm = VIDEO_MODE_NTSC;
+       decoder->input = 0;
+       decoder->enable = 1;
+       decoder->bright = 32768;
+       decoder->contrast = 32768;
+       decoder->hue = 32768;
+       decoder->sat = 32768;
+       i2c_set_clientdata(client, decoder);
+
+       i = i2c_attach_client(client);
+       if (i) {
+               kfree(client);
+               kfree(decoder);
+               return i;
+       }
+
+       i = saa7111_write_block(client, init, sizeof(init));
+       if (i < 0) {
+               dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
+                       I2C_NAME(client), i);
+       } else {
+               dprintk(1,
+                       KERN_INFO
+                       "%s_attach: chip version %x at address 0x%x\n",
+                       I2C_NAME(client), saa7111_read(client, 0x00) >> 4,
+                       client->addr << 1);
+       }
+
+       return 0;
+}
+
+static int
+saa7111_attach_adapter (struct i2c_adapter *adapter)
+{
+       dprintk(1,
+               KERN_INFO
+               "saa7111.c: starting probe for adapter %s (0x%x)\n",
+               I2C_NAME(adapter), adapter->id);
+       return i2c_probe(adapter, &addr_data, &saa7111_detect_client);
+}
+
+static int
+saa7111_detach_client (struct i2c_client *client)
+{
+       struct saa7111 *decoder = i2c_get_clientdata(client);
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+
+       kfree(decoder);
+       kfree(client);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_saa7111 = {
+       .owner = THIS_MODULE,
+       .name = "saa7111",
+
+       .id = I2C_DRIVERID_SAA7111A,
+       .flags = I2C_DF_NOTIFY,
+
+       .attach_adapter = saa7111_attach_adapter,
+       .detach_client = saa7111_detach_client,
+       .command = saa7111_command,
 };
 
-static int saa7111_init(void)
+static int __init
+saa7111_init (void)
 {
        return i2c_add_driver(&i2c_driver_saa7111);
 }
 
-static void saa7111_exit(void)
+static void __exit
+saa7111_exit (void)
 {
        i2c_del_driver(&i2c_driver_saa7111);
 }
 
 module_init(saa7111_init);
 module_exit(saa7111_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
new file mode 100644 (file)
index 0000000..9ab344d
--- /dev/null
@@ -0,0 +1,1235 @@
+/* 
+ * saa7114 - Philips SAA7114H video decoder driver version 0.0.1
+ *
+ * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
+ *
+ * Based on saa7111 driver by Dave Perks
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * Slight changes for video timing and attachment output by
+ * Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
+ *
+ * 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/version.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+
+#include <linux/slab.h>
+
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+
+#include <linux/videodev.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+MODULE_DESCRIPTION("Philips SAA7114H video decoder driver");
+MODULE_AUTHOR("Maxim Yevtyushkin");
+MODULE_LICENSE("GPL");
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define I2C_NAME(x) (x)->dev.name
+
+#include <linux/video_decoder.h>
+
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
+
+/* ----------------------------------------------------------------------- */
+
+struct saa7114 {
+       unsigned char reg[0xf0 * 2];
+
+       int norm;
+       int input;
+       int enable;
+       int bright;
+       int contrast;
+       int hue;
+       int sat;
+       int playback;
+};
+
+#define   I2C_SAA7114        0x42
+#define   I2C_SAA7114A       0x40
+
+#define   I2C_DELAY   10
+
+
+//#define SAA_7114_NTSC_HSYNC_START       (-3)
+//#define SAA_7114_NTSC_HSYNC_STOP        (-18)
+
+#define SAA_7114_NTSC_HSYNC_START  (-17)
+#define SAA_7114_NTSC_HSYNC_STOP   (-32)
+
+//#define SAA_7114_NTSC_HOFFSET           (5)
+#define SAA_7114_NTSC_HOFFSET          (6)
+#define SAA_7114_NTSC_VOFFSET           (10)
+#define SAA_7114_NTSC_WIDTH             (720)
+#define SAA_7114_NTSC_HEIGHT            (250)
+
+#define SAA_7114_SECAM_HSYNC_START      (-17)
+#define SAA_7114_SECAM_HSYNC_STOP       (-32)
+
+#define SAA_7114_SECAM_HOFFSET          (2)
+#define SAA_7114_SECAM_VOFFSET          (10)
+#define SAA_7114_SECAM_WIDTH            (720)
+#define SAA_7114_SECAM_HEIGHT           (300)
+
+#define SAA_7114_PAL_HSYNC_START        (-17)
+#define SAA_7114_PAL_HSYNC_STOP         (-32)
+
+#define SAA_7114_PAL_HOFFSET            (2)
+#define SAA_7114_PAL_VOFFSET            (10)
+#define SAA_7114_PAL_WIDTH              (720)
+#define SAA_7114_PAL_HEIGHT             (300)
+
+
+
+#define SAA_7114_VERTICAL_CHROMA_OFFSET         0      //0x50504040
+#define SAA_7114_VERTICAL_LUMA_OFFSET           0
+
+#define REG_ADDR(x) (((x) << 1) + 1)
+#define LOBYTE(x) ((unsigned char)((x) & 0xff))
+#define HIBYTE(x) ((unsigned char)(((x) >> 8) & 0xff))
+#define LOWORD(x) ((unsigned short int)((x) & 0xffff))
+#define HIWORD(x) ((unsigned short int)(((x) >> 16) & 0xffff))
+
+
+/* ----------------------------------------------------------------------- */
+
+static inline int
+saa7114_write (struct i2c_client *client,
+              u8                 reg,
+              u8                 value)
+{
+       /*struct saa7114 *decoder = i2c_get_clientdata(client);*/
+       /*decoder->reg[reg] = value;*/
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int
+saa7114_write_block (struct i2c_client *client,
+                    const u8          *data,
+                    unsigned int       len)
+{
+       int ret = -1;
+       u8 reg;
+
+       /* the saa7114 has an autoincrement function, use it if
+        * the adapter understands raw I2C */
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               /* do raw I2C, not smbus compatible */
+               /*struct saa7114 *decoder = i2c_get_clientdata(client);*/
+               struct i2c_msg msg;
+               u8 block_data[32];
+               msg.addr = client->addr;
+               msg.flags = client->flags;
+               while (len >= 2) {
+                       msg.buf = (char *) block_data;
+                       msg.len = 0;
+                       block_data[msg.len++] = reg = data[0];
+                       do {
+                               block_data[msg.len++] =
+                                   /*decoder->reg[reg++] =*/ data[1];
+                               len -= 2;
+                               data += 2;
+                       } while (len >= 2 && data[0] == reg &&
+                                msg.len < 32);
+                       if ((ret =
+                            i2c_transfer(client->adapter, &msg, 1)) < 0)
+                               break;
+               }
+       } else {
+               /* do some slow I2C emulation kind of thing */
+               while (len >= 2) {
+                       reg = *data++;
+                       if ((ret =
+                            saa7114_write(client, reg, *data++)) < 0)
+                               break;
+                       len -= 2;
+               }
+       }
+
+       return ret;
+}
+
+static inline int
+saa7114_read (struct i2c_client *client,
+             u8                 reg)
+{
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+// initially set NTSC, composite
+
+
+static const unsigned char init[] = {
+       0x00, 0x00,             /* 00 - ID byte , chip version,
+                                * read only */
+       0x01, 0x08,             /* 01 - X,X,X,X, IDEL3 to IDEL0 -
+                                * horizontal increment delay,
+                                * recommended position */
+       0x02, 0x00,             /* 02 - FUSE=3, GUDL=2, MODE=0 ;
+                                * input control */
+       0x03, 0x10,             /* 03 - HLNRS=0, VBSL=1, WPOFF=0,
+                                * HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
+       0x04, 0x90,             /* 04 - GAI1=256 */
+       0x05, 0x90,             /* 05 - GAI2=256 */
+       0x06, SAA_7114_NTSC_HSYNC_START,        /* 06 - HSB: hsync start,
+                                * depends on the video standard */
+       0x07, SAA_7114_NTSC_HSYNC_STOP, /* 07 - HSS: hsync stop, depends
+                                *on the video standard */
+       0x08, 0xb8,             /* 08 - AUFD=1, FSEL=1, EXFIL=0, VTRC=1,
+                                * HPLL: free running in playback, locked
+                                * in capture, VNOI=0 */
+       0x09, 0x80,             /* 09 - BYPS=0, PREF=0, BPSS=0, VBLB=0,
+                                * UPTCV=0, APER=1; depends from input */
+       0x0a, 0x80,             /* 0a - BRIG=128 */
+       0x0b, 0x44,             /* 0b - CONT=1.109 */
+       0x0c, 0x40,             /* 0c - SATN=1.0 */
+       0x0d, 0x00,             /* 0d - HUE=0 */
+       0x0e, 0x84,             /* 0e - CDTO, CSTD2 to 0, DCVF, FCTC,
+                                * CCOMB; depends from video standard */
+       0x0f, 0x24,             /* 0f - ACGC,CGAIN6 to CGAIN0; depends
+                                * from video standard */
+       0x10, 0x03,             /* 10 - OFFU1 to 0, OFFV1 to 0, CHBW,
+                                * LCBW2 to 0 */
+       0x11, 0x59,             /* 11 - COLO, RTP1, HEDL1 to 0, RTP0,
+                                * YDEL2 to 0 */
+       0x12, 0xc9,             /* 12 - RT signal control RTSE13 to 10
+                                * and 03 to 00 */
+       0x13, 0x80,             /* 13 - RT/X port output control  */
+       0x14, 0x00,             /* 14 - analog, ADC, compatibility control */
+       0x15, 0x00,             /* 15 - VGATE start FID change  */
+       0x16, 0xfe,             /* 16 - VGATE stop */
+       0x17, 0x00,             /* 17 - Misc., VGATE MSBs */
+       0x18, 0x40,             /* RAWG */
+       0x19, 0x80,             /* RAWO */
+       0x1a, 0x00,
+       0x1b, 0x00,
+       0x1c, 0x00,
+       0x1d, 0x00,
+       0x1e, 0x00,
+       0x1f, 0x00,             /* status byte, read only */
+       0x20, 0x00,             /* video decoder reserved part */
+       0x21, 0x00,
+       0x22, 0x00,
+       0x23, 0x00,
+       0x24, 0x00,
+       0x25, 0x00,
+       0x26, 0x00,
+       0x27, 0x00,
+       0x28, 0x00,
+       0x29, 0x00,
+       0x2a, 0x00,
+       0x2b, 0x00,
+       0x2c, 0x00,
+       0x2d, 0x00,
+       0x2e, 0x00,
+       0x2f, 0x00,
+       0x30, 0xbc,             /* audio clock generator */
+       0x31, 0xdf,
+       0x32, 0x02,
+       0x33, 0x00,
+       0x34, 0xcd,
+       0x35, 0xcc,
+       0x36, 0x3a,
+       0x37, 0x00,
+       0x38, 0x03,
+       0x39, 0x10,
+       0x3a, 0x00,
+       0x3b, 0x00,
+       0x3c, 0x00,
+       0x3d, 0x00,
+       0x3e, 0x00,
+       0x3f, 0x00,
+       0x40, 0x00,             /* VBI data slicer */
+       0x41, 0xff,
+       0x42, 0xff,
+       0x43, 0xff,
+       0x44, 0xff,
+       0x45, 0xff,
+       0x46, 0xff,
+       0x47, 0xff,
+       0x48, 0xff,
+       0x49, 0xff,
+       0x4a, 0xff,
+       0x4b, 0xff,
+       0x4c, 0xff,
+       0x4d, 0xff,
+       0x4e, 0xff,
+       0x4f, 0xff,
+       0x50, 0xff,
+       0x51, 0xff,
+       0x52, 0xff,
+       0x53, 0xff,
+       0x54, 0xff,
+       0x55, 0xff,
+       0x56, 0xff,
+       0x57, 0xff,
+       0x58, 0x40,             // framing code 
+       0x59, 0x47,             // horizontal offset
+       0x5a, 0x06,             // vertical offset
+       0x5b, 0x83,             // field offset
+       0x5c, 0x00,             // reserved
+       0x5d, 0x3e,             // header and data
+       0x5e, 0x00,             // sliced data
+       0x5f, 0x00,             // reserved
+       0x60, 0x00,             /* video decoder reserved part */
+       0x61, 0x00,
+       0x62, 0x00,
+       0x63, 0x00,
+       0x64, 0x00,
+       0x65, 0x00,
+       0x66, 0x00,
+       0x67, 0x00,
+       0x68, 0x00,
+       0x69, 0x00,
+       0x6a, 0x00,
+       0x6b, 0x00,
+       0x6c, 0x00,
+       0x6d, 0x00,
+       0x6e, 0x00,
+       0x6f, 0x00,
+       0x70, 0x00,             /* video decoder reserved part */
+       0x71, 0x00,
+       0x72, 0x00,
+       0x73, 0x00,
+       0x74, 0x00,
+       0x75, 0x00,
+       0x76, 0x00,
+       0x77, 0x00,
+       0x78, 0x00,
+       0x79, 0x00,
+       0x7a, 0x00,
+       0x7b, 0x00,
+       0x7c, 0x00,
+       0x7d, 0x00,
+       0x7e, 0x00,
+       0x7f, 0x00,
+       0x80, 0x00,             /* X-port, I-port and scaler */
+       0x81, 0x00,
+       0x82, 0x00,
+       0x83, 0x00,
+       0x84, 0xc5,
+       0x85, 0x0d,             // hsync and vsync ? 
+       0x86, 0x40,
+       0x87, 0x01,
+       0x88, 0x00,
+       0x89, 0x00,
+       0x8a, 0x00,
+       0x8b, 0x00,
+       0x8c, 0x00,
+       0x8d, 0x00,
+       0x8e, 0x00,
+       0x8f, 0x00,
+       0x90, 0x03,             /* Task A definition           */
+       0x91, 0x08,
+       0x92, 0x00,
+       0x93, 0x40,
+       0x94, 0x00,             // window settings
+       0x95, 0x00,
+       0x96, 0x00,
+       0x97, 0x00,
+       0x98, 0x00,
+       0x99, 0x00,
+       0x9a, 0x00,
+       0x9b, 0x00,
+       0x9c, 0x00,
+       0x9d, 0x00,
+       0x9e, 0x00,
+       0x9f, 0x00,
+       0xa0, 0x01,             /* horizontal integer prescaling ratio */
+       0xa1, 0x00,             /* horizontal prescaler accumulation
+                                * sequence length */
+       0xa2, 0x00,             /* UV FIR filter, Y FIR filter, prescaler
+                                * DC gain */
+       0xa3, 0x00,
+       0xa4, 0x80,             // luminance brightness
+       0xa5, 0x40,             // luminance gain
+       0xa6, 0x40,             // chrominance saturation
+       0xa7, 0x00,
+       0xa8, 0x00,             // horizontal luminance scaling increment
+       0xa9, 0x04,
+       0xaa, 0x00,             // horizontal luminance phase offset
+       0xab, 0x00,
+       0xac, 0x00,             // horizontal chrominance scaling increment
+       0xad, 0x02,
+       0xae, 0x00,             // horizontal chrominance phase offset
+       0xaf, 0x00,
+       0xb0, 0x00,             // vertical luminance scaling increment
+       0xb1, 0x04,
+       0xb2, 0x00,             // vertical chrominance scaling increment
+       0xb3, 0x04,
+       0xb4, 0x00,
+       0xb5, 0x00,
+       0xb6, 0x00,
+       0xb7, 0x00,
+       0xb8, 0x00,
+       0xb9, 0x00,
+       0xba, 0x00,
+       0xbb, 0x00,
+       0xbc, 0x00,
+       0xbd, 0x00,
+       0xbe, 0x00,
+       0xbf, 0x00,
+       0xc0, 0x02,             // Task B definition
+       0xc1, 0x08,
+       0xc2, 0x00,
+       0xc3, 0x40,
+       0xc4, 0x00,             // window settings
+       0xc5, 0x00,
+       0xc6, 0x00,
+       0xc7, 0x00,
+       0xc8, 0x00,
+       0xc9, 0x00,
+       0xca, 0x00,
+       0xcb, 0x00,
+       0xcc, 0x00,
+       0xcd, 0x00,
+       0xce, 0x00,
+       0xcf, 0x00,
+       0xd0, 0x01,             // horizontal integer prescaling ratio
+       0xd1, 0x00,             // horizontal prescaler accumulation sequence length
+       0xd2, 0x00,             // UV FIR filter, Y FIR filter, prescaler DC gain
+       0xd3, 0x00,
+       0xd4, 0x80,             // luminance brightness
+       0xd5, 0x40,             // luminance gain
+       0xd6, 0x40,             // chrominance saturation
+       0xd7, 0x00,
+       0xd8, 0x00,             // horizontal luminance scaling increment
+       0xd9, 0x04,
+       0xda, 0x00,             // horizontal luminance phase offset
+       0xdb, 0x00,
+       0xdc, 0x00,             // horizontal chrominance scaling increment 
+       0xdd, 0x02,
+       0xde, 0x00,             // horizontal chrominance phase offset
+       0xdf, 0x00,
+       0xe0, 0x00,             // vertical luminance scaling increment
+       0xe1, 0x04,
+       0xe2, 0x00,             // vertical chrominance scaling increment
+       0xe3, 0x04,
+       0xe4, 0x00,
+       0xe5, 0x00,
+       0xe6, 0x00,
+       0xe7, 0x00,
+       0xe8, 0x00,
+       0xe9, 0x00,
+       0xea, 0x00,
+       0xeb, 0x00,
+       0xec, 0x00,
+       0xed, 0x00,
+       0xee, 0x00,
+       0xef, 0x00
+};
+
+static int
+saa7114_command (struct i2c_client *client,
+                unsigned int       cmd,
+                void              *arg)
+{
+       struct saa7114 *decoder = i2c_get_clientdata(client);
+
+       switch (cmd) {
+
+       case 0:
+               //dprintk(1, KERN_INFO "%s: writing init\n", I2C_NAME(client));
+               //saa7114_write_block(client, init, sizeof(init));
+               break;
+
+       case DECODER_DUMP:
+       {
+               int i;
+
+               dprintk(1, KERN_INFO "%s: decoder dump\n", I2C_NAME(client));
+
+               for (i = 0; i < 32; i += 16) {
+                       int j;
+
+                       printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
+                       for (j = 0; j < 16; ++j) {
+                               printk(" %02x",
+                                      saa7114_read(client, i + j));
+                       }
+                       printk("\n");
+               }
+       }
+               break;
+
+       case DECODER_GET_CAPABILITIES:
+       {
+               struct video_decoder_capability *cap = arg;
+
+               dprintk(1, KERN_DEBUG "%s: decoder get capabilities\n",
+                       I2C_NAME(client));
+
+               cap->flags = VIDEO_DECODER_PAL |
+                            VIDEO_DECODER_NTSC |
+                            VIDEO_DECODER_AUTO |
+                            VIDEO_DECODER_CCIR;
+               cap->inputs = 8;
+               cap->outputs = 1;
+       }
+               break;
+
+       case DECODER_GET_STATUS:
+       {
+               int *iarg = arg;
+               int status;
+               int res;
+
+               status = saa7114_read(client, 0x1f);
+
+               dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
+                       status);
+               res = 0;
+               if ((status & (1 << 6)) == 0) {
+                       res |= DECODER_STATUS_GOOD;
+               }
+               switch (decoder->norm) {
+               case VIDEO_MODE_NTSC:
+                       res |= DECODER_STATUS_NTSC;
+                       break;
+               case VIDEO_MODE_PAL:
+                       res |= DECODER_STATUS_PAL;
+                       break;
+               case VIDEO_MODE_SECAM:
+                       res |= DECODER_STATUS_SECAM;
+                       break;
+               default:
+               case VIDEO_MODE_AUTO:
+                       if ((status & (1 << 5)) != 0) {
+                               res |= DECODER_STATUS_NTSC;
+                       } else {
+                               res |= DECODER_STATUS_PAL;
+                       }
+                       break;
+               }
+               if ((status & (1 << 0)) != 0) {
+                       res |= DECODER_STATUS_COLOR;
+               }
+               *iarg = res;
+       }
+               break;
+
+       case DECODER_SET_NORM:
+       {
+               int *iarg = arg;
+
+               short int hoff = 0, voff = 0, w = 0, h = 0;
+
+               dprintk(1, KERN_DEBUG "%s: decoder set norm ",
+                       I2C_NAME(client));
+               switch (*iarg) {
+
+               case VIDEO_MODE_NTSC:
+                       dprintk(1, "NTSC\n");
+                       decoder->reg[REG_ADDR(0x06)] =
+                           SAA_7114_NTSC_HSYNC_START;
+                       decoder->reg[REG_ADDR(0x07)] =
+                           SAA_7114_NTSC_HSYNC_STOP;
+
+                       decoder->reg[REG_ADDR(0x08)] = decoder->playback ? 0x7c : 0xb8; // PLL free when playback, PLL close when capture
+
+                       decoder->reg[REG_ADDR(0x0e)] = 0x85;
+                       decoder->reg[REG_ADDR(0x0f)] = 0x24;
+
+                       hoff = SAA_7114_NTSC_HOFFSET;
+                       voff = SAA_7114_NTSC_VOFFSET;
+                       w = SAA_7114_NTSC_WIDTH;
+                       h = SAA_7114_NTSC_HEIGHT;
+
+                       break;
+
+               case VIDEO_MODE_PAL:
+                       dprintk(1, "PAL\n");
+                       decoder->reg[REG_ADDR(0x06)] =
+                           SAA_7114_PAL_HSYNC_START;
+                       decoder->reg[REG_ADDR(0x07)] =
+                           SAA_7114_PAL_HSYNC_STOP;
+
+                       decoder->reg[REG_ADDR(0x08)] = decoder->playback ? 0x7c : 0xb8; // PLL free when playback, PLL close when capture
+
+                       decoder->reg[REG_ADDR(0x0e)] = 0x81;
+                       decoder->reg[REG_ADDR(0x0f)] = 0x24;
+
+                       hoff = SAA_7114_PAL_HOFFSET;
+                       voff = SAA_7114_PAL_VOFFSET;
+                       w = SAA_7114_PAL_WIDTH;
+                       h = SAA_7114_PAL_HEIGHT;
+
+                       break;
+
+               default:
+                       dprintk(1, " Unknown video mode!!!\n");
+                       return -EINVAL;
+
+               }
+
+
+               decoder->reg[REG_ADDR(0x94)] = LOBYTE(hoff);    // hoffset low
+               decoder->reg[REG_ADDR(0x95)] = HIBYTE(hoff) & 0x0f;     // hoffset high
+               decoder->reg[REG_ADDR(0x96)] = LOBYTE(w);       // width low
+               decoder->reg[REG_ADDR(0x97)] = HIBYTE(w) & 0x0f;        // width high
+               decoder->reg[REG_ADDR(0x98)] = LOBYTE(voff);    // voffset low
+               decoder->reg[REG_ADDR(0x99)] = HIBYTE(voff) & 0x0f;     // voffset high
+               decoder->reg[REG_ADDR(0x9a)] = LOBYTE(h + 2);   // height low
+               decoder->reg[REG_ADDR(0x9b)] = HIBYTE(h + 2) & 0x0f;    // height high
+               decoder->reg[REG_ADDR(0x9c)] = LOBYTE(w);       // out width low
+               decoder->reg[REG_ADDR(0x9d)] = HIBYTE(w) & 0x0f;        // out width high
+               decoder->reg[REG_ADDR(0x9e)] = LOBYTE(h);       // out height low
+               decoder->reg[REG_ADDR(0x9f)] = HIBYTE(h) & 0x0f;        // out height high
+
+               decoder->reg[REG_ADDR(0xc4)] = LOBYTE(hoff);    // hoffset low
+               decoder->reg[REG_ADDR(0xc5)] = HIBYTE(hoff) & 0x0f;     // hoffset high
+               decoder->reg[REG_ADDR(0xc6)] = LOBYTE(w);       // width low
+               decoder->reg[REG_ADDR(0xc7)] = HIBYTE(w) & 0x0f;        // width high
+               decoder->reg[REG_ADDR(0xc8)] = LOBYTE(voff);    // voffset low
+               decoder->reg[REG_ADDR(0xc9)] = HIBYTE(voff) & 0x0f;     // voffset high
+               decoder->reg[REG_ADDR(0xca)] = LOBYTE(h + 2);   // height low
+               decoder->reg[REG_ADDR(0xcb)] = HIBYTE(h + 2) & 0x0f;    // height high
+               decoder->reg[REG_ADDR(0xcc)] = LOBYTE(w);       // out width low
+               decoder->reg[REG_ADDR(0xcd)] = HIBYTE(w) & 0x0f;        // out width high
+               decoder->reg[REG_ADDR(0xce)] = LOBYTE(h);       // out height low
+               decoder->reg[REG_ADDR(0xcf)] = HIBYTE(h) & 0x0f;        // out height high
+
+
+               saa7114_write(client, 0x80, 0x06);      // i-port and scaler back end clock selection, task A&B off
+               saa7114_write(client, 0x88, 0xd8);      // sw reset scaler
+               saa7114_write(client, 0x88, 0xf8);      // sw reset scaler release
+
+               saa7114_write_block(client, decoder->reg + (0x06 << 1),
+                                   3 << 1);
+               saa7114_write_block(client, decoder->reg + (0x0e << 1),
+                                   2 << 1);
+               saa7114_write_block(client, decoder->reg + (0x5a << 1),
+                                   2 << 1);
+
+               saa7114_write_block(client, decoder->reg + (0x94 << 1),
+                                   (0x9f + 1 - 0x94) << 1);
+               saa7114_write_block(client, decoder->reg + (0xc4 << 1),
+                                   (0xcf + 1 - 0xc4) << 1);
+
+               saa7114_write(client, 0x88, 0xd8);      // sw reset scaler
+               saa7114_write(client, 0x88, 0xf8);      // sw reset scaler release
+               saa7114_write(client, 0x80, 0x36);      // i-port and scaler back end clock selection
+
+               decoder->norm = *iarg;
+       }
+               break;
+
+       case DECODER_SET_INPUT:
+       {
+               int *iarg = arg;
+
+               dprintk(1, KERN_DEBUG "%s: decoder set input (%d)\n",
+                       I2C_NAME(client), *iarg);
+               if (*iarg < 0 || *iarg > 7) {
+                       return -EINVAL;
+               }
+
+               if (decoder->input != *iarg) {
+                       dprintk(1, KERN_DEBUG "%s: now setting %s input\n",
+                               I2C_NAME(client),
+                               *iarg >= 6 ? "S-Video" : "Composite");
+                       decoder->input = *iarg;
+
+                       /* select mode */
+                       decoder->reg[REG_ADDR(0x02)] =
+                           (decoder->
+                            reg[REG_ADDR(0x02)] & 0xf0) | (decoder->
+                                                           input <
+                                                           6 ? 0x0 : 0x9);
+                       saa7114_write(client, 0x02,
+                                     decoder->reg[REG_ADDR(0x02)]);
+
+                       /* bypass chrominance trap for modes 6..9 */
+                       decoder->reg[REG_ADDR(0x09)] =
+                           (decoder->
+                            reg[REG_ADDR(0x09)] & 0x7f) | (decoder->
+                                                           input <
+                                                           6 ? 0x0 :
+                                                           0x80);
+                       saa7114_write(client, 0x09,
+                                     decoder->reg[REG_ADDR(0x09)]);
+
+                       decoder->reg[REG_ADDR(0x0e)] =
+                           decoder->input <
+                           6 ? decoder->
+                           reg[REG_ADDR(0x0e)] | 1 : decoder->
+                           reg[REG_ADDR(0x0e)] & ~1;
+                       saa7114_write(client, 0x0e,
+                                     decoder->reg[REG_ADDR(0x0e)]);
+               }
+       }
+               break;
+
+       case DECODER_SET_OUTPUT:
+       {
+               int *iarg = arg;
+
+               dprintk(1, KERN_DEBUG "%s: decoder set output\n",
+                       I2C_NAME(client));
+
+               /* not much choice of outputs */
+               if (*iarg != 0) {
+                       return -EINVAL;
+               }
+       }
+               break;
+
+       case DECODER_ENABLE_OUTPUT:
+       {
+               int *iarg = arg;
+               int enable = (*iarg != 0);
+
+               dprintk(1, KERN_DEBUG "%s: decoder %s output\n",
+                       I2C_NAME(client), enable ? "enable" : "disable");
+
+               decoder->playback = !enable;
+
+               if (decoder->enable != enable) {
+                       decoder->enable = enable;
+
+                       /* RJ: If output should be disabled (for
+                        * playing videos), we also need a open PLL.
+                        * The input is set to 0 (where no input
+                        * source is connected), although this
+                        * is not necessary.
+                        *
+                        * If output should be enabled, we have to
+                        * reverse the above.
+                        */
+
+                       if (decoder->enable) {
+                               decoder->reg[REG_ADDR(0x08)] = 0xb8;
+                               decoder->reg[REG_ADDR(0x12)] = 0xc9;
+                               decoder->reg[REG_ADDR(0x13)] = 0x80;
+                               decoder->reg[REG_ADDR(0x87)] = 0x01;
+                       } else {
+                               decoder->reg[REG_ADDR(0x08)] = 0x7c;
+                               decoder->reg[REG_ADDR(0x12)] = 0x00;
+                               decoder->reg[REG_ADDR(0x13)] = 0x00;
+                               decoder->reg[REG_ADDR(0x87)] = 0x00;
+                       }
+
+                       saa7114_write_block(client,
+                                           decoder->reg + (0x12 << 1),
+                                           2 << 1);
+                       saa7114_write(client, 0x08,
+                                     decoder->reg[REG_ADDR(0x08)]);
+                       saa7114_write(client, 0x87,
+                                     decoder->reg[REG_ADDR(0x87)]);
+                       saa7114_write(client, 0x88, 0xd8);      // sw reset scaler
+                       saa7114_write(client, 0x88, 0xf8);      // sw reset scaler release            
+                       saa7114_write(client, 0x80, 0x36);
+
+               }
+       }
+               break;
+
+       case DECODER_SET_PICTURE:
+       {
+               struct video_picture *pic = arg;
+
+               dprintk(1,
+                       KERN_DEBUG
+                       "%s: decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n",
+                       I2C_NAME(client), pic->brightness, pic->contrast,
+                       pic->colour, pic->hue);
+
+               if (decoder->bright != pic->brightness) {
+                       /* We want 0 to 255 we get 0-65535 */
+                       decoder->bright = pic->brightness;
+                       saa7114_write(client, 0x0a, decoder->bright >> 8);
+               }
+               if (decoder->contrast != pic->contrast) {
+                       /* We want 0 to 127 we get 0-65535 */
+                       decoder->contrast = pic->contrast;
+                       saa7114_write(client, 0x0b,
+                                     decoder->contrast >> 9);
+               }
+               if (decoder->sat != pic->colour) {
+                       /* We want 0 to 127 we get 0-65535 */
+                       decoder->sat = pic->colour;
+                       saa7114_write(client, 0x0c, decoder->sat >> 9);
+               }
+               if (decoder->hue != pic->hue) {
+                       /* We want -128 to 127 we get 0-65535 */
+                       decoder->hue = pic->hue;
+                       saa7114_write(client, 0x0d,
+                                     (decoder->hue - 32768) >> 8);
+               }
+       }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+static unsigned short normal_i2c[] =
+    { I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+                                                                                
+static struct i2c_client_address_data addr_data = {
+       .normal_i2c             = normal_i2c,
+       .normal_i2c_range       = normal_i2c_range,
+       .probe                  = probe,
+       .probe_range            = probe_range,
+       .ignore                 = ignore,
+       .ignore_range           = ignore_range,
+       .force                  = force
+};
+
+static int saa7114_i2c_id = 0;
+static struct i2c_driver i2c_driver_saa7114;
+
+static int
+saa7114_detect_client (struct i2c_adapter *adapter,
+                      int                 address,
+                      int                 kind)
+{
+       int i, err[30];
+       short int hoff = SAA_7114_NTSC_HOFFSET;
+       short int voff = SAA_7114_NTSC_VOFFSET;
+       short int w = SAA_7114_NTSC_WIDTH;
+       short int h = SAA_7114_NTSC_HEIGHT;
+       struct i2c_client *client;
+       struct saa7114 *decoder;
+
+       dprintk(1,
+               KERN_INFO
+               "saa7114.c: detecting saa7114 client on address 0x%x\n",
+               address << 1);
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return 0;
+
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+       memset(client, 0, sizeof(struct i2c_client));
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &i2c_driver_saa7114;
+       client->flags = I2C_CLIENT_ALLOW_USE;
+       client->id = saa7114_i2c_id++;
+       snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+               "saa7114[%d]", client->id);
+
+       decoder = kmalloc(sizeof(struct saa7114), GFP_KERNEL);
+       if (decoder == NULL) {
+               kfree(client);
+               return -ENOMEM;
+       }
+       memset(decoder, 0, sizeof(struct saa7114));
+       decoder->norm = VIDEO_MODE_NTSC;
+       decoder->input = -1;
+       decoder->enable = 1;
+       decoder->bright = 32768;
+       decoder->contrast = 32768;
+       decoder->hue = 32768;
+       decoder->sat = 32768;
+       decoder->playback = 0;  // initially capture mode useda
+       i2c_set_clientdata(client, decoder);
+
+       memcpy(decoder->reg, init, sizeof(init));
+
+       decoder->reg[REG_ADDR(0x94)] = LOBYTE(hoff);    // hoffset low
+       decoder->reg[REG_ADDR(0x95)] = HIBYTE(hoff) & 0x0f;     // hoffset high
+       decoder->reg[REG_ADDR(0x96)] = LOBYTE(w);       // width low
+       decoder->reg[REG_ADDR(0x97)] = HIBYTE(w) & 0x0f;        // width high
+       decoder->reg[REG_ADDR(0x98)] = LOBYTE(voff);    // voffset low
+       decoder->reg[REG_ADDR(0x99)] = HIBYTE(voff) & 0x0f;     // voffset high
+       decoder->reg[REG_ADDR(0x9a)] = LOBYTE(h + 2);   // height low
+       decoder->reg[REG_ADDR(0x9b)] = HIBYTE(h + 2) & 0x0f;    // height high
+       decoder->reg[REG_ADDR(0x9c)] = LOBYTE(w);       // out width low
+       decoder->reg[REG_ADDR(0x9d)] = HIBYTE(w) & 0x0f;        // out width high
+       decoder->reg[REG_ADDR(0x9e)] = LOBYTE(h);       // out height low
+       decoder->reg[REG_ADDR(0x9f)] = HIBYTE(h) & 0x0f;        // out height high
+
+       decoder->reg[REG_ADDR(0xc4)] = LOBYTE(hoff);    // hoffset low
+       decoder->reg[REG_ADDR(0xc5)] = HIBYTE(hoff) & 0x0f;     // hoffset high
+       decoder->reg[REG_ADDR(0xc6)] = LOBYTE(w);       // width low
+       decoder->reg[REG_ADDR(0xc7)] = HIBYTE(w) & 0x0f;        // width high
+       decoder->reg[REG_ADDR(0xc8)] = LOBYTE(voff);    // voffset low
+       decoder->reg[REG_ADDR(0xc9)] = HIBYTE(voff) & 0x0f;     // voffset high
+       decoder->reg[REG_ADDR(0xca)] = LOBYTE(h + 2);   // height low
+       decoder->reg[REG_ADDR(0xcb)] = HIBYTE(h + 2) & 0x0f;    // height high
+       decoder->reg[REG_ADDR(0xcc)] = LOBYTE(w);       // out width low
+       decoder->reg[REG_ADDR(0xcd)] = HIBYTE(w) & 0x0f;        // out width high
+       decoder->reg[REG_ADDR(0xce)] = LOBYTE(h);       // out height low
+       decoder->reg[REG_ADDR(0xcf)] = HIBYTE(h) & 0x0f;        // out height high
+
+       decoder->reg[REG_ADDR(0xb8)] =
+           LOBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
+       decoder->reg[REG_ADDR(0xb9)] =
+           HIBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
+       decoder->reg[REG_ADDR(0xba)] =
+           LOBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
+       decoder->reg[REG_ADDR(0xbb)] =
+           HIBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
+
+       decoder->reg[REG_ADDR(0xbc)] =
+           LOBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
+       decoder->reg[REG_ADDR(0xbd)] =
+           HIBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
+       decoder->reg[REG_ADDR(0xbe)] =
+           LOBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
+       decoder->reg[REG_ADDR(0xbf)] =
+           HIBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
+
+       decoder->reg[REG_ADDR(0xe8)] =
+           LOBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
+       decoder->reg[REG_ADDR(0xe9)] =
+           HIBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
+       decoder->reg[REG_ADDR(0xea)] =
+           LOBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
+       decoder->reg[REG_ADDR(0xeb)] =
+           HIBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));
+
+       decoder->reg[REG_ADDR(0xec)] =
+           LOBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
+       decoder->reg[REG_ADDR(0xed)] =
+           HIBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
+       decoder->reg[REG_ADDR(0xee)] =
+           LOBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
+       decoder->reg[REG_ADDR(0xef)] =
+           HIBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET));
+
+
+       decoder->reg[REG_ADDR(0x13)] = 0x80;    // RTC0 on
+       decoder->reg[REG_ADDR(0x87)] = 0x01;    // I-Port
+       decoder->reg[REG_ADDR(0x12)] = 0xc9;    // RTS0
+
+       decoder->reg[REG_ADDR(0x02)] = 0xc0;    // set composite1 input, aveasy
+       decoder->reg[REG_ADDR(0x09)] = 0x00;    // chrominance trap
+       decoder->reg[REG_ADDR(0x0e)] |= 1;      // combfilter on
+
+
+       dprintk(1, KERN_DEBUG "%s_attach: starting decoder init\n",
+               I2C_NAME(client));
+
+       err[0] =
+           saa7114_write_block(client, decoder->reg + (0x20 << 1),
+                               0x10 << 1);
+       err[1] =
+           saa7114_write_block(client, decoder->reg + (0x30 << 1),
+                               0x10 << 1);
+       err[2] =
+           saa7114_write_block(client, decoder->reg + (0x63 << 1),
+                               (0x7f + 1 - 0x63) << 1);
+       err[3] =
+           saa7114_write_block(client, decoder->reg + (0x89 << 1),
+                               6 << 1);
+       err[4] =
+           saa7114_write_block(client, decoder->reg + (0xb8 << 1),
+                               8 << 1);
+       err[5] =
+           saa7114_write_block(client, decoder->reg + (0xe8 << 1),
+                               8 << 1);
+
+
+       for (i = 0; i <= 5; i++) {
+               if (err[i] < 0) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s_attach: init error %d at stage %d, leaving attach.\n",
+                               I2C_NAME(client), i, err[i]);
+                       return 0;
+               }
+       }
+
+       for (i = 6; i < 8; i++) {
+               dprintk(1,
+                       KERN_DEBUG
+                       "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
+                       I2C_NAME(client), i, saa7114_read(client, i),
+                       decoder->reg[REG_ADDR(i)]);
+       }
+
+       dprintk(1,
+               KERN_DEBUG
+               "%s_attach: performing decoder reset sequence\n",
+               I2C_NAME(client));
+
+       err[6] = saa7114_write(client, 0x80, 0x06);     // i-port and scaler backend clock selection, task A&B off
+       err[7] = saa7114_write(client, 0x88, 0xd8);     // sw reset scaler
+       err[8] = saa7114_write(client, 0x88, 0xf8);     // sw reset scaler release
+
+       for (i = 6; i <= 8; i++) {
+               if (err[i] < 0) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s_attach: init error %d at stage %d, leaving attach.\n",
+                               I2C_NAME(client), i, err[i]);
+                       return 0;
+               }
+       }
+
+       dprintk(1, KERN_INFO "%s_attach: performing the rest of init\n",
+               I2C_NAME(client));
+
+
+       err[9] = saa7114_write(client, 0x01, decoder->reg[REG_ADDR(0x01)]);
+       err[10] = saa7114_write_block(client, decoder->reg + (0x03 << 1), (0x1e + 1 - 0x03) << 1);      // big seq
+       err[11] = saa7114_write_block(client, decoder->reg + (0x40 << 1), (0x5f + 1 - 0x40) << 1);      // slicer
+       err[12] = saa7114_write_block(client, decoder->reg + (0x81 << 1), 2 << 1);      // ?
+       err[13] = saa7114_write_block(client, decoder->reg + (0x83 << 1), 5 << 1);      // ?
+       err[14] = saa7114_write_block(client, decoder->reg + (0x90 << 1), 4 << 1);      // Task A
+       err[15] =
+           saa7114_write_block(client, decoder->reg + (0x94 << 1),
+                               12 << 1);
+       err[16] =
+           saa7114_write_block(client, decoder->reg + (0xa0 << 1),
+                               8 << 1);
+       err[17] =
+           saa7114_write_block(client, decoder->reg + (0xa8 << 1),
+                               8 << 1);
+       err[18] =
+           saa7114_write_block(client, decoder->reg + (0xb0 << 1),
+                               8 << 1);
+       err[19] = saa7114_write_block(client, decoder->reg + (0xc0 << 1), 4 << 1);      // Task B
+       err[15] =
+           saa7114_write_block(client, decoder->reg + (0xc4 << 1),
+                               12 << 1);
+       err[16] =
+           saa7114_write_block(client, decoder->reg + (0xd0 << 1),
+                               8 << 1);
+       err[17] =
+           saa7114_write_block(client, decoder->reg + (0xd8 << 1),
+                               8 << 1);
+       err[18] =
+           saa7114_write_block(client, decoder->reg + (0xe0 << 1),
+                               8 << 1);
+
+       for (i = 9; i <= 18; i++) {
+               if (err[i] < 0) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s_attach: init error %d at stage %d, leaving attach.\n",
+                               I2C_NAME(client), i, err[i]);
+                       return 0;
+               }
+       }
+
+
+       for (i = 6; i < 8; i++) {
+               dprintk(1,
+                       KERN_DEBUG
+                       "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
+                       I2C_NAME(client), i, saa7114_read(client, i),
+                       decoder->reg[REG_ADDR(i)]);
+       }
+
+
+       for (i = 0x11; i <= 0x13; i++) {
+               dprintk(1,
+                       KERN_DEBUG
+                       "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
+                       I2C_NAME(client), i, saa7114_read(client, i),
+                       decoder->reg[REG_ADDR(i)]);
+       }
+
+
+       dprintk(1, KERN_DEBUG "%s_attach: setting video input\n",
+               I2C_NAME(client));
+
+       err[19] =
+           saa7114_write(client, 0x02, decoder->reg[REG_ADDR(0x02)]);
+       err[20] =
+           saa7114_write(client, 0x09, decoder->reg[REG_ADDR(0x09)]);
+       err[21] =
+           saa7114_write(client, 0x0e, decoder->reg[REG_ADDR(0x0e)]);
+
+       for (i = 19; i <= 21; i++) {
+               if (err[i] < 0) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s_attach: init error %d at stage %d, leaving attach.\n",
+                               I2C_NAME(client), i, err[i]);
+                       return 0;
+               }
+       }
+
+       dprintk(1,
+               KERN_DEBUG
+               "%s_attach: performing decoder reset sequence\n",
+               I2C_NAME(client));
+
+       err[22] = saa7114_write(client, 0x88, 0xd8);    // sw reset scaler
+       err[23] = saa7114_write(client, 0x88, 0xf8);    // sw reset scaler release
+       err[24] = saa7114_write(client, 0x80, 0x36);    // i-port and scaler backend clock selection, task A&B off
+
+
+       for (i = 22; i <= 24; i++) {
+               if (err[i] < 0) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s_attach: init error %d at stage %d, leaving attach.\n",
+                               I2C_NAME(client), i, err[i]);
+                       return 0;
+               }
+       }
+
+       err[25] = saa7114_write(client, 0x06, init[REG_ADDR(0x06)]);
+       err[26] = saa7114_write(client, 0x07, init[REG_ADDR(0x07)]);
+       err[27] = saa7114_write(client, 0x10, init[REG_ADDR(0x10)]);
+
+       dprintk(1,
+               KERN_INFO
+               "%s_attach: chip version %x, decoder status 0x%02x\n",
+               I2C_NAME(client), saa7114_read(client, 0x00) >> 4,
+               saa7114_read(client, 0x1f));
+       dprintk(1,
+               KERN_DEBUG
+               "%s_attach: power save control: 0x%02x, scaler status: 0x%02x\n",
+               I2C_NAME(client), saa7114_read(client, 0x88),
+               saa7114_read(client, 0x8f));
+
+
+       for (i = 0x94; i < 0x96; i++) {
+               dprintk(1,
+                       KERN_DEBUG
+                       "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
+                       I2C_NAME(client), i, saa7114_read(client, i),
+                       decoder->reg[REG_ADDR(i)]);
+       }
+
+       i = i2c_attach_client(client);
+       if (i) {
+               kfree(client);
+               kfree(decoder);
+               return i;
+       }
+
+       //i = saa7114_write_block(client, init, sizeof(init));
+       i = 0;
+       if (i < 0) {
+               dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
+                       I2C_NAME(client), i);
+       } else {
+               dprintk(1,
+                       KERN_INFO
+                       "%s_attach: chip version %x at address 0x%x\n",
+                       I2C_NAME(client), saa7114_read(client, 0x00) >> 4,
+                       client->addr << 1);
+       }
+
+       return 0;
+}
+
+static int
+saa7114_attach_adapter (struct i2c_adapter *adapter)
+{
+       dprintk(1,
+               KERN_INFO
+               "saa7114.c: starting probe for adapter %s (0x%x)\n",
+               I2C_NAME(adapter), adapter->id);
+       return i2c_probe(adapter, &addr_data, &saa7114_detect_client);
+}
+
+static int
+saa7114_detach_client (struct i2c_client *client)
+{
+       struct saa7114 *decoder = i2c_get_clientdata(client);
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+
+       kfree(decoder);
+       kfree(client);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_saa7114 = {
+       .owner = THIS_MODULE,
+       .name = "saa7114",
+
+       .id = I2C_DRIVERID_SAA7114,
+       .flags = I2C_DF_NOTIFY,
+
+       .attach_adapter = saa7114_attach_adapter,
+       .detach_client = saa7114_detach_client,
+       .command = saa7114_command,
+};
+
+static int __init
+saa7114_init (void)
+{
+       return i2c_add_driver(&i2c_driver_saa7114);
+}
+
+static void __exit
+saa7114_exit (void)
+{
+       i2c_del_driver(&i2c_driver_saa7114);
+}
+
+module_init(saa7114_init);
+module_exit(saa7114_exit);
index e99c87b26cbbd8f09a2e9ba70554c49287a20f78..9ac7754fed1f1fccee7e941d6d153f5f2f5fde83 100644 (file)
@@ -1,25 +1,30 @@
 /* 
-    saa7185 - Philips SAA7185B video encoder driver version 0.0.3
+ * saa7185 - Philips SAA7185B video encoder driver version 0.0.3
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * Slight changes for video timing and attachment output by
+ * Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
+ *
+ * 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.
+ */
 
-    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
-
-    Slight changes for video timing and attachment output by
-    Wolfgang Scherr <scherr@net4you.net>
-    
-    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/version.h>
 
 #include <linux/module.h>
 #include <linux/init.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
+#include <asm/segment.h>
 #include <linux/types.h>
 
 #include <linux/videodev.h>
 #include <linux/version.h>
 #include <asm/uaccess.h>
 
+MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
+MODULE_AUTHOR("Dave Perks");
+MODULE_LICENSE("GPL");
+
 #include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define I2C_NAME(s) (s)->dev.name
 
 #include <linux/video_encoder.h>
 
-#define DEBUG(x)               /* Debug driver */
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
 
 /* ----------------------------------------------------------------------- */
 
 struct saa7185 {
-       struct i2c_client *client;
-       int addr;
        unsigned char reg[128];
-       struct semaphore lock;
 
        int norm;
        int enable;
@@ -66,31 +84,76 @@ struct saa7185 {
 
 #define   I2C_SAA7185        0x88
 
-#define I2C_DELAY   10
-
 /* ----------------------------------------------------------------------- */
-static unsigned short normal_i2c[] = { 34>>1, I2C_CLIENT_END };        
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-static unsigned short probe[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
 
-static struct i2c_client_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .normal_i2c_range       = normal_i2c_range,
-       .probe                  = probe, 
-       .probe_range            = probe_range,
-       .ignore                 = ignore,
-       .ignore_range           = ignore_range,
-       .force                  = force
-};
+static inline int
+saa7185_read (struct i2c_client *client)
+{
+       return i2c_smbus_read_byte(client);
+}
+
+static int
+saa7185_write (struct i2c_client *client,
+              u8                 reg,
+              u8                 value)
+{
+       struct saa7185 *encoder = i2c_get_clientdata(client);
+       dprintk(1, KERN_DEBUG "SAA7185: %02x set to %02x\n", reg, value);
+       encoder->reg[reg] = value;
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
 
-static struct i2c_client client_template;
+static int
+saa7185_write_block (struct i2c_client *client,
+                    const u8          *data,
+                    unsigned int       len)
+{
+       int ret = -1;
+       u8 reg;
+
+       /* the adv7175 has an autoincrement function, use it if
+        * the adapter understands raw I2C */
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               /* do raw I2C, not smbus compatible */
+               struct saa7185 *encoder = i2c_get_clientdata(client);
+               struct i2c_msg msg;
+               u8 block_data[32];
+               msg.addr = client->addr;
+               msg.flags = client->flags;
+               while (len >= 2) {
+                       msg.buf = (char *) block_data;
+                       msg.len = 0;
+                       block_data[msg.len++] = reg = data[0];
+                       do {
+                               block_data[msg.len++] =
+                                   encoder->reg[reg++] = data[1];
+                               len -= 2;
+                               data += 2;
+                       } while (len >= 2 && data[0] == reg &&
+                                msg.len < 32);
+                       if ((ret =
+                            i2c_transfer(client->adapter, &msg, 1)) < 0)
+                               break;
+               }
+       } else {
+               /* do some slow I2C emulation kind of thing */
+               while (len >= 2) {
+                       reg = *data++;
+                       if ((ret =
+                            saa7185_write(client, reg, *data++)) < 0)
+                               break;
+                       len -= 2;
+               }
+       }
+
+       return ret;
+}
+
+/* ----------------------------------------------------------------------- */
 
 static const unsigned char init_common[] = {
-       0x3a, 0x0f,             /* CBENB=0, V656=0, VY2C=1, YUV2C=1, MY2C=1, MUV2C=1 */
+       0x3a, 0x0f,             /* CBENB=0, V656=0, VY2C=1,
+                                * YUV2C=1, MY2C=1, MUV2C=1 */
 
        0x42, 0x6b,             /* OVLY0=107 */
        0x43, 0x00,             /* OVLU0=0     white */
@@ -125,7 +188,7 @@ static const unsigned char init_common[] = {
        0x5f, 0x3a,             /* CCRS=0, BLNVB=58 */
        0x60, 0x00,             /* NULL      */
 
-/* 0x61 - 0x66 set according to norm */
+       /* 0x61 - 0x66 set according to norm */
 
        0x67, 0x00,             /* 0 : caption 1st byte odd  field */
        0x68, 0x00,             /* 0 : caption 2nd byte odd  field */
@@ -133,14 +196,16 @@ static const unsigned char init_common[] = {
        0x6a, 0x00,             /* 0 : caption 2nd byte even field */
 
        0x6b, 0x91,             /* MODIN=2, PCREF=0, SCCLN=17 */
-       0x6c, 0x20,             /* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0, CBLF=0, ORCV2=0, PRCV2=0 */
+       0x6c, 0x20,             /* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0,
+                                * CBLF=0, ORCV2=0, PRCV2=0 */
        0x6d, 0x00,             /* SRCM1=0, CCEN=0 */
 
-       0x6e, 0x0e,             /* HTRIG=0x005, approx. centered, at least for PAL */
+       0x6e, 0x0e,             /* HTRIG=0x005, approx. centered, at
+                                * least for PAL */
        0x6f, 0x00,             /* HTRIG upper bits */
        0x70, 0x20,             /* PHRES=0, SBLN=1, VTRIG=0 */
 
-/* The following should not be needed */
+       /* The following should not be needed */
 
        0x71, 0x15,             /* BMRQ=0x115 */
        0x72, 0x90,             /* EMRQ=0x690 */
@@ -152,11 +217,11 @@ static const unsigned char init_common[] = {
        0x78, 0x90,             /* ERCV=0x690 */
        0x79, 0x61,             /* ERCV=0x690, BRCV=0x115 */
 
-/* Field length controls */
+       /* Field length controls */
 
        0x7a, 0x70,             /* FLC=0 */
 
-/* The following should not be needed if SBLN = 1 */
+       /* The following should not be needed if SBLN = 1 */
 
        0x7b, 0x16,             /* FAL=22 */
        0x7c, 0x35,             /* LAL=244 */
@@ -164,7 +229,8 @@ static const unsigned char init_common[] = {
 };
 
 static const unsigned char init_pal[] = {
-       0x61, 0x1e,             /* FISE=0, PAL=1, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */
+       0x61, 0x1e,             /* FISE=0, PAL=1, SCBW=1, RTCE=1,
+                                * YGS=1, INPI=0, DOWN=0 */
        0x62, 0xc8,             /* DECTYP=1, BSTA=72 */
        0x63, 0xcb,             /* FSC0 */
        0x64, 0x8a,             /* FSC1 */
@@ -173,7 +239,8 @@ static const unsigned char init_pal[] = {
 };
 
 static const unsigned char init_ntsc[] = {
-       0x61, 0x1d,             /* FISE=1, PAL=0, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */
+       0x61, 0x1d,             /* FISE=1, PAL=0, SCBW=1, RTCE=1,
+                                * YGS=1, INPI=0, DOWN=0 */
        0x62, 0xe6,             /* DECTYP=1, BSTA=102 */
        0x63, 0x1f,             /* FSC0 */
        0x64, 0x7c,             /* FSC1 */
@@ -181,167 +248,123 @@ static const unsigned char init_ntsc[] = {
        0x66, 0x21,             /* FSC3 */
 };
 
-static int saa7185_attach(struct i2c_adapter *adap, int addr, int kind)
+static int
+saa7185_command (struct i2c_client *client,
+                unsigned int       cmd,
+                void              *arg)
 {
-       int i;
-       struct saa7185 *encoder;
-       struct i2c_client *client;
-
-       client = kmalloc(sizeof(*client), GFP_KERNEL);
-       if (client == NULL)
-               return -ENOMEM;
-       memset(client, 0, sizeof(*client));
-       client_template.adapter = adap;
-       client_template.addr = addr;
-       memcpy(client, &client_template, sizeof(*client));
-       encoder = kmalloc(sizeof(*encoder), GFP_KERNEL);
-       if (encoder == NULL) {
-               kfree(client);
-               return -ENOMEM;
-       }
-
+       struct saa7185 *encoder = i2c_get_clientdata(client);
 
-       memset(encoder, 0, sizeof(*encoder));
-       strlcpy(client->name, "saa7185", DEVICE_NAME_SIZE);
-       encoder->client = client;
-       i2c_set_clientdata(client, encoder);
-       encoder->addr = addr;
-       encoder->norm = VIDEO_MODE_NTSC;
-       encoder->enable = 1;
+       switch (cmd) {
 
-       i = i2c_master_send(client, init_common, sizeof(init_common));
-       if (i >= 0) {
-               i = i2c_master_send(client, init_ntsc,
-                                       sizeof(init_ntsc));
-       }
-       if (i < 0) {
-               printk(KERN_ERR "%s_attach: init error %d\n", client->name, i);
-       } else {
-               printk(KERN_INFO "%s_attach: chip version %d\n",
-                      client->name, i2c_smbus_read_byte(client) >> 5);
-       }
-       init_MUTEX(&encoder->lock);
-       i2c_attach_client(client);
-       MOD_INC_USE_COUNT;
-       return 0;
-}
-static int saa7185_probe(struct i2c_adapter *adap)
-{
-       return i2c_probe(adap, &addr_data, saa7185_attach);
-}
+       case 0:
+               saa7185_write_block(client, init_common,
+                                   sizeof(init_common));
+               switch (encoder->norm) {
 
-static int saa7185_detach(struct i2c_client *client)
-{
-       struct saa7185 *encoder = i2c_get_clientdata(client);
-       i2c_detach_client(client);
-       i2c_smbus_write_byte_data(client, 0x61, (encoder->reg[0x61]) | 0x40);   /* SW: output off is active */
-       //i2c_smbus_write_byte_data(client, 0x3a, (encoder->reg[0x3a]) | 0x80); /* SW: color bar */
-       kfree(encoder);
-       kfree(client);
-       MOD_DEC_USE_COUNT;
-       return 0;
-}
+               case VIDEO_MODE_NTSC:
+                       saa7185_write_block(client, init_ntsc,
+                                           sizeof(init_ntsc));
+                       break;
 
-static int saa7185_command(struct i2c_client *client, unsigned int cmd,
-                          void *arg)
-{
-       struct saa7185 *encoder = i2c_get_clientdata(client);
+               case VIDEO_MODE_PAL:
+                       saa7185_write_block(client, init_pal,
+                                           sizeof(init_pal));
+                       break;
+               }
 
-       switch (cmd) {
+               break;
 
        case ENCODER_GET_CAPABILITIES:
-               {
-                       struct video_encoder_capability *cap = arg;
-
-                       cap->flags
-                           = VIDEO_ENCODER_PAL
-                           | VIDEO_ENCODER_NTSC
-                           | VIDEO_ENCODER_SECAM | VIDEO_ENCODER_CCIR;
-                       cap->inputs = 1;
-                       cap->outputs = 1;
-               }
+       {
+               struct video_encoder_capability *cap = arg;
+
+               cap->flags =
+                   VIDEO_ENCODER_PAL | VIDEO_ENCODER_NTSC |
+                   VIDEO_ENCODER_SECAM | VIDEO_ENCODER_CCIR;
+               cap->inputs = 1;
+               cap->outputs = 1;
+       }
                break;
 
        case ENCODER_SET_NORM:
-               {
-                       int *iarg = arg;
+       {
+               int *iarg = arg;
 
-                       switch (*iarg) {
+               //saa7185_write_block(client, init_common, sizeof(init_common));
 
-                       case VIDEO_MODE_NTSC:
-                               i2c_master_send(client, init_ntsc,
-                                                   sizeof(init_ntsc));
-                               break;
+               switch (*iarg) {
 
-                       case VIDEO_MODE_PAL:
-                               i2c_master_send(client, init_pal,
-                                                   sizeof(init_pal));
-                               break;
+               case VIDEO_MODE_NTSC:
+                       saa7185_write_block(client, init_ntsc,
+                                           sizeof(init_ntsc));
+                       break;
 
-                       case VIDEO_MODE_SECAM:
-                       default:
-                               return -EINVAL;
+               case VIDEO_MODE_PAL:
+                       saa7185_write_block(client, init_pal,
+                                           sizeof(init_pal));
+                       break;
+
+               case VIDEO_MODE_SECAM:
+               default:
+                       return -EINVAL;
 
-                       }
-                       encoder->norm = *iarg;
                }
+               encoder->norm = *iarg;
+       }
                break;
 
        case ENCODER_SET_INPUT:
-               {
-                       int *iarg = arg;
+       {
+               int *iarg = arg;
 
-                       /* RJ: *iarg = 0: input is from SA7111
-                          *iarg = 1: input is from ZR36060 */
+               /* RJ: *iarg = 0: input is from SA7111
+                *iarg = 1: input is from ZR36060 */
 
-                       switch (*iarg) {
+               switch (*iarg) {
 
-                       case 0:
-                               /* Switch RTCE to 1 */
-                               i2c_smbus_write_byte_data(client, 0x61,
-                                             (encoder->
-                                              reg[0x61] & 0xf7) | 0x08);
-                               i2c_smbus_write_byte_data(client, 0x6e, 0x01);
-                               break;
+               case 0:
+                       /* Switch RTCE to 1 */
+                       saa7185_write(client, 0x61,
+                                     (encoder->reg[0x61] & 0xf7) | 0x08);
+                       saa7185_write(client, 0x6e, 0x01);
+                       break;
 
-                       case 1:
-                               /* Switch RTCE to 0 */
-                               i2c_smbus_write_byte_data(client, 0x61,
-                                             (encoder->
-                                              reg[0x61] & 0xf7) | 0x00);
-                               /* SW: a slight sync problem... */
-                               i2c_smbus_write_byte_data(client, 0x6e, 0x00);
-                               break;
+               case 1:
+                       /* Switch RTCE to 0 */
+                       saa7185_write(client, 0x61,
+                                     (encoder->reg[0x61] & 0xf7) | 0x00);
+                       /* SW: a slight sync problem... */
+                       saa7185_write(client, 0x6e, 0x00);
+                       break;
 
-                       default:
-                               return -EINVAL;
+               default:
+                       return -EINVAL;
 
-                       }
                }
+       }
                break;
 
        case ENCODER_SET_OUTPUT:
-               {
-                       int *iarg = arg;
+       {
+               int *iarg = arg;
 
-                       /* not much choice of outputs */
-                       if (*iarg != 0) {
-                               return -EINVAL;
-                       }
+               /* not much choice of outputs */
+               if (*iarg != 0) {
+                       return -EINVAL;
                }
+       }
                break;
 
        case ENCODER_ENABLE_OUTPUT:
-               {
-                       int *iarg = arg;
-
-                       encoder->enable = !!*iarg;
-                       i2c_smbus_write_byte_data(client, 0x61,
-                                     (encoder->
-                                      reg[0x61] & 0xbf) | (encoder->
-                                                           enable ? 0x00 :
-                                                           0x40));
-               }
+       {
+               int *iarg = arg;
+
+               encoder->enable = !!*iarg;
+               saa7185_write(client, 0x61,
+                             (encoder->reg[0x61] & 0xbf) |
+                             (encoder->enable ? 0x00 : 0x40));
+       }
                break;
 
        default:
@@ -353,32 +376,152 @@ static int saa7185_command(struct i2c_client *client, unsigned int cmd,
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa7185 = {
-       .owner          = THIS_MODULE,
-       .name           = "saa7185",             /* name */
-       .id             = I2C_DRIVERID_SAA7185B, /* ID */
-       .flags          = I2C_DF_NOTIFY,
-       .attach_adapter = saa7185_probe,
-       .detach_client  = saa7185_detach,
-       .command        = saa7185_command
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+static unsigned short normal_i2c[] = { I2C_SAA7185 >> 1, I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+                                                                                
+static struct i2c_client_address_data addr_data = {
+       .normal_i2c             = normal_i2c,
+       .normal_i2c_range       = normal_i2c_range,
+       .probe                  = probe,
+       .probe_range            = probe_range,
+       .ignore                 = ignore,
+       .ignore_range           = ignore_range,
+       .force                  = force
 };
 
-static struct i2c_client client_template = {
-       .id     = -1,
-       .driver = &i2c_driver_saa7185,
-       .name   = "saa7185_client",
+static int saa7185_i2c_id = 0;
+static struct i2c_driver i2c_driver_saa7185;
+
+static int
+saa7185_detect_client (struct i2c_adapter *adapter,
+                      int                 address,
+                      int                 kind)
+{
+       int i;
+       struct i2c_client *client;
+       struct saa7185 *encoder;
+
+       dprintk(1,
+               KERN_INFO
+               "saa7185.c: detecting saa7185 client on address 0x%x\n",
+               address << 1);
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return 0;
+
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+       memset(client, 0, sizeof(struct i2c_client));
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &i2c_driver_saa7185;
+       client->flags = I2C_CLIENT_ALLOW_USE;
+       client->id = saa7185_i2c_id++;
+       snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+               "saa7185[%d]", client->id);
+
+       encoder = kmalloc(sizeof(struct saa7185), GFP_KERNEL);
+       if (encoder == NULL) {
+               return -ENOMEM;
+       }
+       memset(encoder, 0, sizeof(struct saa7185));
+       encoder->norm = VIDEO_MODE_NTSC;
+       encoder->enable = 1;
+       i2c_set_clientdata(client, encoder);
+
+       i = i2c_attach_client(client);
+       if (i) {
+               kfree(client);
+               kfree(encoder);
+               return i;
+       }
+
+       i = saa7185_write_block(client, init_common, sizeof(init_common));
+       if (i >= 0) {
+               i = saa7185_write_block(client, init_ntsc,
+                                       sizeof(init_ntsc));
+       }
+       if (i < 0) {
+               dprintk(1, KERN_ERR "%s_attach: init error %d\n",
+                       I2C_NAME(client), i);
+       } else {
+               dprintk(1,
+                       KERN_INFO
+                       "%s_attach: chip version %d at address 0x%x\n",
+                       I2C_NAME(client), saa7185_read(client) >> 5,
+                       client->addr << 1);
+       }
+
+       return 0;
+}
+
+static int
+saa7185_attach_adapter (struct i2c_adapter *adapter)
+{
+       dprintk(1,
+               KERN_INFO
+               "saa7185.c: starting probe for adapter %s (0x%x)\n",
+               I2C_NAME(adapter), adapter->id);
+       return i2c_probe(adapter, &addr_data, &saa7185_detect_client);
+}
+
+static int
+saa7185_detach_client (struct i2c_client *client)
+{
+       struct saa7185 *encoder = i2c_get_clientdata(client);
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+
+       saa7185_write(client, 0x61, (encoder->reg[0x61]) | 0x40);       /* SW: output off is active */
+       //saa7185_write(client, 0x3a, (encoder->reg[0x3a]) | 0x80); /* SW: color bar */
+
+       kfree(encoder);
+       kfree(client);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_saa7185 = {
+       .owner = THIS_MODULE,
+       .name = "saa7185",      /* name */
+
+       .id = I2C_DRIVERID_SAA7185B,
+       .flags = I2C_DF_NOTIFY,
+
+       .attach_adapter = saa7185_attach_adapter,
+       .detach_client = saa7185_detach_client,
+       .command = saa7185_command,
 };
 
-static int saa7185_init(void)
+static int __init
+saa7185_init (void)
 {
        return i2c_add_driver(&i2c_driver_saa7185);
 }
 
-static void saa7185_exit(void)
+static void __exit
+saa7185_exit (void)
 {
        i2c_del_driver(&i2c_driver_saa7185);
 }
 
 module_init(saa7185_init);
 module_exit(saa7185_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/videocodec.c b/drivers/media/video/videocodec.c
new file mode 100644 (file)
index 0000000..d0009b3
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * VIDEO MOTION CODECs internal API for video devices
+ *
+ * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's
+ * bound to a master device.
+ *
+ * (c) 2002 Wolfgang Scherr <scherr@net4you.at>
+ *
+ * $Id: videocodec.c,v 1.1.2.8 2003/03/29 07:16:04 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * ------------------------------------------------------------------------
+ */
+
+#define VIDEOCODEC_VERSION "v0.2"
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+
+// kernel config is here (procfs flag)
+#include <linux/config.h>
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#endif
+
+#include <linux/version.h>
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
+#endif
+
+#include "videocodec.h"
+
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-4)");
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
+
+struct attached_list {
+       struct videocodec *codec;
+       struct attached_list *next;
+};
+
+struct codec_list {
+       const struct videocodec *codec;
+       int attached;
+       struct attached_list *list;
+       struct codec_list *next;
+};
+
+static struct codec_list *codeclist_top = NULL;
+
+/* ================================================= */
+/* function prototypes of the master/slave interface */
+/* ================================================= */
+
+struct videocodec *
+videocodec_attach (struct videocodec_master *master)
+{
+       struct codec_list *h = codeclist_top;
+       struct attached_list *a, *ptr;
+       struct videocodec *codec;
+       int res;
+
+       if (!master) {
+               dprintk(1, KERN_ERR "videocodec_attach: no data\n");
+               return NULL;
+       }
+
+       dprintk(2,
+               "videocodec_attach: '%s', type: %x, flags %lx, magic %lx\n",
+               master->name, master->type, master->flags, master->magic);
+
+       if (!h) {
+               dprintk(1,
+                       KERN_ERR
+                       "videocodec_attach: no device available\n");
+               return NULL;
+       }
+
+       while (h) {
+               // attach only if the slave has at least the flags
+               // expected by the master
+               if ((master->flags & h->codec->flags) == master->flags) {
+                       dprintk(4, "videocodec_attach: try '%s'\n",
+                               h->codec->name);
+                       codec =
+                           kmalloc(sizeof(struct videocodec), GFP_KERNEL);
+                       if (!codec) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "videocodec_attach: no mem\n");
+                               return NULL;
+                       }
+                       memcpy(codec, h->codec, sizeof(struct videocodec));
+
+                       snprintf(codec->name, sizeof(codec->name),
+                                "%s[%d]", codec->name, h->attached);
+                       codec->master_data = master;
+                       res = codec->setup(codec);
+                       if (res == 0) {
+                               dprintk(3, "videocodec_attach '%s'\n",
+                                       codec->name);
+                               ptr = (struct attached_list *)
+                                   kmalloc(sizeof(struct attached_list),
+                                           GFP_KERNEL);
+                               if (!ptr) {
+                                       dprintk(1,
+                                               KERN_ERR
+                                               "videocodec_attach: no memory\n");
+                                       kfree(codec);
+                                       return NULL;
+                               }
+                               memset(ptr, 0,
+                                      sizeof(struct attached_list));
+                               ptr->codec = codec;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+                               MOD_INC_USE_COUNT;
+#else
+                               if (!try_module_get(THIS_MODULE)) {
+                                       dprintk(1,
+                                               KERN_ERR
+                                               "videocodec: failed to increment usecount\n");
+                                       kfree(codec);
+                                       kfree(ptr);
+                                       return NULL;
+                               }
+#endif
+
+                               a = h->list;
+                               if (!a) {
+                                       h->list = ptr;
+                                       dprintk(4,
+                                               "videocodec: first element\n");
+                               } else {
+                                       while (a->next)
+                                               a = a->next;    // find end
+                                       a->next = ptr;
+                                       dprintk(4,
+                                               "videocodec: in after '%s'\n",
+                                               h->codec->name);
+                               }
+
+                               h->attached += 1;
+                               return codec;
+                       } else {
+                               kfree(codec);
+                       }
+               }
+               h = h->next;
+       }
+
+       dprintk(1, KERN_ERR "videocodec_attach: no codec found!\n");
+       return NULL;
+}
+
+int
+videocodec_detach (struct videocodec *codec)
+{
+       struct codec_list *h = codeclist_top;
+       struct attached_list *a, *prev;
+       int res;
+
+       if (!codec) {
+               dprintk(1, KERN_ERR "videocodec_detach: no data\n");
+               return -EINVAL;
+       }
+
+       dprintk(2,
+               "videocodec_detach: '%s', type: %x, flags %lx, magic %lx\n",
+               codec->name, codec->type, codec->flags, codec->magic);
+
+       if (!h) {
+               dprintk(1,
+                       KERN_ERR "videocodec_detach: no device left...\n");
+               return -ENXIO;
+       }
+
+       while (h) {
+               a = h->list;
+               prev = NULL;
+               while (a) {
+                       if (codec == a->codec) {
+                               res = a->codec->unset(a->codec);
+                               if (res >= 0) {
+                                       dprintk(3,
+                                               "videocodec_detach: '%s'\n",
+                                               a->codec->name);
+                                       a->codec->master_data = NULL;
+                               } else {
+                                       dprintk(1,
+                                               KERN_ERR
+                                               "videocodec_detach: '%s'\n",
+                                               a->codec->name);
+                                       a->codec->master_data = NULL;
+                               }
+                               if (prev == NULL) {
+                                       h->list = a->next;
+                                       dprintk(4,
+                                               "videocodec: delete first\n");
+                               } else {
+                                       prev->next = a->next;
+                                       dprintk(4,
+                                               "videocodec: delete middle\n");
+                               }
+                               kfree(a->codec);
+                               kfree(a);
+                               h->attached -= 1;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+                               MOD_DEC_USE_COUNT;
+#else
+                               module_put(THIS_MODULE);
+#endif
+
+                               return 0;
+                       }
+                       prev = a;
+                       a = a->next;
+               }
+               h = h->next;
+       }
+
+       dprintk(1, KERN_ERR "videocodec_detach: given codec not found!\n");
+       return -EINVAL;
+}
+
+int
+videocodec_register (const struct videocodec *codec)
+{
+       struct codec_list *ptr, *h = codeclist_top;
+
+       if (!codec) {
+               dprintk(1, KERN_ERR "videocodec_register: no data!\n");
+               return -EINVAL;
+       }
+
+       dprintk(2,
+               "videocodec: register '%s', type: %x, flags %lx, magic %lx\n",
+               codec->name, codec->type, codec->flags, codec->magic);
+
+       ptr =
+           (struct codec_list *) kmalloc(sizeof(struct codec_list),
+                                         GFP_KERNEL);
+       if (!ptr) {
+               dprintk(1, KERN_ERR "videocodec_register: no memory\n");
+               return -ENOMEM;
+       }
+       memset(ptr, 0, sizeof(struct codec_list));
+       ptr->codec = codec;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+       MOD_INC_USE_COUNT;
+#else
+       if (!try_module_get(THIS_MODULE)) {
+               dprintk(1,
+                       KERN_ERR
+                       "videocodec: failed to increment module count\n");
+               kfree(ptr);
+               return -ENODEV;
+       }
+#endif
+
+       if (!h) {
+               codeclist_top = ptr;
+               dprintk(4, "videocodec: hooked in as first element\n");
+       } else {
+               while (h->next)
+                       h = h->next;    // find the end
+               h->next = ptr;
+               dprintk(4, "videocodec: hooked in after '%s'\n",
+                       h->codec->name);
+       }
+
+       return 0;
+}
+
+int
+videocodec_unregister (const struct videocodec *codec)
+{
+       struct codec_list *prev = NULL, *h = codeclist_top;
+
+       if (!codec) {
+               dprintk(1, KERN_ERR "videocodec_unregister: no data!\n");
+               return -EINVAL;
+       }
+
+       dprintk(2,
+               "videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n",
+               codec->name, codec->type, codec->flags, codec->magic);
+
+       if (!h) {
+               dprintk(1,
+                       KERN_ERR
+                       "videocodec_unregister: no device left...\n");
+               return -ENXIO;
+       }
+
+       while (h) {
+               if (codec == h->codec) {
+                       if (h->attached) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "videocodec: '%s' is used\n",
+                                       h->codec->name);
+                               return -EBUSY;
+                       }
+                       dprintk(3, "videocodec: unregister '%s' is ok.\n",
+                               h->codec->name);
+                       if (prev == NULL) {
+                               codeclist_top = h->next;
+                               dprintk(4,
+                                       "videocodec: delete first element\n");
+                       } else {
+                               prev->next = h->next;
+                               dprintk(4,
+                                       "videocodec: delete middle element\n");
+                       }
+                       kfree(h);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+                       MOD_DEC_USE_COUNT;
+#else
+                       module_put(THIS_MODULE);
+#endif
+
+                       return 0;
+               }
+               prev = h;
+               h = h->next;
+       }
+
+       dprintk(1,
+               KERN_ERR
+               "videocodec_unregister: given codec not found!\n");
+       return -EINVAL;
+}
+
+#ifdef CONFIG_PROC_FS
+/* ============ */
+/* procfs stuff */
+/* ============ */
+
+static char *videocodec_buf = NULL;
+static int videocodec_bufsize = 0;
+
+static int
+videocodec_build_table (void)
+{
+       struct codec_list *h = codeclist_top;
+       struct attached_list *a;
+       int i = 0, size;
+
+       // sum up amount of slaves plus their attached masters
+       while (h) {
+               i += h->attached + 1;
+               h = h->next;
+       }
+#define LINESIZE 100
+       size = LINESIZE * (i + 1);
+
+       dprintk(3, "videocodec_build table: %d entries, %d bytes\n", i,
+               size);
+
+       if (videocodec_buf)
+               kfree(videocodec_buf);
+       videocodec_buf = (char *) kmalloc(size, GFP_KERNEL);
+
+       i = 0;
+       i += snprintf(videocodec_buf + i, size - 1,
+                     "<S>lave or attached <M>aster name  type flags    magic    ");
+       i += snprintf(videocodec_buf + i, size - 1, "(connected as)\n");
+
+       h = codeclist_top;
+       while (h) {
+               if (i > (size - LINESIZE))
+                       break;  // security check
+               i += snprintf(videocodec_buf + i, size,
+                             "S %32s %04x %08lx %08lx (TEMPLATE)\n",
+                             h->codec->name, h->codec->type,
+                             h->codec->flags, h->codec->magic);
+               a = h->list;
+               while (a) {
+                       if (i > (size - LINESIZE))
+                               break;  // security check
+                       i += snprintf(videocodec_buf + i, size,
+                                     "M %32s %04x %08lx %08lx (%s)\n",
+                                     a->codec->master_data->name,
+                                     a->codec->master_data->type,
+                                     a->codec->master_data->flags,
+                                     a->codec->master_data->magic,
+                                     a->codec->name);
+                       a = a->next;
+               }
+               h = h->next;
+       }
+
+       return i;
+}
+
+//The definition:
+//typedef int (read_proc_t)(char *page, char **start, off_t off,
+//                          int count, int *eof, void *data);
+
+static int
+videocodec_info (char  *buffer,
+                char **buffer_location,
+                off_t  offset,
+                int    buffer_length,
+                int   *eof,
+                void  *data)
+{
+       int size;
+
+       dprintk(3, "videocodec_info: offset: %ld, len %d / size %d\n",
+               offset, buffer_length, videocodec_bufsize);
+
+       if (offset == 0) {
+               videocodec_bufsize = videocodec_build_table();
+       }
+       if ((offset < 0) || (offset >= videocodec_bufsize)) {
+               dprintk(4,
+                       "videocodec_info: call delivers no result, return 0\n");
+               *eof = 1;
+               return 0;
+       }
+
+       if (buffer_length < (videocodec_bufsize - offset)) {
+               dprintk(4, "videocodec_info: %ld needed, %d got\n",
+                       videocodec_bufsize - offset, buffer_length);
+               size = buffer_length;
+       } else {
+               dprintk(4, "videocodec_info: last reading of %ld bytes\n",
+                       videocodec_bufsize - offset);
+               size = videocodec_bufsize - offset;
+               *eof = 1;
+       }
+
+       memcpy(buffer, videocodec_buf + offset, size);
+       /* doesn't work...                           */
+       /* copy_to_user(buffer, videocodec_buf+offset, size); */
+       /* *buffer_location = videocodec_buf+offset; */
+
+       return size;
+}
+#endif
+
+/* ===================== */
+/* hook in driver module */
+/* ===================== */
+static int __init
+videocodec_init (void)
+{
+#ifdef CONFIG_PROC_FS
+       static struct proc_dir_entry *videocodec_proc_entry;
+#endif
+
+       printk(KERN_INFO "Linux video codec intermediate layer: %s\n",
+              VIDEOCODEC_VERSION);
+
+#ifdef CONFIG_PROC_FS
+       videocodec_buf = NULL;
+       videocodec_bufsize = 0;
+
+       videocodec_proc_entry = create_proc_entry("videocodecs", 0, 0);
+       if (videocodec_proc_entry) {
+               videocodec_proc_entry->read_proc = videocodec_info;
+               videocodec_proc_entry->write_proc = NULL;
+               videocodec_proc_entry->data = NULL;
+               videocodec_proc_entry->owner = THIS_MODULE;
+       } else {
+               dprintk(1, KERN_ERR "videocodec: can't init procfs.\n");
+       }
+#endif
+       return 0;
+}
+
+static void __exit
+videocodec_exit (void)
+{
+#ifdef CONFIG_PROC_FS
+       remove_proc_entry("videocodecs", 0);
+       if (videocodec_buf)
+               kfree(videocodec_buf);
+#endif
+}
+
+EXPORT_SYMBOL(videocodec_attach);
+EXPORT_SYMBOL(videocodec_detach);
+EXPORT_SYMBOL(videocodec_register);
+EXPORT_SYMBOL(videocodec_unregister);
+
+module_init(videocodec_init);
+module_exit(videocodec_exit);
+
+MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>");
+MODULE_DESCRIPTION("Intermediate API module for video codecs "
+                  VIDEOCODEC_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/videocodec.h b/drivers/media/video/videocodec.h
new file mode 100644 (file)
index 0000000..848022a
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * VIDEO MOTION CODECs internal API for video devices
+ *
+ * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's
+ * bound to a master device.
+ *
+ * (c) 2002 Wolfgang Scherr <scherr@net4you.at>
+ *
+ * $Id: videocodec.h,v 1.1.2.4 2003/01/14 21:15:03 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * ------------------------------------------------------------------------
+ */
+
+/* =================== */
+/* general description */
+/* =================== */
+
+/* Should ease the (re-)usage of drivers supporting cards with (different)
+   video codecs. The codecs register to this module their functionality,
+   and the processors (masters) can attach to them if they fit.
+
+   The codecs are typically have a "strong" binding to their master - so I
+   don't think it makes sense to have a full blown interfacing as with e.g.
+   i2c. If you have an other opinion, let's discuss & implement it :-)))
+
+   Usage:
+
+   The slave has just to setup the videocodec structure and use two functions:
+   videocodec_register(codecdata);
+   videocodec_unregister(codecdata);
+   The best is just calling them at module (de-)initialisation.
+
+   The master sets up the structure videocodec_master and calls:
+   codecdata=videocodec_attach(master_codecdata);
+   videocodec_detach(codecdata);
+
+   The slave is called during attach/detach via functions setup previously
+   during register. At that time, the master_data pointer is set up
+   and the slave can access any io registers of the master device (in the case
+   the slave is bound to it). Otherwise it doesn't need this functions and
+   therfor they may not be initialized.
+
+   The other fuctions are just for convenience, as they are for shure used by
+   most/all of the codecs. The last ones may be ommited, too. 
+
+   See the structure declaration below for more information and which data has
+   to be set up for the master and the slave.
+
+   ----------------------------------------------------------------------------
+   The master should have "knowledge" of the slave and vice versa.  So the data
+   structures sent to/from slave via set_data/get_data set_image/get_image are
+   device dependent and vary between MJPEG/MPEG/WAVELET/... devices. (!!!!)
+   ----------------------------------------------------------------------------
+*/
+\f
+
+/* ========================================== */
+/* description of the videocodec_io structure */
+/* ========================================== */
+
+/*
+   ==== master setup ==== 
+   name -> name of the device structure for reference and debugging
+   master_data ->  data ref. for the master (e.g. the zr36055,57,67)
+   readreg -> ref. to read-fn from register (setup by master, used by slave)
+   writereg -> ref. to write-fn to register (setup by master, used by slave)
+               this two functions do the lowlevel I/O job
+
+   ==== slave functionality setup ==== 
+   slave_data -> data ref. for the slave (e.g. the zr36050,60) 
+   check -> fn-ref. checks availability of an device, returns -EIO on failure or
+            the type on success
+            this makes espcecially sense if a driver module supports more than
+            one codec which may be quite similar to access, nevertheless it
+            is good for a first functionality check 
+
+   -- main functions you always need for compression/decompression -- 
+
+   set_mode -> this fn-ref. resets the entire codec, and sets up the mode
+               with the last defined norm/size (or device default if not
+               available) - it returns 0 if the mode is possible 
+   set_size -> this fn-ref. sets the norm and image size for
+               compression/decompression (returns 0 on success) 
+               the norm param is defined in videodev.h (VIDEO_MODE_*) 
+
+   additional setup may be available, too - but the codec should work with
+   some default values even without this 
+
+   set_data -> sets device-specific data (tables, quality etc.) 
+   get_data -> query device-specific data (tables, quality etc.) 
+
+   if the device delivers interrupts, they may be setup/handled here 
+   setup_interrupt -> codec irq setup (not needed for 36050/60) 
+   handle_interrupt -> codec irq handling (not needed for 36050/60) 
+
+   if the device delivers pictures, they may be handled here 
+   put_image -> puts image data to the codec (not needed for 36050/60) 
+   get_image -> gets image data from the codec (not needed for 36050/60) 
+                the calls include frame numbers and flags (even/odd/...) 
+                if needed and a flag which allows blocking until its ready 
+*/
+\f
+/* ============== */
+/* user interface */
+/* ============== */
+
+/* 
+   Currently there is only a information display planned, as the layer
+   is not visible for the user space at all.
+
+   Information is available via procfs. The current entry is "/proc/videocodecs"
+   but it makes sense to "hide" it in the /proc/video tree of v4l(2) --TODO--.
+
+A example for such an output is:
+
+<S>lave or attached <M>aster name  type flags    magic    (connected as)
+S                          zr36050 0002 0000d001 00000000 (TEMPLATE)
+M                       zr36055[0] 0001 0000c001 00000000 (zr36050[0])
+M                       zr36055[1] 0001 0000c001 00000000 (zr36050[1])
+
+*/
+\f
+
+/* =============================================== */
+/* special defines for the videocodec_io structure */
+/* =============================================== */
+
+#ifndef __LINUX_VIDEOCODEC_H
+#define __LINUX_VIDEOCODEC_H
+
+#include <linux/videodev.h>
+
+//should be in videodev.h ??? (VID_DO_....)
+#define CODEC_DO_COMPRESSION 0
+#define CODEC_DO_EXPANSION   1
+
+/* this are the current codec flags I think they are needed */
+/*  -> type value in structure */
+#define CODEC_FLAG_JPEG      0x00000001L       // JPEG codec
+#define CODEC_FLAG_MPEG      0x00000002L       // MPEG1/2/4 codec
+#define CODEC_FLAG_DIVX      0x00000004L       // DIVX codec
+#define CODEC_FLAG_WAVELET   0x00000008L       // WAVELET codec
+                                         // room for other types
+
+#define CODEC_FLAG_MAGIC     0x00000800L       // magic key must match
+#define CODEC_FLAG_HARDWARE  0x00001000L       // is a hardware codec
+#define CODEC_FLAG_VFE       0x00002000L       // has direct video frontend
+#define CODEC_FLAG_ENCODER   0x00004000L       // compression capability
+#define CODEC_FLAG_DECODER   0x00008000L       // decompression capability
+#define CODEC_FLAG_NEEDIRQ   0x00010000L       // needs irq handling
+#define CODEC_FLAG_RDWRPIC   0x00020000L       // handles picture I/O
+
+/* a list of modes, some are just examples (is there any HW?) */
+#define CODEC_MODE_BJPG      0x0001    // Baseline JPEG
+#define CODEC_MODE_LJPG      0x0002    // Lossless JPEG
+#define CODEC_MODE_MPEG1     0x0003    // MPEG 1
+#define CODEC_MODE_MPEG2     0x0004    // MPEG 2
+#define CODEC_MODE_MPEG4     0x0005    // MPEG 4
+#define CODEC_MODE_MSDIVX    0x0006    // MS DivX
+#define CODEC_MODE_ODIVX     0x0007    // Open DivX
+#define CODEC_MODE_WAVELET   0x0008    // Wavelet
+
+/* this are the current codec types I want to implement */
+/*  -> type value in structure */
+#define CODEC_TYPE_NONE    0
+#define CODEC_TYPE_L64702  1
+#define CODEC_TYPE_ZR36050 2
+#define CODEC_TYPE_ZR36016 3
+#define CODEC_TYPE_ZR36060 4
+
+/* the type of data may be enhanced by future implementations (data-fn.'s) */
+/*  -> used in command                                                     */
+#define CODEC_G_STATUS         0x0000  /* codec status (query only) */
+#define CODEC_S_CODEC_MODE     0x0001  /* codec mode (baseline JPEG, MPEG1,... */
+#define CODEC_G_CODEC_MODE     0x8001
+#define CODEC_S_VFE            0x0002  /* additional video frontend setup */
+#define CODEC_G_VFE            0x8002
+#define CODEC_S_MMAP           0x0003  /* MMAP setup (if available) */
+
+#define CODEC_S_JPEG_TDS_BYTE  0x0010  /* target data size in bytes */
+#define CODEC_G_JPEG_TDS_BYTE  0x8010
+#define CODEC_S_JPEG_SCALE     0x0011  /* scaling factor for quant. tables */
+#define CODEC_G_JPEG_SCALE     0x8011
+#define CODEC_S_JPEG_HDT_DATA  0x0018  /* huffman-tables */
+#define CODEC_G_JPEG_HDT_DATA  0x8018
+#define CODEC_S_JPEG_QDT_DATA  0x0019  /* quantizing-tables */
+#define CODEC_G_JPEG_QDT_DATA  0x8019
+#define CODEC_S_JPEG_APP_DATA  0x001A  /* APP marker */
+#define CODEC_G_JPEG_APP_DATA  0x801A
+#define CODEC_S_JPEG_COM_DATA  0x001B  /* COM marker */
+#define CODEC_G_JPEG_COM_DATA  0x801B
+
+#define CODEC_S_PRIVATE        0x1000  /* "private" commands start here */
+#define CODEC_G_PRIVATE        0x9000
+
+#define CODEC_G_FLAG           0x8000  /* this is how 'get' is detected */
+
+/* types of transfer, directly user space or a kernel buffer (image-fn.'s) */
+/*  -> used in get_image, put_image                                        */
+#define CODEC_TRANSFER_KERNEL 0        /* use "memcopy" */
+#define CODEC_TRANSFER_USER   1        /* use "to/from_user" */
+\f
+
+/* ========================= */
+/* the structures itself ... */
+/* ========================= */
+
+struct vfe_polarity {
+       int vsync_pol:1;
+       int hsync_pol:1;
+       int field_pol:1;
+       int blank_pol:1;
+       int subimg_pol:1;
+       int poe_pol:1;
+       int pvalid_pol:1;
+       int vclk_pol:1;
+};
+
+struct vfe_settings {
+       __u32 x, y;             /* Offsets into image */
+       __u32 width, height;    /* Area to capture */
+       __u16 decimation;       /* Decimation divider */
+       __u16 flags;            /* Flags for capture */
+/* flags are the same as in struct video_capture - see videodev.h:
+#define VIDEO_CAPTURE_ODD              0
+#define VIDEO_CAPTURE_EVEN             1
+*/
+       __u16 quality;          /* quality of the video */
+};
+
+struct tvnorm {
+       u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart;
+};
+
+struct videocodec {
+       /* -- filled in by slave device during register -- */
+       char name[32];
+       unsigned long magic;    /* may be used for client<->master attaching */
+       unsigned long flags;    /* functionality flags */
+       unsigned int type;      /* codec type */
+
+       /* -- these is filled in later during master device attach -- */
+
+       struct videocodec_master *master_data;
+
+       /* -- these are filled in by the slave device during register -- */
+
+       void *data;             /* private slave data */
+
+       /* attach/detach client functions (indirect call) */
+       int (*setup) (struct videocodec * codec);
+       int (*unset) (struct videocodec * codec);
+
+       /* main functions, every client needs them for sure! */
+       // set compression or decompression (or freeze, stop, standby, etc)
+       int (*set_mode) (struct videocodec * codec,
+                        int mode);
+       // setup picture size and norm (for the codec's video frontend)
+       int (*set_video) (struct videocodec * codec,
+                         struct tvnorm * norm,
+                         struct vfe_settings * cap,
+                         struct vfe_polarity * pol);
+       // other control commands, also mmap setup etc.
+       int (*control) (struct videocodec * codec,
+                       int type,
+                       int size,
+                       void *data);
+
+       /* additional setup/query/processing (may be NULL pointer) */
+       // interrupt setup / handling (for irq's delivered by master)
+       int (*setup_interrupt) (struct videocodec * codec,
+                               long mode);
+       int (*handle_interrupt) (struct videocodec * codec,
+                                int source,
+                                long flag);
+       // picture interface (if any)
+       long (*put_image) (struct videocodec * codec,
+                          int tr_type,
+                          int block,
+                          long *fr_num,
+                          long *flag,
+                          long size,
+                          void *buf);
+       long (*get_image) (struct videocodec * codec,
+                          int tr_type,
+                          int block,
+                          long *fr_num,
+                          long *flag,
+                          long size,
+                          void *buf);
+};
+
+struct videocodec_master {
+       /* -- filled in by master device for registration -- */
+       char name[32];
+       unsigned long magic;    /* may be used for client<->master attaching */
+       unsigned long flags;    /* functionality flags */
+       unsigned int type;      /* master type */
+
+       void *data;             /* private master data */
+
+        __u32(*readreg) (struct videocodec * codec,
+                         __u16 reg);
+       void (*writereg) (struct videocodec * codec,
+                         __u16 reg,
+                         __u32 value);
+};
+\f
+
+/* ================================================= */
+/* function prototypes of the master/slave interface */
+/* ================================================= */
+
+/* attach and detach commands for the master */
+// * master structure needs to be kmalloc'ed before calling attach
+//   and free'd after calling detach
+// * returns pointer on success, NULL on failure
+extern struct videocodec *videocodec_attach(struct videocodec_master *);
+// * 0 on success, <0 (errno) on failure
+extern int videocodec_detach(struct videocodec *);
+
+/* register and unregister commands for the slaves */
+// * 0 on success, <0 (errno) on failure
+extern int videocodec_register(const struct videocodec *);
+// * 0 on success, <0 (errno) on failure
+extern int videocodec_unregister(const struct videocodec *);
+
+/* the other calls are directly done via the videocodec structure! */
+
+#endif                         /*ifndef __LINUX_VIDEOCODEC_H */
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
new file mode 100644 (file)
index 0000000..5af57f7
--- /dev/null
@@ -0,0 +1,756 @@
+/* 
+ * vpx3220a, vpx3216b & vpx3214c video decoder driver version 0.0.1
+ *
+ * Copyright (C) 2001 Laurent Pinchart <lpinchart@freegates.be>
+ *
+ * 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/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+
+#include <linux/byteorder/swab.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define I2C_NAME(x) (x)->dev.name
+
+#include <linux/videodev.h>
+#include <linux/video_decoder.h>
+
+#define I2C_VPX3220        0x86
+#define VPX3220_DEBUG  KERN_DEBUG "vpx3220: "
+
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
+
+#define VPX_TIMEOUT_COUNT  10
+
+/* ----------------------------------------------------------------------- */
+
+struct vpx3220 {
+       unsigned char reg[255];
+
+       int norm;
+       int input;
+       int enable;
+       int bright;
+       int contrast;
+       int hue;
+       int sat;
+};
+
+static char *inputs[] = { "internal", "composite", "svideo" };
+
+/* ----------------------------------------------------------------------- */
+static inline int
+vpx3220_write (struct i2c_client *client,
+              u8                 reg,
+              u8                 value)
+{
+       struct vpx3220 *decoder = i2c_get_clientdata(client);
+       decoder->reg[reg] = value;
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int
+vpx3220_read (struct i2c_client *client,
+             u8                 reg)
+{
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int
+vpx3220_fp_status (struct i2c_client *client)
+{
+       unsigned char status;
+       unsigned int i;
+
+       for (i = 0; i < VPX_TIMEOUT_COUNT; i++) {
+               status = vpx3220_read(client, 0x29);
+
+               if (!(status & 4))
+                       return 0;
+
+               udelay(10);
+
+               if (need_resched())
+                       cond_resched();
+       }
+
+       return -1;
+}
+
+static int
+vpx3220_fp_write (struct i2c_client *client,
+                 u8                 fpaddr,
+                 u16                data)
+{
+       /* Write the 16-bit address to the FPWR register */
+       if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
+               dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
+               return -1;
+       }
+
+       if (vpx3220_fp_status(client) < 0)
+               return -1;
+
+       /* Write the 16-bit data to the FPDAT register */
+       if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
+               dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+static u16
+vpx3220_fp_read (struct i2c_client *client,
+                u16                fpaddr)
+{
+       s16 data;
+
+       /* Write the 16-bit address to the FPRD register */
+       if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
+               dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
+               return -1;
+       }
+
+       if (vpx3220_fp_status(client) < 0)
+               return -1;
+
+       /* Read the 16-bit data from the FPDAT register */
+       data = i2c_smbus_read_word_data(client, 0x28);
+       if (data == -1) {
+               dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
+               return -1;
+       }
+
+       return swab16(data);
+}
+
+static int
+vpx3220_write_block (struct i2c_client *client,
+                    const u8          *data,
+                    unsigned int       len)
+{
+       u8 reg;
+       int ret = -1;
+
+       while (len >= 2) {
+               reg = *data++;
+               if ((ret =
+                    vpx3220_write(client, reg, *data++)) < 0)
+                       break;
+               len -= 2;
+       }
+
+       return ret;
+}
+
+static int
+vpx3220_write_fp_block (struct i2c_client *client,
+                       const u16         *data,
+                       unsigned int       len)
+{
+       u8 reg;
+       int ret = 0;
+
+       while (len > 1) {
+               reg = *data++;
+               ret |= vpx3220_fp_write(client, reg, *data++);
+               len -= 2;
+       }
+
+       return ret;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static const unsigned short init_ntsc[] = {
+       0x1c, 0x00,             /* NTSC tint angle */
+       0x88, 17,               /* Window 1 vertical */
+       0x89, 240,              /* Vertical lines in */
+       0x8a, 240,              /* Vertical lines out */
+       0x8b, 000,              /* Horizontal begin */
+       0x8c, 640,              /* Horizontal length */
+       0x8d, 640,              /* Number of pixels */
+       0x8f, 0xc00,            /* Disable window 2 */
+       0xf0, 0x173,            /* 13.5 MHz transport, Forced
+                                * mode, latch windows */
+       0xf2, 0x13,             /* NTSC M, composite input */
+       0xe7, 0x1e1,            /* Enable vertical standard
+                                * locking @ 240 lines */
+};
+
+static const unsigned short init_pal[] = {
+       0x88, 23,               /* Window 1 vertical begin */
+       0x89, 288 + 16,         /* Vertical lines in (16 lines
+                                * skipped by the VFE) */
+       0x8a, 288 + 16,         /* Vertical lines out (16 lines
+                                * skipped by the VFE) */
+       0x8b, 16,               /* Horizontal begin */
+       0x8c, 768,              /* Horizontal length */
+       0x8d, 784,              /* Number of pixels
+                                * Must be >= Horizontal begin + Horizontal length */
+       0x8f, 0xc00,            /* Disable window 2 */
+       0xf0, 0x177,            /* 13.5 MHz transport, Forced
+                                * mode, latch windows */
+       0xf2, 0x3d1,            /* PAL B,G,H,I, composite input */
+       0xe7, 0x261,            /* PAL/SECAM set to 288 + 16 lines 
+                                * change to 0x241 for 288 lines */
+};
+
+static const unsigned short init_secam[] = {
+       0x88, 23  - 16,         /* Window 1 vertical begin */
+       0x89, 288 + 16,         /* Vertical lines in (16 lines
+                                * skipped by the VFE) */
+       0x8a, 288 + 16,         /* Vertical lines out (16 lines
+                                * skipped by the VFE) */
+       0x8b, 16,               /* Horizontal begin */
+       0x8c, 768,              /* Horizontal length */
+       0x8d, 784,              /* Number of pixels
+                                * Must be >= Horizontal begin + Horizontal length */
+       0x8f, 0xc00,            /* Disable window 2 */
+       0xf0, 0x177,            /* 13.5 MHz transport, Forced
+                                * mode, latch windows */
+       0xf2, 0x3d5,            /* SECAM, composite input */
+       0xe7, 0x261,            /* PAL/SECAM set to 288 + 16 lines 
+                                * change to 0x241 for 288 lines */
+};
+
+static const unsigned char init_common[] = {
+       0xf2, 0x00,             /* Disable all outputs */
+       0x33, 0x0d,             /* Luma : VIN2, Chroma : CIN
+                                * (clamp off) */
+       0xd8, 0xa8,             /* HREF/VREF active high, VREF
+                                * pulse = 2, Odd/Even flag */
+       0x20, 0x03,             /* IF compensation 0dB/oct */
+       0xe0, 0xff,             /* Open up all comparators */
+       0xe1, 0x00,
+       0xe2, 0x7f,
+       0xe3, 0x80,
+       0xe4, 0x7f,
+       0xe5, 0x80,
+       0xe6, 0x00,             /* Brightness set to 0 */
+       0xe7, 0xe0,             /* Contrast to 1.0, noise shaping
+                                * 10 to 8 2-bit error diffusion */
+       0xe8, 0xf8,             /* YUV422, CbCr binary offset,
+                                * ... (p.32) */
+       0xea, 0x18,             /* LLC2 connected, output FIFO
+                                * reset with VACTintern */
+       0xf0, 0x8a,             /* Half full level to 10, bus
+                                * shuffler [7:0, 23:16, 15:8] */
+       0xf1, 0x18,             /* Single clock, sync mode, no
+                                * FE delay, no HLEN counter */
+       0xf8, 0x12,             /* Port A, PIXCLK, HF# & FE#
+                                * strength to 2 */
+       0xf9, 0x24,             /* Port B, HREF, VREF, PREF &
+                                * ALPHA strength to 4 */
+};
+
+static const unsigned short init_fp[] = {
+       0x59, 0,
+       0xa0, 2070,             /* ACC reference */
+       0xa3, 0,
+       0xa4, 0,
+       0xa8, 30,
+       0xb2, 768,
+       0xbe, 27,
+       0x58, 0,
+       0x26, 0,
+       0x4b, 0x298,            /* PLL gain */
+};
+
+static void
+vpx3220_dump_i2c (struct i2c_client *client)
+{
+       int len = sizeof(init_common);
+       const unsigned char *data = init_common;
+       while (len > 1) {
+               dprintk(1,
+                       KERN_DEBUG "vpx3216b i2c reg 0x%02x data 0x%02x\n",
+                       *data, vpx3220_read(client, *data));
+               data += 2;
+               len -= 2;
+       }
+}
+
+static int
+vpx3220_command (struct i2c_client *client,
+                unsigned int       cmd,
+                void              *arg)
+{
+       struct vpx3220 *decoder = i2c_get_clientdata(client);
+
+       switch (cmd) {
+       case 0:
+       {
+               vpx3220_write_block(client, init_common,
+                                   sizeof(init_common));
+               vpx3220_write_fp_block(client, init_fp,
+                                      sizeof(init_fp) >> 1);
+               switch (decoder->norm) {
+                       
+               case VIDEO_MODE_NTSC:
+                       vpx3220_write_fp_block(client, init_ntsc,
+                                              sizeof(init_ntsc) >> 1);
+                       break;
+
+               case VIDEO_MODE_PAL:
+                       vpx3220_write_fp_block(client, init_pal,
+                                              sizeof(init_pal) >> 1);
+                       break;
+               case VIDEO_MODE_SECAM:
+                       vpx3220_write_fp_block(client, init_secam,
+                                              sizeof(init_secam) >> 1);
+                       break;
+               default:
+                       vpx3220_write_fp_block(client, init_pal,
+                                              sizeof(init_pal) >> 1);
+                       break;
+               }
+       }               
+               break;
+
+       case DECODER_DUMP:
+       {
+               vpx3220_dump_i2c(client);
+       }
+               break;
+
+       case DECODER_GET_CAPABILITIES:
+       {
+               struct video_decoder_capability *cap = arg;
+
+               dprintk(1, KERN_DEBUG "%s: DECODER_GET_CAPABILITIES\n",
+                       I2C_NAME(client));
+
+               cap->flags = VIDEO_DECODER_PAL |
+                            VIDEO_DECODER_NTSC |
+                            VIDEO_DECODER_SECAM |
+                            VIDEO_DECODER_AUTO |
+                            VIDEO_DECODER_CCIR;
+               cap->inputs = 3;
+               cap->outputs = 1;
+       }
+               break;
+
+       case DECODER_GET_STATUS:
+       {
+               int res = 0, status;
+
+               dprintk(1, KERN_INFO "%s: DECODER_GET_STATUS\n",
+                       I2C_NAME(client));
+
+               status = vpx3220_fp_read(client, 0x0f3);
+
+               dprintk(1, KERN_INFO "%s: status: 0x%04x\n", I2C_NAME(client),
+                       status);
+
+               if (status < 0)
+                       return status;
+
+               if ((status & 0x20) == 0) {
+                       res |= DECODER_STATUS_GOOD | DECODER_STATUS_COLOR;
+
+                       switch (status & 0x18) {
+
+                       case 0x00:
+                       case 0x10:
+                       case 0x14:
+                       case 0x18:
+                               res |= DECODER_STATUS_PAL;
+                               break;
+
+                       case 0x08:
+                               res |= DECODER_STATUS_SECAM;
+                               break;
+
+                       case 0x04:
+                       case 0x0c:
+                       case 0x1c:
+                               res |= DECODER_STATUS_NTSC;
+                               break;
+                       }
+               }
+
+               *(int *) arg = res;
+       }
+               break;
+
+       case DECODER_SET_NORM:
+       {
+               int *iarg = arg, data;
+
+               dprintk(1, KERN_DEBUG "%s: DECODER_SET_NORM %d\n",
+                       I2C_NAME(client), *iarg);
+               switch (*iarg) {
+
+               case VIDEO_MODE_NTSC:
+                       vpx3220_write_fp_block(client, init_ntsc,
+                                              sizeof(init_ntsc) >> 1);
+                       dprintk(1, KERN_INFO "%s: norm switched to NTSC\n",
+                               I2C_NAME(client));
+                       break;
+
+               case VIDEO_MODE_PAL:
+                       vpx3220_write_fp_block(client, init_pal,
+                                              sizeof(init_pal) >> 1);
+                       dprintk(1, KERN_INFO "%s: norm switched to PAL\n",
+                               I2C_NAME(client));
+                       break;
+
+               case VIDEO_MODE_SECAM:
+                       vpx3220_write_fp_block(client, init_secam,
+                                              sizeof(init_secam) >> 1);
+                       dprintk(1, KERN_INFO "%s: norm switched to SECAM\n",
+                               I2C_NAME(client));
+                       break;
+
+               case VIDEO_MODE_AUTO:
+                       /* FIXME This is only preliminary support */
+                       data = vpx3220_fp_read(client, 0xf2) & 0x20;
+                       vpx3220_fp_write(client, 0xf2, 0x00c0 | data);
+                       dprintk(1, KERN_INFO "%s: norm switched to Auto\n",
+                               I2C_NAME(client));
+                       break;
+
+               default:
+                       return -EINVAL;
+
+               }
+               decoder->norm = *iarg;
+       }
+               break;
+
+       case DECODER_SET_INPUT:
+       {
+               int *iarg = arg, data;
+
+               /* RJ:  *iarg = 0: ST8 (PCTV) input
+                *iarg = 1: COMPOSITE  input
+                *iarg = 2: SVHS       input  */
+
+               const int input[3][2] = {
+                       {0x0c, 0},
+                       {0x0d, 0},
+                       {0x0e, 1}
+               };
+
+               if (*iarg < 0 || *iarg > 2)
+                       return -EINVAL;
+
+               dprintk(1, KERN_INFO "%s: input switched to %s\n",
+                       I2C_NAME(client), inputs[*iarg]);
+
+               vpx3220_write(client, 0x33, input[*iarg][0]);
+
+               data = vpx3220_fp_read(client, 0xf2) & ~(0x0020);
+               if (data < 0)
+                       return data;
+               /* 0x0010 is required to latch the setting */
+               vpx3220_fp_write(client, 0xf2,
+                                data | (input[*iarg][1] << 5) | 0x0010);
+
+               udelay(10);
+       }
+               break;
+
+       case DECODER_SET_OUTPUT:
+       {
+               int *iarg = arg;
+
+               /* not much choice of outputs */
+               if (*iarg != 0) {
+                       return -EINVAL;
+               }
+       }
+               break;
+
+       case DECODER_ENABLE_OUTPUT:
+       {
+               int *iarg = arg;
+
+               dprintk(1, KERN_DEBUG "%s: DECODER_ENABLE_OUTPUT %d\n",
+                       I2C_NAME(client), *iarg);
+
+               vpx3220_write(client, 0xf2, (*iarg ? 0x1b : 0x00));
+       }
+               break;
+
+       case DECODER_SET_PICTURE:
+       {
+               struct video_picture *pic = arg;
+
+               if (decoder->bright != pic->brightness) {
+                       /* We want -128 to 128 we get 0-65535 */
+                       decoder->bright = pic->brightness;
+                       vpx3220_write(client, 0xe6,
+                                     (decoder->bright - 32768) >> 8);
+               }
+               if (decoder->contrast != pic->contrast) {
+                       /* We want 0 to 64 we get 0-65535 */
+                       /* Bit 7 and 8 is for noise shaping */
+                       decoder->contrast = pic->contrast;
+                       vpx3220_write(client, 0xe7,
+                                     (decoder->contrast >> 10) + 192);
+               }
+               if (decoder->sat != pic->colour) {
+                       /* We want 0 to 4096 we get 0-65535 */
+                       decoder->sat = pic->colour;
+                       vpx3220_fp_write(client, 0xa0,
+                                        decoder->sat >> 4);
+               }
+               if (decoder->hue != pic->hue) {
+                       /* We want -512 to 512 we get 0-65535 */
+                       decoder->hue = pic->hue;
+                       vpx3220_fp_write(client, 0x1c,
+                                        ((decoder->hue - 32768) >> 6) & 0xFFF);
+               }
+       }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+vpx3220_init_client (struct i2c_client *client)
+{
+       vpx3220_write_block(client, init_common, sizeof(init_common));
+       vpx3220_write_fp_block(client, init_fp, sizeof(init_fp) >> 1);
+       /* Default to PAL */
+       vpx3220_write_fp_block(client, init_pal, sizeof(init_pal) >> 1);
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------
+ * Client managment code
+ */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+static unsigned short normal_i2c[] =
+    { I2C_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4,
+       I2C_CLIENT_END
+};
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+                                                                                
+static struct i2c_client_address_data addr_data = {
+       .normal_i2c             = normal_i2c,
+       .normal_i2c_range       = normal_i2c_range,
+       .probe                  = probe,
+       .probe_range            = probe_range,
+       .ignore                 = ignore,
+       .ignore_range           = ignore_range,
+       .force                  = force
+};
+
+static int vpx3220_i2c_id = 0;
+static struct i2c_driver vpx3220_i2c_driver;
+
+static int
+vpx3220_detach_client (struct i2c_client *client)
+{
+       struct vpx3220 *decoder = i2c_get_clientdata(client);
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+
+       kfree(decoder);
+       kfree(client);
+
+       return 0;
+}
+
+static int
+vpx3220_detect_client (struct i2c_adapter *adapter,
+                      int                 address,
+                      int                 kind)
+{
+       int err;
+       struct i2c_client *client;
+       struct vpx3220 *decoder;
+
+       dprintk(1, VPX3220_DEBUG "%s\n", __func__);
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality
+           (adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+               return 0;
+
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == NULL) {
+               return -ENOMEM;
+       }
+
+       memset(client, 0, sizeof(struct i2c_client));
+
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &vpx3220_i2c_driver;
+       client->flags = I2C_CLIENT_ALLOW_USE;
+       client->id = vpx3220_i2c_id++;
+
+       /* Check for manufacture ID and part number */
+       if (kind < 0) {
+               u8 id;
+               u16 pn;
+
+               id = vpx3220_read(client, 0x00);
+               if (id != 0xec) {
+                       dprintk(1,
+                               KERN_INFO
+                               "vpx3220_attach: Wrong manufacturer ID (0x%02x)\n",
+                               id);
+                       kfree(client);
+                       return 0;
+               }
+
+               pn = (vpx3220_read(client, 0x02) << 8) +
+                   vpx3220_read(client, 0x01);
+               switch (pn) {
+               case 0x4680:
+                       snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+                                "vpx3220a[%d]", client->id);
+                       break;
+               case 0x4260:
+                       snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+                                "vpx3216b[%d]", client->id);
+                       break;
+               case 0x4280:
+                       snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+                                "vpx3214c[%d]", client->id);
+                       break;
+               default:
+                       dprintk(1,
+                               KERN_INFO 
+                               "%s: Wrong part number (0x%04x)\n",
+                               __func__, pn);
+                       kfree(client);
+                       return 0;
+               }
+       } else {
+               snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
+                        "forced vpx32xx[%d]",
+               client->id);
+       }
+
+       decoder = kmalloc(sizeof(struct vpx3220), GFP_KERNEL);
+       if (decoder == NULL) {
+               kfree(client);
+               return -ENOMEM;
+       }
+       memset(decoder, 0, sizeof(struct vpx3220));
+       decoder->norm = VIDEO_MODE_PAL;
+       decoder->input = 0;
+       decoder->enable = 1;
+       decoder->bright = 32768;
+       decoder->contrast = 32768;
+       decoder->hue = 32768;
+       decoder->sat = 32768;
+       i2c_set_clientdata(client, decoder);
+
+       err = i2c_attach_client(client);
+       if (err) {
+               kfree(client);
+               kfree(decoder);
+               return err;
+       }
+
+       dprintk(1, KERN_INFO "%s: vpx32xx client found at address 0x%02x\n",
+               I2C_NAME(client), client->addr << 1);
+
+       vpx3220_init_client(client);
+
+       return 0;
+}
+
+static int
+vpx3220_attach_adapter (struct i2c_adapter *adapter)
+{
+       int ret;
+
+       ret = i2c_probe(adapter, &addr_data, &vpx3220_detect_client);
+       dprintk(1, VPX3220_DEBUG "%s: i2c_probe returned %d\n",
+               __func__, ret);
+       return ret;
+}
+
+/* -----------------------------------------------------------------------
+ * Driver initialization and cleanup code
+ */
+
+static struct i2c_driver vpx3220_i2c_driver = {
+       .owner = THIS_MODULE,
+       .name = "vpx3220",
+
+       .id = I2C_DRIVERID_VPX3220,
+       .flags = I2C_DF_NOTIFY,
+
+       .attach_adapter = vpx3220_attach_adapter,
+       .detach_client = vpx3220_detach_client,
+       .command = vpx3220_command,
+};
+
+static int __init
+vpx3220_init (void)
+{
+       return i2c_add_driver(&vpx3220_i2c_driver);
+}
+
+static void __exit
+vpx3220_cleanup (void)
+{
+       i2c_del_driver(&vpx3220_i2c_driver);
+}
+
+module_init(vpx3220_init);
+module_exit(vpx3220_cleanup);
+
+MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video encoder driver");
+MODULE_AUTHOR("Laurent Pinchart");
+MODULE_LICENSE("GPL");
index 444ebc39cf6597d41a4fdcff897c24910f760b93..73c651475d5b1a65797dcc1c60a536bab3b68896 100644 (file)
@@ -1,54 +1,36 @@
 /* 
-    zoran - Iomega Buz driver
-
-    Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
-
-   based on
-
-    zoran.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net>
-
-   and
-
-    bttv - Bt848 frame grabber driver
-    Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
-
-    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.
-*/
+ * zoran - Iomega Buz driver
+ *
+ * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
+ *
+ * based on
+ *
+ * zoran.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * and
+ *
+ * bttv - Bt848 frame grabber driver
+ * Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+ *                        & Marcus Metzler (mocm@thp.uni-koeln.de)
+ *
+ * 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 _BUZ_H_
 #define _BUZ_H_
 
-#include <linux/config.h>
-
-/* The Buz only supports a maximum width of 720, but some V4L
-   applications (e.g. xawtv are more happy with 768).
-   If XAWTV_HACK is defined, we try to fake a device with bigger width */
-
-//#define XAWTV_HACK
-
-//#ifdef XAWTV_HACK
-//#define   BUZ_MAX_WIDTH   768   /* never display more than 768 pixels */
-#define   BUZ_MAX_WIDTH   (zr->timing->Wa)
-//#else
-//#define   BUZ_MAX_WIDTH   720   /* never display more than 720 pixels */
-//#endif
-//#define   BUZ_MAX_HEIGHT  576   /* never display more than 576 rows */
-#define   BUZ_MAX_HEIGHT  (zr->timing->Ha)
-#define   BUZ_MIN_WIDTH    32  /* never display less than 32 pixels */
-#define   BUZ_MIN_HEIGHT   24  /* never display less than 24 rows */
-
 struct zoran_requestbuffers {
        unsigned long count;    /* Number of buffers for MJPEG grabbing */
        unsigned long size;     /* Size PER BUFFER in bytes */
@@ -80,35 +62,35 @@ struct zoran_params {
        int input;              /* Input channel: 0 = Composite, 1 = S-VHS */
        int norm;               /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
        int decimation;         /* decimation of captured video,
-                                  enlargement of video played back.
-                                  Valid values are 1, 2, 4 or 0.
-                                  0 is a special value where the user
-                                  has full control over video scaling */
+                                * enlargement of video played back.
+                                * Valid values are 1, 2, 4 or 0.
+                                * 0 is a special value where the user
+                                * has full control over video scaling */
 
        /* The following parameters only have to be set if decimation==0,
-          for other values of decimation they provide the data how the image is captured */
+        * for other values of decimation they provide the data how the image is captured */
 
        int HorDcm;             /* Horizontal decimation: 1, 2 or 4 */
        int VerDcm;             /* Vertical decimation: 1 or 2 */
        int TmpDcm;             /* Temporal decimation: 1 or 2,
-                                  if TmpDcm==2 in capture every second frame is dropped,
-                                  in playback every frame is played twice */
+                                * if TmpDcm==2 in capture every second frame is dropped,
+                                * in playback every frame is played twice */
        int field_per_buff;     /* Number of fields per buffer: 1 or 2 */
        int img_x;              /* start of image in x direction */
        int img_y;              /* start of image in y direction */
        int img_width;          /* image width BEFORE decimation,
-                                  must be a multiple of HorDcm*16 */
+                                * must be a multiple of HorDcm*16 */
        int img_height;         /* image height BEFORE decimation,
-                                  must be a multiple of VerDcm*8 */
+                                * must be a multiple of VerDcm*8 */
 
        /* --- End of parameters for decimation==0 only --- */
 
        /* JPEG control parameters */
 
        int quality;            /* Measure for quality of compressed images.
-                                  Scales linearly with the size of the compressed images.
-                                  Must be beetween 0 and 100, 100 is a compression
-                                  ratio of 1:4 */
+                                * Scales linearly with the size of the compressed images.
+                                * Must be beetween 0 and 100, 100 is a compression
+                                * ratio of 1:4 */
 
        int odd_even;           /* Which field should come first ??? */
 
@@ -120,12 +102,12 @@ struct zoran_params {
        char COM_data[60];      /* Data in JPEG COM segment */
 
        unsigned long jpeg_markers;     /* Which markers should go into the JPEG output.
-                                          Unless you exactly know what you do, leave them untouched.
-                                          Inluding less markers will make the resulting code
-                                          smaller, but there will be fewer aplications
-                                          which can read it.
-                                          The presence of the APP and COM marker is
-                                          influenced by APP0_len and COM_len ONLY! */
+                                        * Unless you exactly know what you do, leave them untouched.
+                                        * Inluding less markers will make the resulting code
+                                        * smaller, but there will be fewer aplications
+                                        * which can read it.
+                                        * The presence of the APP and COM marker is
+                                        * influenced by APP0_len and COM_len ONLY! */
 #define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */
 #define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */
 #define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */
@@ -133,11 +115,11 @@ struct zoran_params {
 #define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */
 
        int VFIFO_FB;           /* Flag for enabling Video Fifo Feedback.
-                                  If this flag is turned on and JPEG decompressing
-                                  is going to the screen, the decompress process
-                                  is stopped every time the Video Fifo is full.
-                                  This enables a smooth decompress to the screen
-                                  but the video output signal will get scrambled */
+                                * If this flag is turned on and JPEG decompressing
+                                * is going to the screen, the decompress process
+                                * is stopped every time the Video Fifo is full.
+                                * This enables a smooth decompress to the screen
+                                * but the video output signal will get scrambled */
 
        /* Misc */
 
@@ -158,12 +140,31 @@ Private IOCTL to set up for displaying MJPEG
 
 #ifdef __KERNEL__
 
+#define MAJOR_VERSION 0                /* driver major version */
+#define MINOR_VERSION 9                /* driver minor version */
+#define RELEASE_VERSION 5      /* release version */
+
+#define ZORAN_NAME    "ZORAN"  /* name of the device */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#define ZR_DEVNAME(zr) (zr)->name
+#else
+#define ZR_DEVNAME(zr) (zr)->pci_dev->dev.name
+#endif
+
+#define   BUZ_MAX_WIDTH   (zr->timing->Wa)
+#define   BUZ_MAX_HEIGHT  (zr->timing->Ha)
+#define   BUZ_MIN_WIDTH    32  /* never display less than 32 pixels */
+#define   BUZ_MIN_HEIGHT   24  /* never display less than 24 rows */
+
 #define BUZ_NUM_STAT_COM    4
 #define BUZ_MASK_STAT_COM   3
 
 #define BUZ_MAX_FRAME     256  /* Must be a power of 2 */
 #define BUZ_MASK_FRAME    255  /* Must be BUZ_MAX_FRAME-1 */
 
+#define BUZ_MAX_INPUT       8
+
 #if VIDEO_MAX_FRAME <= 32
 #   define   V4L_MAX_FRAME   32
 #elif VIDEO_MAX_FRAME <= 64
@@ -173,15 +174,29 @@ Private IOCTL to set up for displaying MJPEG
 #endif
 #define   V4L_MASK_FRAME   (V4L_MAX_FRAME - 1)
 
+#define MAX_KMALLOC_MEM (128*1024)
 
 #include "zr36057.h"
 
 enum card_type {
-        UNKNOWN = 0,
-        DC10,
-        DC10plus,
-        LML33,
-        BUZ
+       UNKNOWN = -1,
+
+       /* Pinnacle/Miro */
+       DC10_old,               /* DC30 like */
+       DC10_new,               /* DC10plus like */
+       DC10plus,
+       DC30,
+       DC30plus,
+
+       /* Linux Media Labs */
+       LML33,
+       LML33R10,
+
+       /* Iomega */
+       BUZ,
+
+       /* total number of cards */
+       NUM_CARDS
 };
 
 enum zoran_codec_mode {
@@ -199,84 +214,237 @@ enum zoran_buffer_state {
        BUZ_STATE_DONE          /* buffer is ready to return to application */
 };
 
-struct zoran_gbuffer {
+enum zoran_map_mode {
+       ZORAN_MAP_MODE_RAW,
+       ZORAN_MAP_MODE_JPG_REC,
+#define ZORAN_MAP_MODE_JPG ZORAN_MAP_MODE_JPG_REC
+       ZORAN_MAP_MODE_JPG_PLAY,
+};
+
+enum gpio_type {
+       GPIO_JPEG_SLEEP = 0,
+       GPIO_JPEG_RESET,
+       GPIO_JPEG_FRAME,
+       GPIO_VID_DIR,
+       GPIO_VID_EN,
+       GPIO_VID_RESET,
+       GPIO_CLK_SEL1,
+       GPIO_CLK_SEL2,
+       GPIO_MAX,
+};
+
+enum gpcs_type {
+       GPCS_JPEG_RESET = 0,
+       GPCS_JPEG_START,
+       GPCS_MAX,
+};
+
+struct zoran_format {
+       char *name;
+       int palette;
+       __u32 fourcc;
+       int colorspace;
+       int depth;
+       __u32 flags;
+};
+/* flags */
+#define ZORAN_FORMAT_COMPRESSED 1<<0
+#define ZORAN_FORMAT_OVERLAY    1<<1
+#define ZORAN_FORMAT_CAPTURE   1<<2
+#define ZORAN_FORMAT_PLAYBACK  1<<3
+
+/* overlay-settings */
+struct zoran_overlay_settings {
+       int is_set;
+       int x, y, width, height;        /* position */
+       int clipcount;          /* position and number of clips */
+       const struct zoran_format *format;      /* overlay format */
+};
+
+/* v4l-capture settings */
+struct zoran_v4l_settings {
+       int width, height, bytesperline;        /* capture size */
+       const struct zoran_format *format;      /* capture format */
+};
+
+/* whoops, this one is undeclared if !v4l2 */
+#ifndef HAVE_V4L2
+struct v4l2_jpegcompression {
+       int quality;
+       int APPn;
+       int APP_len;
+       char APP_data[60];
+       int COM_len;
+       char COM_data[60];
+       __u32 jpeg_markers;
+       __u8 reserved[116];
+};
+#endif
+
+/* jpg-capture/-playback settings */
+struct zoran_jpg_settings {
+       int decimation;         /* this bit is used to set everything to default */
+       int HorDcm, VerDcm, TmpDcm;     /* capture decimation settings (TmpDcm=1 means both fields) */
+       int field_per_buff, odd_even;   /* field-settings (odd_even=1 (+TmpDcm=1) means top-field-first) */
+       int img_x, img_y, img_width, img_height;        /* crop settings (subframe capture) */
+       struct v4l2_jpegcompression jpg_comp;   /* JPEG-specific capture settings */
+};
+
+struct zoran_mapping {
+       struct file *file;
+       int count;
+};
+
+struct zoran_jpg_buffer {
+       struct zoran_mapping *map;
        u32 *frag_tab;          /* addresses of frag table */
        u32 frag_tab_bus;       /* same value cached to save time in ISR */
        enum zoran_buffer_state state;  /* non-zero if corresponding buffer is in use in grab queue */
        struct zoran_sync bs;   /* DONE: info to return to application */
 };
 
-struct v4l_gbuffer {
-       char *fbuffer;                  /* virtual  address of frame buffer */
+struct zoran_v4l_buffer {
+       struct zoran_mapping *map;
+       char *fbuffer;          /* virtual  address of frame buffer */
        unsigned long fbuffer_phys;     /* physical address of frame buffer */
        unsigned long fbuffer_bus;      /* bus      address of frame buffer */
        enum zoran_buffer_state state;  /* state: unused/pending/done */
+       struct zoran_sync bs;   /* DONE: info to return to application */
+};
+
+enum zoran_lock_activity {
+       ZORAN_FREE,             /* free for use */
+       ZORAN_ACTIVE,           /* active but unlocked */
+       ZORAN_LOCKED,           /* locked */
+};
+
+/* buffer collections */
+struct zoran_jpg_struct {
+       enum zoran_lock_activity active;        /* feature currently in use? */
+       struct zoran_jpg_buffer buffer[BUZ_MAX_FRAME];  /* buffers */
+       int num_buffers, buffer_size;
+       u8 allocated;           /* Flag if buffers are allocated  */
+       u8 ready_to_be_freed;   /* hack - see zoran_driver.c */
+       u8 need_contiguous;     /* Flag if contiguous buffers are needed */
 };
 
-struct tvnorm {
-       u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart;
+struct zoran_v4l_struct {
+       enum zoran_lock_activity active;        /* feature currently in use? */
+       struct zoran_v4l_buffer buffer[VIDEO_MAX_FRAME];        /* buffers */
+       int num_buffers, buffer_size;
+       u8 allocated;           /* Flag if buffers are allocated  */
+       u8 ready_to_be_freed;   /* hack - see zoran_driver.c */
+};
+
+struct zoran;
+
+/* zoran_fh contains per-open() settings */
+struct zoran_fh {
+       struct zoran *zr;
+
+       enum zoran_map_mode map_mode;   /* Flag which bufferset will map by next mmap() */
+
+       struct zoran_overlay_settings overlay_settings;
+       u32 *overlay_mask;      /* overlay mask */
+       enum zoran_lock_activity overlay_active;        /* feature currently in use? */
+
+       struct zoran_v4l_settings v4l_settings; /* structure with a lot of things to play with */
+       struct zoran_v4l_struct v4l_buffers;    /* V4L buffers' info */
+
+       struct zoran_jpg_settings jpg_settings; /* structure with a lot of things to play with */
+       struct zoran_jpg_struct jpg_buffers;    /* MJPEG buffers' info */
+};
+
+struct card_info {
+       enum card_type type;
+       char name[32];
+       u16 i2c_decoder, i2c_encoder;                   /* I2C types */
+       u16 video_vfe, video_codec;                     /* videocodec types */
+       u16 audio_chip;                                 /* audio type */
+       u16 vendor_id, device_id;       /* subsystem vendor/device ID */
+
+       int inputs;             /* number of video inputs */
+       struct input {
+               int muxsel;
+               char name[32];
+       } input[BUZ_MAX_INPUT];
+
+       int norms;
+       struct tvnorm *tvn[3];  /* supported TV norms */
+
+       u32 jpeg_int;           /* JPEG interrupt */
+       u32 vsync_int;          /* VSYNC interrupt */
+       s8 gpio[GPIO_MAX];
+       u8 gpcs[GPCS_MAX];
+
+       struct vfe_polarity vfe_pol;
+       u8 gpio_pol[GPIO_MAX];
+
+       /* is the /GWS line conected? */
+       u8 gws_not_connected;
+
+       void (*init) (struct zoran * zr);
 };
 
 struct zoran {
        struct video_device video_dev;
-       struct i2c_bus i2c;
 
-       int initialized;                /* flag if zoran has been correctly initalized */
-       int user;                       /* number of current users (0 or 1) */
-        enum card_type card;
-        struct tvnorm *timing;
+       struct i2c_adapter i2c_adapter; /* */
+       struct i2c_algo_bit_data i2c_algo;      /* */
+       u32 i2cbr;
+
+       struct i2c_client *decoder;     /* video decoder i2c client */
+       struct i2c_client *encoder;     /* video encoder i2c client */
 
-       unsigned short id;              /* number of this device */
-       char name[32];                  /* name of this device */
+       struct videocodec *codec;       /* video codec */
+       struct videocodec *vfe; /* video front end */
+
+       struct semaphore resource_lock; /* prevent evil stuff */
+
+       u8 initialized;         /* flag if zoran has been correctly initalized */
+       int user;               /* number of current users */
+       struct card_info card;
+       struct tvnorm *timing;
+
+       unsigned short id;      /* number of this device */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+       char name[32];          /* name of this device */
+#endif
        struct pci_dev *pci_dev;        /* PCI device */
-       unsigned char revision;         /* revision of zr36057 */
+       unsigned char revision; /* revision of zr36057 */
        unsigned int zr36057_adr;       /* bus address of IO mem returned by PCI BIOS */
        unsigned char *zr36057_mem;     /* pointer to mapped IO memory */
 
-       int map_mjpeg_buffers;          /* Flag which bufferset will map by next mmap() */
-
-       spinlock_t lock;                /* Spinlock irq and hardware */
-       struct semaphore sem;           /* Guard parallel ioctls and mmap */
+       spinlock_t spinlock;    /* Spinlock */
 
        /* Video for Linux parameters */
-
-       struct video_picture picture;   /* Current picture params */
+       int input, norm;        /* card's norm and input - norm=VIDEO_MODE_* */
+       int hue, saturation, contrast, brightness;      /* Current picture params */
        struct video_buffer buffer;     /* Current buffer params */
-       struct video_window window;     /* Current window params */
-       int buffer_set, window_set;     /* Flags if the above structures are set */
-       int video_interlace;            /* Image on screen is interlaced */
+       struct zoran_overlay_settings overlay_settings;
+       u32 *overlay_mask;      /* overlay mask */
+       enum zoran_lock_activity overlay_active;        /* feature currently in use? */
 
-       u32 *overlay_mask;
-        wait_queue_head_t v4l_capq;
+       wait_queue_head_t v4l_capq;
 
-       int v4l_overlay_active;         /* Overlay grab is activated */
-       int v4l_memgrab_active;         /* Memory grab is activated */
+       int v4l_overlay_active; /* Overlay grab is activated */
+       int v4l_memgrab_active; /* Memory grab is activated */
 
-       int v4l_grab_frame;             /* Frame number being currently grabbed */
+       int v4l_grab_frame;     /* Frame number being currently grabbed */
 #define NO_GRAB_ACTIVE (-1)
-       int v4l_grab_seq;               /* Number of frames grabbed */
-       int gwidth;                     /* Width of current memory capture */
-       int gheight;                    /* Height of current memory capture */
-       int gformat;                    /* Format of ... */
-       int gbpl;                       /* byte per line of ... */
+       unsigned long v4l_grab_seq;     /* Number of frames grabbed */
+       struct zoran_v4l_settings v4l_settings; /* structure with a lot of things to play with */
 
        /* V4L grab queue of frames pending */
-
-       unsigned v4l_pend_head;
-       unsigned v4l_pend_tail;
+       unsigned long v4l_pend_head;
+       unsigned long v4l_pend_tail;
+       unsigned long v4l_sync_tail;
        int v4l_pend[V4L_MAX_FRAME];
-
-       struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME];   /* V4L   buffers' info */
+       struct zoran_v4l_struct v4l_buffers;    /* V4L buffers' info */
 
        /* Buz MJPEG parameters */
-
-       unsigned long jpg_nbufs;        /* Number of buffers */
-       unsigned long jpg_bufsize;      /* Size of mjpeg buffers in bytes */
-       int jpg_buffers_allocated;      /* Flag if buffers are allocated  */
-       int need_contiguous;    /* Flag if contiguous buffers are needed */
-
        enum zoran_codec_mode codec_mode;       /* status of codec */
-       struct zoran_params params;     /* structure with a lot of things to play with */
+       struct zoran_jpg_settings jpg_settings; /* structure with a lot of things to play with */
 
        wait_queue_head_t jpg_capq;     /* wait here for grab to finish */
 
@@ -293,17 +461,20 @@ struct zoran {
        unsigned long jpg_queued_num;   /* count of frames queued since grab/play started */
 
        /* zr36057's code buffer table */
-       u32 *stat_com;                  /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
+       u32 *stat_com;          /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
 
        /* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */
        int jpg_pend[BUZ_MAX_FRAME];
 
        /* array indexed by frame number */
-       struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME];   /* MJPEG buffers' info */
+       struct zoran_jpg_struct jpg_buffers;    /* MJPEG buffers' info */
 
        /* Additional stuff for testing */
+#ifdef CONFIG_PROC_FS
        struct proc_dir_entry *zoran_proc;
-
+#else
+       void *zoran_proc;
+#endif
        int testing;
        int jpeg_error;
        int intr_counter_GIRQ1;
@@ -330,8 +501,6 @@ struct zoran {
        wait_queue_head_t test_q;
 };
 
-#endif
-
 /*The following should be done in more portable way. It depends on define
   of _ALPHA_BUZ in the Makefile.*/
 
@@ -347,22 +516,6 @@ struct zoran {
 #define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
 #define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
 
-#define I2C_TSA5522        0xc2
-#define I2C_TDA9850        0xb6
-#define I2C_HAUPEE         0xa0
-#define I2C_STBEE          0xae
-#define   I2C_SAA7111        0x48
-#define   I2C_SAA7110        0x9c
-#define   I2C_SAA7185        0x88
-//#define   I2C_ADV7175        0xd4
-#define   I2C_ADV7175        0x54
-
-#define TDA9850_CON1       0x04
-#define TDA9850_CON2       0x05
-#define TDA9850_CON3       0x06
-#define TDA9850_CON4       0x07
-#define TDA9850_ALI1       0x08
-#define TDA9850_ALI2       0x09
-#define TDA9850_ALI3       0x0a
+#endif                         /* __kernel__ */
 
 #endif
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
new file mode 100644 (file)
index 0000000..062c315
--- /dev/null
@@ -0,0 +1,1554 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles card-specific data and detection
+ * 
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.net>
+ *
+ * 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/config.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+
+#include <linux/proc_fs.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/videodev.h>
+#include <linux/spinlock.h>
+#include <linux/sem.h>
+#include <linux/kmod.h>
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/video_decoder.h>
+#include <linux/video_encoder.h>
+
+#include "videocodec.h"
+#include "zoran.h"
+#include "zoran_card.h"
+#include "zoran_device.h"
+#include "zoran_procfs.h"
+
+#define I2C_NAME(x) (x)->dev.name
+
+extern const struct zoran_format zoran_formats[];
+extern const int zoran_num_formats;
+
+static int card[BUZ_MAX] = { -1, -1, -1, -1 };
+MODULE_PARM(card, "1-" __stringify(BUZ_MAX) "i");
+MODULE_PARM_DESC(card, "The type of card");
+
+static int encoder[BUZ_MAX] = { -1, -1, -1, -1 };
+MODULE_PARM(encoder, "1-" __stringify(BUZ_MAX) "i");
+MODULE_PARM_DESC(encoder, "i2c TV encoder");
+
+static int decoder[BUZ_MAX] = { -1, -1, -1, -1 };
+MODULE_PARM(decoder, "1-" __stringify(BUZ_MAX) "i");
+MODULE_PARM_DESC(decoder, "i2c TV decoder");
+
+/*
+   The video mem address of the video card.
+   The driver has a little database for some videocards
+   to determine it from there. If your video card is not in there
+   you have either to give it to the driver as a parameter
+   or set in in a VIDIOCSFBUF ioctl
+ */
+
+static unsigned long vidmem = 0;       /* Video memory base address */
+MODULE_PARM(vidmem, "i");
+
+/*
+   Default input and video norm at startup of the driver.
+*/
+
+static int default_input = 0;  /* 0=Composite, 1=S-Video */
+MODULE_PARM(default_input, "i");
+MODULE_PARM_DESC(default_input,
+                "Default input (0=Composite, 1=S-Video, 2=Internal)");
+
+static int default_norm = 0;   /* 0=PAL, 1=NTSC 2=SECAM */
+MODULE_PARM(default_norm, "i");
+MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
+
+static int video_nr = -1;      /* /dev/videoN, -1 for autodetect */
+MODULE_PARM(video_nr, "i");
+MODULE_PARM_DESC(video_nr, "video device number");
+
+/*
+   Number and size of grab buffers for Video 4 Linux
+   The vast majority of applications should not need more than 2,
+   the very popular BTTV driver actually does ONLY have 2.
+   Time sensitive applications might need more, the maximum
+   is VIDEO_MAX_FRAME (defined in <linux/videodev.h>).
+
+   The size is set so that the maximum possible request
+   can be satisfied. Decrease  it, if bigphys_area alloc'd
+   memory is low. If you don't have the bigphys_area patch,
+   set it to 128 KB. Will you allow only to grab small
+   images with V4L, but that's better than nothing.
+
+   v4l_bufsize has to be given in KB !
+
+*/
+
+int v4l_nbufs = 2;
+int v4l_bufsize = 128;         /* Everybody should be able to work with this setting */
+MODULE_PARM(v4l_nbufs, "i");
+MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use");
+MODULE_PARM(v4l_bufsize, "i");
+MODULE_PARM_DESC(v4l_bufsize, "Maximum size per V4L buffer (in kB)");
+
+int jpg_nbufs = 32;
+int jpg_bufsize = 512;         /* max size for 100% quality full-PAL frame */
+MODULE_PARM(jpg_nbufs, "i");
+MODULE_PARM_DESC(jpg_nbufs, "Maximum number of JPG buffers to use");
+MODULE_PARM(jpg_bufsize, "i");
+MODULE_PARM_DESC(jpg_bufsize, "Maximum size per JPG buffer (in kB)");
+
+int pass_through = 0;          /* 1=Pass through TV signal when device is not used */
+                               /* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */
+MODULE_PARM(pass_through, "i");
+MODULE_PARM_DESC(pass_through,
+                "Pass TV signal through to TV-out when idling");
+
+int debug = 1;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-4)");
+
+MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver");
+MODULE_AUTHOR("Serguei Miridonov");
+MODULE_LICENSE("GPL");
+
+static struct pci_device_id zr36067_pci_tbl[] = {
+       {PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0}
+};
+MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl);
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
+
+int zoran_num;                 /* number of Buzs in use */
+struct zoran zoran[BUZ_MAX];
+
+/* videocodec bus functions ZR36060 */
+static u32
+zr36060_read (struct videocodec *codec,
+             u16                reg)
+{
+       struct zoran *zr = (struct zoran *) codec->master_data->data;
+       __u32 data;
+
+       if (post_office_wait(zr)
+           || post_office_write(zr, 0, 1, reg >> 8)
+           || post_office_write(zr, 0, 2, reg & 0xff)) {
+               return -1;
+       }
+
+       data = post_office_read(zr, 0, 3) & 0xff;
+       return data;
+}
+
+static void
+zr36060_write (struct videocodec *codec,
+              u16                reg,
+              u32                val)
+{
+       struct zoran *zr = (struct zoran *) codec->master_data->data;
+
+       if (post_office_wait(zr)
+           || post_office_write(zr, 0, 1, reg >> 8)
+           || post_office_write(zr, 0, 2, reg & 0xff)) {
+               return;
+       }
+
+       post_office_write(zr, 0, 3, val & 0xff);
+}
+
+/* videocodec bus functions ZR36050 */
+static u32
+zr36050_read (struct videocodec *codec,
+             u16                reg)
+{
+       struct zoran *zr = (struct zoran *) codec->master_data->data;
+       __u32 data;
+
+       if (post_office_wait(zr)
+           || post_office_write(zr, 1, 0, reg >> 2)) { // reg. HIGHBYTES
+               return -1;
+       }
+
+       data = post_office_read(zr, 0, reg & 0x03) & 0xff;      // reg. LOWBYTES + read
+       return data;
+}
+
+static void
+zr36050_write (struct videocodec *codec,
+              u16                reg,
+              u32                val)
+{
+       struct zoran *zr = (struct zoran *) codec->master_data->data;
+
+       if (post_office_wait(zr)
+           || post_office_write(zr, 1, 0, reg >> 2)) { // reg. HIGHBYTES
+               return;
+       }
+
+       post_office_write(zr, 0, reg & 0x03, val & 0xff);       // reg. LOWBYTES + wr. data
+}
+
+/* videocodec bus functions ZR36016 */
+static u32
+zr36016_read (struct videocodec *codec,
+             u16                reg)
+{
+       struct zoran *zr = (struct zoran *) codec->master_data->data;
+       __u32 data;
+
+       if (post_office_wait(zr)) {
+               return -1;
+       }
+
+       data = post_office_read(zr, 2, reg & 0x03) & 0xff;      // read
+       return data;
+}
+
+/* hack for in zoran_device.c */
+void
+zr36016_write (struct videocodec *codec,
+              u16                reg,
+              u32                val)
+{
+       struct zoran *zr = (struct zoran *) codec->master_data->data;
+
+       if (post_office_wait(zr)) {
+               return;
+       }
+
+       post_office_write(zr, 2, reg & 0x03, val & 0x0ff);      // wr. data
+}
+
+/*
+ * Board specific information
+ */
+
+static void
+dc10_init (struct zoran *zr)
+{
+       dprintk(3, KERN_DEBUG "%s: dc10_init()\n", ZR_DEVNAME(zr));
+
+       /* Pixel clock selection */
+       GPIO(zr, 4, 0);
+       GPIO(zr, 5, 1);
+       /* Enable the video bus sync signals */
+       GPIO(zr, 7, 0);
+}
+
+static void
+dc10plus_init (struct zoran *zr)
+{
+       dprintk(3, KERN_DEBUG "%s: dc10plus_init()\n", ZR_DEVNAME(zr));
+}
+
+static void
+buz_init (struct zoran *zr)
+{
+       dprintk(3, KERN_DEBUG "%s: buz_init()\n", ZR_DEVNAME(zr));
+
+       /* some stuff from Iomega */
+       pci_write_config_dword(zr->pci_dev, 0xfc, 0x90680f15);
+       pci_write_config_dword(zr->pci_dev, 0x0c, 0x00012020);
+       pci_write_config_dword(zr->pci_dev, 0xe8, 0xc0200000);
+}
+
+static void
+lml33_init (struct zoran *zr)
+{
+       dprintk(3, KERN_DEBUG "%s: lml33_init()\n", ZR_DEVNAME(zr));
+
+       GPIO(zr, 2, 1);         // Set Composite input/output
+}
+
+static char *
+i2cid_to_modulename (u16 i2c_id)
+{
+       char *name = NULL;
+
+       switch (i2c_id) {
+       case I2C_DRIVERID_SAA7110:
+               name = "saa7110";
+               break;
+       case I2C_DRIVERID_SAA7111A:
+               name = "saa7111";
+               break;
+       case I2C_DRIVERID_SAA7114:
+               name = "saa7114";
+               break;
+       case I2C_DRIVERID_SAA7185B:
+               name = "saa7185";
+               break;
+       case I2C_DRIVERID_ADV7170:
+               name = "adv7170";
+               break;
+       case I2C_DRIVERID_ADV7175:
+               name = "adv7175";
+               break;
+       case I2C_DRIVERID_BT819:
+               name = "bt819";
+               break;
+       case I2C_DRIVERID_BT856:
+               name = "bt856";
+               break;
+       case I2C_DRIVERID_VPX3220:
+               name = "vpx3220";
+               break;
+/*     case I2C_DRIVERID_VPX3224:
+               name = "vpx3224";
+               break;
+       case I2C_DRIVERID_MSE3000:
+               name = "mse3000";
+               break;*/
+       default:
+               break;
+       }
+
+       return name;
+}
+
+static char *
+codecid_to_modulename (u16 codecid)
+{
+       char *name = NULL;
+
+       switch (codecid) {
+       case CODEC_TYPE_ZR36060:
+               name = "zr36060";
+               break;
+       case CODEC_TYPE_ZR36050:
+               name = "zr36050";
+               break;
+       case CODEC_TYPE_ZR36016:
+               name = "zr36016";
+               break;
+       default:
+               break;
+       }
+
+       return name;
+}
+
+// struct tvnorm {
+//      u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart;
+// };
+
+static struct tvnorm f50sqpixel = { 944, 768, 83, 880, 625, 576, 16 };
+static struct tvnorm f60sqpixel = { 780, 640, 51, 716, 525, 480, 12 };
+static struct tvnorm f50ccir601 = { 864, 720, 75, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601 = { 858, 720, 57, 788, 525, 480, 16 };
+
+static struct tvnorm f50ccir601_lml33 = { 864, 720, 75+34, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601_lml33 = { 858, 720, 57+34, 788, 525, 480, 16 };
+
+/* The DC10 (57/16/50) uses VActive as HSync, so HStart must be 0 */
+static struct tvnorm f50sqpixel_dc10 = { 944, 768, 0, 880, 625, 576, 0 };
+static struct tvnorm f60sqpixel_dc10 = { 780, 640, 0, 716, 525, 480, 12 };
+
+/* FIXME: I cannot swap U and V in saa7114, so i do one
+ * pixel left shift in zoran (75 -> 74)
+ * (Maxim Yevtyushkin <max@linuxmedialabs.com>) */
+static struct tvnorm f50ccir601_lm33r10 = { 864, 720, 74+54, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56+54, 788, 525, 480, 16 };
+
+static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+       {
+               .type = DC10_old,
+               .name = "DC10(old)",
+               .i2c_decoder = I2C_DRIVERID_VPX3220,
+               /*.i2c_encoder = I2C_DRIVERID_MSE3000,*/
+               .video_codec = CODEC_TYPE_ZR36050,
+               .video_vfe = CODEC_TYPE_ZR36016,
+
+               .inputs = 3,
+               .input = {
+                       { 1, "Composite" },
+                       { 2, "S-Video" },
+                       { 0, "Internal/comp" }
+               },
+               .norms = 3,
+               .tvn = {
+                       &f50sqpixel_dc10,
+                       &f60sqpixel_dc10,
+                       &f50sqpixel_dc10
+               },
+               .jpeg_int = 0,
+               .vsync_int = ZR36057_ISR_GIRQ1,
+               .gpio = { 2, 1, -1, 3, 7, 0, 4, 5 },
+               .gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 },
+               .gpcs = { -1, 0 },
+               .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+               .gws_not_connected = 0,
+               .init = &dc10_init,
+       }, {
+               .type = DC10_new,
+               .name = "DC10(new)",
+               .i2c_decoder = I2C_DRIVERID_SAA7110,
+               .i2c_encoder = I2C_DRIVERID_ADV7175,
+               .video_codec = CODEC_TYPE_ZR36060,
+
+               .inputs = 3,
+               .input = {
+                               { 0, "Composite" },
+                               { 7, "S-Video" },
+                               { 5, "Internal/comp" }
+                       },
+               .norms = 3,
+               .tvn = {
+                               &f50sqpixel,
+                               &f60sqpixel,
+                               &f50sqpixel},
+               .jpeg_int = ZR36057_ISR_GIRQ0,
+               .vsync_int = ZR36057_ISR_GIRQ1,
+               .gpio = { 3, 0, 6, 1, 2, -1, 4, 5 },
+               .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+               .gpcs = { -1, 1},
+               .vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
+               .gws_not_connected = 0,
+               .init = &dc10plus_init,
+       }, {
+               .type = DC10plus,
+               .name = "DC10plus",
+               .vendor_id = PCI_VENDOR_ID_MIRO,
+               .device_id = PCI_DEVICE_ID_MIRO_DC10PLUS,
+               .i2c_decoder = I2C_DRIVERID_SAA7110,
+               .i2c_encoder = I2C_DRIVERID_ADV7175,
+               .video_codec = CODEC_TYPE_ZR36060,
+
+               .inputs = 3,
+               .input = {
+                       { 0, "Composite" },
+                       { 7, "S-Video" },
+                       { 5, "Internal/comp" }
+               },
+               .norms = 3,
+               .tvn = {
+                       &f50sqpixel,
+                       &f60sqpixel,
+                       &f50sqpixel
+               },
+               .jpeg_int = ZR36057_ISR_GIRQ0,
+               .vsync_int = ZR36057_ISR_GIRQ1,
+               .gpio = { 3, 0, 6, 1, 2, -1, 4, 5 },
+               .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+               .gpcs = { -1, 1 },
+               .vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
+               .gws_not_connected = 0,
+               .init = &dc10plus_init,
+       }, {
+               .type = DC30,
+               .name = "DC30",
+               .i2c_decoder = I2C_DRIVERID_VPX3220,
+               .i2c_encoder = I2C_DRIVERID_ADV7175,
+               .video_codec = CODEC_TYPE_ZR36050,
+               .video_vfe = CODEC_TYPE_ZR36016,
+
+               .inputs = 3,
+               .input = {
+                       { 1, "Composite" },
+                       { 2, "S-Video" },
+                       { 0, "Internal/comp" }
+               },
+               .norms = 3,
+               .tvn = {
+                       &f50sqpixel_dc10,
+                       &f60sqpixel_dc10,
+                       &f50sqpixel_dc10
+               },
+               .jpeg_int = 0,
+               .vsync_int = ZR36057_ISR_GIRQ1,
+               .gpio = { 2, 1, -1, 3, 7, 0, 4, 5 },
+               .gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 },
+               .gpcs = { -1, 0 },
+               .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+               .gws_not_connected = 0,
+               .init = &dc10_init,
+       }, {
+               .type = DC30plus,
+               .name = "DC30plus",
+               .vendor_id = PCI_VENDOR_ID_MIRO,
+               .device_id = PCI_DEVICE_ID_MIRO_DC30PLUS,
+               .i2c_decoder = I2C_DRIVERID_VPX3220,
+               .i2c_encoder = I2C_DRIVERID_ADV7175,
+               .video_codec = CODEC_TYPE_ZR36050,
+               .video_vfe = CODEC_TYPE_ZR36016,
+
+               .inputs = 3,
+               .input = {
+                       { 1, "Composite" },
+                       { 2, "S-Video" },
+                       { 0, "Internal/comp" }
+               },
+               .norms = 3,
+               .tvn = {
+                       &f50sqpixel_dc10,
+                       &f60sqpixel_dc10,
+                       &f50sqpixel_dc10
+               },
+               .jpeg_int = 0,
+               .vsync_int = ZR36057_ISR_GIRQ1,
+               .gpio = { 2, 1, -1, 3, 7, 0, 4, 5 },
+               .gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 },
+               .gpcs = { -1, 0 },
+               .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+               .gws_not_connected = 0,
+               .init = &dc10_init,
+       }, {
+               .type = LML33,
+               .name = "LML33",
+               .i2c_decoder = I2C_DRIVERID_BT819,
+               .i2c_encoder = I2C_DRIVERID_BT856,
+               .video_codec = CODEC_TYPE_ZR36060,
+
+               .inputs = 2,
+               .input = {
+                       { 0, "Composite" },
+                       { 7, "S-Video" }
+               },
+               .norms = 2,
+               .tvn = {
+                       &f50ccir601_lml33,
+                       &f60ccir601_lml33,
+                       NULL
+               },
+               .jpeg_int = ZR36057_ISR_GIRQ1,
+               .vsync_int = ZR36057_ISR_GIRQ0,
+               .gpio = { 1, -1, 3, 5, 7, -1, -1, -1 },
+               .gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 },
+               .gpcs = { 3, 1 },
+               .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
+               .gws_not_connected = 1,
+               .init = &lml33_init,
+       }, {
+               .type = LML33R10,
+               .name = "LML33R10",
+               .vendor_id = PCI_VENDOR_ID_ELECTRONICDESIGNGMBH,
+               .device_id = PCI_DEVICE_ID_LML_33R10,
+               .i2c_decoder = I2C_DRIVERID_SAA7114,
+               .i2c_encoder = I2C_DRIVERID_ADV7170,
+               .video_codec = CODEC_TYPE_ZR36060,
+
+               .inputs = 2,
+               .input = {
+                       { 0, "Composite" },
+                       { 7, "S-Video" }
+               },
+               .norms = 2,
+               .tvn = {
+                       &f50ccir601_lm33r10,
+                       &f60ccir601_lm33r10,
+                       NULL
+               },
+               .jpeg_int = ZR36057_ISR_GIRQ1,
+               .vsync_int = ZR36057_ISR_GIRQ0,
+               .gpio = { 1, -1, 3, 5, 7, -1, -1, -1 },
+               .gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 },
+               .gpcs = { 3, 1 },
+               .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
+               .gws_not_connected = 1,
+               .init = &lml33_init,
+       }, {
+               .type = BUZ,
+               .name = "Buz",
+               .vendor_id = PCI_VENDOR_ID_IOMEGA,
+               .device_id = PCI_DEVICE_ID_IOMEGA_BUZ,
+               .i2c_decoder = I2C_DRIVERID_SAA7111A,
+               .i2c_encoder = I2C_DRIVERID_SAA7185B,
+               .video_codec = CODEC_TYPE_ZR36060,
+
+               .inputs = 2,
+               .input = {
+                       { 3, "Composite" },
+                       { 7, "S-Video" }
+               },
+               .norms = 3,
+               .tvn = {
+                       &f50ccir601,
+                       &f60ccir601,
+                       &f50ccir601
+               },
+               .jpeg_int = ZR36057_ISR_GIRQ1,
+               .vsync_int = ZR36057_ISR_GIRQ0,
+               .gpio = { 1, -1, 3, -1, -1, -1, -1, -1 },
+               .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+               .gpcs = { 3, 1 },
+               .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
+               .gws_not_connected = 1,
+               .init = &buz_init,
+       }
+};
+
+/*
+ * I2C functions
+ */
+/* software I2C functions */
+static int
+zoran_i2c_getsda (void *data)
+{
+       struct zoran *zr = (struct zoran *) data;
+       return (btread(ZR36057_I2CBR) >> 1) & 1;
+}
+
+static int
+zoran_i2c_getscl (void *data)
+{
+       struct zoran *zr = (struct zoran *) data;
+       return btread(ZR36057_I2CBR) & 1;
+}
+
+static void
+zoran_i2c_setsda (void *data,
+                 int   state)
+{
+       struct zoran *zr = (struct zoran *) data;
+       if (state)
+               zr->i2cbr |= 2;
+       else
+               zr->i2cbr &= ~2;
+       btwrite(zr->i2cbr, ZR36057_I2CBR);
+}
+
+static void
+zoran_i2c_setscl (void *data,
+                 int   state)
+{
+       struct zoran *zr = (struct zoran *) data;
+       if (state)
+               zr->i2cbr |= 1;
+       else
+               zr->i2cbr &= ~1;
+       btwrite(zr->i2cbr, ZR36057_I2CBR);
+}
+
+static int
+zoran_i2c_client_register (struct i2c_client *client)
+{
+       struct zoran *zr = (struct zoran *) i2c_get_adapdata(client->adapter);
+       int res = 0;
+
+       dprintk(2,
+               KERN_DEBUG "%s: i2c_client_register() - driver id = %d\n",
+               ZR_DEVNAME(zr), client->driver->id);
+
+       down(&zr->resource_lock);
+
+       if (zr->user > 0) {
+               /* we're already busy, so we keep a reference to
+                * them... Could do a lot of stuff here, but this
+                * is easiest. (Did I ever mention I'm a lazy ass?)
+                */
+               res = -EBUSY;
+               goto clientreg_unlock_and_return;
+       }
+
+       if (client->driver->id == zr->card.i2c_decoder)
+               zr->decoder = client;
+       else if (client->driver->id == zr->card.i2c_encoder)
+               zr->encoder = client;
+       else {
+               res = -ENODEV;
+               goto clientreg_unlock_and_return;
+       }
+
+clientreg_unlock_and_return:
+       up(&zr->resource_lock);
+
+       return res;
+}
+
+static int
+zoran_i2c_client_unregister (struct i2c_client *client)
+{
+       struct zoran *zr = (struct zoran *) i2c_get_adapdata(client->adapter);
+       int res = 0;
+
+       dprintk(2, KERN_DEBUG "%s: i2c_client_unregister()\n", ZR_DEVNAME(zr));
+
+       down(&zr->resource_lock);
+
+       if (zr->user > 0) {
+               res = -EBUSY;
+               goto clientunreg_unlock_and_return;
+       }
+
+       /* try to locate it */
+       if (client == zr->encoder) {
+               zr->encoder = NULL;
+       } else if (client == zr->decoder) {
+               zr->decoder = NULL;
+               snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%d]", zr->id);
+       }
+clientunreg_unlock_and_return:
+       up(&zr->resource_lock);
+       return res;
+}
+
+static struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
+       .setsda = zoran_i2c_setsda,
+       .setscl = zoran_i2c_setscl,
+       .getsda = zoran_i2c_getsda,
+       .getscl = zoran_i2c_getscl,
+       .udelay = 10,
+       .mdelay = 0,
+       .timeout = 100,
+};
+
+static struct i2c_adapter zoran_i2c_adapter_template = {
+       I2C_DEVNAME("zr36057"),
+       .id = I2C_HW_B_ZR36067,
+       .algo = NULL,
+       .client_register = zoran_i2c_client_register,
+       .client_unregister = zoran_i2c_client_unregister,
+};
+
+static int
+zoran_register_i2c (struct zoran *zr)
+{
+       memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template,
+              sizeof(struct i2c_algo_bit_data));
+       zr->i2c_algo.data = zr;
+       memcpy(&zr->i2c_adapter, &zoran_i2c_adapter_template,
+              sizeof(struct i2c_adapter));
+       strncpy(I2C_NAME(&zr->i2c_adapter), ZR_DEVNAME(zr),
+               sizeof(I2C_NAME(&zr->i2c_adapter)) - 1);
+       i2c_set_adapdata(&zr->i2c_adapter, zr);
+       zr->i2c_adapter.algo_data = &zr->i2c_algo;
+       return i2c_bit_add_bus(&zr->i2c_adapter);
+}
+
+static void
+zoran_unregister_i2c (struct zoran *zr)
+{
+       i2c_bit_del_bus((&zr->i2c_adapter));
+}
+
+/* Check a zoran_params struct for correctness, insert default params */
+
+int
+zoran_check_jpg_settings (struct zoran              *zr,
+                         struct zoran_jpg_settings *settings)
+{
+       int err = 0, err0 = 0;
+       dprintk(4,
+               KERN_DEBUG
+               "%s: check_jpg_settings() - dec: %d, Hdcm: %d, Vdcm: %d, Tdcm: %d\n",
+               ZR_DEVNAME(zr), settings->decimation, settings->HorDcm,
+               settings->VerDcm, settings->TmpDcm);
+       dprintk(4,
+               KERN_DEBUG
+               "%s: check_jpg_settings() - x: %d, y: %d, w: %d, y: %d\n",
+               ZR_DEVNAME(zr), settings->img_x, settings->img_y,
+               settings->img_width, settings->img_height);
+       /* Check decimation, set default values for decimation = 1, 2, 4 */
+       switch (settings->decimation) {
+       case 1:
+
+               settings->HorDcm = 1;
+               settings->VerDcm = 1;
+               settings->TmpDcm = 1;
+               settings->field_per_buff = 2;
+               settings->img_x = 0;
+               settings->img_y = 0;
+               settings->img_width = BUZ_MAX_WIDTH;
+               settings->img_height = BUZ_MAX_HEIGHT / 2;
+               break;
+       case 2:
+
+               settings->HorDcm = 2;
+               settings->VerDcm = 1;
+               settings->TmpDcm = 2;
+               settings->field_per_buff = 1;
+               settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
+               settings->img_y = 0;
+               settings->img_width =
+                   (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
+               settings->img_height = BUZ_MAX_HEIGHT / 2;
+               break;
+       case 4:
+
+               if (zr->card.type == DC10_new) {
+                       dprintk(1,
+                               KERN_DEBUG
+                               "%s: check_jpg_settings() - HDec by 4 is not supported on the DC10\n",
+                               ZR_DEVNAME(zr));
+                       err0++;
+                       break;
+               }
+
+               settings->HorDcm = 4;
+               settings->VerDcm = 2;
+               settings->TmpDcm = 2;
+               settings->field_per_buff = 1;
+               settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
+               settings->img_y = 0;
+               settings->img_width =
+                   (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
+               settings->img_height = BUZ_MAX_HEIGHT / 2;
+               break;
+       case 0:
+
+               /* We have to check the data the user has set */
+
+               if (settings->HorDcm != 1 && settings->HorDcm != 2 &&
+                   (zr->card.type == DC10_new || settings->HorDcm != 4))
+                       err0++;
+               if (settings->VerDcm != 1 && settings->VerDcm != 2)
+                       err0++;
+               if (settings->TmpDcm != 1 && settings->TmpDcm != 2)
+                       err0++;
+               if (settings->field_per_buff != 1 &&
+                   settings->field_per_buff != 2)
+                       err0++;
+               if (settings->img_x < 0)
+                       err0++;
+               if (settings->img_y < 0)
+                       err0++;
+               if (settings->img_width < 0)
+                       err0++;
+               if (settings->img_height < 0)
+                       err0++;
+               if (settings->img_x + settings->img_width > BUZ_MAX_WIDTH)
+                       err0++;
+               if (settings->img_y + settings->img_height >
+                   BUZ_MAX_HEIGHT / 2)
+                       err0++;
+               if (settings->HorDcm && settings->VerDcm) {
+                       if (settings->img_width %
+                           (16 * settings->HorDcm) != 0)
+                               err0++;
+                       if (settings->img_height %
+                           (8 * settings->VerDcm) != 0)
+                               err0++;
+               }
+
+               if (err0) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: check_jpg_settings() - error in params for decimation = 0\n",
+                               ZR_DEVNAME(zr));
+                       err++;
+               }
+               break;
+       default:
+               dprintk(1,
+                       KERN_ERR
+                       "%s: check_jpg_settings() - decimation = %d, must be 0, 1, 2 or 4\n",
+                       ZR_DEVNAME(zr), settings->decimation);
+               err++;
+               break;
+       }
+
+       if (settings->jpg_comp.quality > 100)
+               settings->jpg_comp.quality = 100;
+       if (settings->jpg_comp.quality < 5)
+               settings->jpg_comp.quality = 5;
+       if (settings->jpg_comp.APPn < 0)
+               settings->jpg_comp.APPn = 0;
+       if (settings->jpg_comp.APPn > 15)
+               settings->jpg_comp.APPn = 15;
+       if (settings->jpg_comp.APP_len < 0)
+               settings->jpg_comp.APP_len = 0;
+       if (settings->jpg_comp.APP_len > 60)
+               settings->jpg_comp.APP_len = 60;
+       if (settings->jpg_comp.COM_len < 0)
+               settings->jpg_comp.COM_len = 0;
+       if (settings->jpg_comp.COM_len > 60)
+               settings->jpg_comp.COM_len = 60;
+       if (err)
+               return -EINVAL;
+       return 0;
+}
+
+void
+zoran_open_init_params (struct zoran *zr)
+{
+       int i;
+
+       /* User must explicitly set a window */
+       zr->overlay_settings.is_set = 0;
+       zr->overlay_mask = NULL;
+       zr->overlay_active = ZORAN_FREE;
+
+       zr->v4l_memgrab_active = 0;
+       zr->v4l_overlay_active = 0;
+       zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+       zr->v4l_grab_seq = 0;
+       zr->v4l_settings.width = 192;
+       zr->v4l_settings.height = 144;
+       zr->v4l_settings.format = &zoran_formats[4];    /* YUY2 - YUV-4:2:2 packed */
+       zr->v4l_settings.bytesperline =
+           zr->v4l_settings.width *
+           ((zr->v4l_settings.format->depth + 7) / 8);
+
+       /* DMA ring stuff for V4L */
+       zr->v4l_pend_tail = 0;
+       zr->v4l_pend_head = 0;
+       zr->v4l_sync_tail = 0;
+       zr->v4l_buffers.active = ZORAN_FREE;
+       for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+               zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER;       /* nothing going on */
+       }
+       zr->v4l_buffers.allocated = 0;
+
+       for (i = 0; i < BUZ_MAX_FRAME; i++) {
+               zr->jpg_buffers.buffer[i].state = BUZ_STATE_USER;       /* nothing going on */
+       }
+       zr->jpg_buffers.active = ZORAN_FREE;
+       zr->jpg_buffers.allocated = 0;
+       /* Set necessary params and call zoran_check_jpg_settings to set the defaults */
+       zr->jpg_settings.decimation = 1;
+       zr->jpg_settings.jpg_comp.quality = 50; /* default compression factor 8 */
+       if (zr->card.type != BUZ)
+               zr->jpg_settings.odd_even = 1;
+       else
+               zr->jpg_settings.odd_even = 0;
+       zr->jpg_settings.jpg_comp.APPn = 0;
+       zr->jpg_settings.jpg_comp.APP_len = 0;  /* No APPn marker */
+       memset(zr->jpg_settings.jpg_comp.APP_data, 0,
+              sizeof(zr->jpg_settings.jpg_comp.APP_data));
+       zr->jpg_settings.jpg_comp.COM_len = 0;  /* No COM marker */
+       memset(zr->jpg_settings.jpg_comp.COM_data, 0,
+              sizeof(zr->jpg_settings.jpg_comp.COM_data));
+       zr->jpg_settings.jpg_comp.jpeg_markers =
+           JPEG_MARKER_DHT | JPEG_MARKER_DQT;
+       i = zoran_check_jpg_settings(zr, &zr->jpg_settings);
+       if (i)
+               dprintk(1,
+                       KERN_ERR
+                       "%s: zoran_open_init_params() internal error\n",
+                       ZR_DEVNAME(zr));
+
+       clear_interrupt_counters(zr);
+       zr->testing = 0;
+}
+
+static void __devinit
+test_interrupts (struct zoran *zr)
+{
+       int timeout, icr;
+
+       clear_interrupt_counters(zr);
+
+       zr->testing = 1;
+       icr = btread(ZR36057_ICR);
+       btwrite(0x78000000 | ZR36057_ICR_IntPinEn, ZR36057_ICR);
+       timeout = interruptible_sleep_on_timeout(&zr->test_q, 1 * HZ);
+       btwrite(0, ZR36057_ICR);
+       btwrite(0x78000000, ZR36057_ISR);
+       zr->testing = 0;
+       dprintk(5, KERN_INFO "%s: Testing interrupts...\n", ZR_DEVNAME(zr));
+       if (timeout) {
+               dprintk(1, ": time spent: %d\n", 1 * HZ - timeout);
+       }
+       if (debug > 1)
+               print_interrupts(zr);
+       btwrite(icr, ZR36057_ICR);
+}
+
+static int __devinit
+zr36057_init (struct zoran *zr)
+{
+       unsigned long mem;
+       unsigned mem_needed;
+       int j;
+       int two = 2;
+       int zero = 0;
+
+       dprintk(1,
+               KERN_INFO
+               "%s: zr36057_init() - initializing card[%d], zr=%p\n",
+               ZR_DEVNAME(zr), zr->id, zr);
+
+       /* default setup of all parameters which will persist between opens */
+       zr->user = 0;
+
+       init_waitqueue_head(&zr->v4l_capq);
+       init_waitqueue_head(&zr->jpg_capq);
+       init_waitqueue_head(&zr->test_q);
+       zr->jpg_buffers.allocated = 0;
+       zr->v4l_buffers.allocated = 0;
+
+       zr->buffer.base = (void *) vidmem;
+       zr->buffer.width = 0;
+       zr->buffer.height = 0;
+       zr->buffer.depth = 0;
+       zr->buffer.bytesperline = 0;
+
+       /* Avoid nonsense settings from user for default input/norm */
+       if (default_norm < VIDEO_MODE_PAL &&
+           default_norm > VIDEO_MODE_SECAM)
+               default_norm = VIDEO_MODE_PAL;
+       zr->norm = default_norm;
+       if (!(zr->timing = zr->card.tvn[zr->norm])) {
+               dprintk(1,
+                       KERN_WARNING
+                       "%s: zr36057_init() - default TV standard not supported by hardware. PAL will be used.\n",
+                       ZR_DEVNAME(zr));
+               zr->norm = VIDEO_MODE_PAL;
+               zr->timing = zr->card.tvn[zr->norm];
+       }
+
+       zr->input = default_input = (default_input ? 1 : 0);
+
+       /* Should the following be reset at every open ? */
+       zr->hue = 32768;
+       zr->contrast = 32768;
+       zr->saturation = 32768;
+       zr->brightness = 32768;
+
+       /* default setup (will be repeated at every open) */
+       zoran_open_init_params(zr);
+
+       /* allocate memory *before* doing anything to the hardware
+        * in case allocation fails */
+       mem_needed = BUZ_NUM_STAT_COM * 4;
+       mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL);
+       if (!mem) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: zr36057_init() - kmalloc (STAT_COM) failed\n",
+                       ZR_DEVNAME(zr));
+               return -ENOMEM;
+       }
+       memset((void *) mem, 0, mem_needed);
+       zr->stat_com = (u32 *) mem;
+       for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+               zr->stat_com[j] = 1;    /* mark as unavailable to zr36057 */
+       }
+
+       /*
+        *   Now add the template and register the device unit.
+        */
+       memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template));
+       strcpy(zr->video_dev.name, ZR_DEVNAME(zr));
+       if (video_register_device
+           (&zr->video_dev, VFL_TYPE_GRABBER, video_nr) < 0) {
+               zoran_unregister_i2c(zr);
+               kfree((void *) zr->stat_com);
+               return -1;
+       }
+
+       zoran_init_hardware(zr);
+       if (debug > 2)
+               detect_guest_activity(zr);
+       test_interrupts(zr);
+       if (!pass_through) {
+               decoder_command(zr, DECODER_ENABLE_OUTPUT, &zero);
+               encoder_command(zr, ENCODER_SET_INPUT, &two);
+       }
+
+       zr->zoran_proc = NULL;
+       zr->initialized = 1;
+       return 0;
+}
+
+static void
+zoran_release (struct zoran *zr)
+{
+       if (!zr->initialized)
+               return;
+       /* unregister videocodec bus */
+       if (zr->codec) {
+               struct videocodec_master *master = zr->codec->master_data;
+               videocodec_detach(zr->codec);
+               if (master)
+                       kfree(master);
+       }
+       if (zr->vfe) {
+               struct videocodec_master *master = zr->vfe->master_data;
+               videocodec_detach(zr->vfe);
+               if (master)
+                       kfree(master);
+       }
+
+       /* unregister i2c bus */
+       zoran_unregister_i2c(zr);
+       /* disable PCI bus-mastering */
+       zoran_set_pci_master(zr, 0);
+       /* put chip into reset */
+       btwrite(0, ZR36057_SPGPPCR);
+       free_irq(zr->pci_dev->irq, zr);
+       /* unmap and free memory */
+       kfree((void *) zr->stat_com);
+       zoran_proc_cleanup(zr);
+       iounmap(zr->zr36057_mem);
+       video_unregister_device(&zr->video_dev);
+}
+
+static struct videocodec_master * __devinit
+zoran_setup_videocodec (struct zoran *zr,
+                       int           type)
+{
+       struct videocodec_master *m = NULL;
+
+       m = kmalloc(sizeof(struct videocodec_master), GFP_KERNEL);
+       if (!m) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: zoran_setup_videocodec() - no memory\n",
+                       ZR_DEVNAME(zr));
+               return m;
+       }
+
+       m->magic = 0L; /* magic not used */
+       m->type = VID_HARDWARE_ZR36067;
+       m->flags = CODEC_FLAG_ENCODER | CODEC_FLAG_DECODER;
+       strncpy(m->name, ZR_DEVNAME(zr), sizeof(m->name));
+       m->data = zr;
+
+       switch (type)
+       {
+       case CODEC_TYPE_ZR36060:
+               m->readreg = zr36060_read;
+               m->writereg = zr36060_write;
+               m->flags |= CODEC_FLAG_JPEG | CODEC_FLAG_VFE;
+               break;
+       case CODEC_TYPE_ZR36050:
+               m->readreg = zr36050_read;
+               m->writereg = zr36050_write;
+               m->flags |= CODEC_FLAG_JPEG;
+               break;
+       case CODEC_TYPE_ZR36016:
+               m->readreg = zr36016_read;
+               m->writereg = zr36016_write;
+               m->flags |= CODEC_FLAG_VFE;
+               break;
+       }
+
+       return m;
+}
+
+/*
+ *   Scan for a Buz card (actually for the PCI contoler ZR36057),
+ *   request the irq and map the io memory
+ */
+static int __devinit
+find_zr36057 (void)
+{
+       unsigned char latency, need_latency;
+       struct zoran *zr;
+       struct pci_dev *dev = NULL;
+       int result;
+       struct videocodec_master *master_vfe = NULL;
+       struct videocodec_master *master_codec = NULL;
+       int card_num;
+       char *i2c_enc_name, *i2c_dec_name, *codec_name, *vfe_name;
+
+       zoran_num = 0;
+       while (zoran_num < BUZ_MAX &&
+              (dev =
+               pci_find_device(PCI_VENDOR_ID_ZORAN,
+                               PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
+               card_num = card[zoran_num];
+               zr = &zoran[zoran_num];
+               memset(zr, 0, sizeof(struct zoran));    // Just in case if previous cycle failed
+               zr->pci_dev = dev;
+               //zr->zr36057_mem = NULL;
+               zr->id = zoran_num;
+               snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id);
+               spin_lock_init(&zr->spinlock);
+               init_MUTEX(&zr->resource_lock);
+               if (pci_enable_device(dev))
+                       continue;
+               zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0);
+               pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION,
+                                    &zr->revision);
+               if (zr->revision < 2) {
+                       dprintk(1,
+                               KERN_INFO
+                               "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n",
+                               ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq,
+                               zr->zr36057_adr);
+
+                       if (card_num == -1) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: find_zr36057() - no card specified, please use the card=X insmod option\n",
+                                       ZR_DEVNAME(zr));
+                               continue;
+                       }
+               } else {
+                       int i;
+                       unsigned short ss_vendor, ss_device;
+                       ss_vendor = zr->pci_dev->subsystem_vendor;
+                       ss_device = zr->pci_dev->subsystem_device;
+                       dprintk(1,
+                               KERN_INFO
+                               "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n",
+                               ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq,
+                               zr->zr36057_adr);
+                       dprintk(1,
+                               KERN_INFO
+                               "%s: subsystem vendor=0x%04x id=0x%04x\n",
+                               ZR_DEVNAME(zr), ss_vendor, ss_device);
+                       if (card_num == -1) {
+                               dprintk(3,
+                                       KERN_DEBUG
+                                       "%s: find_zr36057() - trying to autodetect card type\n",
+                                       ZR_DEVNAME(zr));
+                               for (i=0;i<NUM_CARDS;i++) {
+                                       if (ss_vendor == zoran_cards[i].vendor_id &&
+                                           ss_device == zoran_cards[i].device_id) {
+                                               dprintk(3,
+                                                       KERN_DEBUG
+                                                       "%s: find_zr36057() - card %s detected\n",
+                                                       ZR_DEVNAME(zr),
+                                                       zoran_cards[i].name);
+                                               card_num = i;
+                                               break;
+                                       }
+                               }
+                               if (i == NUM_CARDS) {
+                                       dprintk(1,
+                                               KERN_ERR
+                                               "%s: find_zr36057() - unknown card\n",
+                                               ZR_DEVNAME(zr));
+                                       continue;
+                               }
+                       }
+               }
+
+               if (card_num < 0 || card_num >= NUM_CARDS) {
+                       dprintk(2,
+                               KERN_ERR
+                               "%s: find_zr36057() - invalid cardnum %d\n",
+                               ZR_DEVNAME(zr), card_num);
+                       continue;
+               }
+
+               /* even though we make this a non pointer and thus
+                * theoretically allow for making changes to this struct
+                * on a per-individual card basis at runtime, this is
+                * strongly discouraged. This structure is intended to
+                * keep general card information, no settings or anything */
+               zr->card = zoran_cards[card_num];
+               snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)),
+                        "%s[%u]", zr->card.name, zr->id);
+
+               zr->zr36057_mem = ioremap_nocache(zr->zr36057_adr, 0x1000);
+               if (!zr->zr36057_mem) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: find_zr36057() - ioremap failed\n",
+                               ZR_DEVNAME(zr));
+                       continue;
+               }
+
+               result = request_irq(zr->pci_dev->irq,
+                                    zoran_irq,
+                                    SA_SHIRQ | SA_INTERRUPT,
+                                    ZR_DEVNAME(zr),
+                                    (void *) zr);
+               if (result < 0) {
+                       if (result == -EINVAL) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: find_zr36057() - bad irq number or handler\n",
+                                       ZR_DEVNAME(zr));
+                       } else if (result == -EBUSY) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: find_zr36057() - IRQ %d busy, change your PnP config in BIOS\n",
+                                       ZR_DEVNAME(zr), zr->pci_dev->irq);
+                       } else {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: find_zr36057() - can't assign irq, error code %d\n",
+                                       ZR_DEVNAME(zr), result);
+                       }
+                       goto zr_unmap;
+               }
+
+               /* set PCI latency timer */
+               pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER,
+                                    &latency);
+               need_latency = zr->revision > 1 ? 32 : 48;
+               if (latency != need_latency) {
+                       dprintk(2,
+                               KERN_INFO
+                               "%s: Changing PCI latency from %d to %d.\n",
+                               ZR_DEVNAME(zr), latency, need_latency);
+                       pci_write_config_byte(zr->pci_dev,
+                                             PCI_LATENCY_TIMER,
+                                             need_latency);
+               }
+
+               zr36057_restart(zr);
+               /* i2c */
+               dprintk(2, KERN_INFO "%s: Initializing i2c bus...\n",
+                       ZR_DEVNAME(zr));
+
+               /* i2c decoder */
+               if (decoder[zr->id] != -1) {
+                       i2c_dec_name = i2cid_to_modulename(decoder[zr->id]);
+                       zr->card.i2c_decoder = decoder[zr->id];
+               } else if (zr->card.i2c_decoder != 0) {
+                       i2c_dec_name =
+                               i2cid_to_modulename(zr->card.i2c_decoder);
+               } else {
+                       i2c_dec_name = NULL;
+               }
+
+               if (i2c_dec_name) {
+                       if ((result = request_module(i2c_dec_name)) < 0) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: failed to load module %s: %d\n",
+                                       ZR_DEVNAME(zr), i2c_dec_name, result);
+                       }
+               }
+
+               /* i2c encoder */
+               if (encoder[zr->id] != -1) {
+                       i2c_enc_name = i2cid_to_modulename(encoder[zr->id]);
+                       zr->card.i2c_encoder = encoder[zr->id];
+               } else if (zr->card.i2c_encoder != 0) {
+                       i2c_enc_name =
+                               i2cid_to_modulename(zr->card.i2c_encoder);
+               } else {
+                       i2c_enc_name = NULL;
+               }
+
+               if (i2c_enc_name) {
+                       if ((result = request_module(i2c_enc_name)) < 0) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: failed to load module %s: %d\n",
+                                       ZR_DEVNAME(zr), i2c_enc_name, result);
+                       }
+               }
+
+               if (zoran_register_i2c(zr) < 0) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: find_zr36057() - can't initialize i2c bus\n",
+                               ZR_DEVNAME(zr));
+                       goto zr_free_irq;
+               }
+
+               dprintk(2,
+                       KERN_INFO "%s: Initializing videocodec bus...\n",
+                       ZR_DEVNAME(zr));
+
+               if (zr->card.video_codec != 0 &&
+                   (codec_name =
+                    codecid_to_modulename(zr->card.video_codec)) != NULL) {
+                       if ((result = request_module(codec_name)) < 0) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: failed to load modules %s: %d\n",
+                                       ZR_DEVNAME(zr), codec_name, result);
+                       }
+               }
+               if (zr->card.video_vfe != 0 &&
+                   (vfe_name =
+                    codecid_to_modulename(zr->card.video_vfe)) != NULL) {
+                       if ((result = request_module(vfe_name)) < 0) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: failed to load modules %s: %d\n",
+                                       ZR_DEVNAME(zr), vfe_name, result);
+                       }
+               }
+
+               /* reset JPEG codec */
+               jpeg_codec_sleep(zr, 1);
+               jpeg_codec_reset(zr);
+               /* video bus enabled */
+               /* display codec revision */
+               if (zr->card.video_codec != 0) {
+                       master_codec = zoran_setup_videocodec(zr,
+                                                             zr->card.video_codec);
+                       if (!master_codec)
+                               goto zr_unreg_i2c;
+                       zr->codec = videocodec_attach(master_codec);
+                       if (!zr->codec) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: find_zr36057() - no codec found\n",
+                                       ZR_DEVNAME(zr));
+                               goto zr_free_codec;
+                       }
+                       if (zr->codec->type != zr->card.video_codec) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: find_zr36057() - wrong codec\n",
+                                       ZR_DEVNAME(zr));
+                               goto zr_detach_codec;
+                       }
+               }
+               if (zr->card.video_vfe != 0) {
+                       master_vfe = zoran_setup_videocodec(zr,
+                                                           zr->card.video_vfe);
+                       if (!master_vfe)
+                               goto zr_detach_codec;
+                       zr->vfe = videocodec_attach(master_vfe);
+                       if (!zr->vfe) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: find_zr36057() - no VFE found\n",
+                                       ZR_DEVNAME(zr));
+                               goto zr_free_vfe;
+                       }
+                       if (zr->vfe->type != zr->card.video_vfe) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: find_zr36057() = wrong VFE\n",
+                                       ZR_DEVNAME(zr));
+                               goto zr_detach_vfe;
+                       }
+               }
+
+               zoran_num++;
+               continue;
+
+               // Init errors
+             zr_detach_vfe:
+               videocodec_detach(zr->vfe);
+             zr_free_vfe:
+               kfree(master_vfe);
+             zr_detach_codec:
+               videocodec_detach(zr->codec);
+             zr_free_codec:
+               kfree(master_codec);
+             zr_unreg_i2c:
+               zoran_unregister_i2c(zr);
+             zr_free_irq:
+               btwrite(0, ZR36057_SPGPPCR);
+               free_irq(zr->pci_dev->irq, zr);
+             zr_unmap:
+               iounmap(zr->zr36057_mem);
+               continue;
+       }
+       if (zoran_num == 0) {
+               dprintk(1, KERN_INFO "No known MJPEG cards found.\n");
+       }
+       return zoran_num;
+}
+
+static int __init
+init_dc10_cards (void)
+{
+       int i;
+       memset(zoran, 0, sizeof(zoran));
+       printk(KERN_INFO "Zoran MJPEG board driver version %d.%d.%d\n",
+              MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION);
+
+       /* Look for cards */
+       if (find_zr36057() < 0) {
+               return -EIO;
+       }
+       if (zoran_num == 0)
+               return -ENODEV;
+       dprintk(1, KERN_INFO "%s: %d card(s) found\n", ZORAN_NAME,
+               zoran_num);
+       /* check the parameters we have been given, adjust if necessary */
+       if (v4l_nbufs < 2)
+               v4l_nbufs = 2;
+       if (v4l_nbufs > VIDEO_MAX_FRAME)
+               v4l_nbufs = VIDEO_MAX_FRAME;
+       /* The user specfies the in KB, we want them in byte
+        * (and page aligned) */
+       v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024);
+       if (v4l_bufsize < 32768)
+               v4l_bufsize = 32768;
+       /* 2 MB is arbitrary but sufficient for the maximum possible images */
+       if (v4l_bufsize > 2048 * 1024)
+               v4l_bufsize = 2048 * 1024;
+       if (jpg_nbufs < 4)
+               jpg_nbufs = 4;
+       if (jpg_nbufs > BUZ_MAX_FRAME)
+               jpg_nbufs = BUZ_MAX_FRAME;
+       jpg_bufsize = PAGE_ALIGN(jpg_bufsize * 1024);
+       if (jpg_bufsize < 8192)
+               jpg_bufsize = 8192;
+       if (jpg_bufsize > (512 * 1024))
+               jpg_bufsize = 512 * 1024;
+       /* Use parameter for vidmem or try to find a video card */
+       if (vidmem) {
+               dprintk(1,
+                       KERN_INFO
+                       "%s: Using supplied video memory base address @ 0x%lx\n",
+                       ZORAN_NAME, vidmem);
+       }
+
+       /* random nonsense */
+       dprintk(5, KERN_DEBUG "Jotti is een held!\n");
+
+       /* some mainboards might not do PCI-PCI data transfer well */
+       if (pci_pci_problems & PCIPCI_FAIL) {
+               dprintk(1,
+                       KERN_WARNING
+                       "%s: chipset may not support reliable PCI-PCI DMA\n",
+                       ZORAN_NAME);
+       }
+
+       /* take care of Natoma chipset and a revision 1 zr36057 */
+       for (i = 0; i < zoran_num; i++) {
+               struct zoran *zr = &zoran[i];
+               if (pci_pci_problems & PCIPCI_NATOMA && zr->revision <= 1) {
+                       zr->jpg_buffers.need_contiguous = 1;
+                       dprintk(1,
+                               KERN_INFO
+                               "%s: ZR36057/Natoma bug, max. buffer size is 128K\n",
+                               ZR_DEVNAME(zr));
+               }
+
+               if (zr36057_init(zr) < 0) {
+                       for (i = 0; i < zoran_num; i++)
+                               zoran_release(&zoran[i]);
+                       return -EIO;
+               }
+               zoran_proc_init(zr);
+       }
+
+       return 0;
+}
+
+static void __exit
+unload_dc10_cards (void)
+{
+       int i;
+       for (i = 0; i < zoran_num; i++)
+               zoran_release(&zoran[i]);
+}
+
+module_init(init_dc10_cards);
+module_exit(unload_dc10_cards);
diff --git a/drivers/media/video/zoran_card.h b/drivers/media/video/zoran_card.h
new file mode 100644 (file)
index 0000000..d5fbecf
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles card-specific data and detection
+ * 
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.net>
+ *
+ * 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 __ZORAN_CARD_H__
+#define __ZORAN_CARD_H__
+
+/* Anybody who uses more than four? */
+#define BUZ_MAX 4
+extern int zoran_num;
+extern struct zoran zoran[BUZ_MAX];
+
+extern struct video_device zoran_template;
+
+extern int zoran_check_jpg_settings(struct zoran *zr,
+                                   struct zoran_jpg_settings *settings);
+extern void zoran_open_init_params(struct zoran *zr);
+
+#endif                         /* __ZORAN_CARD_H__ */
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
new file mode 100644 (file)
index 0000000..59017c5
--- /dev/null
@@ -0,0 +1,1772 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles device access (PCI/I2C/codec/...)
+ * 
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.net>
+ *
+ * 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/config.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/videodev.h>
+#include <linux/spinlock.h>
+#include <linux/sem.h>
+
+#include <linux/pci.h>
+#include <linux/video_decoder.h>
+#include <linux/video_encoder.h>
+#include <linux/delay.h>
+
+#include "videocodec.h"
+#include "zoran.h"
+#include "zoran_device.h"
+
+#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | \
+                  ZR36057_ISR_GIRQ1 | \
+                  ZR36057_ISR_JPEGRepIRQ )
+
+extern const struct zoran_format zoran_formats[];
+extern const int zoran_num_formats;
+
+extern int debug;
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
+
+static int lml33dpath = 0;     /* 1 will use digital path in capture
+                                * mode instead of analog. It can be
+                                * used for picture adjustments using
+                                * tool like xawtv while watching image
+                                * on TV monitor connected to the output.
+                                * However, due to absence of 75 Ohm
+                                * load on Bt819 input, there will be
+                                * some image imperfections */
+
+MODULE_PARM(lml33dpath, "i");
+MODULE_PARM_DESC(lml33dpath,
+                "Use digital path capture mode (on LML33 cards)");
+
+/*
+ * General Purpose I/O and Guest bus access
+ */
+
+/*
+ * This is a bit tricky. When a board lacks a GPIO function, the corresponding
+ * GPIO bit number in the card_info structure is set to 0.
+ */
+
+void
+GPIO (struct zoran *zr,
+      int           bit,
+      unsigned int  value)
+{
+       u32 reg;
+       u32 mask;
+
+       /* Make sure the bit number is legal
+        * A bit number of -1 (lacking) gives a mask of 0,
+        * making it harmless */
+       mask = (1 << (24 + bit)) & 0xff000000;
+       reg = btread(ZR36057_GPPGCR1) & ~mask;
+       if (value) {
+               reg |= mask;
+       }
+       btwrite(reg, ZR36057_GPPGCR1);
+       udelay(1);
+}
+
+/*
+ * Wait til post office is no longer busy
+ */
+
+int
+post_office_wait (struct zoran *zr)
+{
+       u32 por;
+
+//      while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) {
+       while ((por = btread(ZR36057_POR)) & ZR36057_POR_POPen) {
+               /* wait for something to happen */
+       }
+       if ((por & ZR36057_POR_POTime) && !zr->card.gws_not_connected) {
+               /* In LML33/BUZ \GWS line is not connected, so it has always timeout set */
+               dprintk(1, KERN_INFO "%s: pop timeout %08x\n", ZR_DEVNAME(zr),
+                       por);
+               return -1;
+       }
+
+       return 0;
+}
+
+int
+post_office_write (struct zoran *zr,
+                  unsigned int  guest,
+                  unsigned int  reg,
+                  unsigned int  value)
+{
+       u32 por;
+
+       por =
+           ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) |
+           ((reg & 7) << 16) | (value & 0xFF);
+       btwrite(por, ZR36057_POR);
+
+       return post_office_wait(zr);
+}
+
+int
+post_office_read (struct zoran *zr,
+                 unsigned int  guest,
+                 unsigned int  reg)
+{
+       u32 por;
+
+       por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16);
+       btwrite(por, ZR36057_POR);
+       if (post_office_wait(zr) < 0) {
+               return -1;
+       }
+
+       return btread(ZR36057_POR) & 0xFF;
+}
+
+/*
+ * detect guests
+ */
+
+static void
+dump_guests (struct zoran *zr)
+{
+       if (debug > 2) {
+               int i, guest[8];
+
+               for (i = 1; i < 8; i++) {       // Don't read jpeg codec here
+                       guest[i] = post_office_read(zr, i, 0);
+               }
+
+               printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr));
+
+               for (i = 1; i < 8; i++) {
+                       printk(" 0x%02x", guest[i]);
+               }
+               printk("\n");
+       }
+}
+
+static inline unsigned long
+get_time (void)
+{
+       struct timeval tv;
+       do_gettimeofday(&tv);
+       return (1000000 * tv.tv_sec + tv.tv_usec);
+}
+
+void
+detect_guest_activity (struct zoran *zr)
+{
+       int timeout, i, j, res, guest[8], guest0[8], change[8][3];
+       unsigned long t0, t1;
+
+       dump_guests(zr);
+       printk(KERN_INFO "%s: Detecting guests activity, please wait...\n",
+              ZR_DEVNAME(zr));
+       for (i = 1; i < 8; i++) {       // Don't read jpeg codec here
+               guest0[i] = guest[i] = post_office_read(zr, i, 0);
+       }
+
+       timeout = 0;
+       j = 0;
+       t0 = get_time();
+       while (timeout < 10000) {
+               udelay(10);
+               timeout++;
+               for (i = 1; (i < 8) && (j < 8); i++) {
+                       res = post_office_read(zr, i, 0);
+                       if (res != guest[i]) {
+                               t1 = get_time();
+                               change[j][0] = (t1 - t0);
+                               t0 = t1;
+                               change[j][1] = i;
+                               change[j][2] = res;
+                               j++;
+                               guest[i] = res;
+                       }
+               }
+               if (j >= 8)
+                       break;
+       }
+       printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr));
+
+       for (i = 1; i < 8; i++) {
+               printk(" 0x%02x", guest0[i]);
+       }
+       printk("\n");
+       if (j == 0) {
+               printk(KERN_INFO "%s: No activity detected.\n", ZR_DEVNAME(zr));
+               return;
+       }
+       for (i = 0; i < j; i++) {
+               printk(KERN_INFO "%s: %6d: %d => 0x%02x\n", ZR_DEVNAME(zr),
+                      change[i][0], change[i][1], change[i][2]);
+       }
+}
+
+/*
+ * JPEG Codec access
+ */
+
+void
+jpeg_codec_sleep (struct zoran *zr,
+                 int           sleep)
+{
+       GPIO(zr, zr->card.gpio[GPIO_JPEG_SLEEP], !sleep);
+       if (!sleep) {
+               dprintk(3,
+                       KERN_DEBUG
+                       "%s: jpeg_codec_sleep() - wake GPIO=0x%08x\n",
+                       ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1));
+               udelay(500);
+       } else {
+               dprintk(3,
+                       KERN_DEBUG
+                       "%s: jpeg_codec_sleep() - sleep GPIO=0x%08x\n",
+                       ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1));
+               udelay(2);
+       }
+}
+
+int
+jpeg_codec_reset (struct zoran *zr)
+{
+       /* Take the codec out of sleep */
+       jpeg_codec_sleep(zr, 0);
+
+       if (zr->card.gpcs[GPCS_JPEG_RESET] != 0xff) {
+               post_office_write(zr, zr->card.gpcs[GPCS_JPEG_RESET], 0,
+                                 0);
+               udelay(2);
+       } else {
+               GPIO(zr, zr->card.gpio[GPIO_JPEG_RESET], 0);
+               udelay(2);
+               GPIO(zr, zr->card.gpio[GPIO_JPEG_RESET], 1);
+               udelay(2);
+       }
+
+       return 0;
+}
+
+/*
+ *   Set the registers for the size we have specified. Don't bother
+ *   trying to understand this without the ZR36057 manual in front of
+ *   you [AC].
+ *
+ *   PS: The manual is free for download in .pdf format from
+ *   www.zoran.com - nicely done those folks.
+ */
+
+static void
+zr36057_adjust_vfe (struct zoran          *zr,
+                   enum zoran_codec_mode  mode)
+{
+       u32 reg;
+
+       switch (mode) {
+       case BUZ_MODE_MOTION_DECOMPRESS:
+               btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+               reg = btread(ZR36057_VFEHCR);
+               if ((reg & (1 << 10)) && zr->card.type != LML33R10) {
+                       reg += ((1 << 10) | 1);
+               }
+               btwrite(reg, ZR36057_VFEHCR);
+               break;
+       case BUZ_MODE_MOTION_COMPRESS:
+       case BUZ_MODE_IDLE:
+       default:
+               if (zr->norm == VIDEO_MODE_NTSC ||
+                   (zr->card.type == LML33R10 &&
+                    zr->norm == VIDEO_MODE_PAL))
+                       btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+               else
+                       btor(ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+               reg = btread(ZR36057_VFEHCR);
+               if (!(reg & (1 << 10)) && zr->card.type != LML33R10) {
+                       reg -= ((1 << 10) | 1);
+               }
+               btwrite(reg, ZR36057_VFEHCR);
+               break;
+       }
+}
+
+/*
+ * set geometry
+ */
+
+static void
+zr36057_set_vfe (struct zoran              *zr,
+                int                        video_width,
+                int                        video_height,
+                const struct zoran_format *format)
+{
+       struct tvnorm *tvn;
+       unsigned HStart, HEnd, VStart, VEnd;
+       unsigned DispMode;
+       unsigned VidWinWid, VidWinHt;
+       unsigned hcrop1, hcrop2, vcrop1, vcrop2;
+       unsigned Wa, We, Ha, He;
+       unsigned X, Y, HorDcm, VerDcm;
+       u32 reg;
+       unsigned mask_line_size;
+
+       tvn = zr->timing;
+
+       Wa = tvn->Wa;
+       Ha = tvn->Ha;
+
+       dprintk(2, KERN_INFO "%s: set_vfe() - width = %d, height = %d\n",
+               ZR_DEVNAME(zr), video_width, video_height);
+
+       if (zr->norm != VIDEO_MODE_PAL &&
+           zr->norm != VIDEO_MODE_NTSC &&
+           zr->norm != VIDEO_MODE_SECAM) {
+               dprintk(1,
+                       KERN_ERR "%s: set_vfe() - norm = %d not valid\n",
+                       ZR_DEVNAME(zr), zr->norm);
+               return;
+       }
+       if (video_width < BUZ_MIN_WIDTH ||
+           video_height < BUZ_MIN_HEIGHT ||
+           video_width > Wa || video_height > Ha) {
+               dprintk(1, KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n",
+                       ZR_DEVNAME(zr), video_width, video_height);
+               return;
+       }
+
+       /**** zr36057 ****/
+
+       /* horizontal */
+       VidWinWid = video_width;
+       X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa;
+       We = (VidWinWid * 64) / X;
+       HorDcm = 64 - X;
+       hcrop1 = 2 * ((tvn->Wa - We) / 4);
+       hcrop2 = tvn->Wa - We - hcrop1;
+       HStart = tvn->HStart ? tvn->HStart : 1;
+       /* (Ronald) Original comment:
+        * "| 1 Doesn't have any effect, tested on both a DC10 and a DC10+"
+        * this is false. It inverses chroma values on the LML33R10 (so Cr
+        * suddenly is shown as Cb and reverse, really cool effect if you
+        * want to see blue faces, not useful otherwise). So don't use |1.
+        * However, the DC10 has '0' as HStart, but does need |1, so we
+        * use a dirty check...
+        */
+       HEnd = HStart + tvn->Wa - 1;
+       HStart += hcrop1;
+       HEnd -= hcrop2;
+       reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart)
+           | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd);
+       if (zr->card.vfe_pol.hsync_pol)
+               reg |= ZR36057_VFEHCR_HSPol;
+       btwrite(reg, ZR36057_VFEHCR);
+
+       /* Vertical */
+       DispMode = !(video_height > BUZ_MAX_HEIGHT / 2);
+       VidWinHt = DispMode ? video_height : video_height / 2;
+       Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha;
+       He = (VidWinHt * 64) / Y;
+       VerDcm = 64 - Y;
+       vcrop1 = (tvn->Ha / 2 - He) / 2;
+       vcrop2 = tvn->Ha / 2 - He - vcrop1;
+       VStart = tvn->VStart;
+       VEnd = VStart + tvn->Ha / 2;    // - 1; FIXME SnapShot times out with -1 in 768*576 on the DC10 - LP
+       VStart += vcrop1;
+       VEnd -= vcrop2;
+       reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart)
+           | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd);
+       if (zr->card.vfe_pol.vsync_pol)
+               reg |= ZR36057_VFEVCR_VSPol;
+       btwrite(reg, ZR36057_VFEVCR);
+
+       /* scaler and pixel format */
+       reg = 0;
+       reg |= (HorDcm << ZR36057_VFESPFR_HorDcm);
+       reg |= (VerDcm << ZR36057_VFESPFR_VerDcm);
+       reg |= (DispMode << ZR36057_VFESPFR_DispMode);
+       if (format->palette != VIDEO_PALETTE_YUV422)
+               reg |= ZR36057_VFESPFR_LittleEndian;
+       /* RJ: I don't know, why the following has to be the opposite
+        * of the corresponding ZR36060 setting, but only this way
+        * we get the correct colors when uncompressing to the screen  */
+       //reg |= ZR36057_VFESPFR_VCLKPol; /**/
+       /* RJ: Don't know if that is needed for NTSC also */
+       if (zr->norm != VIDEO_MODE_NTSC)
+               reg |= ZR36057_VFESPFR_ExtFl;   // NEEDED!!!!!!! Wolfgang
+       reg |= ZR36057_VFESPFR_TopField;
+       switch (format->palette) {
+
+       case VIDEO_PALETTE_YUV422:
+               reg |= ZR36057_VFESPFR_YUV422;
+               break;
+
+       case VIDEO_PALETTE_RGB555:
+               reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif;
+               break;
+
+       case VIDEO_PALETTE_RGB565:
+               reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif;
+               break;
+
+       case VIDEO_PALETTE_RGB24:
+               reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24;
+               break;
+
+       case VIDEO_PALETTE_RGB32:
+               reg |= ZR36057_VFESPFR_RGB888;
+               break;
+
+       default:
+               dprintk(1,
+                       KERN_INFO "%s: set_vfe() - unknown color_fmt=%x\n",
+                       ZR_DEVNAME(zr), format->palette);
+               return;
+
+       }
+       if (HorDcm >= 48) {
+               reg |= 3 << ZR36057_VFESPFR_HFilter;    /* 5 tap filter */
+       } else if (HorDcm >= 32) {
+               reg |= 2 << ZR36057_VFESPFR_HFilter;    /* 4 tap filter */
+       } else if (HorDcm >= 16) {
+               reg |= 1 << ZR36057_VFESPFR_HFilter;    /* 3 tap filter */
+       }
+       btwrite(reg, ZR36057_VFESPFR);
+
+       /* display configuration */
+       reg = (16 << ZR36057_VDCR_MinPix)
+           | (VidWinHt << ZR36057_VDCR_VidWinHt)
+           | (VidWinWid << ZR36057_VDCR_VidWinWid);
+       if (pci_pci_problems & PCIPCI_TRITON)
+               // || zr->revision < 1) // Revision 1 has also Triton support
+               reg &= ~ZR36057_VDCR_Triton;
+       else
+               reg |= ZR36057_VDCR_Triton;
+       btwrite(reg, ZR36057_VDCR);
+
+       /* (Ronald) don't write this if overlay_mask = NULL */
+       if (zr->overlay_mask) {
+               /* Write overlay clipping mask data, but don't enable overlay clipping */
+               /* RJ: since this makes only sense on the screen, we use 
+                * zr->overlay_settings.width instead of video_width */
+
+               mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
+               reg = virt_to_bus(zr->overlay_mask);
+               btwrite(reg, ZR36057_MMTR);
+               reg = virt_to_bus(zr->overlay_mask + mask_line_size);
+               btwrite(reg, ZR36057_MMBR);
+               reg =
+                   mask_line_size - (zr->overlay_settings.width +
+                                     31) / 32;
+               if (DispMode == 0)
+                       reg += mask_line_size;
+               reg <<= ZR36057_OCR_MaskStride;
+               btwrite(reg, ZR36057_OCR);
+       }
+
+       zr36057_adjust_vfe(zr, zr->codec_mode);
+}
+
+/*
+ * Switch overlay on or off
+ */
+
+void
+zr36057_overlay (struct zoran *zr,
+                int           on)
+{
+       u32 reg;
+
+       if (on) {
+               /* do the necessary settings ... */
+               btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);       /* switch it off first */
+
+               zr36057_set_vfe(zr,
+                               zr->overlay_settings.width,
+                               zr->overlay_settings.height,
+                               zr->overlay_settings.format);
+
+               /* Start and length of each line MUST be 4-byte aligned.
+                * This should be allready checked before the call to this routine.
+                * All error messages are internal driver checking only! */
+
+               /* video display top and bottom registers */
+               reg = (u32) zr->buffer.base +
+                   zr->overlay_settings.x *
+                   ((zr->overlay_settings.format->depth + 7) / 8) +
+                   zr->overlay_settings.y *
+                   zr->buffer.bytesperline;
+               btwrite(reg, ZR36057_VDTR);
+               if (reg & 3)
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: zr36057_overlay() - video_address not aligned\n",
+                               ZR_DEVNAME(zr));
+               if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2)
+                       reg += zr->buffer.bytesperline;
+               btwrite(reg, ZR36057_VDBR);
+
+               /* video stride, status, and frame grab register */
+               reg = zr->buffer.bytesperline -
+                   zr->overlay_settings.width *
+                   ((zr->overlay_settings.format->depth + 7) / 8);
+               if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2)
+                       reg += zr->buffer.bytesperline;
+               if (reg & 3)
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: zr36057_overlay() - video_stride not aligned\n",
+                               ZR_DEVNAME(zr));
+               reg = (reg << ZR36057_VSSFGR_DispStride);
+               reg |= ZR36057_VSSFGR_VidOvf;   /* clear overflow status */
+               btwrite(reg, ZR36057_VSSFGR);
+
+               /* Set overlay clipping */
+               if (zr->overlay_settings.clipcount > 0)
+                       btor(ZR36057_OCR_OvlEnable, ZR36057_OCR);
+
+               /* ... and switch it on */
+               btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);
+       } else {
+               /* Switch it off */
+               btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+       }
+}
+
+/*
+ * The overlay mask has one bit for each pixel on a scan line,
+ *  and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels.
+ */
+
+void
+write_overlay_mask (struct file       *file,
+                   struct video_clip *vp,
+                   int                count)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
+       u32 *mask;
+       int x, y, width, height;
+       unsigned i, j, k;
+       u32 reg;
+
+       /* fill mask with one bits */
+       memset(fh->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT);
+       reg = 0;
+
+       for (i = 0; i < count; ++i) {
+               /* pick up local copy of clip */
+               x = vp[i].x;
+               y = vp[i].y;
+               width = vp[i].width;
+               height = vp[i].height;
+
+               /* trim clips that extend beyond the window */
+               if (x < 0) {
+                       width += x;
+                       x = 0;
+               }
+               if (y < 0) {
+                       height += y;
+                       y = 0;
+               }
+               if (x + width > fh->overlay_settings.width) {
+                       width = fh->overlay_settings.width - x;
+               }
+               if (y + height > fh->overlay_settings.height) {
+                       height = fh->overlay_settings.height - y;
+               }
+
+               /* ignore degenerate clips */
+               if (height <= 0) {
+                       continue;
+               }
+               if (width <= 0) {
+                       continue;
+               }
+
+               /* apply clip for each scan line */
+               for (j = 0; j < height; ++j) {
+                       /* reset bit for each pixel */
+                       /* this can be optimized later if need be */
+                       mask = fh->overlay_mask + (y + j) * mask_line_size;
+                       for (k = 0; k < width; ++k) {
+                               mask[(x + k) / 32] &=
+                                   ~((u32) 1 << (x + k) % 32);
+                       }
+               }
+       }
+}
+
+/* Enable/Disable uncompressed memory grabbing of the 36057 */
+
+void
+zr36057_set_memgrab (struct zoran *zr,
+                    int           mode)
+{
+       if (mode) {
+               if (btread(ZR36057_VSSFGR) &
+                   (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab))
+                       dprintk(1,
+                               KERN_WARNING
+                               "%s: zr36057_set_memgrab(1) with SnapShot or FrameGrab on!?\n",
+                               ZR_DEVNAME(zr));
+
+               /* switch on VSync interrupts */
+               btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts
+               btor(zr->card.vsync_int, ZR36057_ICR);  // SW
+
+               /* enable SnapShot */
+               btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
+
+               /* Set zr36057 video front end  and enable video */
+               zr36057_set_vfe(zr, zr->v4l_settings.width,
+                               zr->v4l_settings.height,
+                               zr->v4l_settings.format);
+
+               zr->v4l_memgrab_active = 1;
+       } else {
+               zr->v4l_memgrab_active = 0;
+
+               /* switch off VSync interrupts */
+               btand(~zr->card.vsync_int, ZR36057_ICR);        // SW
+
+               /* reenable grabbing to screen if it was running */
+               if (zr->v4l_overlay_active) {
+                       zr36057_overlay(zr, 1);
+               } else {
+                       btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+                       btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
+               }
+       }
+}
+
+int
+wait_grab_pending (struct zoran *zr)
+{
+       unsigned long flags;
+
+       /* wait until all pending grabs are finished */
+
+       if (!zr->v4l_memgrab_active)
+               return 0;
+
+       while (zr->v4l_pend_tail != zr->v4l_pend_head) {
+               interruptible_sleep_on(&zr->v4l_capq);
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+       }
+
+       spin_lock_irqsave(&zr->spinlock, flags);
+       zr36057_set_memgrab(zr, 0);
+       spin_unlock_irqrestore(&zr->spinlock, flags);
+
+       return 0;
+}
+
+/*****************************************************************************
+ *                                                                           *
+ *  Set up the Buz-specific MJPEG part                                       *
+ *                                                                           *
+ *****************************************************************************/
+
+static inline void
+set_frame (struct zoran *zr,
+          int           val)
+{
+       GPIO(zr, zr->card.gpio[GPIO_JPEG_FRAME], val);
+}
+
+static void
+set_videobus_dir (struct zoran *zr,
+                 int           val)
+{
+       switch (zr->card.type) {
+       case LML33:
+       case LML33R10:
+               if (lml33dpath == 0)
+                       GPIO(zr, 5, val);
+               else
+                       GPIO(zr, 5, 1);
+               break;
+       default:
+               GPIO(zr, zr->card.gpio[GPIO_VID_DIR],
+                    zr->card.gpio_pol[GPIO_VID_DIR] ? !val : val);
+               break;
+       }
+}
+
+static void
+init_jpeg_queue (struct zoran *zr)
+{
+       int i;
+
+       /* re-initialize DMA ring stuff */
+       zr->jpg_que_head = 0;
+       zr->jpg_dma_head = 0;
+       zr->jpg_dma_tail = 0;
+       zr->jpg_que_tail = 0;
+       zr->jpg_seq_num = 0;
+       zr->JPEG_error = 0;
+       zr->num_errors = 0;
+       zr->jpg_err_seq = 0;
+       zr->jpg_err_shift = 0;
+       zr->jpg_queued_num = 0;
+       for (i = 0; i < zr->jpg_buffers.num_buffers; i++) {
+               zr->jpg_buffers.buffer[i].state = BUZ_STATE_USER;       /* nothing going on */
+       }
+       for (i = 0; i < BUZ_NUM_STAT_COM; i++) {
+               zr->stat_com[i] = 1;    /* mark as unavailable to zr36057 */
+       }
+}
+
+static void
+zr36057_set_jpg (struct zoran          *zr,
+                enum zoran_codec_mode  mode)
+{
+       struct tvnorm *tvn;
+       u32 reg;
+
+       tvn = zr->timing;
+
+       /* assert P_Reset, disable code transfer, deassert Active */
+       btwrite(0, ZR36057_JPC);
+
+       /* MJPEG compression mode */
+       switch (mode) {
+
+       case BUZ_MODE_MOTION_COMPRESS:
+       default:
+               reg = ZR36057_JMC_MJPGCmpMode;
+               break;
+
+       case BUZ_MODE_MOTION_DECOMPRESS:
+               reg = ZR36057_JMC_MJPGExpMode;
+               reg |= ZR36057_JMC_SyncMstr;
+               /* RJ: The following is experimental - improves the output to screen */
+               //if(zr->jpg_settings.VFIFO_FB) reg |= ZR36057_JMC_VFIFO_FB; // No, it doesn't. SM
+               break;
+
+       case BUZ_MODE_STILL_COMPRESS:
+               reg = ZR36057_JMC_JPGCmpMode;
+               break;
+
+       case BUZ_MODE_STILL_DECOMPRESS:
+               reg = ZR36057_JMC_JPGExpMode;
+               break;
+
+       }
+       reg |= ZR36057_JMC_JPG;
+       if (zr->jpg_settings.field_per_buff == 1)
+               reg |= ZR36057_JMC_Fld_per_buff;
+       btwrite(reg, ZR36057_JMC);
+
+       /* vertical */
+       btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR);
+       reg = (6 << ZR36057_VSP_VsyncSize) |
+             (tvn->Ht << ZR36057_VSP_FrmTot);
+       btwrite(reg, ZR36057_VSP);
+       reg = ((zr->jpg_settings.img_y + tvn->VStart) << ZR36057_FVAP_NAY) |
+             (zr->jpg_settings.img_height << ZR36057_FVAP_PAY);
+       btwrite(reg, ZR36057_FVAP);
+
+       /* horizontal */
+       if (zr->card.vfe_pol.hsync_pol)
+               btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
+       else
+               btand(~ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);           
+       reg = ((tvn->HSyncStart) << ZR36057_HSP_HsyncStart) |
+             (tvn->Wt << ZR36057_HSP_LineTot);
+       btwrite(reg, ZR36057_HSP);
+       reg = ((zr->jpg_settings.img_x +
+               tvn->HStart + 4) << ZR36057_FHAP_NAX) |
+             (zr->jpg_settings.img_width << ZR36057_FHAP_PAX);
+       btwrite(reg, ZR36057_FHAP);
+
+       /* field process parameters */
+       if (zr->jpg_settings.odd_even)
+               reg = ZR36057_FPP_Odd_Even;
+       else
+               reg = 0;
+
+       btwrite(reg, ZR36057_FPP);
+
+       /* Set proper VCLK Polarity, else colors will be wrong during playback */
+       //btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR);
+
+       /* code base address */
+       reg = virt_to_bus(zr->stat_com);
+       btwrite(reg, ZR36057_JCBA);
+
+       /* FIFO threshold (FIFO is 160. double words) */
+       /* NOTE: decimal values here */
+       switch (mode) {
+
+       case BUZ_MODE_STILL_COMPRESS:
+       case BUZ_MODE_MOTION_COMPRESS:
+               if (zr->card.type != BUZ)
+                       reg = 140;
+               else
+                       reg = 60;
+               break;
+
+       case BUZ_MODE_STILL_DECOMPRESS:
+       case BUZ_MODE_MOTION_DECOMPRESS:
+               reg = 20;
+               break;
+
+       default:
+               reg = 80;
+               break;
+
+       }
+       btwrite(reg, ZR36057_JCFT);
+       zr36057_adjust_vfe(zr, mode);
+
+}
+
+void
+print_interrupts (struct zoran *zr)
+{
+       int res, noerr;
+       noerr = 0;
+       printk(KERN_INFO "%s: interrupts received:", ZR_DEVNAME(zr));
+       if ((res = zr->field_counter) < -1 || res > 1) {
+               printk(" FD:%d", res);
+       }
+       if ((res = zr->intr_counter_GIRQ1) != 0) {
+               printk(" GIRQ1:%d", res);
+               noerr++;
+       }
+       if ((res = zr->intr_counter_GIRQ0) != 0) {
+               printk(" GIRQ0:%d", res);
+               noerr++;
+       }
+       if ((res = zr->intr_counter_CodRepIRQ) != 0) {
+               printk(" CodRepIRQ:%d", res);
+               noerr++;
+       }
+       if ((res = zr->intr_counter_JPEGRepIRQ) != 0) {
+               printk(" JPEGRepIRQ:%d", res);
+               noerr++;
+       }
+       if (zr->JPEG_max_missed) {
+               printk(" JPEG delays: max=%d min=%d", zr->JPEG_max_missed,
+                      zr->JPEG_min_missed);
+       }
+       if (zr->END_event_missed) {
+               printk(" ENDs missed: %d", zr->END_event_missed);
+       }
+       //if (zr->jpg_queued_num) {
+       printk(" queue_state=%ld/%ld/%ld/%ld", zr->jpg_que_tail,
+              zr->jpg_dma_tail, zr->jpg_dma_head, zr->jpg_que_head);
+       //}
+       if (!noerr) {
+               printk(": no interrupts detected.");
+       }
+       printk("\n");
+}
+
+void
+clear_interrupt_counters (struct zoran *zr)
+{
+       zr->intr_counter_GIRQ1 = 0;
+       zr->intr_counter_GIRQ0 = 0;
+       zr->intr_counter_CodRepIRQ = 0;
+       zr->intr_counter_JPEGRepIRQ = 0;
+       zr->field_counter = 0;
+       zr->IRQ1_in = 0;
+       zr->IRQ1_out = 0;
+       zr->JPEG_in = 0;
+       zr->JPEG_out = 0;
+       zr->JPEG_0 = 0;
+       zr->JPEG_1 = 0;
+       zr->END_event_missed = 0;
+       zr->JPEG_missed = 0;
+       zr->JPEG_max_missed = 0;
+       zr->JPEG_min_missed = 0x7fffffff;
+}
+
+static u32
+count_reset_interrupt (struct zoran *zr)
+{
+       u32 isr;
+       if ((isr = btread(ZR36057_ISR) & 0x78000000)) {
+               if (isr & ZR36057_ISR_GIRQ1) {
+                       btwrite(ZR36057_ISR_GIRQ1, ZR36057_ISR);
+                       zr->intr_counter_GIRQ1++;
+               }
+               if (isr & ZR36057_ISR_GIRQ0) {
+                       btwrite(ZR36057_ISR_GIRQ0, ZR36057_ISR);
+                       zr->intr_counter_GIRQ0++;
+               }
+               if (isr & ZR36057_ISR_CodRepIRQ) {
+                       btwrite(ZR36057_ISR_CodRepIRQ, ZR36057_ISR);
+                       zr->intr_counter_CodRepIRQ++;
+               }
+               if (isr & ZR36057_ISR_JPEGRepIRQ) {
+                       btwrite(ZR36057_ISR_JPEGRepIRQ, ZR36057_ISR);
+                       zr->intr_counter_JPEGRepIRQ++;
+               }
+       }
+       return isr;
+}
+
+/* hack */
+extern void zr36016_write (struct videocodec *codec,
+                          u16                reg,
+                          u32                val);
+
+void
+jpeg_start (struct zoran *zr)
+{
+       int reg;
+       zr->frame_num = 0;
+
+       /* deassert P_reset, disable code transfer, deassert Active */
+       btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC);
+       /* stop flushing the internal code buffer */
+       btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+       /* enable code transfer */
+       btor(ZR36057_JPC_CodTrnsEn, ZR36057_JPC);
+
+       /* clear IRQs */
+       btwrite(IRQ_MASK, ZR36057_ISR);
+       /* enable the JPEG IRQs */
+       btwrite(zr->card.jpeg_int |
+                       ZR36057_ICR_JPEGRepIRQ |
+                       ZR36057_ICR_IntPinEn,
+               ZR36057_ICR);
+
+       set_frame(zr, 0);       // \FRAME
+
+       /* set the JPEG codec guest ID */
+       reg = (zr->card.gpcs[1] << ZR36057_JCGI_JPEGuestID) |
+              (0 << ZR36057_JCGI_JPEGuestReg);
+       btwrite(reg, ZR36057_JCGI);
+
+       if (zr->card.video_vfe == CODEC_TYPE_ZR36016 &&
+           zr->card.video_codec == CODEC_TYPE_ZR36050) {
+               /* Enable processing on the ZR36016 */
+               if (zr->vfe)
+                       zr36016_write(zr->vfe, 0, 1);
+
+               /* load the address of the GO register in the ZR36050 latch */
+               post_office_write(zr, 0, 0, 0);
+       }
+
+       /* assert Active */
+       btor(ZR36057_JPC_Active, ZR36057_JPC);
+
+       /* enable the Go generation */
+       btor(ZR36057_JMC_Go_en, ZR36057_JMC);
+       udelay(30);
+
+       set_frame(zr, 1);       // /FRAME
+
+       dprintk(3, KERN_DEBUG "%s: jpeg_start\n", ZR_DEVNAME(zr));
+}
+
+void
+zr36057_enable_jpg (struct zoran          *zr,
+                   enum zoran_codec_mode  mode)
+{
+       static int zero = 0;
+       static int one = 1;
+       struct vfe_settings cap;
+       int field_size =
+           zr->jpg_buffers.buffer_size / zr->jpg_settings.field_per_buff;
+
+       zr->codec_mode = mode;
+
+       cap.x = zr->jpg_settings.img_x;
+       cap.y = zr->jpg_settings.img_y;
+       cap.width = zr->jpg_settings.img_width;
+       cap.height = zr->jpg_settings.img_height;
+       cap.decimation =
+           zr->jpg_settings.HorDcm | (zr->jpg_settings.VerDcm << 8);
+       cap.quality = zr->jpg_settings.jpg_comp.quality;
+
+       switch (mode) {
+
+       case BUZ_MODE_MOTION_COMPRESS:
+               /* In motion compress mode, the decoder output must be enabled, and
+                * the video bus direction set to input.
+                */
+               set_videobus_dir(zr, 0);
+               decoder_command(zr, DECODER_ENABLE_OUTPUT, &one);
+               encoder_command(zr, ENCODER_SET_INPUT, &zero);
+
+               /* Take the JPEG codec and the VFE out of sleep */
+               jpeg_codec_sleep(zr, 0);
+               /* Setup the JPEG codec */
+               zr->codec->control(zr->codec, CODEC_S_JPEG_TDS_BYTE,
+                                  sizeof(int), &field_size);
+               zr->codec->set_video(zr->codec, zr->timing, &cap,
+                                    &zr->card.vfe_pol);
+               zr->codec->set_mode(zr->codec, CODEC_DO_COMPRESSION);
+
+               /* Setup the VFE */
+               if (zr->vfe) {
+                       zr->vfe->control(zr->vfe, CODEC_S_JPEG_TDS_BYTE,
+                                        sizeof(int), &field_size);
+                       zr->vfe->set_video(zr->vfe, zr->timing, &cap,
+                                          &zr->card.vfe_pol);
+                       zr->vfe->set_mode(zr->vfe, CODEC_DO_COMPRESSION);
+               }
+
+               init_jpeg_queue(zr);
+               zr36057_set_jpg(zr, mode);      // \P_Reset, ... Video param, FIFO
+
+               clear_interrupt_counters(zr);
+               dprintk(2, KERN_INFO "%s: enable_jpg(MOTION_COMPRESS)\n",
+                       ZR_DEVNAME(zr));
+               break;
+
+       case BUZ_MODE_MOTION_DECOMPRESS:
+               /* In motion decompression mode, the decoder output must be disabled, and
+                * the video bus direction set to output.
+                */
+               decoder_command(zr, DECODER_ENABLE_OUTPUT, &zero);
+               set_videobus_dir(zr, 1);
+               encoder_command(zr, ENCODER_SET_INPUT, &one);
+
+               /* Take the JPEG codec and the VFE out of sleep */
+               jpeg_codec_sleep(zr, 0);
+               /* Setup the VFE */
+               if (zr->vfe) {
+                       zr->vfe->set_video(zr->vfe, zr->timing, &cap,
+                                          &zr->card.vfe_pol);
+                       zr->vfe->set_mode(zr->vfe, CODEC_DO_EXPANSION);
+               }
+               /* Setup the JPEG codec */
+               zr->codec->set_video(zr->codec, zr->timing, &cap,
+                                    &zr->card.vfe_pol);
+               zr->codec->set_mode(zr->codec, CODEC_DO_EXPANSION);
+
+               init_jpeg_queue(zr);
+               zr36057_set_jpg(zr, mode);      // \P_Reset, ... Video param, FIFO
+
+               clear_interrupt_counters(zr);
+               dprintk(2, KERN_INFO "%s: enable_jpg(MOTION_DECOMPRESS)\n",
+                       ZR_DEVNAME(zr));
+               break;
+
+       case BUZ_MODE_IDLE:
+       default:
+               /* shut down processing */
+               btand(~(zr->card.jpeg_int | ZR36057_ICR_JPEGRepIRQ),
+                     ZR36057_ICR);
+               btwrite(zr->card.jpeg_int | ZR36057_ICR_JPEGRepIRQ,
+                       ZR36057_ISR);
+               btand(~ZR36057_JMC_Go_en, ZR36057_JMC); // \Go_en
+
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(HZ / 20);
+
+               set_videobus_dir(zr, 0);
+               set_frame(zr, 1);       // /FRAME
+               btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);      // /CFlush
+               btwrite(0, ZR36057_JPC);        // \P_Reset,\CodTrnsEn,\Active
+               btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC);
+               btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC);
+               jpeg_codec_reset(zr);
+               jpeg_codec_sleep(zr, 1);
+               zr36057_adjust_vfe(zr, mode);
+
+               decoder_command(zr, DECODER_ENABLE_OUTPUT, &one);
+               encoder_command(zr, ENCODER_SET_INPUT, &zero);
+
+               dprintk(2, KERN_INFO "%s: enable_jpg(IDLE)\n", ZR_DEVNAME(zr));
+               break;
+
+       }
+}
+
+/* when this is called the spinlock must be held */
+void
+zoran_feed_stat_com (struct zoran *zr)
+{
+       /* move frames from pending queue to DMA */
+
+       int frame, i, max_stat_com;
+
+       max_stat_com =
+           (zr->jpg_settings.TmpDcm ==
+            1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1);
+
+       while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com &&
+              zr->jpg_dma_head < zr->jpg_que_head) {
+
+               frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME];
+               if (zr->jpg_settings.TmpDcm == 1) {
+                       /* fill 1 stat_com entry */
+                       i = (zr->jpg_dma_head -
+                            zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+                       if (!(zr->stat_com[i] & 1))
+                               break;
+                       zr->stat_com[i] =
+                           zr->jpg_buffers.buffer[frame].frag_tab_bus;
+               } else {
+                       /* fill 2 stat_com entries */
+                       i = ((zr->jpg_dma_head -
+                             zr->jpg_err_shift) & 1) * 2;
+                       if (!(zr->stat_com[i] & 1))
+                               break;
+                       zr->stat_com[i] =
+                           zr->jpg_buffers.buffer[frame].frag_tab_bus;
+                       zr->stat_com[i + 1] =
+                           zr->jpg_buffers.buffer[frame].frag_tab_bus;
+               }
+               zr->jpg_buffers.buffer[frame].state = BUZ_STATE_DMA;
+               zr->jpg_dma_head++;
+
+       }
+       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS)
+               zr->jpg_queued_num++;
+}
+
+/* when this is called the spinlock must be held */
+static void
+zoran_reap_stat_com (struct zoran *zr)
+{
+       /* move frames from DMA queue to done queue */
+
+       int i;
+       u32 stat_com;
+       unsigned int seq;
+       unsigned int dif;
+       struct zoran_jpg_buffer *buffer;
+       int frame;
+
+       /* In motion decompress we don't have a hardware frame counter,
+        * we just count the interrupts here */
+
+       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
+               zr->jpg_seq_num++;
+       }
+       while (zr->jpg_dma_tail < zr->jpg_dma_head) {
+               if (zr->jpg_settings.TmpDcm == 1)
+                       i = (zr->jpg_dma_tail -
+                            zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+               else
+                       i = ((zr->jpg_dma_tail -
+                             zr->jpg_err_shift) & 1) * 2 + 1;
+
+               stat_com = zr->stat_com[i];
+
+               if ((stat_com & 1) == 0) {
+                       return;
+               }
+               frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
+               buffer = &zr->jpg_buffers.buffer[frame];
+               do_gettimeofday(&buffer->bs.timestamp);
+
+               if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+                       buffer->bs.length = (stat_com & 0x7fffff) >> 1;
+
+                       /* update sequence number with the help of the counter in stat_com */
+
+                       seq = ((stat_com >> 24) + zr->jpg_err_seq) & 0xff;
+                       dif = (seq - zr->jpg_seq_num) & 0xff;
+                       zr->jpg_seq_num += dif;
+               } else {
+                       buffer->bs.length = 0;
+               }
+               buffer->bs.seq =
+                   zr->jpg_settings.TmpDcm ==
+                   2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num;
+               buffer->state = BUZ_STATE_DONE;
+
+               zr->jpg_dma_tail++;
+       }
+}
+
+static void
+error_handler (struct zoran *zr,
+              u32           astat,
+              u32           stat)
+{
+       /* This is JPEG error handling part */
+       if ((zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) &&
+           (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS)) {
+               //dprintk(1, KERN_ERR "%s: Internal error: error handling request in mode %d\n", ZR_DEVNAME(zr), zr->codec_mode);
+               return;
+       }
+
+       if ((stat & 1) == 0 &&
+           zr->codec_mode == BUZ_MODE_MOTION_COMPRESS &&
+           zr->jpg_dma_tail - zr->jpg_que_tail >=
+            zr->jpg_buffers.num_buffers) {
+               /* No free buffers... */
+               zoran_reap_stat_com(zr);
+               zoran_feed_stat_com(zr);
+               wake_up_interruptible(&zr->jpg_capq);
+               zr->JPEG_missed = 0;
+               return;
+       }
+
+       if (zr->JPEG_error != 1) {
+               /*
+                * First entry: error just happened during normal operation
+                * 
+                * In BUZ_MODE_MOTION_COMPRESS:
+                * 
+                * Possible glitch in TV signal. In this case we should
+                * stop the codec and wait for good quality signal before
+                * restarting it to avoid further problems
+                * 
+                * In BUZ_MODE_MOTION_DECOMPRESS:
+                * 
+                * Bad JPEG frame: we have to mark it as processed (codec crashed
+                * and was not able to do it itself), and to remove it from queue.
+                */
+               btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
+               udelay(1);
+               stat = stat | (post_office_read(zr, 7, 0) & 3) << 8;
+               btwrite(0, ZR36057_JPC);
+               btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+               jpeg_codec_reset(zr);
+               jpeg_codec_sleep(zr, 1);
+               zr->JPEG_error = 1;
+               zr->num_errors++;
+
+               /* Report error */
+               if (debug > 1 && zr->num_errors <= 8) {
+                       long frame;
+                       frame =
+                           zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
+                       printk(KERN_ERR
+                              "%s: JPEG error stat=0x%08x(0x%08x) queue_state=%ld/%ld/%ld/%ld seq=%ld frame=%ld. Codec stopped. ",
+                              ZR_DEVNAME(zr), stat, zr->last_isr,
+                              zr->jpg_que_tail, zr->jpg_dma_tail,
+                              zr->jpg_dma_head, zr->jpg_que_head,
+                              zr->jpg_seq_num, frame);
+                       printk("stat_com frames:");
+                       {
+                               int i, j;
+                               for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+                                       for (i = 0;
+                                            i < zr->jpg_buffers.num_buffers;
+                                            i++) {
+                                               if (zr->stat_com[j] ==
+                                                   zr->jpg_buffers.
+                                                   buffer[i].
+                                                   frag_tab_bus) {
+                                                       printk("% d->%d",
+                                                              j, i);
+                                               }
+                                       }
+                               }
+                               printk("\n");
+                       }
+               }
+
+               /* Find an entry in stat_com and rotate contents */
+               {
+                       int i;
+
+                       if (zr->jpg_settings.TmpDcm == 1)
+                               i = (zr->jpg_dma_tail -
+                                    zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+                       else
+                               i = ((zr->jpg_dma_tail -
+                                     zr->jpg_err_shift) & 1) * 2;
+                       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
+                               /* Mimic zr36067 operation */
+                               zr->stat_com[i] |= 1;
+                               if (zr->jpg_settings.TmpDcm != 1)
+                                       zr->stat_com[i + 1] |= 1;
+                               /* Refill */
+                               zoran_reap_stat_com(zr);
+                               zoran_feed_stat_com(zr);
+                               wake_up_interruptible(&zr->jpg_capq);
+                               /* Find an entry in stat_com again after refill */
+                               if (zr->jpg_settings.TmpDcm == 1)
+                                       i = (zr->jpg_dma_tail -
+                                            zr->jpg_err_shift) &
+                                           BUZ_MASK_STAT_COM;
+                               else
+                                       i = ((zr->jpg_dma_tail -
+                                             zr->jpg_err_shift) & 1) * 2;
+                       }
+                       if (i) {
+                               /* Rotate stat_comm entries to make current entry first */
+                               int j;
+                               u32 bus_addr[BUZ_NUM_STAT_COM];
+
+                               memcpy(bus_addr, zr->stat_com,
+                                      sizeof(bus_addr));
+                               for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+                                       zr->stat_com[j] =
+                                           bus_addr[(i + j) &
+                                                    BUZ_MASK_STAT_COM];
+                               }
+                               zr->jpg_err_shift += i;
+                               zr->jpg_err_shift &= BUZ_MASK_STAT_COM;
+                       }
+                       if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)
+                               zr->jpg_err_seq = zr->jpg_seq_num;      /* + 1; */
+               }
+       }
+
+       /* Now the stat_comm buffer is ready for restart */
+       do {
+               int status, mode;
+
+               if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+                       decoder_command(zr, DECODER_GET_STATUS, &status);
+                       mode = CODEC_DO_COMPRESSION;
+               } else {
+                       status = 0;
+                       mode = CODEC_DO_EXPANSION;
+               }
+               if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
+                   (status & DECODER_STATUS_GOOD)) {
+                       /********** RESTART code *************/
+                       jpeg_codec_reset(zr);
+                       zr->codec->set_mode(zr->codec, mode);
+                       zr36057_set_jpg(zr, zr->codec_mode);
+                       jpeg_start(zr);
+
+                       if (zr->num_errors <= 8)
+                               dprintk(2, KERN_INFO "%s: Restart\n",
+                                       ZR_DEVNAME(zr));
+
+                       zr->JPEG_missed = 0;
+                       zr->JPEG_error = 2;
+                       /********** End RESTART code ***********/
+               }
+       } while (0);
+}
+
+irqreturn_t
+zoran_irq (int             irq,
+          void           *dev_id,
+          struct pt_regs *regs)
+{
+       u32 stat, astat;
+       int count;
+       struct zoran *zr;
+       unsigned long flags;
+
+       zr = (struct zoran *) dev_id;
+       count = 0;
+
+       if (zr->testing) {
+               /* Testing interrupts */
+               spin_lock_irqsave(&zr->spinlock, flags);
+               while ((stat = count_reset_interrupt(zr))) {
+                       if (count++ > 100) {
+                               btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: IRQ lockup while testing, isr=0x%08x, cleared int mask\n",
+                                       ZR_DEVNAME(zr), stat);
+                               wake_up_interruptible(&zr->test_q);
+                       }
+               }
+               zr->last_isr = stat;
+               spin_unlock_irqrestore(&zr->spinlock, flags);
+               return IRQ_HANDLED;
+       }
+
+       spin_lock_irqsave(&zr->spinlock, flags);
+       while (1) {
+               /* get/clear interrupt status bits */
+               stat = count_reset_interrupt(zr);
+               astat = stat & IRQ_MASK;
+               if (!astat) {
+                       break;
+               }
+               dprintk(4,
+                       KERN_DEBUG
+                       "zoran_irq: astat: 0x%08x, mask: 0x%08x\n",
+                       astat, btread(ZR36057_ICR));
+               if (astat & zr->card.vsync_int) {       // SW
+
+                       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
+                           zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+                               /* count missed interrupts */
+                               zr->JPEG_missed++;
+                       }
+                       //post_office_read(zr,1,0);
+                       /* Interrupts may still happen when
+                        * zr->v4l_memgrab_active is switched off.
+                        * We simply ignore them */
+
+                       if (zr->v4l_memgrab_active) {
+
+                               /* A lot more checks should be here ... */
+                               if ((btread(ZR36057_VSSFGR) &
+                                    ZR36057_VSSFGR_SnapShot) == 0)
+                                       dprintk(1,
+                                               KERN_WARNING
+                                               "%s: BuzIRQ with SnapShot off ???\n",
+                                               ZR_DEVNAME(zr));
+
+                               if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) {
+                                       /* There is a grab on a frame going on, check if it has finished */
+
+                                       if ((btread(ZR36057_VSSFGR) &
+                                            ZR36057_VSSFGR_FrameGrab) ==
+                                           0) {
+                                               /* it is finished, notify the user */
+
+                                               zr->v4l_buffers.buffer[zr->
+                                                                      v4l_grab_frame].
+                                                   state = BUZ_STATE_DONE;
+                                               zr->v4l_buffers.buffer[zr->
+                                                                      v4l_grab_frame].
+                                                   bs.seq =
+                                                   zr->v4l_grab_seq;
+                                               do_gettimeofday(&zr->
+                                                               v4l_buffers.
+                                                               buffer[zr->
+                                                                      v4l_grab_frame].
+                                                               bs.
+                                                               timestamp);
+                                               zr->v4l_grab_frame =
+                                                   NO_GRAB_ACTIVE;
+                                               zr->v4l_pend_tail++;
+                                       }
+                               }
+
+                               if (zr->v4l_grab_frame == NO_GRAB_ACTIVE)
+                                       wake_up_interruptible(&zr->
+                                                             v4l_capq);
+
+                               /* Check if there is another grab queued */
+
+                               if (zr->v4l_grab_frame == NO_GRAB_ACTIVE &&
+                                   zr->v4l_pend_tail !=
+                                   zr->v4l_pend_head) {
+
+                                       int frame =
+                                           zr->v4l_pend[zr->
+                                                        v4l_pend_tail &
+                                                        V4L_MASK_FRAME];
+                                       u32 reg;
+
+                                       zr->v4l_grab_frame = frame;
+
+                                       /* Set zr36057 video front end and enable video */
+
+                                       /* Buffer address */
+
+                                       reg =
+                                           zr->v4l_buffers.buffer[frame].
+                                           fbuffer_bus;
+                                       btwrite(reg, ZR36057_VDTR);
+                                       if (zr->v4l_settings.height >
+                                           BUZ_MAX_HEIGHT / 2)
+                                               reg +=
+                                                   zr->v4l_settings.
+                                                   bytesperline;
+                                       btwrite(reg, ZR36057_VDBR);
+
+                                       /* video stride, status, and frame grab register */
+                                       reg = 0;
+                                       if (zr->v4l_settings.height >
+                                           BUZ_MAX_HEIGHT / 2)
+                                               reg +=
+                                                   zr->v4l_settings.
+                                                   bytesperline;
+                                       reg =
+                                           (reg <<
+                                            ZR36057_VSSFGR_DispStride);
+                                       reg |= ZR36057_VSSFGR_VidOvf;
+                                       reg |= ZR36057_VSSFGR_SnapShot;
+                                       reg |= ZR36057_VSSFGR_FrameGrab;
+                                       btwrite(reg, ZR36057_VSSFGR);
+
+                                       btor(ZR36057_VDCR_VidEn,
+                                            ZR36057_VDCR);
+                               }
+                       }
+
+                       /* even if we don't grab, we do want to increment
+                        * the sequence counter to see lost frames */
+                       zr->v4l_grab_seq++;
+               }
+#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ)
+               if (astat & ZR36057_ISR_CodRepIRQ) {
+                       zr->intr_counter_CodRepIRQ++;
+                       IDEBUG(printk
+                              (KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n",
+                               ZR_DEVNAME(zr)));
+                       btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR);
+               }
+#endif                         /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */
+
+#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ)
+               if (astat & ZR36057_ISR_JPEGRepIRQ) {
+
+                       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
+                           zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+                               if (debug > 1 &&
+                                   (!zr->frame_num || zr->JPEG_error)) {
+                                       printk(KERN_INFO
+                                              "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n",
+                                              ZR_DEVNAME(zr), stat,
+                                              zr->jpg_settings.odd_even,
+                                              zr->jpg_settings.
+                                              field_per_buff,
+                                              zr->JPEG_missed);
+                                       {
+                                               char sc[] = "0000";
+                                               char sv[5];
+                                               int i;
+                                               strcpy(sv, sc);
+                                               for (i = 0; i < 4; i++) {
+                                                       if (zr->
+                                                           stat_com[i] &
+                                                           1)
+                                                               sv[i] =
+                                                                   '1';
+                                               }
+                                               sv[4] = 0;
+                                               printk(KERN_INFO
+                                                      "%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n",
+                                                      ZR_DEVNAME(zr), sv,
+                                                      zr->jpg_que_tail,
+                                                      zr->jpg_dma_tail,
+                                                      zr->jpg_dma_head,
+                                                      zr->jpg_que_head);
+                                       }
+                               } else {
+                                       if (zr->JPEG_missed > zr->JPEG_max_missed)      // Get statistics
+                                               zr->JPEG_max_missed =
+                                                   zr->JPEG_missed;
+                                       if (zr->JPEG_missed <
+                                           zr->JPEG_min_missed)
+                                               zr->JPEG_min_missed =
+                                                   zr->JPEG_missed;
+                               }
+
+                               if (debug > 2 && zr->frame_num < 6) {
+                                       int i;
+                                       printk("%s: seq=%ld stat_com:",
+                                              ZR_DEVNAME(zr), zr->jpg_seq_num);
+                                       for (i = 0; i < 4; i++) {
+                                               printk(" %08x",
+                                                      zr->stat_com[i]);
+                                       }
+                                       printk("\n");
+                               }
+                               zr->frame_num++;
+                               zr->JPEG_missed = 0;
+                               zr->JPEG_error = 0;
+                               zoran_reap_stat_com(zr);
+                               zoran_feed_stat_com(zr);
+                               wake_up_interruptible(&zr->jpg_capq);
+                       } /*else {
+                             dprintk(1,
+                                       KERN_ERR
+                                       "%s: JPEG interrupt while not in motion (de)compress mode!\n",
+                                       ZR_DEVNAME(zr));
+                       }*/
+               }
+#endif                         /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */
+
+               /* DATERR, too many fields missed, error processing */
+               if ((astat & zr->card.jpeg_int) ||
+                   zr->JPEG_missed > 25 ||
+                   zr->JPEG_error == 1 ||
+                   ((zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) &&
+                    (zr->frame_num & (zr->JPEG_missed >
+                                      zr->jpg_settings.field_per_buff)))) {
+                       error_handler(zr, astat, stat);
+               }
+
+               count++;
+               if (count > 10) {
+                       dprintk(2, KERN_WARNING "%s: irq loop %d\n",
+                               ZR_DEVNAME(zr), count);
+                       if (count > 20) {
+                               btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+                               dprintk(2,
+                                       KERN_ERR
+                                       "%s: IRQ lockup, cleared int mask\n",
+                                       ZR_DEVNAME(zr));
+                               break;
+                       }
+               }
+               zr->last_isr = stat;
+       }
+       spin_unlock_irqrestore(&zr->spinlock, flags);
+
+       return IRQ_HANDLED;
+}
+
+void
+zoran_set_pci_master (struct zoran *zr,
+                     int           set_master)
+{
+       u16 command;
+       if (set_master) {
+               pci_set_master(zr->pci_dev);
+       } else {
+               pci_read_config_word(zr->pci_dev, PCI_COMMAND, &command);
+               command &= ~PCI_COMMAND_MASTER;
+               pci_write_config_word(zr->pci_dev, PCI_COMMAND, command);
+       }
+}
+
+void
+zoran_init_hardware (struct zoran *zr)
+{
+       int j, zero = 0;
+       /* Enable bus-mastering */
+       zoran_set_pci_master(zr, 1);
+
+       /* Initialize the board */
+       if (zr->card.init) {
+               zr->card.init(zr);
+       }
+
+       j = zr->card.input[zr->input].muxsel;
+
+       decoder_command(zr, 0, NULL);
+       decoder_command(zr, DECODER_SET_NORM, &zr->norm);
+       decoder_command(zr, DECODER_SET_INPUT, &j);
+
+       encoder_command(zr, 0, NULL);
+       encoder_command(zr, ENCODER_SET_NORM, &zr->norm);
+       encoder_command(zr, ENCODER_SET_INPUT, &zero);
+
+       /* toggle JPEG codec sleep to sync PLL */
+       jpeg_codec_sleep(zr, 1);
+       jpeg_codec_sleep(zr, 0);
+
+       /* set individual interrupt enables (without GIRQ1)
+        * but don't global enable until zoran_open() */
+
+       //btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ1, ZR36057_ICR);  // SW
+       // It looks like using only JPEGRepIRQEn is not always reliable,
+       // may be when JPEG codec crashes it won't generate IRQ? So,
+        /*CP*/                 //        btwrite(IRQ_MASK, ZR36057_ICR); // Enable Vsync interrupts too. SM    WHY ? LP
+           zr36057_init_vfe(zr);
+
+       zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+
+       btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts
+}
+
+void
+zr36057_restart (struct zoran *zr)
+{
+       btwrite(0, ZR36057_SPGPPCR);
+       mdelay(1);
+       btor(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR);
+       mdelay(1);
+
+       /* assert P_Reset */
+       btwrite(0, ZR36057_JPC);
+       /* set up GPIO direction - all output */
+       btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR);
+
+       /* set up GPIO pins and guest bus timing */
+       btwrite((0x81 << 24) | 0x8888, ZR36057_GPPGCR1);
+}
+
+/*
+ * initialize video front end
+ */
+
+void
+zr36057_init_vfe (struct zoran *zr)
+{
+       u32 reg;
+       reg = btread(ZR36057_VFESPFR);
+       reg |= ZR36057_VFESPFR_LittleEndian;
+       reg &= ~ZR36057_VFESPFR_VCLKPol;
+       reg |= ZR36057_VFESPFR_ExtFl;
+       reg |= ZR36057_VFESPFR_TopField;
+       btwrite(reg, ZR36057_VFESPFR);
+       reg = btread(ZR36057_VDCR);
+       if (pci_pci_problems & PCIPCI_TRITON)
+               // || zr->revision < 1) // Revision 1 has also Triton support
+               reg &= ~ZR36057_VDCR_Triton;
+       else
+               reg |= ZR36057_VDCR_Triton;
+       btwrite(reg, ZR36057_VDCR);
+}
+
+/*
+ * Interface to decoder and encoder chips using i2c bus
+ */
+
+int
+decoder_command (struct zoran *zr,
+                int           cmd,
+                void         *data)
+{
+       if (zr->decoder == NULL)
+               return -EIO;
+
+       if (zr->card.type == LML33 &&
+           (cmd == DECODER_SET_NORM || DECODER_SET_INPUT)) {
+               int res;
+               // Bt819 needs to reset its FIFO buffer using #FRST pin and
+               // LML33 card uses GPIO(7) for that.
+               GPIO(zr, 7, 0);
+               res = zr->decoder->driver->command(zr->decoder, cmd, data);
+               // Pull #FRST high.
+               GPIO(zr, 7, 1);
+               return res;
+       } else
+               return zr->decoder->driver->command(zr->decoder, cmd,
+                                                   data);
+}
+
+int
+encoder_command (struct zoran *zr,
+                int           cmd,
+                void         *data)
+{
+       if (zr->encoder == NULL)
+               return -1;
+
+       return zr->encoder->driver->command(zr->encoder, cmd, data);
+}
diff --git a/drivers/media/video/zoran_device.h b/drivers/media/video/zoran_device.h
new file mode 100644 (file)
index 0000000..3f68b57
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles card-specific data and detection
+ * 
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.net>
+ *
+ * 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 __ZORAN_DEVICE_H__
+#define __ZORAN_DEVICE_H__
+
+/* general purpose I/O */
+extern void GPIO(struct zoran *zr,
+                int bit,
+                unsigned int value);
+
+/* codec (or actually: guest bus) access */
+extern int post_office_wait(struct zoran *zr);
+extern int post_office_write(struct zoran *zr,
+                            unsigned guest,
+                            unsigned reg,
+                            unsigned value);
+extern int post_office_read(struct zoran *zr,
+                           unsigned guest,
+                           unsigned reg);
+
+extern void detect_guest_activity(struct zoran *zr);
+
+extern void jpeg_codec_sleep(struct zoran *zr,
+                            int sleep);
+extern int jpeg_codec_reset(struct zoran *zr);
+
+/* zr360x7 access to raw capture */
+extern void zr36057_overlay(struct zoran *zr,
+                           int on);
+extern void write_overlay_mask(struct file *file,
+                              struct video_clip *vp,
+                              int count);
+extern void zr36057_set_memgrab(struct zoran *zr,
+                               int mode);
+extern int wait_grab_pending(struct zoran *zr);
+
+/* interrupts */
+extern void print_interrupts(struct zoran *zr);
+extern void clear_interrupt_counters(struct zoran *zr);
+extern irqreturn_t zoran_irq(int irq,
+                            void *dev_id,
+                            struct pt_regs *regs);
+
+/* JPEG codec access */
+extern void jpeg_start(struct zoran *zr);
+extern void zr36057_enable_jpg(struct zoran *zr,
+                              enum zoran_codec_mode mode);
+extern void zoran_feed_stat_com(struct zoran *zr);
+
+/* general */
+extern void zoran_set_pci_master(struct zoran *zr,
+                                int set_master);
+extern void zoran_init_hardware(struct zoran *zr);
+extern void zr36057_restart(struct zoran *zr);
+extern void zr36057_init_vfe(struct zoran *zr);
+
+/* i2c */
+extern int decoder_command(struct zoran *zr,
+                          int cmd,
+                          void *data);
+extern int encoder_command(struct zoran *zr,
+                          int cmd,
+                          void *data);
+
+#endif                         /* __ZORAN_DEVICE_H__ */
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
new file mode 100644 (file)
index 0000000..d2d5da0
--- /dev/null
@@ -0,0 +1,4669 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Changes for BUZ by Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Changes for DC10/DC30 by Laurent Pinchart <laurent.pinchart@skynet.be>
+ *
+ * Changes for LML33R10 by Maxim Yevtyushkin <max@linuxmedialabs.com>
+ *
+ * Changes for videodev2/v4l2 by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * Based on
+ *
+ * Miro DC10 driver
+ * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Iomega Buz driver version 1.0
+ * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
+ *
+ * buz.0.0.3
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * bttv - Bt848 frame grabber driver
+ * Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+ *                        & Marcus Metzler (mocm@thp.uni-koeln.de)
+ *
+ *
+ * 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/config.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <linux/spinlock.h>
+#define     MAP_NR(x)       virt_to_page(x)
+#define     ZORAN_HARDWARE  VID_HARDWARE_ZR36067
+#define     ZORAN_VID_TYPE  ( \
+                               VID_TYPE_CAPTURE | \
+                               VID_TYPE_OVERLAY | \
+                               VID_TYPE_CLIPPING | \
+                               VID_TYPE_FRAMERAM | \
+                               VID_TYPE_SCALES | \
+                               VID_TYPE_MJPEG_DECODER | \
+                               VID_TYPE_MJPEG_ENCODER \
+                            )
+
+#include <linux/videodev.h>
+#include "videocodec.h"
+
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+
+#include <linux/video_decoder.h>
+#include <linux/video_encoder.h>
+#include "zoran.h"
+#include "zoran_device.h"
+#include "zoran_card.h"
+
+#ifdef HAVE_V4L2
+       /* we declare some card type definitions here, they mean
+        * the same as the v4l1 ZORAN_VID_TYPE above, except it's v4l2 */
+#define ZORAN_V4L2_VID_FLAGS ( \
+                               V4L2_CAP_STREAMING |\
+                               V4L2_CAP_VIDEO_CAPTURE |\
+                               V4L2_CAP_VIDEO_OUTPUT |\
+                               V4L2_CAP_VIDEO_OVERLAY \
+                              )
+#endif
+
+#include <asm/byteorder.h>
+
+const struct zoran_format zoran_formats[] = {
+       {
+               .name = "15-bit RGB",
+               .palette = VIDEO_PALETTE_RGB555,
+#ifdef HAVE_V4L2
+#ifdef __LITTLE_ENDIAN
+               .fourcc = V4L2_PIX_FMT_RGB555,
+#else
+               .fourcc = V4L2_PIX_FMT_RGB555X,
+#endif
+               .colorspace = V4L2_COLORSPACE_SRGB,
+#endif
+               .depth = 15,
+               .flags = ZORAN_FORMAT_CAPTURE |
+                        ZORAN_FORMAT_OVERLAY,
+       }, {
+               .name = "16-bit RGB",
+               .palette = VIDEO_PALETTE_RGB565,
+#ifdef HAVE_V4L2
+#ifdef __LITTLE_ENDIAN
+               .fourcc = V4L2_PIX_FMT_RGB565,
+#else
+               .fourcc = V4L2_PIX_FMT_RGB565X,
+#endif
+               .colorspace = V4L2_COLORSPACE_SRGB,
+#endif
+               .depth = 16,
+               .flags = ZORAN_FORMAT_CAPTURE |
+                        ZORAN_FORMAT_OVERLAY,
+       }, {
+               .name = "24-bit RGB",
+               .palette = VIDEO_PALETTE_RGB24,
+#ifdef HAVE_V4L2
+#ifdef __LITTLE_ENDIAN
+               .fourcc = V4L2_PIX_FMT_BGR24,
+#else
+               .fourcc = V4L2_PIX_FMT_RGB24,
+#endif
+               .colorspace = V4L2_COLORSPACE_SRGB,
+#endif
+               .depth = 24,
+               .flags = ZORAN_FORMAT_CAPTURE |
+                        ZORAN_FORMAT_OVERLAY,
+       }, {
+               .name = "32-bit RGB",
+               .palette = VIDEO_PALETTE_RGB32,
+#ifdef HAVE_V4L2
+#ifdef __LITTLE_ENDIAN
+               .fourcc = V4L2_PIX_FMT_BGR32,
+#else
+               .fourcc = V4L2_PIX_FMT_RGB32,
+#endif
+               .colorspace = V4L2_COLORSPACE_SRGB,
+#endif
+               .depth = 32,
+               .flags = ZORAN_FORMAT_CAPTURE |
+                        ZORAN_FORMAT_OVERLAY,
+       }, {
+               .name = "4:2:2, packed, YUYV",
+               .palette = VIDEO_PALETTE_YUV422,
+#ifdef HAVE_V4L2
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .colorspace = V4L2_COLORSPACE_SMPTE170M,
+#endif
+               .depth = 16,
+               .flags = ZORAN_FORMAT_CAPTURE |
+                        ZORAN_FORMAT_OVERLAY,
+       }, {
+               .name = "Hardware-encoded Motion-JPEG",
+               .palette = -1,
+#ifdef HAVE_V4L2
+               .fourcc = V4L2_PIX_FMT_MJPEG,
+               .colorspace = V4L2_COLORSPACE_SMPTE170M,
+#endif
+               .depth = 0,
+               .flags = ZORAN_FORMAT_CAPTURE |
+                        ZORAN_FORMAT_PLAYBACK |
+                        ZORAN_FORMAT_COMPRESSED,
+       }
+};
+const int zoran_num_formats =
+    (sizeof(zoran_formats) / sizeof(struct zoran_format));
+
+// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
+#if !defined(CONFIG_BIGPHYS_AREA)
+//#undef CONFIG_BIGPHYS_AREA
+#define BUZ_USE_HIMEM
+#endif
+
+#if defined(CONFIG_BIGPHYS_AREA)
+#   include <linux/bigphysarea.h>
+#endif
+
+extern int debug;
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
+
+extern int v4l_nbufs;
+extern int v4l_bufsize;
+extern int jpg_nbufs;
+extern int jpg_bufsize;
+extern int pass_through;
+
+static int lock_norm = 0;      /* 1=Don't change TV standard (norm) */
+MODULE_PARM(lock_norm, "i");
+MODULE_PARM_DESC(lock_norm, "Users can't change norm");
+
+#ifdef HAVE_V4L2
+       /* small helper function for calculating buffersizes for v4l2
+        * we calculate the nearest higher power-of-two, which
+        * will be the recommended buffersize */
+static __u32
+zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings)
+{
+       __u8 div = settings->VerDcm * settings->HorDcm * settings->TmpDcm;
+       __u32 num = (1024 * 512) / (div);
+       __u32 result = 2;
+
+       num--;
+       while (num) {
+               num >>= 1;
+               result <<= 1;
+       }
+
+       if (result > jpg_bufsize)
+               return jpg_bufsize;
+       if (result < 8192)
+               return 8192;
+       return result;
+}
+#endif
+
+/* forward references */
+static void v4l_fbuffer_free(struct file *file);
+static void jpg_fbuffer_free(struct file *file);
+
+/*
+ *   Allocate the V4L grab buffers
+ *
+ *   These have to be pysically contiguous.
+ *   If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc
+ *   else we try to allocate them with bigphysarea_alloc_pages
+ *   if the bigphysarea patch is present in the kernel,
+ *   else we try to use high memory (if the user has bootet
+ *   Linux with the necessary memory left over).
+ */
+
+#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
+static unsigned long
+get_high_mem (unsigned long size)
+{
+/*
+ * Check if there is usable memory at the end of Linux memory
+ * of at least size. Return the physical address of this memory,
+ * return 0 on failure.
+ *
+ * The idea is from Alexandro Rubini's book "Linux device drivers".
+ * The driver from him which is downloadable from O'Reilly's
+ * web site misses the "virt_to_phys(high_memory)" part
+ * (and therefore doesn't work at all - at least with 2.2.x kernels).
+ *
+ * It should be unnecessary to mention that THIS IS DANGEROUS,
+ * if more than one driver at a time has the idea to use this memory!!!!
+ */
+
+       volatile unsigned char *mem;
+       unsigned char c;
+       unsigned long hi_mem_ph;
+       unsigned long i;
+
+       /* Map the high memory to user space */
+
+       hi_mem_ph = virt_to_phys(high_memory);
+
+       mem = ioremap(hi_mem_ph, size);
+       if (!mem) {
+               dprintk(1,
+                       KERN_ERR "%s: get_high_mem() - ioremap failed\n",
+                       ZORAN_NAME);
+               return 0;
+       }
+
+       for (i = 0; i < size; i++) {
+               /* Check if it is memory */
+               c = i & 0xff;
+               mem[i] = c;
+               if (mem[i] != c)
+                       break;
+               c = 255 - c;
+               mem[i] = c;
+               if (mem[i] != c)
+                       break;
+               mem[i] = 0;     /* zero out memory */
+
+               /* give the kernel air to breath */
+               if ((i & 0x3ffff) == 0x3ffff)
+                       schedule();
+       }
+
+       iounmap((void *) mem);
+
+       if (i != size) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: get_high_mem() - requested %lu, avail %lu\n",
+                       ZORAN_NAME, size, i);
+               return 0;
+       }
+
+       return hi_mem_ph;
+}
+#endif
+
+static int
+v4l_fbuffer_alloc (struct file *file)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       int i, off;
+       unsigned char *mem;
+#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
+       unsigned long pmem = 0;
+#endif
+
+       /* we might have old buffers lying around... */
+       if (fh->v4l_buffers.ready_to_be_freed) {
+               v4l_fbuffer_free(file);
+       }
+
+       for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
+               if (fh->v4l_buffers.buffer[i].fbuffer)
+                       dprintk(2,
+                               KERN_WARNING
+                               "%s: v4l_fbuffer_alloc() - buffer %d allready allocated!?\n",
+                               ZR_DEVNAME(zr), i);
+
+               //udelay(20);
+               if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) {
+                       /* Use kmalloc */
+
+                       mem =
+                           (unsigned char *) kmalloc(fh->v4l_buffers.
+                                                     buffer_size,
+                                                     GFP_KERNEL);
+                       if (mem == 0) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: v4l_fbuffer_alloc() - kmalloc for V4L buf %d failed\n",
+                                       ZR_DEVNAME(zr), i);
+                               v4l_fbuffer_free(file);
+                               return -ENOBUFS;
+                       }
+                       fh->v4l_buffers.buffer[i].fbuffer = mem;
+                       fh->v4l_buffers.buffer[i].fbuffer_phys =
+                           virt_to_phys(mem);
+                       fh->v4l_buffers.buffer[i].fbuffer_bus =
+                           virt_to_bus(mem);
+                       for (off = 0; off < fh->v4l_buffers.buffer_size;
+                            off += PAGE_SIZE)
+                               SetPageReserved(MAP_NR(mem + off));
+                       dprintk(4,
+                               KERN_INFO
+                               "%s: v4l_fbuffer_alloc() - V4L frame %d mem 0x%lx (bus: 0x%lx)\n",
+                               ZR_DEVNAME(zr), i, (unsigned long) mem,
+                               virt_to_bus(mem));
+               } else {
+#if defined(CONFIG_BIGPHYS_AREA)
+                       /* Use bigphysarea_alloc_pages */
+
+                       int n =
+                           (fh->v4l_buffers.buffer_size + PAGE_SIZE -
+                            1) / PAGE_SIZE;
+                       mem =
+                           (unsigned char *) bigphysarea_alloc_pages(n, 0,
+                                                                     GFP_KERNEL);
+                       if (mem == 0) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: v4l_fbuffer_alloc() - bigphysarea_alloc_pages for V4L buf %d failed\n",
+                                       ZR_DEVNAME(zr), i);
+                               v4l_fbuffer_free(file);
+                               return -ENOBUFS;
+                       }
+                       fh->v4l_buffers.buffer[i].fbuffer = mem;
+                       fh->v4l_buffers.buffer[i].fbuffer_phys =
+                           virt_to_phys(mem);
+                       fh->v4l_buffers.buffer[i].fbuffer_bus =
+                           virt_to_bus(mem);
+                       dprintk(4,
+                               KERN_INFO
+                               "%s: Bigphysarea frame %d mem 0x%x (bus: 0x%x)\n",
+                               ZR_DEVNAME(zr), i, (unsigned) mem,
+                               (unsigned) virt_to_bus(mem));
+
+                       /* Zero out the allocated memory */
+                       memset(fh->v4l_buffers.buffer[i].fbuffer, 0,
+                              fh->v4l_buffers.buffer_size);
+#elif defined(BUZ_USE_HIMEM)
+
+                       /* Use high memory which has been left at boot time */
+
+                       /* Ok., Ok. this is an evil hack - we make
+                        * the assumption that physical addresses are
+                        * the same as bus addresses (true at least
+                        * for Intel processors). The whole method of
+                        * obtaining and using this memory is not very
+                        * nice - but I hope it saves some poor users
+                        * from kernel hacking, which might have even
+                        * more evil results */
+
+                       if (i == 0) {
+                               int size =
+                                   fh->v4l_buffers.num_buffers *
+                                   fh->v4l_buffers.buffer_size;
+                               pmem = get_high_mem(size);
+                               if (pmem == 0) {
+                                       dprintk(1,
+                                               KERN_ERR
+                                               "%s: v4l_fbuffer_alloc() - get_high_mem (size = %d KB) for V4L bufs failed\n",
+                                               ZR_DEVNAME(zr), size >> 10);
+                                       return -ENOBUFS;
+                               }
+                               fh->v4l_buffers.buffer[0].fbuffer = 0;
+                               fh->v4l_buffers.buffer[0].fbuffer_phys =
+                                   pmem;
+                               fh->v4l_buffers.buffer[0].fbuffer_bus =
+                                   pmem;
+                               dprintk(4,
+                                       KERN_INFO
+                                       "%s: v4l_fbuffer_alloc() - using %d KB high memory\n",
+                                       ZR_DEVNAME(zr), size >> 10);
+                       } else {
+                               fh->v4l_buffers.buffer[i].fbuffer = 0;
+                               fh->v4l_buffers.buffer[i].fbuffer_phys =
+                                   pmem + i * fh->v4l_buffers.buffer_size;
+                               fh->v4l_buffers.buffer[i].fbuffer_bus =
+                                   pmem + i * fh->v4l_buffers.buffer_size;
+                       }
+#else
+                       /* No bigphysarea present, usage of high memory disabled,
+                        * but user wants buffers of more than MAX_KMALLOC_MEM */
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: v4l_fbuffer_alloc() - no bigphysarea_patch present, usage of high memory disabled,\n",
+                               ZR_DEVNAME(zr));
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: v4l_fbuffer_alloc() - sorry, could not allocate %d V4L buffers of size %d KB.\n",
+                               ZR_DEVNAME(zr), fh->v4l_buffers.num_buffers,
+                               fh->v4l_buffers.buffer_size >> 10);
+                       return -ENOBUFS;
+#endif
+               }
+       }
+
+       fh->v4l_buffers.allocated = 1;
+
+       return 0;
+}
+
+/* free the V4L grab buffers */
+static void
+v4l_fbuffer_free (struct file *file)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       int i, off;
+       unsigned char *mem;
+
+       dprintk(4, KERN_INFO "%s: v4l_fbuffer_free()\n", ZR_DEVNAME(zr));
+
+       for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
+               if (!fh->v4l_buffers.buffer[i].fbuffer)
+                       continue;
+
+               if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) {
+                       mem = fh->v4l_buffers.buffer[i].fbuffer;
+                       for (off = 0; off < fh->v4l_buffers.buffer_size;
+                            off += PAGE_SIZE)
+                               ClearPageReserved(MAP_NR(mem + off));
+                       kfree((void *) fh->v4l_buffers.buffer[i].fbuffer);
+               }
+#if defined(CONFIG_BIGPHYS_AREA)
+               else
+                       bigphysarea_free_pages((void *) fh->v4l_buffers.
+                                              buffer[i].fbuffer);
+#endif
+               fh->v4l_buffers.buffer[i].fbuffer = NULL;
+       }
+
+       fh->v4l_buffers.allocated = 0;
+       fh->v4l_buffers.ready_to_be_freed = 0;
+}
+
+/*
+ *   Allocate the MJPEG grab buffers.
+ *
+ *   If the requested buffer size is smaller than MAX_KMALLOC_MEM,
+ *   kmalloc is used to request a physically contiguous area,
+ *   else we allocate the memory in framgents with get_zeroed_page.
+ *
+ *   If a Natoma chipset is present and this is a revision 1 zr36057,
+ *   each MJPEG buffer needs to be physically contiguous.
+ *   (RJ: This statement is from Dave Perks' original driver,
+ *   I could never check it because I have a zr36067)
+ *   The driver cares about this because it reduces the buffer
+ *   size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation).
+ *
+ *   RJ: The contents grab buffers needs never be accessed in the driver.
+ *       Therefore there is no need to allocate them with vmalloc in order
+ *       to get a contiguous virtual memory space.
+ *       I don't understand why many other drivers first allocate them with
+ *       vmalloc (which uses internally also get_zeroed_page, but delivers you
+ *       virtual addresses) and then again have to make a lot of efforts
+ *       to get the physical address.
+ *
+ */
+
+static int
+jpg_fbuffer_alloc (struct file *file)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       int i, j, off;
+       unsigned long mem;
+
+       /* we might have old buffers lying around */
+       if (fh->jpg_buffers.ready_to_be_freed) {
+               jpg_fbuffer_free(file);
+       }
+
+       for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
+               if (fh->jpg_buffers.buffer[i].frag_tab)
+                       dprintk(2,
+                               KERN_WARNING
+                               "%s: jpg_fbuffer_alloc() - buffer %d allready allocated!?\n",
+                               ZR_DEVNAME(zr), i);
+
+               /* Allocate fragment table for this buffer */
+
+               mem = get_zeroed_page(GFP_KERNEL);
+               if (mem == 0) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: jpg_fbuffer_alloc() - get_zeroed_page (frag_tab) failed for buffer %d\n",
+                               ZR_DEVNAME(zr), i);
+                       jpg_fbuffer_free(file);
+                       return -ENOBUFS;
+               }
+               memset((void *) mem, 0, PAGE_SIZE);
+               fh->jpg_buffers.buffer[i].frag_tab = (u32 *) mem;
+               fh->jpg_buffers.buffer[i].frag_tab_bus =
+                   virt_to_bus((void *) mem);
+
+               //if (alloc_contig) {
+               if (fh->jpg_buffers.need_contiguous) {
+                       mem =
+                           (unsigned long) kmalloc(fh->jpg_buffers.
+                                                   buffer_size,
+                                                   GFP_KERNEL);
+                       if (mem == 0) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: jpg_fbuffer_alloc() - kmalloc failed for buffer %d\n",
+                                       ZR_DEVNAME(zr), i);
+                               jpg_fbuffer_free(file);
+                               return -ENOBUFS;
+                       }
+                       fh->jpg_buffers.buffer[i].frag_tab[0] =
+                           virt_to_bus((void *) mem);
+                       fh->jpg_buffers.buffer[i].frag_tab[1] =
+                           ((fh->jpg_buffers.buffer_size / 4) << 1) | 1;
+                       for (off = 0; off < fh->jpg_buffers.buffer_size;
+                            off += PAGE_SIZE)
+                               SetPageReserved(MAP_NR(mem + off));
+               } else {
+                       /* jpg_bufsize is allreay page aligned */
+                       for (j = 0;
+                            j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
+                            j++) {
+                               mem = get_zeroed_page(GFP_KERNEL);
+                               if (mem == 0) {
+                                       dprintk(1,
+                                               KERN_ERR
+                                               "%s: jpg_fbuffer_alloc() - get_zeroed_page failed for buffer %d\n",
+                                               ZR_DEVNAME(zr), i);
+                                       jpg_fbuffer_free(file);
+                                       return -ENOBUFS;
+                               }
+
+                               fh->jpg_buffers.buffer[i].frag_tab[2 * j] =
+                                   virt_to_bus((void *) mem);
+                               fh->jpg_buffers.buffer[i].frag_tab[2 * j +
+                                                                  1] =
+                                   (PAGE_SIZE / 4) << 1;
+                               SetPageReserved(MAP_NR(mem));
+                       }
+
+                       fh->jpg_buffers.buffer[i].frag_tab[2 * j - 1] |= 1;
+               }
+       }
+
+       dprintk(4,
+               KERN_DEBUG "%s: jpg_fbuffer_alloc() - %d KB allocated\n",
+               ZR_DEVNAME(zr),
+               (fh->jpg_buffers.num_buffers *
+                fh->jpg_buffers.buffer_size) >> 10);
+
+       fh->jpg_buffers.allocated = 1;
+
+       return 0;
+}
+
+/* free the MJPEG grab buffers */
+static void
+jpg_fbuffer_free (struct file *file)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       int i, j, off;
+       unsigned char *mem;
+
+       dprintk(4, KERN_DEBUG "%s: jpg_fbuffer_free()\n", ZR_DEVNAME(zr));
+
+       for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
+               if (!fh->jpg_buffers.buffer[i].frag_tab)
+                       continue;
+
+               //if (alloc_contig) {
+               if (fh->jpg_buffers.need_contiguous) {
+                       if (fh->jpg_buffers.buffer[i].frag_tab[0]) {
+                               mem =
+                                   (unsigned char *) bus_to_virt(fh->
+                                                                 jpg_buffers.
+                                                                 buffer
+                                                                 [i].
+                                                                 frag_tab
+                                                                 [0]);
+                               for (off = 0;
+                                    off < fh->jpg_buffers.buffer_size;
+                                    off += PAGE_SIZE)
+                                       ClearPageReserved(MAP_NR
+                                                         (mem + off));
+                               kfree((void *) mem);
+                               fh->jpg_buffers.buffer[i].frag_tab[0] = 0;
+                               fh->jpg_buffers.buffer[i].frag_tab[1] = 0;
+                       }
+               } else {
+                       for (j = 0;
+                            j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
+                            j++) {
+                               if (!fh->jpg_buffers.buffer[i].
+                                   frag_tab[2 * j])
+                                       break;
+                               ClearPageReserved(MAP_NR
+                                                 (bus_to_virt
+                                                  (fh->jpg_buffers.
+                                                   buffer[i].frag_tab[2 *
+                                                                      j])));
+                               free_page((unsigned long)
+                                         bus_to_virt(fh->jpg_buffers.
+                                                     buffer[i].
+                                                     frag_tab[2 * j]));
+                               fh->jpg_buffers.buffer[i].frag_tab[2 * j] =
+                                   0;
+                               fh->jpg_buffers.buffer[i].frag_tab[2 * j +
+                                                                  1] = 0;
+                       }
+               }
+
+               free_page((unsigned long) fh->jpg_buffers.buffer[i].
+                         frag_tab);
+               fh->jpg_buffers.buffer[i].frag_tab = NULL;
+       }
+
+       fh->jpg_buffers.allocated = 0;
+       fh->jpg_buffers.ready_to_be_freed = 0;
+}
+
+/*
+ *   V4L Buffer grabbing
+ */
+
+static int
+zoran_v4l_set_format (struct file               *file,
+                     int                        width,
+                     int                        height,
+                     const struct zoran_format *format)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       int bpp;
+
+       /* Check size and format of the grab wanted */
+
+       if (height < BUZ_MIN_HEIGHT || width < BUZ_MIN_WIDTH ||
+           height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: v4l_set_format() - wrong frame size (%dx%d)\n",
+                       ZR_DEVNAME(zr), width, height);
+               return -EINVAL;
+       }
+
+       bpp = (format->depth + 7) / 8;
+
+       /* Check against available buffer size */
+       if (height * width * bpp > fh->v4l_buffers.buffer_size) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: v4l_set_format() - video buffer size (%d kB) is too small\n",
+                       ZR_DEVNAME(zr), fh->v4l_buffers.buffer_size >> 10);
+               return -EINVAL;
+       }
+
+       /* The video front end needs 4-byte alinged line sizes */
+
+       if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: v4l_set_format() - wrong frame alingment\n",
+                       ZR_DEVNAME(zr));
+               return -EINVAL;
+       }
+
+       fh->v4l_settings.width = width;
+       fh->v4l_settings.height = height;
+       fh->v4l_settings.format = format;
+       fh->v4l_settings.bytesperline = bpp * fh->v4l_settings.width;
+
+       return 0;
+}
+
+static int
+zoran_v4l_queue_frame (struct file *file,
+                      int          num)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       unsigned long flags;
+       int res = 0;
+
+       if (!fh->v4l_buffers.allocated) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: v4l_queue_frame() - buffers not yet allocated\n",
+                       ZR_DEVNAME(zr));
+               res = -ENOMEM;
+       }
+
+       /* No grabbing outside the buffer range! */
+       if (num >= fh->v4l_buffers.num_buffers || num < 0) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: v4l_queue_frame() - buffer %d is out of range\n",
+                       ZR_DEVNAME(zr), num);
+               res = -EINVAL;
+       }
+
+       spin_lock_irqsave(&zr->spinlock, flags);
+
+       if (fh->v4l_buffers.active == ZORAN_FREE) {
+               if (zr->v4l_buffers.active == ZORAN_FREE) {
+                       zr->v4l_buffers = fh->v4l_buffers;
+                       fh->v4l_buffers.active = ZORAN_ACTIVE;
+               } else {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: v4l_queue_frame() - another session is already capturing\n",
+                               ZR_DEVNAME(zr));
+                       res = -EBUSY;
+               }
+       }
+
+       /* make sure a grab isn't going on currently with this buffer */
+       if (!res) {
+               switch (zr->v4l_buffers.buffer[num].state) {
+               default:
+               case BUZ_STATE_PEND:
+                       if (zr->v4l_buffers.active == ZORAN_FREE) {
+                               fh->v4l_buffers.active = ZORAN_FREE;
+                               zr->v4l_buffers.allocated = 0;
+                       }
+                       res = -EBUSY;   /* what are you doing? */
+                       break;
+               case BUZ_STATE_DONE:
+                       dprintk(2,
+                               KERN_WARNING
+                               "%s: v4l_queue_frame() - queueing buffer %d in state DONE!?\n",
+                               ZR_DEVNAME(zr), num);
+               case BUZ_STATE_USER:
+                       /* since there is at least one unused buffer there's room for at least
+                        * one more pend[] entry */
+                       zr->v4l_pend[zr->v4l_pend_head++ &
+                                       V4L_MASK_FRAME] = num;
+                       zr->v4l_buffers.buffer[num].state = BUZ_STATE_PEND;
+                       zr->v4l_buffers.buffer[num].bs.length =
+                           fh->v4l_settings.bytesperline *
+                           zr->v4l_settings.height;
+                       fh->v4l_buffers.buffer[num] =
+                           zr->v4l_buffers.buffer[num];
+                       break;
+               }
+       }
+
+       spin_unlock_irqrestore(&zr->spinlock, flags);
+
+       if (!res && zr->v4l_buffers.active == ZORAN_FREE)
+               zr->v4l_buffers.active = fh->v4l_buffers.active;
+
+       return res;
+}
+
+static int
+v4l_grab (struct file       *file,
+         struct video_mmap *mp)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       int res = 0, i;
+
+       for (i = 0; i < zoran_num_formats; i++) {
+               if (zoran_formats[i].palette == mp->format &&
+                   zoran_formats[i].flags & ZORAN_FORMAT_CAPTURE &&
+                   !(zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED))
+                       break;
+       }
+       if (i == zoran_num_formats || zoran_formats[i].depth == 0) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: v4l_grab() - wrong bytes-per-pixel format\n",
+                       ZR_DEVNAME(zr));
+               return -EINVAL;
+       }
+
+       /*
+        * To minimize the time spent in the IRQ routine, we avoid setting up
+        * the video front end there.
+        * If this grab has different parameters from a running streaming capture
+        * we stop the streaming capture and start it over again.
+        */
+       if (zr->v4l_memgrab_active &&
+           (zr->v4l_settings.width != mp->width ||
+            zr->v4l_settings.height != mp->height ||
+            zr->v4l_settings.format->palette != mp->format)) {
+               res = wait_grab_pending(zr);
+               if (res)
+                       return res;
+       }
+       if ((res =
+            zoran_v4l_set_format(file, mp->width, mp->height,
+                                 &zoran_formats[i])))
+               return res;
+       zr->v4l_settings = fh->v4l_settings;
+
+       /* queue the frame in the pending queue */
+       if ((res = zoran_v4l_queue_frame(file, mp->frame))) {
+               fh->v4l_buffers.active = ZORAN_FREE;
+               return res;
+       }
+
+       /* put the 36057 into frame grabbing mode */
+       if (!res && !zr->v4l_memgrab_active)
+               zr36057_set_memgrab(zr, 1);
+
+       //dprintk(4, KERN_INFO "%s: Frame grab 3...\n", ZR_DEVNAME(zr));
+
+       return res;
+}
+
+/*
+ * Sync on a V4L buffer
+ */
+
+static int
+v4l_sync (struct file *file,
+         int          frame)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       unsigned long flags;
+
+       if (fh->v4l_buffers.active == ZORAN_FREE) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: v4l_sync() - no grab active for this session\n",
+                       ZR_DEVNAME(zr));
+               return -EINVAL;
+       }
+
+       /* check passed-in frame number */
+       if (frame >= fh->v4l_buffers.num_buffers || frame < 0) {
+               dprintk(1,
+                       KERN_ERR "%s: v4l_sync() - frame %d is invalid\n",
+                       ZR_DEVNAME(zr), frame);
+               return -EINVAL;
+       }
+
+       /* Check if is buffer was queued at all */
+       if (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_USER) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: v4l_sync() - attempt to sync on a buffer which was not queued?\n",
+                       ZR_DEVNAME(zr));
+               return -EPROTO;
+       }
+
+       /* wait on this buffer to get ready */
+       while (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_PEND) {
+               if (!interruptible_sleep_on_timeout(&zr->v4l_capq, 10 * HZ))
+                       return -ETIME;
+               else if (signal_pending(current))
+                       return -ERESTARTSYS;
+       }
+
+       /* buffer should now be in BUZ_STATE_DONE */
+       if (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_DONE)
+               dprintk(2,
+                       KERN_ERR "%s: v4l_sync() - internal state error\n",
+                       ZR_DEVNAME(zr));
+
+       zr->v4l_buffers.buffer[frame].state = BUZ_STATE_USER;
+       fh->v4l_buffers.buffer[frame] = zr->v4l_buffers.buffer[frame];
+
+       spin_lock_irqsave(&zr->spinlock, flags);
+
+       /* Check if streaming capture has finished */
+       if (zr->v4l_pend_tail == zr->v4l_pend_head) {
+               zr36057_set_memgrab(zr, 0);
+               if (zr->v4l_buffers.active == ZORAN_ACTIVE) {
+                       fh->v4l_buffers.active = zr->v4l_buffers.active =
+                           ZORAN_FREE;
+                       zr->v4l_buffers.allocated = 0;
+               }
+       }
+
+       spin_unlock_irqrestore(&zr->spinlock, flags);
+
+       return 0;
+}
+
+/*
+ *   Queue a MJPEG buffer for capture/playback
+ */
+
+static int
+zoran_jpg_queue_frame (struct file          *file,
+                      int                   num,
+                      enum zoran_codec_mode mode)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       unsigned long flags;
+       int res = 0;
+
+       /* Check if buffers are allocated */
+       if (!fh->jpg_buffers.allocated) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: jpg_queue_frame() - buffers not yet allocated\n",
+                       ZR_DEVNAME(zr));
+               return -ENOMEM;
+       }
+
+       /* No grabbing outside the buffer range! */
+       if (num >= fh->jpg_buffers.num_buffers || num < 0) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: jpg_queue_frame() - buffer %d out of range\n",
+                       ZR_DEVNAME(zr), num);
+               return -EINVAL;
+       }
+
+       /* what is the codec mode right now? */
+       if (zr->codec_mode == BUZ_MODE_IDLE) {
+               zr->jpg_settings = fh->jpg_settings;
+       } else if (zr->codec_mode != mode) {
+               /* wrong codec mode active - invalid */
+               dprintk(1,
+                       KERN_ERR
+                       "%s: jpg_queue_frame() - codec in wrong mode\n",
+                       ZR_DEVNAME(zr));
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&zr->spinlock, flags);
+
+       if (fh->jpg_buffers.active == ZORAN_FREE) {
+               if (zr->jpg_buffers.active == ZORAN_FREE) {
+                       zr->jpg_buffers = fh->jpg_buffers;
+                       fh->jpg_buffers.active = ZORAN_ACTIVE;
+               } else {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: jpg_queue_frame() - another session is already capturing\n",
+                               ZR_DEVNAME(zr));
+                       res = -EBUSY;
+               }
+       }
+
+       if (!res && zr->codec_mode == BUZ_MODE_IDLE) {
+               /* Ok load up the jpeg codec */
+               zr36057_enable_jpg(zr, mode);
+       }
+
+       if (!res) {
+               switch (zr->jpg_buffers.buffer[num].state) {
+               case BUZ_STATE_DONE:
+                       dprintk(2,
+                               KERN_WARNING
+                               "%s: jpg_queue_frame() - queing frame in BUZ_STATE_DONE state!?\n",
+                               ZR_DEVNAME(zr));
+               case BUZ_STATE_USER:
+                       /* since there is at least one unused buffer there's room for at
+                        *least one more pend[] entry */
+                       zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] =
+                           num;
+                       zr->jpg_buffers.buffer[num].state = BUZ_STATE_PEND;
+                       fh->jpg_buffers.buffer[num] =
+                           zr->jpg_buffers.buffer[num];
+                       zoran_feed_stat_com(zr);
+                       break;
+               default:
+               case BUZ_STATE_DMA:
+               case BUZ_STATE_PEND:
+                       if (zr->jpg_buffers.active == ZORAN_FREE) {
+                               fh->jpg_buffers.active = ZORAN_FREE;
+                               zr->jpg_buffers.allocated = 0;
+                       }
+                       res = -EBUSY;   /* what are you doing? */
+                       break;
+               }
+       }
+
+       spin_unlock_irqrestore(&zr->spinlock, flags);
+
+       if (!res && zr->jpg_buffers.active == ZORAN_FREE) {
+               zr->jpg_buffers.active = fh->jpg_buffers.active;
+       }
+
+       return res;
+}
+
+static int
+jpg_qbuf (struct file          *file,
+         int                   frame,
+         enum zoran_codec_mode mode)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       int res = 0;
+
+       /* Does the user want to stop streaming? */
+       if (frame < 0) {
+               if (zr->codec_mode == mode) {
+                       if (fh->jpg_buffers.active == ZORAN_FREE) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: jpg_qbuf(-1) - session not active\n",
+                                       ZR_DEVNAME(zr));
+                               return -EINVAL;
+                       }
+                       fh->jpg_buffers.active = zr->jpg_buffers.active =
+                           ZORAN_FREE;
+                       zr->jpg_buffers.allocated = 0;
+                       zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+                       return 0;
+               } else {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: jpg_qbuf() - stop streaming but not in streaming mode\n",
+                               ZR_DEVNAME(zr));
+                       return -EINVAL;
+               }
+       }
+
+       if ((res = zoran_jpg_queue_frame(file, frame, mode)))
+               return res;
+
+       /* Start the jpeg codec when the first frame is queued  */
+       if (!res && zr->jpg_que_head == 1)
+               jpeg_start(zr);
+
+       return res;
+}
+
+/*
+ *   Sync on a MJPEG buffer
+ */
+
+static int
+jpg_sync (struct file       *file,
+         struct zoran_sync *bs)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       unsigned long flags;
+       int frame, timeout;
+
+       if (fh->jpg_buffers.active == ZORAN_FREE) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: jpg_sync() - capture is not currently active\n",
+                       ZR_DEVNAME(zr));
+               return -EINVAL;
+       }
+       if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS &&
+           zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: jpg_sync() - codec not in streaming mode\n",
+                       ZR_DEVNAME(zr));
+               return -EINVAL;
+       }
+       while (zr->jpg_que_tail == zr->jpg_dma_tail) {
+               if (zr->jpg_dma_tail == zr->jpg_dma_head)
+                       break;
+
+               timeout =
+                   interruptible_sleep_on_timeout(&zr->jpg_capq, 10 * HZ);
+               if (!timeout) {
+                       int isr;
+
+                       btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
+                       udelay(1);
+                       zr->codec->control(zr->codec, CODEC_G_STATUS,
+                                          sizeof(isr), &isr);
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: jpg_sync() - timeout: codec isr=0x%02x\n",
+                               ZR_DEVNAME(zr), isr);
+
+                       return -ETIME;
+
+               } else if (signal_pending(current))
+                       return -ERESTARTSYS;
+       }
+
+       spin_lock_irqsave(&zr->spinlock, flags);
+
+       if (zr->jpg_dma_tail != zr->jpg_dma_head)
+               frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME];
+       else
+               frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
+
+       /* buffer should now be in BUZ_STATE_DONE */
+       if (debug > 0)
+               if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE)
+                       dprintk(2,
+                               KERN_ERR
+                               "%s: jpg_sync() - internal state error\n",
+                               ZR_DEVNAME(zr));
+
+       *bs = zr->jpg_buffers.buffer[frame].bs;
+       bs->frame = frame;
+       zr->jpg_buffers.buffer[frame].state = BUZ_STATE_USER;
+       fh->jpg_buffers.buffer[frame] = zr->jpg_buffers.buffer[frame];
+
+       spin_unlock_irqrestore(&zr->spinlock, flags);
+
+       return 0;
+}
+
+static void
+zoran_open_init_session (struct file *file)
+{
+       int i;
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+
+       /* Per default, map the V4L Buffers */
+       fh->map_mode = ZORAN_MAP_MODE_RAW;
+
+       /* take over the card's current settings */
+       fh->overlay_settings = zr->overlay_settings;
+       fh->overlay_settings.is_set = 0;
+       fh->overlay_settings.format = zr->overlay_settings.format;
+       fh->overlay_active = ZORAN_FREE;
+
+       /* v4l settings */
+       fh->v4l_settings = zr->v4l_settings;
+
+       /* v4l_buffers */
+       memset(&fh->v4l_buffers, 0, sizeof(struct zoran_v4l_struct));
+       for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+               fh->v4l_buffers.buffer[i].state = BUZ_STATE_USER;       /* nothing going on */
+               fh->v4l_buffers.buffer[i].bs.frame = i;
+       }
+       fh->v4l_buffers.allocated = 0;
+       fh->v4l_buffers.ready_to_be_freed = 0;
+       fh->v4l_buffers.active = ZORAN_FREE;
+       fh->v4l_buffers.buffer_size = v4l_bufsize;
+       fh->v4l_buffers.num_buffers = v4l_nbufs;
+
+       /* jpg settings */
+       fh->jpg_settings = zr->jpg_settings;
+
+       /* jpg_buffers */
+       memset(&fh->jpg_buffers, 0, sizeof(struct zoran_jpg_struct));
+       for (i = 0; i < BUZ_MAX_FRAME; i++) {
+               fh->jpg_buffers.buffer[i].state = BUZ_STATE_USER;       /* nothing going on */
+               fh->jpg_buffers.buffer[i].bs.frame = i;
+       }
+       fh->jpg_buffers.need_contiguous = zr->jpg_buffers.need_contiguous;
+       fh->jpg_buffers.allocated = 0;
+       fh->jpg_buffers.ready_to_be_freed = 0;
+       fh->jpg_buffers.active = ZORAN_FREE;
+       fh->jpg_buffers.buffer_size = jpg_bufsize;
+       fh->jpg_buffers.num_buffers = jpg_nbufs;
+}
+
+static void
+zoran_close_end_session (struct file *file)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+
+       /* overlay */
+       if (fh->overlay_active != ZORAN_FREE) {
+               fh->overlay_active = zr->overlay_active = ZORAN_FREE;
+               zr->v4l_overlay_active = 0;
+               if (!zr->v4l_memgrab_active)
+                       zr36057_overlay(zr, 0);
+               zr->overlay_mask = NULL;
+       }
+
+       /* v4l capture */
+       if (fh->v4l_buffers.active != ZORAN_FREE) {
+               zr36057_set_memgrab(zr, 0);
+               zr->v4l_buffers.allocated = 0;
+               zr->v4l_buffers.active = fh->v4l_buffers.active =
+                   ZORAN_FREE;
+       }
+
+       /* v4l buffers */
+       if (fh->v4l_buffers.allocated ||
+           fh->v4l_buffers.ready_to_be_freed) {
+               v4l_fbuffer_free(file);
+       }
+
+       /* jpg capture */
+       if (fh->jpg_buffers.active != ZORAN_FREE) {
+               zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+               zr->jpg_buffers.allocated = 0;
+               zr->jpg_buffers.active = fh->jpg_buffers.active =
+                   ZORAN_FREE;
+       }
+
+       /* jpg buffers */
+       if (fh->jpg_buffers.allocated ||
+           fh->jpg_buffers.ready_to_be_freed) {
+               jpg_fbuffer_free(file);
+       }
+}
+
+/*
+ *   Open a zoran card. Right now the flags stuff is just playing
+ */
+
+static int
+zoran_open (struct inode *inode,
+           struct file  *file)
+{
+       unsigned int minor = minor(inode->i_rdev);
+       struct zoran *zr = NULL;
+       struct zoran_fh *fh;
+       int i, res, first_open = 0, have_module_locks = 0;
+
+       /* find the device */
+       for (i = 0; i < zoran_num; i++) {
+               if (zoran[i].video_dev.minor == minor) {
+                       zr = &zoran[i];
+                       break;
+               }
+       }
+
+       if (!zr) {
+               dprintk(1, KERN_ERR "%s: device not found!\n", ZORAN_NAME);
+               res = -ENODEV;
+               goto open_unlock_and_return;
+       }
+
+       /* see fs/device.c - the kernel already locks during open(),
+        * so locking ourselves only causes deadlocks */
+       /*down(&zr->resource_lock);*/
+
+       if (!zr->decoder) {
+               dprintk(1,
+                       KERN_ERR "%s: no TV decoder loaded for device!\n",
+                       ZR_DEVNAME(zr));
+               res = -EIO;
+               goto open_unlock_and_return;
+       }
+
+       /* try to grab a module lock */
+       if (!try_module_get(THIS_MODULE)) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: failed to acquire my own lock! PANIC!\n",
+                       ZR_DEVNAME(zr));
+               res = -ENODEV;
+               goto open_unlock_and_return;
+       }
+       if (!try_module_get(zr->decoder->driver->owner)) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: failed to grab ownership of i2c decoder\n",
+                       ZR_DEVNAME(zr));
+               res = -EIO;
+               module_put(THIS_MODULE);
+               goto open_unlock_and_return;
+       }
+       if (zr->encoder &&
+           !try_module_get(zr->encoder->driver->owner)) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: failed to grab ownership of i2c encoder\n",
+                       ZR_DEVNAME(zr));
+               res = -EIO;
+               module_put(zr->decoder->driver->owner);
+               module_put(THIS_MODULE);
+               goto open_unlock_and_return;
+       }
+
+       have_module_locks = 1;
+
+       if (zr->user >= 2048) {
+               dprintk(1, KERN_ERR "%s: too many users (%d) on device\n",
+                       ZR_DEVNAME(zr), zr->user);
+               res = -EBUSY;
+               goto open_unlock_and_return;
+       }
+
+       dprintk(1, KERN_INFO "%s: zoran_open(%s, pid=[%d]), users(-)=%d\n",
+               ZR_DEVNAME(zr), current->comm, current->pid, zr->user);
+
+       /* now, create the open()-specific file_ops struct */
+       fh = kmalloc(sizeof(struct zoran_fh), GFP_KERNEL);
+       if (!fh) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: zoran_open() - allocation of zoran_fh failed\n",
+                       ZR_DEVNAME(zr));
+               res = -ENOMEM;
+               goto open_unlock_and_return;
+       }
+       memset(fh, 0, sizeof(struct zoran_fh));
+       /* used to be BUZ_MAX_WIDTH/HEIGHT, but that gives overflows
+        * on norm-change! */
+       fh->overlay_mask =
+           kmalloc(((768 + 31) / 32) * 576 * 4, GFP_KERNEL);
+       if (!fh->overlay_mask) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: zoran_open() - allocation of overlay_mask failed\n",
+                       ZR_DEVNAME(zr));
+               kfree(fh);
+               res = -ENOMEM;
+               goto open_unlock_and_return;
+       }
+
+       if (zr->user++ == 0)
+               first_open = 1;
+
+       /*up(&zr->resource_lock);*/
+
+       /* default setup - TODO: look at flags */
+       if (first_open) {       /* First device open */
+               zr36057_restart(zr);
+               zoran_open_init_params(zr);
+               zoran_init_hardware(zr);
+
+               btor(ZR36057_ICR_IntPinEn, ZR36057_ICR);
+       }
+
+       /* set file_ops stuff */
+       file->private_data = fh;
+       fh->zr = zr;
+       zoran_open_init_session(file);
+
+       return 0;
+
+open_unlock_and_return:
+       /* if we grabbed locks, release them accordingly */
+       if (have_module_locks) {
+               module_put(zr->decoder->driver->owner);
+               if (zr->encoder) {
+                       module_put(zr->encoder->driver->owner);
+               }
+               module_put(THIS_MODULE);
+       }
+
+       /* if there's no device found, we didn't obtain the lock either */
+       if (zr) {
+               /*up(&zr->resource_lock);*/
+       }
+
+       return res;
+}
+
+static int
+zoran_close (struct inode *inode,
+            struct file  *file)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+
+       dprintk(1, KERN_INFO "%s: zoran_close(%s, pid=[%d]), users(+)=%d\n",
+               ZR_DEVNAME(zr), current->comm, current->pid, zr->user);
+
+       /* kernel locks (fs/device.c), so don't do that ourselves
+        * (prevents deadlocks) */
+       /*down(&zr->resource_lock);*/
+
+       zoran_close_end_session(file);
+
+       if (zr->user-- == 1) {  /* Last process */
+               /* Clean up JPEG process */
+               wake_up_interruptible(&zr->jpg_capq);
+               zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+               zr->jpg_buffers.allocated = 0;
+               zr->jpg_buffers.active = ZORAN_FREE;
+
+               /* disable interrupts */
+               btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+
+               if (debug > 1)
+                       print_interrupts(zr);
+
+               /* Overlay off */
+               zr->v4l_overlay_active = 0;
+               zr36057_overlay(zr, 0);
+               zr->overlay_mask = NULL;
+
+               /* capture off */
+               wake_up_interruptible(&zr->v4l_capq);
+               zr36057_set_memgrab(zr, 0);
+               zr->v4l_buffers.allocated = 0;
+               zr->v4l_buffers.active = ZORAN_FREE;
+               zoran_set_pci_master(zr, 0);
+
+               if (!pass_through) {    /* Switch to color bar */
+                       int zero = 0, two = 2;
+                       decoder_command(zr, DECODER_ENABLE_OUTPUT, &zero);
+                       encoder_command(zr, ENCODER_SET_INPUT, &two);
+               }
+       }
+
+       file->private_data = NULL;
+       kfree(fh->overlay_mask);
+       kfree(fh);
+
+       /* release locks on the i2c modules */
+       module_put(zr->decoder->driver->owner);
+       if (zr->encoder) {
+                module_put(zr->encoder->driver->owner);
+       }
+       module_put(THIS_MODULE);
+
+       /*up(&zr->resource_lock);*/
+
+       dprintk(4, KERN_INFO "%s: zoran_close() done\n", ZR_DEVNAME(zr));
+
+       return 0;
+}
+
+
+static ssize_t
+zoran_read (struct file *file,
+           char        *data,
+           size_t       count,
+           loff_t      *ppos)
+{
+       /* we simply don't support read() (yet)... */
+
+       return -EINVAL;
+}
+
+static ssize_t
+zoran_write (struct file *file,
+            const char  *data,
+            size_t       count,
+            loff_t      *ppos)
+{
+       /* ...and the same goes for write() */
+
+       return -EINVAL;
+}
+
+static int
+setup_fbuffer (struct file               *file,
+              void                      *base,
+              const struct zoran_format *fmt,
+              int                        width,
+              int                        height,
+              int                        bytesperline)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+
+       /* (Ronald) v4l/v4l2 guidelines */
+       if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
+       /* we need a bytesperline value, even if not given */
+       if (!bytesperline)
+               bytesperline = width * ((fmt->depth + 7) & ~7) / 8;
+
+#if 0
+       if (zr->overlay_active) {
+               /* dzjee... stupid users... don't even bother to turn off
+                * overlay before changing the memory location...
+                * normally, we would return errors here. However, one of
+                * the tools that does this is... xawtv! and since xawtv
+                * is used by +/- 99% of the users, we'd rather be user-
+                * friendly and silently do as if nothing went wrong */
+               dprintk(3,
+                       KERN_ERR
+                       "%s: setup_fbuffer() - forced overlay turnoff because framebuffer changed\n",
+                       ZR_DEVNAME(zr));
+               zr36057_overlay(zr, 0);
+       }
+#endif
+
+       if (!(fmt->flags & ZORAN_FORMAT_OVERLAY)) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: setup_fbuffer() - no valid overlay format given\n",
+                       ZR_DEVNAME(zr));
+               return -EINVAL;
+       }
+       if (height <= 0 || width <= 0 || bytesperline <= 0) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: setup_fbuffer() - invalid height/width/bpl value (%d|%d|%d)\n",
+                       ZR_DEVNAME(zr), width, height, bytesperline);
+               return -EINVAL;
+       }
+       if (bytesperline & 3) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: setup_fbuffer() - bytesperline (%d) must be 4-byte aligned\n",
+                       ZR_DEVNAME(zr), bytesperline);
+               return -EINVAL;
+       }
+
+       zr->buffer.base = (void *) ((unsigned long) base & ~3);
+       zr->buffer.height = height;
+       zr->buffer.width = width;
+       zr->buffer.depth = fmt->depth;
+       zr->overlay_settings.format = fmt;
+       zr->buffer.bytesperline = bytesperline;
+
+       /* The user should set new window parameters */
+       zr->overlay_settings.is_set = 0;
+
+       return 0;
+}
+
+
+static int
+setup_window (struct file       *file,
+             int                x,
+             int                y,
+             int                width,
+             int                height,
+             struct video_clip *clips,
+             int                clipcount,
+             void              *bitmap)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       struct video_clip *vcp = NULL;
+       int on, end;
+
+
+       if (!zr->buffer.base) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: setup_window() - frame buffer has to be set first\n",
+                       ZR_DEVNAME(zr));
+               return -EINVAL;
+       }
+
+       if (!fh->overlay_settings.format) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: setup_window() - no overlay format set\n",
+                       ZR_DEVNAME(zr));
+               return -EINVAL;
+       }
+
+       /*
+        * The video front end needs 4-byte alinged line sizes, we correct that
+        * silently here if necessary
+        */
+       if (zr->buffer.depth == 15 || zr->buffer.depth == 16) {
+               end = (x + width) & ~1; /* round down */
+               x = (x + 1) & ~1;       /* round up */
+               width = end - x;
+       }
+
+       if (zr->buffer.depth == 24) {
+               end = (x + width) & ~3; /* round down */
+               x = (x + 3) & ~3;       /* round up */
+               width = end - x;
+       }
+
+       if (width > BUZ_MAX_WIDTH)
+               width = BUZ_MAX_WIDTH;
+       if (height > BUZ_MAX_HEIGHT)
+               height = BUZ_MAX_HEIGHT;
+
+       /* Check for vaild parameters */
+       if (width < BUZ_MIN_WIDTH || height < BUZ_MIN_HEIGHT ||
+           width > BUZ_MAX_WIDTH || height > BUZ_MAX_HEIGHT) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: setup_window() - width = %d or height = %d invalid\n",
+                       ZR_DEVNAME(zr), width, height);
+               return -EINVAL;
+       }
+
+       fh->overlay_settings.x = x;
+       fh->overlay_settings.y = y;
+       fh->overlay_settings.width = width;
+       fh->overlay_settings.height = height;
+       fh->overlay_settings.clipcount = clipcount;
+
+       /*
+        * If an overlay is running, we have to switch it off
+        * and switch it on again in order to get the new settings in effect.
+        *
+        * We also want to avoid that the overlay mask is written
+        * when an overlay is running.
+        */
+
+       on = zr->v4l_overlay_active && !zr->v4l_memgrab_active &&
+           zr->overlay_active != ZORAN_FREE &&
+           fh->overlay_active != ZORAN_FREE;
+       if (on)
+               zr36057_overlay(zr, 0);
+
+       /*
+        *   Write the overlay mask if clips are wanted.
+        *   We prefer a bitmap.
+        */
+       if (bitmap) {
+               /* fake value - it just means we want clips */
+               fh->overlay_settings.clipcount = 1;
+
+               if (copy_from_user(fh->overlay_mask, bitmap,
+                                  (width * height + 7) / 8)) {
+                       return -EFAULT;
+               }
+       } else if (clipcount > 0) {
+               /* write our own bitmap from the clips */
+               vcp = vmalloc(sizeof(struct video_clip) * (clipcount + 4));
+               if (vcp == NULL) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: setup_window() - Alloc of clip mask failed\n",
+                               ZR_DEVNAME(zr));
+                       return -ENOMEM;
+               }
+               if (copy_from_user
+                   (vcp, clips, sizeof(struct video_clip) * clipcount)) {
+                       vfree(vcp);
+                       return -EFAULT;
+               }
+               write_overlay_mask(file, vcp, clipcount);
+               vfree(vcp);
+       }
+
+       fh->overlay_settings.is_set = 1;
+       if (fh->overlay_active != ZORAN_FREE &&
+           zr->overlay_active != ZORAN_FREE)
+               zr->overlay_settings = fh->overlay_settings;
+
+       if (on)
+               zr36057_overlay(zr, 1);
+
+       /* Make sure the changes come into effect */
+       return wait_grab_pending(zr);
+}
+
+static int
+setup_overlay (struct file *file,
+              int          on)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+
+       /* If there is nothing to do, return immediatly */
+       if ((on && fh->overlay_active != ZORAN_FREE) ||
+           (!on && fh->overlay_active == ZORAN_FREE))
+               return 0;
+
+       /* check whether we're touching someone else's overlay */
+       if (on && zr->overlay_active != ZORAN_FREE &&
+           fh->overlay_active == ZORAN_FREE) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: setup_overlay() - overlay is already active for another session\n",
+                       ZR_DEVNAME(zr));
+               return -EBUSY;
+       }
+       if (!on && zr->overlay_active != ZORAN_FREE &&
+           fh->overlay_active == ZORAN_FREE) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: setup_overlay() - you cannot cancel someone else's session\n",
+                       ZR_DEVNAME(zr));
+               return -EPERM;
+       }
+
+       if (on == 0) {
+               zr->overlay_active = fh->overlay_active = ZORAN_FREE;
+               zr->v4l_overlay_active = 0;
+               /* When a grab is running, the video simply
+                * won't be switched on any more */
+               if (!zr->v4l_memgrab_active)
+                       zr36057_overlay(zr, 0);
+               zr->overlay_mask = NULL;
+       } else {
+               if (!zr->buffer.base || !fh->overlay_settings.is_set) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: setup_overlay() - buffer or window not set\n",
+                               ZR_DEVNAME(zr));
+                       return -EINVAL;
+               }
+               if (!fh->overlay_settings.format) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: setup_overlay() - no overlay format set\n",
+                               ZR_DEVNAME(zr));
+                       return -EINVAL;
+               }
+               zr->overlay_active = fh->overlay_active = ZORAN_LOCKED;
+               zr->v4l_overlay_active = 1;
+               zr->overlay_mask = fh->overlay_mask;
+               zr->overlay_settings = fh->overlay_settings;
+               if (!zr->v4l_memgrab_active)
+                       zr36057_overlay(zr, 1);
+               /* When a grab is running, the video will be
+                * switched on when grab is finished */
+       }
+
+       /* Make sure the changes come into effect */
+       return wait_grab_pending(zr);
+}
+
+#ifdef HAVE_V4L2
+       /* get the status of a buffer in the clients buffer queue */
+static int
+zoran_v4l2_buffer_status (struct file        *file,
+                         struct v4l2_buffer *buf,
+                         int                 num)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+
+       buf->flags = V4L2_BUF_FLAG_MAPPED;
+
+       switch (fh->map_mode) {
+       case ZORAN_MAP_MODE_RAW:
+
+               /* check range */
+               if (num < 0 || num >= fh->v4l_buffers.num_buffers ||
+                   !fh->v4l_buffers.allocated) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: v4l2_buffer_status() - wrong number or buffers not allocated\n",
+                               ZR_DEVNAME(zr));
+                       return -EINVAL;
+               }
+
+               buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               buf->length = fh->v4l_buffers.buffer_size;
+
+               /* get buffer */
+               buf->bytesused = fh->v4l_buffers.buffer[num].bs.length;
+               if (fh->v4l_buffers.buffer[num].state == BUZ_STATE_DONE ||
+                   fh->v4l_buffers.buffer[num].state == BUZ_STATE_USER) {
+                       buf->sequence = fh->v4l_buffers.buffer[num].bs.seq;
+                       buf->flags |= V4L2_BUF_FLAG_DONE;
+                       buf->timestamp =
+                           fh->v4l_buffers.buffer[num].bs.timestamp;
+               } else {
+                       buf->flags |= V4L2_BUF_FLAG_QUEUED;
+               }
+
+               if (fh->v4l_settings.height <= BUZ_MAX_HEIGHT / 2)
+                       buf->field = V4L2_FIELD_TOP;
+               else
+                       buf->field = V4L2_FIELD_INTERLACED;
+
+               break;
+
+       case ZORAN_MAP_MODE_JPG_REC:
+       case ZORAN_MAP_MODE_JPG_PLAY:
+
+               /* check range */
+               if (num < 0 || num >= fh->jpg_buffers.num_buffers ||
+                   !fh->jpg_buffers.allocated) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: v4l2_buffer_status() - wrong number or buffers not allocated\n",
+                               ZR_DEVNAME(zr));
+                       return -EINVAL;
+               }
+
+               buf->type = (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ?
+                             V4L2_BUF_TYPE_VIDEO_CAPTURE :
+                             V4L2_BUF_TYPE_VIDEO_OUTPUT;
+               buf->length = fh->jpg_buffers.buffer_size;
+
+               /* these variables are only written after frame has been captured */
+               if (fh->jpg_buffers.buffer[num].state == BUZ_STATE_DONE ||
+                   fh->jpg_buffers.buffer[num].state == BUZ_STATE_USER) {
+                       buf->sequence = fh->jpg_buffers.buffer[num].bs.seq;
+                       buf->timestamp =
+                           fh->jpg_buffers.buffer[num].bs.timestamp;
+                       buf->bytesused =
+                           fh->jpg_buffers.buffer[num].bs.length;
+                       buf->flags |= V4L2_BUF_FLAG_DONE;
+               } else {
+                       buf->flags |= V4L2_BUF_FLAG_QUEUED;
+               }
+
+               /* which fields are these? */
+               if (fh->jpg_settings.TmpDcm != 1)
+                       buf->field =
+                           fh->jpg_settings.
+                           odd_even ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
+               else
+                       buf->field =
+                           fh->jpg_settings.
+                           odd_even ? V4L2_FIELD_SEQ_TB :
+                           V4L2_FIELD_SEQ_BT;
+
+               break;
+
+       default:
+
+               dprintk(5,
+                       KERN_ERR
+                       "%s: v4l2_buffer_status() - invalid buffer type|map_mode (%d|%d)\n",
+                       ZR_DEVNAME(zr), buf->type, fh->map_mode);
+               return -EINVAL;
+       }
+
+       buf->memory = V4L2_MEMORY_MMAP;
+       buf->index = num;
+       buf->m.offset = buf->length * num;
+
+       return 0;
+}
+#endif
+
+static int
+zoran_set_norm (struct zoran *zr,
+               int           norm) /* VIDEO_MODE_* */
+{
+       int norm_encoder, on;
+
+       if (zr->v4l_buffers.active != ZORAN_FREE ||
+           zr->jpg_buffers.active != ZORAN_FREE) {
+               dprintk(1,
+                       KERN_WARNING
+                       "%s: set_norm() called while in playback/capture mode\n",
+                       ZR_DEVNAME(zr));
+               return -EBUSY;
+       }
+
+       if (lock_norm && norm != zr->norm) {
+               if (lock_norm > 1) {
+                       dprintk(1,
+                               KERN_WARNING
+                               "%s: set_norm() - TV standard is locked, can not switch norm\n",
+                               ZR_DEVNAME(zr));
+                       return -EPERM;
+               } else {
+                       dprintk(1,
+                               KERN_WARNING
+                               "%s: set_norm() - TV standard is locked, norm was not changed\n",
+                               ZR_DEVNAME(zr));
+                       norm = zr->norm;
+               }
+       }
+
+       if (norm != VIDEO_MODE_AUTO &&
+           (norm < 0 || norm >= zr->card.norms ||
+            !zr->card.tvn[norm])) {
+               dprintk(1,
+                       KERN_ERR "%s: set_norm() - unsupported norm %d\n",
+                       ZR_DEVNAME(zr), norm);
+               return -EINVAL;
+       }
+
+       if (norm == VIDEO_MODE_AUTO) {
+               int status;
+
+               /* if we have autodetect, ... */
+               struct video_decoder_capability caps;
+               decoder_command(zr, DECODER_GET_CAPABILITIES, &caps);
+               if (!(caps.flags & VIDEO_DECODER_AUTO)) {
+                       dprintk(1, KERN_ERR "%s: norm=auto unsupported\n",
+                               ZR_DEVNAME(zr));
+                       return -EINVAL;
+               }
+
+               decoder_command(zr, DECODER_SET_NORM, &norm);
+
+               /* let changes come into effect */
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(2 * HZ);
+
+               decoder_command(zr, DECODER_GET_STATUS, &status);
+               if (!(status & DECODER_STATUS_GOOD)) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: set_norm() - no norm detected\n",
+                               ZR_DEVNAME(zr));
+                       /* reset norm */
+                       decoder_command(zr, DECODER_SET_NORM, &zr->norm);
+                       return -EIO;
+               }
+
+               if (status & DECODER_STATUS_NTSC)
+                       norm = VIDEO_MODE_NTSC;
+               else if (status & DECODER_STATUS_SECAM)
+                       norm = VIDEO_MODE_SECAM;
+               else
+                       norm = VIDEO_MODE_PAL;
+       }
+       zr->timing = zr->card.tvn[norm];
+       norm_encoder = norm;
+
+       /* We switch overlay off and on since a change in the
+        * norm needs different VFE settings */
+       on = zr->overlay_active && !zr->v4l_memgrab_active;
+       if (on)
+               zr36057_overlay(zr, 0);
+
+       decoder_command(zr, DECODER_SET_NORM, &norm);
+       encoder_command(zr, ENCODER_SET_NORM, &norm_encoder);
+
+       if (on)
+               zr36057_overlay(zr, 1);
+
+       /* Make sure the changes come into effect */
+       zr->norm = norm;
+
+       return 0;
+}
+
+static int
+zoran_set_input (struct zoran *zr,
+                int           input)
+{
+       int realinput;
+
+       if (input == zr->input) {
+               return 0;
+       }
+
+       if (zr->v4l_buffers.active != ZORAN_FREE ||
+           zr->jpg_buffers.active != ZORAN_FREE) {
+               dprintk(1,
+                       KERN_WARNING
+                       "%s: set_input() called while in playback/capture mode\n",
+                       ZR_DEVNAME(zr));
+               return -EBUSY;
+       }
+
+       if (input < 0 || input >= zr->card.inputs) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: set_input() - unnsupported input %d\n",
+                       ZR_DEVNAME(zr), input);
+               return -EINVAL;
+       }
+
+       realinput = zr->card.input[input].muxsel;
+       zr->input = input;
+
+       decoder_command(zr, DECODER_SET_INPUT, &realinput);
+
+       return 0;
+}
+
+/*
+ *   ioctl routine
+ */
+
+static int
+zoran_do_ioctl (struct inode *inode,
+               struct file  *file,
+               unsigned int  cmd,
+               void         *arg)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+
+       /* we might have older buffers lying around... We don't want
+        * to wait, but we do want to try cleaning them up ASAP. So
+        * we try to obtain the lock and free them. If that fails, we
+        * don't do anything and wait for the next turn. In the end,
+        * zoran_close() or a new allocation will still free them...
+        * This is just a 'the sooner the better' extra 'feature'
+        *
+        * We don't free the buffers right on munmap() because that
+        * causes oopses (kfree() inside munmap() oopses for no
+        * apparent reason - it's also not reproduceable in any way,
+        * but moving the free code outside the munmap() handler fixes
+        * all this... If someone knows why, please explain me (Ronald)
+        */
+       if (!down_trylock(&zr->resource_lock)) {
+               /* we obtained it! Let's try to free some things */
+               if (fh->jpg_buffers.ready_to_be_freed)
+                       jpg_fbuffer_free(file);
+               if (fh->v4l_buffers.ready_to_be_freed)
+                       v4l_fbuffer_free(file);
+
+               up(&zr->resource_lock);
+       }
+
+       switch (cmd) {
+
+       case VIDIOCGCAP:
+       {
+               struct video_capability *vcap = arg;
+               dprintk(3, KERN_DEBUG "%s: VIDIOCGCAP\n", ZR_DEVNAME(zr));
+
+               memset(vcap, 0, sizeof(struct video_capability));
+               strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name));
+               vcap->type = ZORAN_VID_TYPE;
+
+               vcap->channels = zr->card.inputs;
+               vcap->audios = 0;
+               down(&zr->resource_lock);
+               vcap->maxwidth = BUZ_MAX_WIDTH;
+               vcap->maxheight = BUZ_MAX_HEIGHT;
+               vcap->minwidth = BUZ_MIN_WIDTH;
+               vcap->minheight = BUZ_MIN_HEIGHT;
+               up(&zr->resource_lock);
+
+               return 0;
+       }
+               break;
+
+       case VIDIOCGCHAN:
+       {
+               struct video_channel *vchan = arg;
+               int channel = vchan->channel;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOCGCHAN - channel=%d\n",
+                       ZR_DEVNAME(zr), vchan->channel);
+
+               memset(vchan, 0, sizeof(struct video_channel));
+               if (channel > zr->card.inputs || channel < 0) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOCGCHAN on not existing channel %d\n",
+                               ZR_DEVNAME(zr), channel);
+                       return -EINVAL;
+               }
+
+               strcpy(vchan->name, zr->card.input[channel].name);
+
+               vchan->tuners = 0;
+               vchan->flags = 0;
+               vchan->type = VIDEO_TYPE_CAMERA;
+               down(&zr->resource_lock);
+               vchan->norm = zr->norm;
+               up(&zr->resource_lock);
+               vchan->channel = channel;
+
+               return 0;
+       }
+               break;
+
+               /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says:
+                * 
+                * * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input."
+                * *                                 ^^^^^^^
+                * * The famos BTTV driver has it implemented with a struct video_channel argument
+                * * and we follow it for compatibility reasons
+                * *
+                * * BTW: this is the only way the user can set the norm!
+                */
+
+       case VIDIOCSCHAN:
+       {
+               struct video_channel *vchan = arg;
+               int res;
+
+               dprintk(3,
+                       KERN_DEBUG
+                       "%s: VIDIOCSCHAN - channel=%d, norm=%d\n",
+                       ZR_DEVNAME(zr), vchan->channel, vchan->norm);
+
+               down(&zr->resource_lock);
+               if ((res = zoran_set_input(zr, vchan->channel)))
+                       goto schan_unlock_and_return;
+               if ((res = zoran_set_norm(zr, vchan->norm)))
+                       goto schan_unlock_and_return;
+
+               /* Make sure the changes come into effect */
+               res = wait_grab_pending(zr);
+       schan_unlock_and_return:
+               up(&zr->resource_lock);
+               return res;
+       }
+               break;
+
+       case VIDIOCGPICT:
+       {
+               struct video_picture *vpict = arg;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOCGPICT\n", ZR_DEVNAME(zr));
+
+               memset(vpict, 0, sizeof(struct video_picture));
+               down(&zr->resource_lock);
+               vpict->hue = zr->hue;
+               vpict->brightness = zr->brightness;
+               vpict->contrast = zr->contrast;
+               vpict->colour = zr->saturation;
+               if (fh->overlay_settings.format) {
+                       vpict->depth = fh->overlay_settings.format->depth;
+                       vpict->palette = fh->overlay_settings.format->palette;
+               } else {
+                       vpict->depth = 0;
+               }
+               up(&zr->resource_lock);
+
+               return 0;
+       }
+               break;
+
+       case VIDIOCSPICT:
+       {
+               struct video_picture *vpict = arg;
+               int i;
+
+               dprintk(3,
+                       KERN_DEBUG
+                       "%s: VIDIOCSPICT - bri=%d, hue=%d, col=%d, con=%d, dep=%d, pal=%d\n",
+                       ZR_DEVNAME(zr), vpict->brightness, vpict->hue,
+                       vpict->colour, vpict->contrast, vpict->depth,
+                       vpict->palette);
+
+               for (i = 0; i < zoran_num_formats; i++) {
+                       const struct zoran_format *fmt = &zoran_formats[i];
+                       if (fmt->palette != -1 &&
+                           fmt->flags & ZORAN_FORMAT_OVERLAY &&
+                           fmt->palette == vpict->palette &&
+                           fmt->depth == vpict->depth)
+                               break;
+               }
+               if (i == zoran_num_formats) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOCSPICT - Invalid palette %d\n",
+                               ZR_DEVNAME(zr), vpict->palette);
+                       return -EINVAL;
+               }
+
+               down(&zr->resource_lock);
+
+               decoder_command(zr, DECODER_SET_PICTURE, vpict);
+
+               zr->hue = vpict->hue;
+               zr->contrast = vpict->contrast;
+               zr->saturation = vpict->colour;
+               zr->brightness = vpict->brightness;
+
+               fh->overlay_settings.format = &zoran_formats[i];
+
+               up(&zr->resource_lock);
+
+               return 0;
+       }
+               break;
+
+       case VIDIOCCAPTURE:
+       {
+               int *on = arg, res;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOCCAPTURE - on=%d\n",
+                       ZR_DEVNAME(zr), *on);
+
+               down(&zr->resource_lock);
+               res = setup_overlay(file, *on);
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case VIDIOCGWIN:
+       {
+               struct video_window *vwin = arg;
+               dprintk(3, KERN_DEBUG "%s: VIDIOCGWIN\n", ZR_DEVNAME(zr));
+               memset(vwin, 0, sizeof(struct video_window));
+               down(&zr->resource_lock);
+               vwin->x = fh->overlay_settings.x;
+               vwin->y = fh->overlay_settings.y;
+               vwin->width = fh->overlay_settings.width;
+               vwin->height = fh->overlay_settings.height;
+               up(&zr->resource_lock);
+               vwin->clipcount = 0;
+               return 0;
+       }
+               break;
+
+       case VIDIOCSWIN:
+       {
+               struct video_window *vwin = arg;
+               int res;
+
+               dprintk(3,
+                       KERN_DEBUG
+                       "%s: VIDIOCSWIN - x=%d, y=%d, w=%d, h=%d, clipcount=%d\n",
+                       ZR_DEVNAME(zr), vwin->x, vwin->y, vwin->width,
+                       vwin->height, vwin->clipcount);
+
+               down(&zr->resource_lock);
+               res =
+                   setup_window(file, vwin->x, vwin->y, vwin->width,
+                                vwin->height, vwin->clips,
+                                vwin->clipcount, NULL);
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case VIDIOCGFBUF:
+       {
+               struct video_buffer *vbuf = arg;
+               dprintk(3, KERN_DEBUG "%s: VIDIOCGFBUF\n", ZR_DEVNAME(zr));
+               down(&zr->resource_lock);
+               *vbuf = zr->buffer;
+               up(&zr->resource_lock);
+               return 0;
+       }
+               break;
+
+       case VIDIOCSFBUF:
+       {
+               struct video_buffer *vbuf = arg;
+               int i, res = 0;
+
+               dprintk(3,
+                       KERN_DEBUG
+                       "%s: VIDIOCSFBUF - base=0x%x, w=%d, h=%d, depth=%d, bpl=%d\n",
+                       ZR_DEVNAME(zr), (u32) vbuf->base, vbuf->width,
+                       vbuf->height, vbuf->depth, vbuf->bytesperline);
+
+               for (i = 0; i < zoran_num_formats; i++)
+                       if (zoran_formats[i].depth == vbuf->depth)
+                               break;
+               if (i == zoran_num_formats) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOCSFBUF - invalid fbuf depth %d\n",
+                               ZR_DEVNAME(zr), vbuf->depth);
+                       return -EINVAL;
+               }
+
+               down(&zr->resource_lock);
+               res =
+                   setup_fbuffer(file, vbuf->base, &zoran_formats[i],
+                                 vbuf->width, vbuf->height,
+                                 vbuf->bytesperline);
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case VIDIOCSYNC:
+       {
+               int *frame = arg, res;
+               dprintk(3, KERN_DEBUG "%s: VIDIOCSYNC - frame=%d\n",
+                       ZR_DEVNAME(zr), *frame);
+               down(&zr->resource_lock);
+               res = v4l_sync(file, *frame);
+               up(&zr->resource_lock);
+               if (!res)
+                       zr->v4l_sync_tail++;
+               return res;
+       }
+               break;
+
+       case VIDIOCMCAPTURE:
+       {
+               struct video_mmap *vmap = arg;
+               int res;
+               dprintk(3,
+                       KERN_DEBUG
+                       "%s: VIDIOCMCAPTURE - frame=%d, geom=%dx%d, fmt=%d\n",
+                       ZR_DEVNAME(zr), vmap->frame, vmap->width, vmap->height,
+                       vmap->format);
+               down(&zr->resource_lock);
+               res = v4l_grab(file, vmap);
+               up(&zr->resource_lock);
+               return res;
+       }
+               break;
+
+       case VIDIOCGMBUF:
+       {
+               struct video_mbuf *vmbuf = arg;
+               int i, res = 0;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOCGMBUF\n", ZR_DEVNAME(zr));
+
+               vmbuf->size =
+                   fh->v4l_buffers.num_buffers *
+                   fh->v4l_buffers.buffer_size;
+               vmbuf->frames = fh->v4l_buffers.num_buffers;
+               for (i = 0; i < vmbuf->frames; i++) {
+                       vmbuf->offsets[i] =
+                           i * fh->v4l_buffers.buffer_size;
+               }
+
+               down(&zr->resource_lock);
+
+               if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOCGMBUF - buffers already allocated\n",
+                               ZR_DEVNAME(zr));
+                       res = -EINVAL;
+                       goto v4l1reqbuf_unlock_and_return;
+               }
+
+               if (v4l_fbuffer_alloc(file)) {
+                       res = -ENOMEM;
+                       goto v4l1reqbuf_unlock_and_return;
+               }
+
+               /* The next mmap will map the V4L buffers */
+               fh->map_mode = ZORAN_MAP_MODE_RAW;
+       v4l1reqbuf_unlock_and_return:
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case VIDIOCGUNIT:
+       {
+               struct video_unit *vunit = arg;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOCGUNIT\n", ZR_DEVNAME(zr));
+               vunit->video = zr->video_dev.minor;
+               vunit->vbi = VIDEO_NO_UNIT;
+               vunit->radio = VIDEO_NO_UNIT;
+               vunit->audio = VIDEO_NO_UNIT;
+               vunit->teletext = VIDEO_NO_UNIT;
+
+               return 0;
+       }
+               break;
+
+               /*
+                * RJ: In principal we could support subcaptures for V4L grabbing.
+                *     Not even the famous BTTV driver has them, however.
+                *     If there should be a strong demand, one could consider
+                *     to implement them.
+                */
+       case VIDIOCGCAPTURE:
+       {
+               dprintk(3, KERN_ERR "%s: VIDIOCGCAPTURE not supported\n",
+                       ZR_DEVNAME(zr));
+               return -EINVAL;
+       }
+               break;
+
+       case VIDIOCSCAPTURE:
+       {
+               dprintk(3, KERN_ERR "%s: VIDIOCSCAPTURE not supported\n",
+                       ZR_DEVNAME(zr));
+               return -EINVAL;
+       }
+               break;
+
+       case BUZIOC_G_PARAMS:
+       {
+               struct zoran_params *bparams = arg;
+               dprintk(3, KERN_DEBUG "%s: BUZIOC_G_PARAMS\n", ZR_DEVNAME(zr));
+
+               memset(bparams, 0, sizeof(struct zoran_params));
+               bparams->major_version = MAJOR_VERSION;
+               bparams->minor_version = MINOR_VERSION;
+
+               down(&zr->resource_lock);
+
+               bparams->norm = zr->norm;
+               bparams->input = zr->input;
+
+               bparams->decimation = fh->jpg_settings.decimation;
+               bparams->HorDcm = fh->jpg_settings.HorDcm;
+               bparams->VerDcm = fh->jpg_settings.VerDcm;
+               bparams->TmpDcm = fh->jpg_settings.TmpDcm;
+               bparams->field_per_buff = fh->jpg_settings.field_per_buff;
+               bparams->img_x = fh->jpg_settings.img_x;
+               bparams->img_y = fh->jpg_settings.img_y;
+               bparams->img_width = fh->jpg_settings.img_width;
+               bparams->img_height = fh->jpg_settings.img_height;
+               bparams->odd_even = fh->jpg_settings.odd_even;
+
+               bparams->quality = fh->jpg_settings.jpg_comp.quality;
+               bparams->APPn = fh->jpg_settings.jpg_comp.APPn;
+               bparams->APP_len = fh->jpg_settings.jpg_comp.APP_len;
+               memcpy(bparams->APP_data,
+                      fh->jpg_settings.jpg_comp.APP_data,
+                      sizeof(bparams->APP_data));
+               bparams->COM_len = zr->jpg_settings.jpg_comp.COM_len;
+               memcpy(bparams->COM_data,
+                      fh->jpg_settings.jpg_comp.COM_data,
+                      sizeof(bparams->COM_data));
+               bparams->jpeg_markers =
+                   fh->jpg_settings.jpg_comp.jpeg_markers;
+
+               up(&zr->resource_lock);
+
+               bparams->VFIFO_FB = 0;
+
+               return 0;
+       }
+               break;
+
+       case BUZIOC_S_PARAMS:
+       {
+               struct zoran_params *bparams = arg;
+               struct zoran_jpg_settings settings;
+               int res = 0;
+
+               dprintk(3, KERN_DEBUG "%s: BUZIOC_S_PARAMS\n", ZR_DEVNAME(zr));
+
+               settings.decimation = bparams->decimation;
+               settings.HorDcm = bparams->HorDcm;
+               settings.VerDcm = bparams->VerDcm;
+               settings.TmpDcm = bparams->TmpDcm;
+               settings.field_per_buff = bparams->field_per_buff;
+               settings.img_x = bparams->img_x;
+               settings.img_y = bparams->img_y;
+               settings.img_width = bparams->img_width;
+               settings.img_height = bparams->img_height;
+               settings.odd_even = bparams->odd_even;
+
+               settings.jpg_comp.quality = bparams->quality;
+               settings.jpg_comp.APPn = bparams->APPn;
+               settings.jpg_comp.APP_len = bparams->APP_len;
+               memcpy(settings.jpg_comp.APP_data, bparams->APP_data,
+                      sizeof(bparams->APP_data));
+               settings.jpg_comp.COM_len = bparams->COM_len;
+               memcpy(settings.jpg_comp.COM_data, bparams->COM_data,
+                      sizeof(bparams->COM_data));
+               settings.jpg_comp.jpeg_markers = bparams->jpeg_markers;
+
+               down(&zr->resource_lock);
+
+               if (zr->codec_mode != BUZ_MODE_IDLE) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: BUZIOC_S_PARAMS called, but Buz in capture/playback mode\n",
+                               ZR_DEVNAME(zr));
+                       res = -EINVAL;
+                       goto sparams_unlock_and_return;
+               }
+
+               /* Check the params first before overwriting our
+                * nternal values */
+               if (zoran_check_jpg_settings(zr, &settings)) {
+                       res = -EINVAL;
+                       goto sparams_unlock_and_return;
+               }
+
+               fh->jpg_settings = settings;
+       sparams_unlock_and_return:
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case BUZIOC_REQBUFS:
+       {
+               struct zoran_requestbuffers *breq = arg;
+               int res = 0;
+
+               dprintk(3,
+                       KERN_DEBUG
+                       "%s: BUZIOC_REQBUFS - count=%lu, size=%lu\n",
+                       ZR_DEVNAME(zr), breq->count, breq->size);
+
+               /* Enforce reasonable lower and upper limits */
+               if (breq->count < 4)
+                       breq->count = 4;        /* Could be choosen smaller */
+               if (breq->count > jpg_nbufs)
+                       breq->count = jpg_nbufs;
+               breq->size = PAGE_ALIGN(breq->size);
+               if (breq->size < 8192)
+                       breq->size = 8192;      /* Arbitrary */
+               /* breq->size is limited by 1 page for the stat_com
+                * tables to a Maximum of 2 MB */
+               if (breq->size > jpg_bufsize)
+                       breq->size = jpg_bufsize;
+               if (fh->jpg_buffers.need_contiguous &&
+                   breq->size > MAX_KMALLOC_MEM)
+                       breq->size = MAX_KMALLOC_MEM;
+
+               down(&zr->resource_lock);
+
+               if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: BUZIOC_REQBUFS - buffers allready allocated\n",
+                               ZR_DEVNAME(zr));
+                       res = -EBUSY;
+                       goto jpgreqbuf_unlock_and_return;
+               }
+
+               fh->jpg_buffers.num_buffers = breq->count;
+               fh->jpg_buffers.buffer_size = breq->size;
+
+               if (jpg_fbuffer_alloc(file)) {
+                       res = -ENOMEM;
+                       goto jpgreqbuf_unlock_and_return;
+               }
+
+               /* The next mmap will map the MJPEG buffers - could
+                * also be *_PLAY, but it doesn't matter here */
+               fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
+       jpgreqbuf_unlock_and_return:
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case BUZIOC_QBUF_CAPT:
+       {
+               int *frame = arg, res;
+
+               dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_CAPT - frame=%d\n",
+                       ZR_DEVNAME(zr), *frame);
+
+               down(&zr->resource_lock);
+               res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_COMPRESS);
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case BUZIOC_QBUF_PLAY:
+       {
+               int *frame = arg, res;
+
+               dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_PLAY - frame=%d\n",
+                       ZR_DEVNAME(zr), *frame);
+
+               down(&zr->resource_lock);
+               res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_DECOMPRESS);
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case BUZIOC_SYNC:
+       {
+               struct zoran_sync *bsync = arg;
+               int res;
+
+               dprintk(3, KERN_DEBUG "%s: BUZIOC_SYNC\n", ZR_DEVNAME(zr));
+
+               down(&zr->resource_lock);
+               res = jpg_sync(file, bsync);
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case BUZIOC_G_STATUS:
+       {
+               struct zoran_status *bstat = arg;
+               int norm, input, status, res = 0;
+
+               dprintk(3, KERN_DEBUG "%s: BUZIOC_G_STATUS\n", ZR_DEVNAME(zr));
+
+               if (zr->codec_mode != BUZ_MODE_IDLE) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: BUZIOC_G_STATUS called but Buz in capture/playback mode\n",
+                               ZR_DEVNAME(zr));
+                       return -EINVAL;
+               }
+
+               input = zr->card.input[bstat->input].muxsel;
+               norm = VIDEO_MODE_AUTO;
+
+               down(&zr->resource_lock);
+
+               if (zr->codec_mode != BUZ_MODE_IDLE) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: BUZIOC_G_STATUS called, but Buz in capture/playback mode\n",
+                               ZR_DEVNAME(zr));
+                       res = -EINVAL;
+                       goto gstat_unlock_and_return;
+               }
+
+               decoder_command(zr, DECODER_SET_INPUT, &input);
+               decoder_command(zr, DECODER_SET_NORM, &norm);
+
+               /* sleep 1 second */
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(1 * HZ);
+
+               /* Get status of video decoder */
+               decoder_command(zr, DECODER_GET_STATUS, &status);
+
+               /* restore previous input and norm */
+               input = zr->card.input[zr->input].muxsel;
+               decoder_command(zr, DECODER_SET_INPUT, &input);
+               decoder_command(zr, DECODER_SET_NORM, &zr->norm);
+       gstat_unlock_and_return:
+               up(&zr->resource_lock);
+
+               if (!res) {
+                       bstat->signal =
+                           (status & DECODER_STATUS_GOOD) ? 1 : 0;
+                       if (status & DECODER_STATUS_NTSC)
+                               bstat->norm = VIDEO_MODE_NTSC;
+                       else if (status & DECODER_STATUS_SECAM)
+                               bstat->norm = VIDEO_MODE_SECAM;
+                       else
+                               bstat->norm = VIDEO_MODE_PAL;
+
+                       bstat->color =
+                           (status & DECODER_STATUS_COLOR) ? 1 : 0;
+               }
+
+               return res;
+       }
+               break;
+
+#ifdef HAVE_V4L2
+
+               /* The new video4linux2 capture interface - much nicer than video4linux1, since
+                * it allows for integrating the JPEG capturing calls inside standard v4l2
+                */
+
+       case VIDIOC_QUERYCAP:
+       {
+               struct v4l2_capability *cap = arg;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCAP\n", ZR_DEVNAME(zr));
+
+               memset(cap, 0, sizeof(*cap));
+               strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card));
+               strncpy(cap->driver, "zoran", sizeof(cap->driver));
+               snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+                        zr->pci_dev->slot_name);
+               cap->version =
+                   KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION,
+                                  RELEASE_VERSION);
+               cap->capabilities = ZORAN_V4L2_VID_FLAGS;
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_ENUM_FMT:
+       {
+               struct v4l2_fmtdesc *fmt = arg;
+               int index = fmt->index, num = -1, i, flag = 0, type =
+                   fmt->type;
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUM_FMT - index=%d\n",
+                       ZR_DEVNAME(zr), fmt->index);
+
+               switch (fmt->type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                       flag = ZORAN_FORMAT_CAPTURE;
+                       break;
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+                       flag = ZORAN_FORMAT_PLAYBACK;
+                       break;
+               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+                       flag = ZORAN_FORMAT_OVERLAY;
+                       break;
+               default:
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_ENUM_FMT - unknown type %d\n",
+                               ZR_DEVNAME(zr), fmt->type);
+                       return -EINVAL;
+               }
+
+               for (i = 0; i < zoran_num_formats; i++) {
+                       if (zoran_formats[i].flags & flag)
+                               num++;
+                       if (num == fmt->index)
+                               break;
+               }
+               if (fmt->index < 0 /* late, but not too late */  ||
+                   i == zoran_num_formats)
+                       return -EINVAL;
+
+               memset(fmt, 0, sizeof(*fmt));
+               fmt->index = index;
+               fmt->type = type;
+               strncpy(fmt->description, zoran_formats[i].name, 31);
+               fmt->pixelformat = zoran_formats[i].fourcc;
+               if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
+                       fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_G_FMT:
+       {
+               struct v4l2_format *fmt = arg;
+               int type = fmt->type;
+
+               dprintk(5, KERN_DEBUG "%s: VIDIOC_G_FMT\n", ZR_DEVNAME(zr));
+
+               memset(fmt, 0, sizeof(*fmt));
+               fmt->type = type;
+
+               switch (fmt->type) {
+               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+
+                       down(&zr->resource_lock);
+
+                       fmt->fmt.win.w.left = fh->overlay_settings.x;
+                       fmt->fmt.win.w.top = fh->overlay_settings.y;
+                       fmt->fmt.win.w.width = fh->overlay_settings.width;
+                       fmt->fmt.win.w.height =
+                           fh->overlay_settings.height;
+                       if (fh->overlay_settings.width * 2 >
+                           BUZ_MAX_HEIGHT)
+                               fmt->fmt.win.field = V4L2_FIELD_INTERLACED;
+                       else
+                               fmt->fmt.win.field = V4L2_FIELD_TOP;
+
+                       up(&zr->resource_lock);
+
+                       break;
+
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+
+                       down(&zr->resource_lock);
+
+                       if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+                           fh->map_mode == ZORAN_MAP_MODE_RAW) {
+
+                               fmt->fmt.pix.width =
+                                   fh->v4l_settings.width;
+                               fmt->fmt.pix.height =
+                                   fh->v4l_settings.height;
+                               fmt->fmt.pix.sizeimage =
+                                   fh->v4l_buffers.buffer_size;
+                               fmt->fmt.pix.pixelformat =
+                                   fh->v4l_settings.format->fourcc;
+                               fmt->fmt.pix.colorspace =
+                                   fh->v4l_settings.format->colorspace;
+                               fmt->fmt.pix.bytesperline = 0;
+                               if (BUZ_MAX_HEIGHT <
+                                   (fh->v4l_settings.height * 2))
+                                       fmt->fmt.pix.field =
+                                           V4L2_FIELD_INTERLACED;
+                               else
+                                       fmt->fmt.pix.field =
+                                           V4L2_FIELD_TOP;
+
+                       } else {
+
+                               fmt->fmt.pix.width =
+                                   fh->jpg_settings.img_width /
+                                   fh->jpg_settings.HorDcm;
+                               fmt->fmt.pix.height =
+                                   fh->jpg_settings.img_height /
+                                   (fh->jpg_settings.VerDcm *
+                                    fh->jpg_settings.TmpDcm);
+                               fmt->fmt.pix.sizeimage =
+                                   zoran_v4l2_calc_bufsize(&fh->
+                                                           jpg_settings);;
+                               fmt->fmt.pix.pixelformat =
+                                   V4L2_PIX_FMT_MJPEG;
+                               if (fh->jpg_settings.TmpDcm == 1)
+                                       fmt->fmt.pix.field =
+                                           (fh->jpg_settings.
+                                            odd_even ? V4L2_FIELD_SEQ_BT :
+                                            V4L2_FIELD_SEQ_BT);
+                               else
+                                       fmt->fmt.pix.field =
+                                           (fh->jpg_settings.
+                                            odd_even ? V4L2_FIELD_TOP :
+                                            V4L2_FIELD_BOTTOM);
+
+                               fmt->fmt.pix.bytesperline = 0;
+                               fmt->fmt.pix.colorspace =
+                                   V4L2_COLORSPACE_SMPTE170M;
+                       }
+
+                       up(&zr->resource_lock);
+
+                       break;
+
+               default:
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_G_FMT - unsupported type %d\n",
+                               ZR_DEVNAME(zr), fmt->type);
+                       return -EINVAL;
+               }
+               return 0;
+       }
+               break;
+
+       case VIDIOC_S_FMT:
+       {
+               struct v4l2_format *fmt = arg;
+               int i, res = 0;
+               __u32 printformat;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_S_FMT - type=%d, ",
+                       ZR_DEVNAME(zr), fmt->type);
+
+               switch (fmt->type) {
+               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+
+                       dprintk(3, "x=%d, y=%d, w=%d, h=%d, cnt=%d, map=0x%p\n",
+                               fmt->fmt.win.w.left, fmt->fmt.win.w.top,
+                               fmt->fmt.win.w.width,
+                               fmt->fmt.win.w.height,
+                               fmt->fmt.win.clipcount,
+                               fmt->fmt.win.bitmap);
+                       down(&zr->resource_lock);
+                       res =
+                           setup_window(file, fmt->fmt.win.w.left,
+                                        fmt->fmt.win.w.top,
+                                        fmt->fmt.win.w.width,
+                                        fmt->fmt.win.w.height,
+                                        (struct video_clip *)
+                                          fmt->fmt.win.clips,
+                                        fmt->fmt.win.clipcount,
+                                        fmt->fmt.win.bitmap);
+                       up(&zr->resource_lock);
+                       return res;
+                       break;
+
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+
+                       printformat =
+                           __cpu_to_le32(fmt->fmt.pix.pixelformat);
+                       dprintk(3, "size=%dx%d, fmt=0x%x (%4.4s)\n",
+                               fmt->fmt.pix.width, fmt->fmt.pix.height,
+                               fmt->fmt.pix.pixelformat,
+                               (char *) &printformat);
+
+                       if (fmt->fmt.pix.bytesperline > 0) {
+                               dprintk(5,
+                                       KERN_ERR "%s: bpl not supported\n",
+                                       ZR_DEVNAME(zr));
+                               return -EINVAL;
+                       }
+
+                       /* we can be requested to do JPEG/raw playback/capture */
+                       if (!
+                           (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                            (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+                             fmt->fmt.pix.pixelformat ==
+                             V4L2_PIX_FMT_MJPEG))) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: VIDIOC_S_FMT - unknown type %d/0x%x(%4.4s) combination\n",
+                                       ZR_DEVNAME(zr), fmt->type,
+                                       fmt->fmt.pix.pixelformat,
+                                       (char *) &printformat);
+                               return -EINVAL;
+                       }
+
+                       if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
+                               struct zoran_jpg_settings settings;
+
+                               down(&zr->resource_lock);
+
+                               settings = fh->jpg_settings;
+
+                               if (fh->v4l_buffers.allocated ||
+                                   fh->jpg_buffers.allocated) {
+                                       dprintk(1,
+                                               KERN_ERR
+                                               "%s: VIDIOC_S_FMT - cannot change capture mode\n",
+                                               ZR_DEVNAME(zr));
+                                       res = -EBUSY;
+                                       goto sfmtjpg_unlock_and_return;
+                               }
+
+                               /* we actually need to set 'real' parameters now */
+                               if ((fmt->fmt.pix.height * 2) >
+                                   BUZ_MAX_HEIGHT)
+                                       settings.TmpDcm = 1;
+                               else
+                                       settings.TmpDcm = 2;
+                               settings.decimation = 0;
+                               if (fmt->fmt.pix.height <=
+                                   fh->jpg_settings.img_height / 2)
+                                       settings.VerDcm = 2;
+                               else
+                                       settings.VerDcm = 1;
+                               if (fmt->fmt.pix.width <=
+                                   fh->jpg_settings.img_width / 4)
+                                       settings.HorDcm = 4;
+                               else if (fmt->fmt.pix.width <=
+                                        fh->jpg_settings.img_width / 2)
+                                       settings.HorDcm = 2;
+                               else
+                                       settings.HorDcm = 1;
+                               if (settings.TmpDcm == 1)
+                                       settings.field_per_buff = 2;
+                               else
+                                       settings.field_per_buff = 1;
+
+                               /* check */
+                               if ((res =
+                                    zoran_check_jpg_settings(zr,
+                                                             &settings)))
+                                       goto sfmtjpg_unlock_and_return;
+
+                               /* it's ok, so set them */
+                               fh->jpg_settings = settings;
+
+                               /* tell the user what we actually did */
+                               fmt->fmt.pix.width =
+                                   settings.img_width / settings.HorDcm;
+                               fmt->fmt.pix.height =
+                                   settings.img_height * 2 /
+                                   (settings.TmpDcm * settings.VerDcm);
+                               if (settings.TmpDcm == 1)
+                                       fmt->fmt.pix.field =
+                                           (fh->jpg_settings.
+                                            odd_even ? V4L2_FIELD_SEQ_TB :
+                                            V4L2_FIELD_SEQ_BT);
+                               else
+                                       fmt->fmt.pix.field =
+                                           (fh->jpg_settings.
+                                            odd_even ? V4L2_FIELD_TOP :
+                                            V4L2_FIELD_BOTTOM);
+                               fh->jpg_buffers.buffer_size =
+                                   zoran_v4l2_calc_bufsize(&fh->
+                                                           jpg_settings);
+                               fmt->fmt.pix.sizeimage =
+                                   fh->jpg_buffers.buffer_size;
+
+                               /* we hereby abuse this variable to show that
+                                * we're gonna do mjpeg capture */
+                               fh->map_mode =
+                                   (fmt->type ==
+                                    V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
+                                   ZORAN_MAP_MODE_JPG_REC :
+                                   ZORAN_MAP_MODE_JPG_PLAY;
+                       sfmtjpg_unlock_and_return:
+                               up(&zr->resource_lock);
+                       } else {
+                               for (i = 0; i < zoran_num_formats; i++)
+                                       if (fmt->fmt.pix.pixelformat ==
+                                           zoran_formats[i].fourcc)
+                                               break;
+                               if (i == zoran_num_formats) {
+                                       dprintk(1,
+                                               KERN_ERR
+                                               "%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x (%4.4s)\n",
+                                               ZR_DEVNAME(zr),
+                                               fmt->fmt.pix.pixelformat,
+                                               (char *) &printformat);
+                                       return -EINVAL;
+                               }
+                               down(&zr->resource_lock);
+                               if (fh->jpg_buffers.allocated ||
+                                   (fh->v4l_buffers.allocated &&
+                                    fh->v4l_buffers.active !=
+                                    ZORAN_FREE)) {
+                                       dprintk(1,
+                                               KERN_ERR
+                                               "%s: VIDIOC_S_FMT - cannot change capture mode\n",
+                                               ZR_DEVNAME(zr));
+                                       res = -EBUSY;
+                                       goto sfmtv4l_unlock_and_return;
+                               }
+                               if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
+                                       fmt->fmt.pix.height =
+                                           BUZ_MAX_HEIGHT;
+                               if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
+                                       fmt->fmt.pix.width = BUZ_MAX_WIDTH;
+
+                               if ((res =
+                                    zoran_v4l_set_format(file,
+                                                         fmt->fmt.pix.
+                                                         width,
+                                                         fmt->fmt.pix.
+                                                         height,
+                                                         &zoran_formats
+                                                         [i])))
+                                       goto sfmtv4l_unlock_and_return;
+
+                               /* tell the user the
+                                * results/missing stuff */
+                               fmt->fmt.pix.sizeimage = fh->v4l_buffers.buffer_size    /*zr->gbpl * zr->gheight */
+                                   ;
+                               if (BUZ_MAX_HEIGHT <
+                                   (fh->v4l_settings.height * 2))
+                                       fmt->fmt.pix.field =
+                                           V4L2_FIELD_INTERLACED;
+                               else
+                                       fmt->fmt.pix.field =
+                                           V4L2_FIELD_TOP;
+
+                               fh->map_mode = ZORAN_MAP_MODE_RAW;
+                       sfmtv4l_unlock_and_return:
+                               up(&zr->resource_lock);
+                       }
+
+                       break;
+
+               default:
+                       dprintk(3, "unsupported\n");
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_S_FMT - unsupported type %d\n",
+                               ZR_DEVNAME(zr), fmt->type);
+                       return -EINVAL;
+               }
+
+               return res;
+       }
+               break;
+
+       case VIDIOC_G_FBUF:
+       {
+               struct v4l2_framebuffer *fb = arg;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_G_FBUF\n", ZR_DEVNAME(zr));
+
+               memset(fb, 0, sizeof(*fb));
+               down(&zr->resource_lock);
+               fb->base = zr->buffer.base;
+               fb->fmt.width = zr->buffer.width;
+               fb->fmt.height = zr->buffer.height;
+               if (zr->overlay_settings.format) {
+                       fb->fmt.pixelformat =
+                               fh->overlay_settings.format->fourcc;
+               }
+               fb->fmt.bytesperline = zr->buffer.bytesperline;
+               up(&zr->resource_lock);
+               fb->fmt.colorspace = V4L2_COLORSPACE_SRGB;
+               fb->fmt.field = V4L2_FIELD_INTERLACED;
+               fb->flags = V4L2_FBUF_FLAG_OVERLAY;
+               fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_S_FBUF:
+       {
+               int i, res = 0;
+               struct v4l2_framebuffer *fb = arg;
+               __u32 printformat = __cpu_to_le32(fb->fmt.pixelformat);
+
+               dprintk(3,
+                       KERN_DEBUG
+                       "%s: VIDIOC_S_FBUF - base=0x%p, size=%dx%d, bpl=%d, fmt=0x%x (%4.4s)\n",
+                       ZR_DEVNAME(zr), fb->base, fb->fmt.width, fb->fmt.height,
+                       fb->fmt.bytesperline, fb->fmt.pixelformat,
+                       (char *) &printformat);
+
+               for (i = 0; i < zoran_num_formats; i++)
+                       if (zoran_formats[i].fourcc == fb->fmt.pixelformat)
+                               break;
+               if (i == zoran_num_formats) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n",
+                               ZR_DEVNAME(zr), fb->fmt.pixelformat,
+                               (char *) &printformat);
+                       return -EINVAL;
+               }
+
+               down(&zr->resource_lock);
+               res =
+                   setup_fbuffer(file, fb->base, &zoran_formats[i],
+                                 fb->fmt.width, fb->fmt.height,
+                                 fb->fmt.bytesperline);
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case VIDIOC_OVERLAY:
+       {
+               int *on = arg, res;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_PREVIEW - on=%d\n",
+                       ZR_DEVNAME(zr), *on);
+
+               down(&zr->resource_lock);
+               res = setup_overlay(file, *on);
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case VIDIOC_REQBUFS:
+       {
+               struct v4l2_requestbuffers *req = arg;
+               int res = 0;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_REQBUFS - type=%d\n",
+                       ZR_DEVNAME(zr), req->type);
+
+               if (req->memory != V4L2_MEMORY_MMAP) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: only MEMORY_MMAP capture is supported, not %d\n",
+                               ZR_DEVNAME(zr), req->memory);
+                       return -EINVAL;
+               }
+
+               down(&zr->resource_lock);
+
+               if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_REQBUFS - buffers allready allocated\n",
+                               ZR_DEVNAME(zr));
+                       res = -EBUSY;
+                       goto v4l2reqbuf_unlock_and_return;
+               }
+
+               if (fh->map_mode == ZORAN_MAP_MODE_RAW &&
+                   req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+
+                       /* control user input */
+                       if (req->count < 2)
+                               req->count = 2;
+                       if (req->count > v4l_nbufs)
+                               req->count = v4l_nbufs;
+                       fh->v4l_buffers.num_buffers = req->count;
+
+                       if (v4l_fbuffer_alloc(file)) {
+                               res = -ENOMEM;
+                               goto v4l2reqbuf_unlock_and_return;
+                       }
+
+                       /* The next mmap will map the V4L buffers */
+                       fh->map_mode = ZORAN_MAP_MODE_RAW;
+
+               } else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC ||
+                          fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
+
+                       /* we need to calculate size ourselves now */
+                       if (req->count < 4)
+                               req->count = 4;
+                       if (req->count > jpg_nbufs)
+                               req->count = jpg_nbufs;
+                       fh->jpg_buffers.num_buffers = req->count;
+                       fh->jpg_buffers.buffer_size =
+                           zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+
+                       if (jpg_fbuffer_alloc(file)) {
+                               res = -ENOMEM;
+                               goto v4l2reqbuf_unlock_and_return;
+                       }
+
+                       /* The next mmap will map the MJPEG buffers */
+                       if (req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                               fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
+                       else
+                               fh->map_mode = ZORAN_MAP_MODE_JPG_PLAY;
+
+               } else {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_REQBUFS - unknown type %d\n",
+                               ZR_DEVNAME(zr), req->type);
+                       res = -EINVAL;
+                       goto v4l2reqbuf_unlock_and_return;
+               }
+       v4l2reqbuf_unlock_and_return:
+               up(&zr->resource_lock);
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_QUERYBUF:
+       {
+               struct v4l2_buffer *buf = arg;
+               __u32 type = buf->type;
+               int index = buf->index, res;
+
+               dprintk(3,
+                       KERN_DEBUG
+                       "%s: VIDIOC_QUERYBUF - index=%d, type=%d\n",
+                       ZR_DEVNAME(zr), buf->index, buf->type);
+
+               memset(buf, 0, sizeof(buf));
+               buf->type = type;
+               buf->index = index;
+
+               down(&zr->resource_lock);
+               res = zoran_v4l2_buffer_status(file, buf, buf->index);
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case VIDIOC_QBUF:
+       {
+               struct v4l2_buffer *buf = arg;
+               int res = 0, codec_mode, buf_type;
+
+               dprintk(3,
+                       KERN_DEBUG "%s: VIDIOC_QBUF - type=%d, index=%d\n",
+                       ZR_DEVNAME(zr), buf->type, buf->index);
+
+               down(&zr->resource_lock);
+
+               switch (fh->map_mode) {
+               case ZORAN_MAP_MODE_RAW:
+                       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+                                       ZR_DEVNAME(zr), buf->type, fh->map_mode);
+                               res = -EINVAL;
+                               goto qbuf_unlock_and_return;
+                       }
+
+                       res = zoran_v4l_queue_frame(file, buf->index);
+                       if (res)
+                               goto qbuf_unlock_and_return;
+                       if (!zr->v4l_memgrab_active &&
+                           fh->v4l_buffers.active == ZORAN_LOCKED)
+                               zr36057_set_memgrab(zr, 1);
+                       break;
+
+               case ZORAN_MAP_MODE_JPG_REC:
+               case ZORAN_MAP_MODE_JPG_PLAY:
+                       if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
+                               buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+                               codec_mode = BUZ_MODE_MOTION_DECOMPRESS;
+                       } else {
+                               buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                               codec_mode = BUZ_MODE_MOTION_COMPRESS;
+                       }
+
+                       if (buf->type != buf_type) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+                                       ZR_DEVNAME(zr), buf->type, fh->map_mode);
+                               res = -EINVAL;
+                               goto qbuf_unlock_and_return;
+                       }
+
+                       res =
+                           zoran_jpg_queue_frame(file, buf->index,
+                                                 codec_mode);
+                       if (res != 0)
+                               goto qbuf_unlock_and_return;
+                       if (zr->codec_mode == BUZ_MODE_IDLE &&
+                           fh->jpg_buffers.active == ZORAN_LOCKED) {
+                               zr36057_enable_jpg(zr, codec_mode);
+                       }
+                       break;
+
+               default:
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_QBUF - unsupported type %d\n",
+                               ZR_DEVNAME(zr), buf->type);
+                       res = -EINVAL;
+                       goto qbuf_unlock_and_return;
+               }
+       qbuf_unlock_and_return:
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case VIDIOC_DQBUF:
+       {
+               struct v4l2_buffer *buf = arg;
+               int res = 0, buf_type, num = -1;        /* compiler borks here (?) */
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_DQBUF - type=%d\n",
+                       ZR_DEVNAME(zr), buf->type);
+
+               down(&zr->resource_lock);
+
+               switch (fh->map_mode) {
+               case ZORAN_MAP_MODE_RAW:
+                       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+                                       ZR_DEVNAME(zr), buf->type, fh->map_mode);
+                               res = -EINVAL;
+                               goto dqbuf_unlock_and_return;
+                       }
+
+                       num = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME];
+                       if (file->f_flags & O_NONBLOCK &&
+                           zr->v4l_buffers.buffer[num].state !=
+                           BUZ_STATE_DONE) {
+                               res = -EAGAIN;
+                               goto dqbuf_unlock_and_return;
+                       }
+                       res = v4l_sync(file, num);
+                       if (res)
+                               goto dqbuf_unlock_and_return;
+                       else
+                               zr->v4l_sync_tail++;
+                       res = zoran_v4l2_buffer_status(file, buf, num);
+                       break;
+
+               case ZORAN_MAP_MODE_JPG_REC:
+               case ZORAN_MAP_MODE_JPG_PLAY:
+               {
+                       struct zoran_sync bs;
+
+                       if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY)
+                               buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+                       else
+                               buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+                       if (buf->type != buf_type) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+                                       ZR_DEVNAME(zr), buf->type, fh->map_mode);
+                               res = -EINVAL;
+                               goto dqbuf_unlock_and_return;
+                       }
+
+                       num =
+                           zr->jpg_pend[zr->
+                                        jpg_que_tail & BUZ_MASK_FRAME];
+
+                       if (file->f_flags & O_NONBLOCK &&
+                           zr->jpg_buffers.buffer[num].state !=
+                           BUZ_STATE_DONE) {
+                               res = -EAGAIN;
+                               goto dqbuf_unlock_and_return;
+                       }
+                       res = jpg_sync(file, &bs);
+                       if (res)
+                               goto dqbuf_unlock_and_return;
+                       res =
+                           zoran_v4l2_buffer_status(file, buf, bs.frame);
+                       break;
+               }
+
+               default:
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_DQBUF - unsupported type %d\n",
+                               ZR_DEVNAME(zr), buf->type);
+                       res = -EINVAL;
+                       goto dqbuf_unlock_and_return;
+               }
+       dqbuf_unlock_and_return:
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case VIDIOC_STREAMON:
+       {
+               int res = 0;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMON\n", ZR_DEVNAME(zr));
+
+               down(&zr->resource_lock);
+
+               switch (fh->map_mode) {
+               case ZORAN_MAP_MODE_RAW:        /* raw capture */
+                       if (zr->v4l_buffers.active != ZORAN_ACTIVE ||
+                           fh->v4l_buffers.active != ZORAN_ACTIVE) {
+                               res = -EBUSY;
+                               goto strmon_unlock_and_return;
+                       }
+
+                       zr->v4l_buffers.active = fh->v4l_buffers.active =
+                           ZORAN_LOCKED;
+                       zr->v4l_settings = fh->v4l_settings;
+
+                       zr->v4l_sync_tail = zr->v4l_pend_tail;
+                       if (!zr->v4l_memgrab_active &&
+                           zr->v4l_pend_head != zr->v4l_pend_tail) {
+                               zr36057_set_memgrab(zr, 1);
+                       }
+                       break;
+
+               case ZORAN_MAP_MODE_JPG_REC:
+               case ZORAN_MAP_MODE_JPG_PLAY:
+                       /* what is the codec mode right now? */
+                       if (zr->jpg_buffers.active != ZORAN_ACTIVE ||
+                           fh->jpg_buffers.active != ZORAN_ACTIVE) {
+                               res = -EBUSY;
+                               goto strmon_unlock_and_return;
+                       }
+
+                       zr->jpg_buffers.active = fh->jpg_buffers.active =
+                           ZORAN_LOCKED;
+
+                       if (zr->jpg_que_head != zr->jpg_que_tail) {
+                               /* Start the jpeg codec when the first frame is queued  */
+                               jpeg_start(zr);
+                       }
+
+                       break;
+               default:
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_STREAMON - invalid map mode %d\n",
+                               ZR_DEVNAME(zr), fh->map_mode);
+                       res = -EINVAL;
+                       goto strmon_unlock_and_return;
+               }
+       strmon_unlock_and_return:
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case VIDIOC_STREAMOFF:
+       {
+               int i, res = 0;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMOFF\n", ZR_DEVNAME(zr));
+
+               down(&zr->resource_lock);
+
+               switch (fh->map_mode) {
+               case ZORAN_MAP_MODE_RAW:        /* raw capture */
+                       if (fh->v4l_buffers.active == ZORAN_FREE &&
+                           zr->v4l_buffers.active != ZORAN_FREE) {
+                               res = -EPERM;   /* stay off other's settings! */
+                               goto strmoff_unlock_and_return;
+                       }
+                       if (zr->v4l_buffers.active == ZORAN_FREE)
+                               goto strmoff_unlock_and_return;
+
+                       /* unload capture */
+                       if (zr->v4l_memgrab_active)
+                               zr36057_set_memgrab(zr, 0);
+
+                       for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
+                               zr->v4l_buffers.buffer[i].state =
+                                   BUZ_STATE_USER;
+                       fh->v4l_buffers = zr->v4l_buffers;
+
+                       zr->v4l_buffers.active = fh->v4l_buffers.active =
+                           ZORAN_FREE;
+
+                       zr->v4l_grab_seq = 0;
+                       zr->v4l_pend_head = zr->v4l_pend_tail = 0;
+                       zr->v4l_sync_tail = 0;
+
+                       break;
+
+               case ZORAN_MAP_MODE_JPG_REC:
+               case ZORAN_MAP_MODE_JPG_PLAY:
+                       if (fh->jpg_buffers.active == ZORAN_FREE &&
+                           zr->jpg_buffers.active != ZORAN_FREE) {
+                               res = -EPERM;   /* stay off other's settings! */
+                               goto strmoff_unlock_and_return;
+                       }
+                       if (zr->jpg_buffers.active == ZORAN_FREE)
+                               goto strmoff_unlock_and_return;
+
+                       res =
+                           jpg_qbuf(file, -1,
+                                    (fh->map_mode ==
+                                     ZORAN_MAP_MODE_JPG_REC) ?
+                                    BUZ_MODE_MOTION_COMPRESS :
+                                    BUZ_MODE_MOTION_DECOMPRESS);
+                       if (res)
+                               goto strmoff_unlock_and_return;
+                       break;
+               default:
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_STREAMOFF - invalid map mode %d\n",
+                               ZR_DEVNAME(zr), fh->map_mode);
+                       res = -EINVAL;
+                       goto strmoff_unlock_and_return;
+               }
+       strmoff_unlock_and_return:
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *ctrl = arg;
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCTRL - id=%d\n",
+                       ZR_DEVNAME(zr), ctrl->id);
+
+               /* we only support hue/saturation/contrast/brightness */
+               if (ctrl->id < V4L2_CID_BRIGHTNESS ||
+                   ctrl->id > V4L2_CID_HUE)
+                       return -EINVAL;
+               else {
+                       int id = ctrl->id;
+                       memset(ctrl, 0, sizeof(*ctrl));
+                       ctrl->id = id;
+               }
+
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       strncpy(ctrl->name, "Brightness", 31);
+                       break;
+               case V4L2_CID_CONTRAST:
+                       strncpy(ctrl->name, "Contrast", 31);
+                       break;
+               case V4L2_CID_SATURATION:
+                       strncpy(ctrl->name, "Saturation", 31);
+                       break;
+               case V4L2_CID_HUE:
+                       strncpy(ctrl->name, "Hue", 31);
+                       break;
+               }
+
+               ctrl->minimum = 0;
+               ctrl->maximum = 65535;
+               ctrl->step = 1;
+               ctrl->default_value = 32768;
+               ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_G_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_G_CTRL - id=%d\n",
+                       ZR_DEVNAME(zr), ctrl->id);
+
+               /* we only support hue/saturation/contrast/brightness */
+               if (ctrl->id < V4L2_CID_BRIGHTNESS ||
+                   ctrl->id > V4L2_CID_HUE)
+                       return -EINVAL;
+
+               down(&zr->resource_lock);
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       ctrl->value = zr->brightness;
+                       break;
+               case V4L2_CID_CONTRAST:
+                       ctrl->value = zr->contrast;
+                       break;
+               case V4L2_CID_SATURATION:
+                       ctrl->value = zr->saturation;
+                       break;
+               case V4L2_CID_HUE:
+                       ctrl->value = zr->hue;
+                       break;
+               }
+               up(&zr->resource_lock);
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_S_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+               struct video_picture pict;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_S_CTRL - id=%d\n",
+                       ZR_DEVNAME(zr), ctrl->id);
+
+               /* we only support hue/saturation/contrast/brightness */
+               if (ctrl->id < V4L2_CID_BRIGHTNESS ||
+                   ctrl->id > V4L2_CID_HUE)
+                       return -EINVAL;
+
+               if (ctrl->value < 0 || ctrl->value > 65535) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_S_CTRL - invalid value %d for id=%d\n",
+                               ZR_DEVNAME(zr), ctrl->value, ctrl->id);
+                       return -EINVAL;
+               }
+
+               down(&zr->resource_lock);
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       zr->brightness = ctrl->value;
+                       break;
+               case V4L2_CID_CONTRAST:
+                       zr->contrast = ctrl->value;
+                       break;
+               case V4L2_CID_SATURATION:
+                       zr->saturation = ctrl->value;
+                       break;
+               case V4L2_CID_HUE:
+                       zr->hue = ctrl->value;
+                       break;
+               }
+               pict.brightness = zr->brightness;
+               pict.contrast = zr->contrast;
+               pict.colour = zr->saturation;
+               pict.hue = zr->hue;
+
+               decoder_command(zr, DECODER_SET_PICTURE, &pict);
+
+               up(&zr->resource_lock);
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_ENUMSTD:
+       {
+               struct v4l2_standard *std = arg;
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMSTD - index=%d\n",
+                       ZR_DEVNAME(zr), std->index);
+
+               if (std->index < 0 || std->index >= (zr->card.norms + 1))
+                       return -EINVAL;
+               else {
+                       int id = std->index;
+                       memset(std, 0, sizeof(*std));
+                       std->index = id;
+               }
+
+               if (std->index == zr->card.norms) {
+                       /* if we have autodetect, ... */
+                       struct video_decoder_capability caps;
+                       decoder_command(zr, DECODER_GET_CAPABILITIES,
+                                       &caps);
+                       if (caps.flags & VIDEO_DECODER_AUTO) {
+                               std->id = V4L2_STD_ALL;
+                               strncpy(std->name, "Autodetect", 31);
+                               return 0;
+                       } else
+                               return -EINVAL;
+               }
+               switch (std->index) {
+               case 0:
+                       std->id = V4L2_STD_PAL;
+                       strncpy(std->name, "PAL", 31);
+                       std->frameperiod.numerator = 1;
+                       std->frameperiod.denominator = 25;
+                       std->framelines = zr->card.tvn[0]->Ht;
+                       break;
+               case 1:
+                       std->id = V4L2_STD_NTSC;
+                       strncpy(std->name, "NTSC", 31);
+                       std->frameperiod.numerator = 1001;
+                       std->frameperiod.denominator = 30000;
+                       std->framelines = zr->card.tvn[1]->Ht;
+                       break;
+               case 2:
+                       std->id = V4L2_STD_SECAM;
+                       strncpy(std->name, "SECAM", 31);
+                       std->frameperiod.numerator = 1;
+                       std->frameperiod.denominator = 25;
+                       std->framelines = zr->card.tvn[2]->Ht;
+                       break;
+               }
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_G_STD:
+       {
+               v4l2_std_id *std = arg;
+               int norm;
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_G_STD\n", ZR_DEVNAME(zr));
+
+               down(&zr->resource_lock);
+               norm = zr->norm;
+               up(&zr->resource_lock);
+
+               switch (norm) {
+               case VIDEO_MODE_PAL:
+                       *std = V4L2_STD_PAL;
+                       break;
+               case VIDEO_MODE_NTSC:
+                       *std = V4L2_STD_NTSC;
+                       break;
+               case VIDEO_MODE_SECAM:
+                       *std = V4L2_STD_SECAM;
+                       break;
+               }
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_S_STD:
+       {
+               int norm = -1, res = 0;
+               v4l2_std_id *std = arg;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_S_STD - norm=0x%llx\n",
+                       ZR_DEVNAME(zr), *std);
+
+               if (*std == V4L2_STD_PAL)
+                       norm = VIDEO_MODE_PAL;
+               else if (*std == V4L2_STD_NTSC)
+                       norm = VIDEO_MODE_NTSC;
+               else if (*std == V4L2_STD_SECAM)
+                       norm = VIDEO_MODE_SECAM;
+               else if (*std == V4L2_STD_ALL)
+                       norm = VIDEO_MODE_AUTO;
+               else {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_S_STD - invalid norm 0x%llx\n",
+                               ZR_DEVNAME(zr), *std);
+                       return -EINVAL;
+               }
+
+               down(&zr->resource_lock);
+               if ((res = zoran_set_norm(zr, norm)))
+                       goto sstd_unlock_and_return;
+
+               res = wait_grab_pending(zr);
+       sstd_unlock_and_return:
+               up(&zr->resource_lock);
+               return res;
+       }
+               break;
+
+       case VIDIOC_ENUMINPUT:
+       {
+               struct v4l2_input *inp = arg;
+               int status;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMINPUT - index=%d\n",
+                       ZR_DEVNAME(zr), inp->index);
+
+               if (inp->index < 0 || inp->index >= zr->card.inputs)
+                       return -EINVAL;
+               else {
+                       int id = inp->index;
+                       memset(inp, 0, sizeof(*inp));
+                       inp->index = id;
+               }
+
+               strncpy(inp->name, zr->card.input[inp->index].name,
+                       sizeof(inp->name) - 1);
+               inp->type = V4L2_INPUT_TYPE_CAMERA;
+               inp->std = V4L2_STD_ALL;
+
+               /* Get status of video decoder */
+               down(&zr->resource_lock);
+               decoder_command(zr, DECODER_GET_STATUS, &status);
+               up(&zr->resource_lock);
+
+               if (!(status & DECODER_STATUS_GOOD)) {
+                       inp->status |= V4L2_IN_ST_NO_POWER;
+                       inp->status |= V4L2_IN_ST_NO_SIGNAL;
+               }
+               if (!(status & DECODER_STATUS_COLOR))
+                       inp->status |= V4L2_IN_ST_NO_COLOR;
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_G_INPUT:
+       {
+               int *input = arg;
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_G_INPUT\n", ZR_DEVNAME(zr));
+
+               down(&zr->resource_lock);
+               *input = zr->input;
+               up(&zr->resource_lock);
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_S_INPUT:
+       {
+               int *input = arg, res = 0;
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_S_INPUT - input=%d\n",
+                       ZR_DEVNAME(zr), *input);
+
+               down(&zr->resource_lock);
+               if ((res = zoran_set_input(zr, *input)))
+                       goto sinput_unlock_and_return;
+
+               /* Make sure the changes come into effect */
+               res = wait_grab_pending(zr);
+       sinput_unlock_and_return:
+               up(&zr->resource_lock);
+               return res;
+       }
+               break;
+
+       case VIDIOC_ENUMOUTPUT:
+       {
+               struct v4l2_output *outp = arg;
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMOUTPUT - index=%d\n",
+                       ZR_DEVNAME(zr), outp->index);
+
+               if (outp->index != 0)
+                       return -EINVAL;
+
+               memset(outp, 0, sizeof(*outp));
+               outp->index = 0;
+               outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
+               strncpy(outp->name, "Autodetect", 31);
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_G_OUTPUT:
+       {
+               int *output = arg;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_G_OUTPUT\n", ZR_DEVNAME(zr));
+
+               *output = 0;
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_S_OUTPUT:
+       {
+               int *output = arg;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_S_OUTPUT - output=%d\n",
+                       ZR_DEVNAME(zr), *output);
+
+               if (*output != 0)
+                       return -EINVAL;
+
+               return 0;
+       }
+               break;
+
+               /* cropping (sub-frame capture) */
+       case VIDIOC_CROPCAP:
+       {
+               struct v4l2_cropcap *cropcap = arg;
+               int type = cropcap->type, res = 0;
+
+               dprintk(3, KERN_ERR "%s: VIDIOC_CROPCAP - type=%d\n",
+                       ZR_DEVNAME(zr), cropcap->type);
+
+               memset(cropcap, 0, sizeof(*cropcap));
+               cropcap->type = type;
+
+               down(&zr->resource_lock);
+
+               if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+                   (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                    fh->map_mode == ZORAN_MAP_MODE_RAW)) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_CROPCAP - subcapture only supported for compressed capture\n",
+                               ZR_DEVNAME(zr));
+                       res = -EINVAL;
+                       goto cropcap_unlock_and_return;
+               }
+
+               cropcap->bounds.top = cropcap->bounds.left = 0;
+               cropcap->bounds.width = BUZ_MAX_WIDTH;
+               cropcap->bounds.height = BUZ_MAX_HEIGHT;
+               cropcap->defrect.top = cropcap->defrect.left = 0;
+               cropcap->defrect.width = BUZ_MIN_WIDTH;
+               cropcap->defrect.height = BUZ_MIN_HEIGHT;
+       cropcap_unlock_and_return:
+               up(&zr->resource_lock);
+               return res;
+       }
+               break;
+
+       case VIDIOC_G_CROP:
+       {
+               struct v4l2_crop *crop = arg;
+               int type = crop->type, res = 0;
+
+               dprintk(3, KERN_ERR "%s: VIDIOC_G_CROP - type=%d\n",
+                       ZR_DEVNAME(zr), crop->type);
+
+               memset(crop, 0, sizeof(*crop));
+               crop->type = type;
+
+               down(&zr->resource_lock);
+
+               if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+                   (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                    fh->map_mode == ZORAN_MAP_MODE_RAW)) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
+                               ZR_DEVNAME(zr));
+                       res = -EINVAL;
+                       goto gcrop_unlock_and_return;
+               }
+
+               crop->c.top = fh->jpg_settings.img_y;
+               crop->c.left = fh->jpg_settings.img_x;
+               crop->c.width = fh->jpg_settings.img_width;
+               crop->c.height = fh->jpg_settings.img_height;
+
+       gcrop_unlock_and_return:
+               up(&zr->resource_lock);
+
+               return res;
+       }
+               break;
+
+       case VIDIOC_S_CROP:
+       {
+               struct v4l2_crop *crop = arg;
+               int res = 0;
+               struct zoran_jpg_settings settings = fh->jpg_settings;
+
+               dprintk(3,
+                       KERN_ERR
+                       "%s: VIDIOC_S_CROP - type=%d, x=%d,y=%d,w=%d,h=%d\n",
+                       ZR_DEVNAME(zr), crop->type, crop->c.left, crop->c.top,
+                       crop->c.width, crop->c.height);
+
+               down(&zr->resource_lock);
+
+               if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_S_CROP - cannot change settings while active\n",
+                               ZR_DEVNAME(zr));
+                       res = -EBUSY;
+                       goto scrop_unlock_and_return;
+               }
+
+               if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+                   (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                    fh->map_mode == ZORAN_MAP_MODE_RAW)) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
+                               ZR_DEVNAME(zr));
+                       res = -EINVAL;
+                       goto scrop_unlock_and_return;
+               }
+
+               /* move into a form that we understand */
+               settings.img_x = crop->c.left;
+               settings.img_y = crop->c.top;
+               settings.img_width = crop->c.width;
+               settings.img_height = crop->c.height;
+
+               /* check validity */
+               if ((res = zoran_check_jpg_settings(zr, &settings)))
+                       goto scrop_unlock_and_return;
+
+               /* accept */
+               fh->jpg_settings = settings;
+
+       scrop_unlock_and_return:
+               up(&zr->resource_lock);
+               return res;
+       }
+               break;
+
+       case VIDIOC_G_JPEGCOMP:
+       {
+               struct v4l2_jpegcompression *params = arg;
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_G_JPEGCOMP\n", ZR_DEVNAME(zr));
+
+               memset(params, 0, sizeof(*params));
+
+               down(&zr->resource_lock);
+
+               params->quality = fh->jpg_settings.jpg_comp.quality;
+               params->APPn = fh->jpg_settings.jpg_comp.APPn;
+               memcpy(params->APP_data,
+                      fh->jpg_settings.jpg_comp.APP_data,
+                      fh->jpg_settings.jpg_comp.APP_len);
+               params->APP_len = fh->jpg_settings.jpg_comp.APP_len;
+               memcpy(params->COM_data,
+                      fh->jpg_settings.jpg_comp.COM_data,
+                      fh->jpg_settings.jpg_comp.COM_len);
+               params->COM_len = fh->jpg_settings.jpg_comp.COM_len;
+               params->jpeg_markers =
+                   fh->jpg_settings.jpg_comp.jpeg_markers;
+
+               up(&zr->resource_lock);
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_S_JPEGCOMP:
+       {
+               struct v4l2_jpegcompression *params = arg;
+               struct zoran_jpg_settings settings = fh->jpg_settings;
+               int res = 0;
+
+               dprintk(3,
+                       KERN_DEBUG
+                       "%s: VIDIOC_S_JPEGCOMP - quality=%d, APPN=%d, APP_len=%d, COM_len=%d\n",
+                       ZR_DEVNAME(zr), params->quality, params->APPn,
+                       params->APP_len, params->COM_len);
+
+               settings.jpg_comp = *params;
+
+               down(&zr->resource_lock);
+
+               if (fh->v4l_buffers.active != ZORAN_FREE ||
+                   fh->jpg_buffers.active != ZORAN_FREE) {
+                       dprintk(1,
+                               KERN_WARNING
+                               "%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n",
+                               ZR_DEVNAME(zr));
+                       res = -EBUSY;
+                       goto sjpegc_unlock_and_return;
+               }
+
+               if ((res = zoran_check_jpg_settings(zr, &settings)))
+                       goto sjpegc_unlock_and_return;
+               if (!fh->jpg_buffers.allocated)
+                       fh->jpg_buffers.buffer_size =
+                           zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+               fh->jpg_settings.jpg_comp = *params = settings.jpg_comp;
+       sjpegc_unlock_and_return:
+               up(&zr->resource_lock);
+
+               return 0;
+       }
+               break;
+
+       case VIDIOC_QUERYSTD:   /* why is this useful? */
+       {
+               v4l2_std_id *std = arg;
+
+               dprintk(3,
+                       KERN_DEBUG "%s: VIDIOC_QUERY_STD - std=0x%llx\n",
+                       ZR_DEVNAME(zr), *std);
+
+               if (*std == V4L2_STD_ALL || *std == V4L2_STD_NTSC ||
+                   *std == V4L2_STD_PAL || (*std == V4L2_STD_SECAM &&
+                                            zr->card.norms == 3)) {
+                       return 0;
+               }
+
+               return -EINVAL;
+       }
+               break;
+
+       case VIDIOC_TRY_FMT:
+       {
+               struct v4l2_format *fmt = arg;
+               int res = 0;
+
+               dprintk(3, KERN_DEBUG "%s: VIDIOC_TRY_FMT - type=%d\n",
+                       ZR_DEVNAME(zr), fmt->type);
+
+               switch (fmt->type) {
+               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+                       down(&zr->resource_lock);
+
+                       if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH)
+                               fmt->fmt.win.w.width = BUZ_MAX_WIDTH;
+                       if (fmt->fmt.win.w.width < BUZ_MIN_WIDTH)
+                               fmt->fmt.win.w.width = BUZ_MIN_WIDTH;
+                       if (fmt->fmt.win.w.height > BUZ_MAX_HEIGHT)
+                               fmt->fmt.win.w.height = BUZ_MAX_HEIGHT;
+                       if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT)
+                               fmt->fmt.win.w.height = BUZ_MIN_HEIGHT;
+
+                       up(&zr->resource_lock);
+                       break;
+
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+                       if (fmt->fmt.pix.bytesperline > 0)
+                               return -EINVAL;
+
+                       down(&zr->resource_lock);
+
+                       if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
+                               struct zoran_jpg_settings settings =
+                                   fh->jpg_settings;
+
+                               /* we actually need to set 'real' parameters now */
+                               if ((fmt->fmt.pix.height * 2) >
+                                   BUZ_MAX_HEIGHT)
+                                       settings.TmpDcm = 1;
+                               else
+                                       settings.TmpDcm = 2;
+                               settings.decimation = 0;
+                               if (fmt->fmt.pix.height <=
+                                   fh->jpg_settings.img_height / 2)
+                                       settings.VerDcm = 2;
+                               else
+                                       settings.VerDcm = 1;
+                               if (fmt->fmt.pix.width <=
+                                   fh->jpg_settings.img_width / 4)
+                                       settings.HorDcm = 4;
+                               else if (fmt->fmt.pix.width <=
+                                        fh->jpg_settings.img_width / 2)
+                                       settings.HorDcm = 2;
+                               else
+                                       settings.HorDcm = 1;
+                               if (settings.TmpDcm == 1)
+                                       settings.field_per_buff = 2;
+                               else
+                                       settings.field_per_buff = 1;
+
+                               /* check */
+                               if ((res =
+                                    zoran_check_jpg_settings(zr,
+                                                             &settings)))
+                                       goto tryfmt_unlock_and_return;
+
+                               /* tell the user what we actually did */
+                               fmt->fmt.pix.width =
+                                   settings.img_width / settings.HorDcm;
+                               fmt->fmt.pix.height =
+                                   settings.img_height * 2 /
+                                   (settings.TmpDcm * settings.VerDcm);
+                               if (settings.TmpDcm == 1)
+                                       fmt->fmt.pix.field =
+                                           (fh->jpg_settings.
+                                            odd_even ? V4L2_FIELD_SEQ_TB :
+                                            V4L2_FIELD_SEQ_BT);
+                               else
+                                       fmt->fmt.pix.field =
+                                           (fh->jpg_settings.
+                                            odd_even ? V4L2_FIELD_TOP :
+                                            V4L2_FIELD_BOTTOM);
+
+                               fmt->fmt.pix.sizeimage =
+                                   zoran_v4l2_calc_bufsize(&settings);
+                       } else if (fmt->type ==
+                                  V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                               int i;
+                               for (i = 0; i < zoran_num_formats; i++)
+                                       if (zoran_formats[i].fourcc ==
+                                           fmt->fmt.pix.pixelformat)
+                                               break;
+                               if (i == zoran_num_formats) {
+                                       res = -EINVAL;
+                                       goto tryfmt_unlock_and_return;
+                               }
+
+                               if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
+                                       fmt->fmt.pix.width = BUZ_MAX_WIDTH;
+                               if (fmt->fmt.pix.width < BUZ_MIN_WIDTH)
+                                       fmt->fmt.pix.width = BUZ_MIN_WIDTH;
+                               if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
+                                       fmt->fmt.pix.height =
+                                           BUZ_MAX_HEIGHT;
+                               if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT)
+                                       fmt->fmt.pix.height =
+                                           BUZ_MIN_HEIGHT;
+                       } else {
+                               res = -EINVAL;
+                               goto tryfmt_unlock_and_return;
+                       }
+               tryfmt_unlock_and_return:
+                       up(&zr->resource_lock);
+
+                       return res;
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+
+               return 0;
+       }
+               break;
+#endif
+
+       default:
+               dprintk(1, KERN_DEBUG "%s: UNKNOWN ioctl cmd: 0x%x\n",
+                       ZR_DEVNAME(zr), cmd);
+               return -ENOIOCTLCMD;
+               break;
+
+       }
+       return 0;
+}
+
+
+static int
+zoran_ioctl (struct inode *inode,
+            struct file  *file,
+            unsigned int  cmd,
+            unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, zoran_do_ioctl);
+}
+
+static unsigned int
+zoran_poll (struct file *file,
+           poll_table  *wait)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       wait_queue_head_t *queue = NULL;
+       int res = 0, frame;
+
+       /* we should check whether buffers are ready to be synced on
+        * (w/o waits - O_NONBLOCK) here
+        * if ready for read (sync), return POLLIN|POLLRDNORM,
+        * if ready for write (sync), return POLLOUT|POLLWRNORM,
+        * if error, return POLLERR,
+        * if no buffers queued or so, return POLLNVAL
+        */
+
+       down(&zr->resource_lock);
+
+       switch (fh->map_mode) {
+       case ZORAN_MAP_MODE_RAW:
+               if (fh->v4l_buffers.active == ZORAN_FREE ||
+                   zr->v4l_pend_head == zr->v4l_pend_tail) {
+                       dprintk(1,
+                               "%s: zoran_poll() - no buffers queued\n",
+                               ZR_DEVNAME(zr));
+                       res = POLLNVAL;
+                       goto poll_unlock_and_return;
+               }
+               queue = &zr->v4l_capq;
+               frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME];
+               poll_wait(file, queue, wait);
+               if (fh->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE)
+                       res = POLLIN | POLLRDNORM;
+               break;
+
+       case ZORAN_MAP_MODE_JPG_REC:
+       case ZORAN_MAP_MODE_JPG_PLAY:
+               if (fh->jpg_buffers.active == ZORAN_FREE ||
+                   zr->jpg_que_head == zr->jpg_que_tail) {
+                       dprintk(1,
+                               "%s: zoran_poll() - no buffers queued\n",
+                               ZR_DEVNAME(zr));
+                       res = POLLNVAL;
+                       goto poll_unlock_and_return;
+               }
+               queue = &zr->jpg_capq;
+               frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
+               poll_wait(file, queue, wait);
+               if (fh->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) {
+                       if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC)
+                               res = POLLIN | POLLRDNORM;
+                       else
+                               res = POLLOUT | POLLWRNORM;
+               }
+               break;
+
+       default:
+               dprintk(1,
+                       "%s: zoran_poll() - internal error, unknown map_mode=%d\n",
+                       ZR_DEVNAME(zr), fh->map_mode);
+               res = POLLNVAL;
+               goto poll_unlock_and_return;
+       }
+
+poll_unlock_and_return:
+       up(&zr->resource_lock);
+
+       return res;
+}
+
+
+/*
+ * This maps the buffers to user space.
+ *
+ * Depending on the state of fh->map_mode
+ * the V4L or the MJPEG buffers are mapped
+ * per buffer or all together
+ *
+ * Note that we need to connect to some
+ * unmap signal event to unmap the de-allocate
+ * the buffer accordingly (zoran_vm_close())
+ */
+
+static void
+zoran_vm_open (struct vm_area_struct *vma)
+{
+       struct zoran_mapping *map = vma->vm_private_data;
+       map->count++;
+}
+
+static void
+zoran_vm_close (struct vm_area_struct *vma)
+{
+       struct zoran_mapping *map = vma->vm_private_data;
+       struct file *file = map->file;
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       int i;
+
+       map->count--;
+       if (map->count == 0) {
+               switch (fh->map_mode) {
+               case ZORAN_MAP_MODE_JPG_REC:
+               case ZORAN_MAP_MODE_JPG_PLAY:
+
+                       dprintk(3, KERN_INFO "%s: munmap(MJPEG)\n",
+                               ZR_DEVNAME(zr));
+
+                       for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
+                               if (fh->jpg_buffers.buffer[i].map == map) {
+                                       fh->jpg_buffers.buffer[i].map =
+                                           NULL;
+                               }
+                       }
+                       kfree(map);
+
+                       for (i = 0; i < fh->jpg_buffers.num_buffers; i++)
+                               if (fh->jpg_buffers.buffer[i].map)
+                                       break;
+                       if (i == fh->jpg_buffers.num_buffers) {
+                               down(&zr->resource_lock);
+
+                               if (fh->jpg_buffers.active != ZORAN_FREE) {
+                                       jpg_qbuf(file, -1, zr->codec_mode);
+                                       zr->jpg_buffers.allocated = 0;
+                                       zr->jpg_buffers.active =
+                                           fh->jpg_buffers.active =
+                                           ZORAN_FREE;
+                               }
+                               //jpg_fbuffer_free(file);
+                               fh->jpg_buffers.allocated = 0;
+                               fh->jpg_buffers.ready_to_be_freed = 1;
+
+                               up(&zr->resource_lock);
+                       }
+
+                       break;
+
+               case ZORAN_MAP_MODE_RAW:
+
+                       dprintk(3, KERN_INFO "%s: munmap(V4L)\n",
+                               ZR_DEVNAME(zr));
+
+                       for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
+                               if (fh->v4l_buffers.buffer[i].map == map) {
+                                       /* unqueue/unmap */
+                                       fh->v4l_buffers.buffer[i].map =
+                                           NULL;
+                               }
+                       }
+                       kfree(map);
+
+                       for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
+                               if (fh->v4l_buffers.buffer[i].map)
+                                       break;
+                       if (i == fh->v4l_buffers.num_buffers) {
+                               down(&zr->resource_lock);
+
+                               if (fh->v4l_buffers.active != ZORAN_FREE) {
+                                       zr36057_set_memgrab(zr, 0);
+                                       zr->v4l_buffers.allocated = 0;
+                                       zr->v4l_buffers.active =
+                                           fh->v4l_buffers.active =
+                                           ZORAN_FREE;
+                               }
+                               //v4l_fbuffer_free(file);
+                               fh->v4l_buffers.allocated = 0;
+                               fh->v4l_buffers.ready_to_be_freed = 1;
+
+                               up(&zr->resource_lock);
+                       }
+
+                       break;
+
+               default:
+                       printk(KERN_ERR
+                              "%s: munmap() - internal error - unknown map mode %d\n",
+                              ZR_DEVNAME(zr), fh->map_mode);
+                       break;
+
+               }
+       }
+}
+
+static struct vm_operations_struct zoran_vm_ops = {
+       .open = zoran_vm_open,
+       .close = zoran_vm_close,
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#define zr_remap_page_range(a,b,c,d,e) remap_page_range(b,c,d,e)
+#else
+#define zr_remap_page_range(a,b,c,d,e) remap_page_range(a,b,c,d,e)
+#endif
+
+static int
+zoran_mmap (struct file           *file,
+           struct vm_area_struct *vma)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       unsigned long size = (vma->vm_end - vma->vm_start);
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       int i, j;
+       unsigned long page, start = vma->vm_start, todo, pos, fraglen;
+       int first, last;
+       struct zoran_mapping *map;
+       int res = 0;
+
+       dprintk(3,
+               KERN_INFO "%s: mmap(%s) of 0x%08lx-0x%08lx (size=%lu)\n",
+               ZR_DEVNAME(zr),
+               fh->map_mode == ZORAN_MAP_MODE_RAW ? "V4L" : "MJPEG",
+               vma->vm_start, vma->vm_end, size);
+
+       if (!(vma->vm_flags & VM_SHARED) || !(vma->vm_flags & VM_READ) ||
+           !(vma->vm_flags & VM_WRITE)) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: mmap() - no MAP_SHARED/PROT_{READ,WRITE} given\n",
+                       ZR_DEVNAME(zr));
+               return -EINVAL;
+       }
+
+       switch (fh->map_mode) {
+
+       case ZORAN_MAP_MODE_JPG_REC:
+       case ZORAN_MAP_MODE_JPG_PLAY:
+
+               /* lock */
+               down(&zr->resource_lock);
+
+               /* Map the MJPEG buffers */
+               if (!fh->jpg_buffers.allocated) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: zoran_mmap(MJPEG) - buffers not yet allocated\n",
+                               ZR_DEVNAME(zr));
+                       res = -ENOMEM;
+                       goto jpg_mmap_unlock_and_return;
+               }
+
+               first = offset / fh->jpg_buffers.buffer_size;
+               last = first - 1 + size / fh->jpg_buffers.buffer_size;
+               if (offset % fh->jpg_buffers.buffer_size != 0 ||
+                   size % fh->jpg_buffers.buffer_size != 0 || first < 0 ||
+                   last < 0 || first >= fh->jpg_buffers.num_buffers ||
+                   last >= fh->jpg_buffers.num_buffers) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: mmap(MJPEG) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
+                               ZR_DEVNAME(zr), offset, size,
+                               fh->jpg_buffers.buffer_size,
+                               fh->jpg_buffers.num_buffers);
+                       res = -EINVAL;
+                       goto jpg_mmap_unlock_and_return;
+               }
+               for (i = first; i <= last; i++) {
+                       if (fh->jpg_buffers.buffer[i].map) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: mmap(MJPEG) - buffer %d already mapped\n",
+                                       ZR_DEVNAME(zr), i);
+                               res = -EBUSY;
+                               goto jpg_mmap_unlock_and_return;
+                       }
+               }
+
+               /* map these buffers (v4l_buffers[i]) */
+               map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
+               if (!map) {
+                       res = -ENOMEM;
+                       goto jpg_mmap_unlock_and_return;
+               }
+               map->file = file;
+               map->count = 1;
+
+               vma->vm_ops = &zoran_vm_ops;
+               vma->vm_flags |= VM_DONTEXPAND;
+               vma->vm_private_data = map;
+
+               for (i = first; i <= last; i++) {
+                       for (j = 0;
+                            j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
+                            j++) {
+                               fraglen =
+                                   (fh->jpg_buffers.buffer[i].
+                                    frag_tab[2 * j + 1] & ~1) << 1;
+                               todo = size;
+                               if (todo > fraglen)
+                                       todo = fraglen;
+                               pos =
+                                   (unsigned long) fh->jpg_buffers.
+                                   buffer[i].frag_tab[2 * j];
+                               page = virt_to_phys(bus_to_virt(pos));  /* should just be pos on i386 */
+                               if (zr_remap_page_range
+                                   (vma, start, page, todo, PAGE_SHARED)) {
+                                       dprintk(1,
+                                               KERN_ERR
+                                               "%s: zoran_mmap(V4L) - remap_page_range failed\n",
+                                               ZR_DEVNAME(zr));
+                                       res = -EAGAIN;
+                                       goto jpg_mmap_unlock_and_return;
+                               }
+                               size -= todo;
+                               start += todo;
+                               if (size == 0)
+                                       break;
+                               if (fh->jpg_buffers.buffer[i].
+                                   frag_tab[2 * j + 1] & 1)
+                                       break;  /* was last fragment */
+                       }
+                       fh->jpg_buffers.buffer[i].map = map;
+                       if (size == 0)
+                               break;
+
+               }
+       jpg_mmap_unlock_and_return:
+               up(&zr->resource_lock);
+
+               break;
+
+       case ZORAN_MAP_MODE_RAW:
+
+               down(&zr->resource_lock);
+
+               /* Map the V4L buffers */
+               if (!fh->v4l_buffers.allocated) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: zoran_mmap(V4L) - buffers not yet allocated\n",
+                               ZR_DEVNAME(zr));
+                       res = -ENOMEM;
+                       goto v4l_mmap_unlock_and_return;
+               }
+
+               first = offset / fh->v4l_buffers.buffer_size;
+               last = first - 1 + size / fh->v4l_buffers.buffer_size;
+               if (offset % fh->v4l_buffers.buffer_size != 0 ||
+                   size % fh->v4l_buffers.buffer_size != 0 || first < 0 ||
+                   last < 0 || first >= fh->v4l_buffers.num_buffers ||
+                   last >= fh->v4l_buffers.buffer_size) {
+                       dprintk(1,
+                               KERN_ERR
+                               "%s: mmap(V4L) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
+                               ZR_DEVNAME(zr), offset, size,
+                               fh->v4l_buffers.buffer_size,
+                               fh->v4l_buffers.num_buffers);
+                       res = -EINVAL;
+                       goto v4l_mmap_unlock_and_return;
+               }
+               for (i = first; i <= last; i++) {
+                       if (fh->v4l_buffers.buffer[i].map) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: mmap(V4L) - buffer %d already mapped\n",
+                                       ZR_DEVNAME(zr), i);
+                               res = -EBUSY;
+                               goto v4l_mmap_unlock_and_return;
+                       }
+               }
+
+               /* map these buffers (v4l_buffers[i]) */
+               map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
+               if (!map) {
+                       res = -ENOMEM;
+                       goto v4l_mmap_unlock_and_return;
+               }
+               map->file = file;
+               map->count = 1;
+
+               vma->vm_ops = &zoran_vm_ops;
+               vma->vm_flags |= VM_DONTEXPAND;
+               vma->vm_private_data = map;
+
+               for (i = first; i <= last; i++) {
+                       todo = size;
+                       if (todo > fh->v4l_buffers.buffer_size)
+                               todo = fh->v4l_buffers.buffer_size;
+                       page = fh->v4l_buffers.buffer[i].fbuffer_phys;
+                       if (zr_remap_page_range
+                           (vma, start, page, todo, PAGE_SHARED)) {
+                               dprintk(1,
+                                       KERN_ERR
+                                       "%s: zoran_mmap(V4L)i - remap_page_range failed\n",
+                                       ZR_DEVNAME(zr));
+                               res = -EAGAIN;
+                               goto v4l_mmap_unlock_and_return;
+                       }
+                       size -= todo;
+                       start += todo;
+                       fh->v4l_buffers.buffer[i].map = map;
+                       if (size == 0)
+                               break;
+               }
+       v4l_mmap_unlock_and_return:
+               up(&zr->resource_lock);
+
+               break;
+
+       default:
+               dprintk(1,
+                       KERN_ERR
+                       "%s: zoran_mmap() - internal error - unknown map mode %d\n",
+                       ZR_DEVNAME(zr), fh->map_mode);
+               break;
+       }
+
+       return 0;
+}
+
+static struct file_operations zoran_fops = {
+       .owner = THIS_MODULE,
+       .open = zoran_open,
+       .release = zoran_close,
+       .ioctl = zoran_ioctl,
+       .llseek = no_llseek,
+       .read = zoran_read,
+       .write = zoran_write,
+       .mmap = zoran_mmap,
+       .poll = zoran_poll,
+};
+
+struct video_device zoran_template __devinitdata = {
+       .name = ZORAN_NAME,
+       .type = ZORAN_VID_TYPE,
+#ifdef HAVE_V4L2
+       .type2 = ZORAN_V4L2_VID_FLAGS,
+#endif
+       .hardware = ZORAN_HARDWARE,
+       .fops = &zoran_fops,
+       .minor = -1
+};
index 833eef65bc4451fa204c4720f437af9c4b883bcf..d2ee0c72064402ebf563ab9298f80b895cf04cf9 100644 (file)
@@ -1,6 +1,63 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles the procFS entries (/proc/ZORAN[%d])
+ * 
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.net>
+ *
+ * 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/config.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/videodev.h>
+#include <linux/spinlock.h>
+#include <linux/sem.h>
+
 #include <linux/ctype.h>
+#include <asm/io.h>
+
+#include "videocodec.h"
+#include "zoran.h"
+#include "zoran_procfs.h"
+
+extern int debug;
 
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
+
+#ifdef CONFIG_PROC_FS
 struct procfs_params_zr36067 {
        char *name;
        short reg;
@@ -8,7 +65,7 @@ struct procfs_params_zr36067 {
        short bit;
 };
 
-static struct procfs_params_zr36067 zr67[] = {
+static const struct procfs_params_zr36067 zr67[] = {
        {"HSPol", 0x000, 1, 30},
        {"HStart", 0x000, 0x3ff, 10},
        {"HEnd", 0x000, 0x3ff, 0},
@@ -31,15 +88,27 @@ static struct procfs_params_zr36067 zr67[] = {
 
        {"NAY", 0x114, 0xffff, 16},
        {"PAY", 0x114, 0xffff, 0},
-/*    {"",,,}, */
+
+       /* {"",,,}, */
 
        {NULL, 0, 0, 0},
 };
 
-static void setparam(struct zoran *zr, char *name, char *sval)
+struct procfs_io {
+       char *buffer;
+       char *end;
+       int neof;
+       int count;
+       int count_current;
+};
+
+static void
+setparam (struct zoran *zr,
+         char         *name,
+         char         *sval)
 {
-       int i, reg0, reg, val;
-       i = 0;
+       int i = 0, reg0, reg, val;
+
        while (zr67[i].name != NULL) {
                if (!strncmp(name, zr67[i].name, strlen(zr67[i].name))) {
                        reg = reg0 = btread(zr67[i].reg);
@@ -50,8 +119,11 @@ static void setparam(struct zoran *zr, char *name, char *sval)
                        if ((val & ~zr67[i].mask))
                                break;
                        reg |= (val & zr67[i].mask) << zr67[i].bit;
-                       printk(KERN_INFO "%s: setparam: setting ZR36067 register 0x%03x: 0x%08x=>0x%08x %s=%d\n",
-                              zr->name, zr67[i].reg, reg0, reg, zr67[i].name, val);
+                       dprintk(4,
+                               KERN_INFO
+                               "%s: setparam: setting ZR36067 register 0x%03x: 0x%08x=>0x%08x %s=%d\n",
+                               ZR_DEVNAME(zr), zr67[i].reg, reg0, reg,
+                               zr67[i].name, val);
                        btwrite(reg, zr67[i].reg);
                        break;
                }
@@ -59,72 +131,97 @@ static void setparam(struct zoran *zr, char *name, char *sval)
        }
 }
 
-/* This macro was stolen from /usr/src/drivers/char/nvram.c and modified */
-#define        PRINT_PROC(args...)                                     \
-       do {                                                    \
-               if (begin + len > offset + size) {              \
-                       *eof = 0;                               \
-                        break;                                 \
-               }                                               \
-                len += sprintf( buffer+len, ##args );          \
-               if (begin + len < offset) {                     \
-                       begin += len;                           \
-                       len = 0;                                \
-               }                                               \
-       } while(0)
-
-static int zoran_read_proc(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
+static int
+print_procfs (struct procfs_io *io,
+             const char       *fmt,
+             ...)
 {
-#ifdef CONFIG_PROC_FS
-       int len = 0;
-       off_t begin = 0;
+       va_list args;
+       int i;
+
+       if (io->buffer >= io->end) {
+               io->neof++;
+               return 0;
+       }
+       if (io->count > io->count_current++)
+               return 0;
+       va_start(args, fmt);
+       i = vsprintf(io->buffer, fmt, args);
+       io->buffer += i;
+       va_end(args);
+       return i;
+}
 
+static void
+zoran_procfs_output (struct procfs_io *io,
+                    void             *data)
+{
        int i;
        struct zoran *zr;
-
        zr = (struct zoran *) data;
-       DEBUG2(printk(KERN_INFO "%s: read_proc: buffer=%x, offset=%d, size=%d, data=%x\n", zr->name, (int) buffer, (int) offset, size, (int) data));
-       *eof = 1;
-       PRINT_PROC("ZR36067 registers:");
+
+       print_procfs(io, "ZR36067 registers:");
        for (i = 0; i < 0x130; i += 4) {
                if (!(i % 16)) {
-                       PRINT_PROC("\n%03X", i);
-               }
-               PRINT_PROC(" %08X ", btread(i));
-       }
-       PRINT_PROC("\n");
-       if (offset >= len + begin) {
-               return 0;
-       }
-       *start = buffer + begin - offset;
-       return ((size < begin + len - offset) ? size : begin + len - offset);
-#endif
+                       print_procfs(io, "\n%03X", i);
+               };
+               print_procfs(io, " %08X ", btread(i));
+       };
+       print_procfs(io, "\n");
+}
+
+static int
+zoran_read_proc (char  *buffer,
+                char **start,
+                off_t  offset,
+                int    size,
+                int   *eof,
+                void  *data)
+{
+       struct procfs_io io;
+       int nbytes;
+
+       io.buffer = buffer;
+       io.end = buffer + size - 128;   // Just to make it a little bit safer
+       io.count = offset;
+       io.count_current = 0;
+       io.neof = 0;
+       zoran_procfs_output(&io, data);
+       *start = (char *) (io.count_current - io.count);
+       nbytes = (int) (io.buffer - buffer);
+       *eof = !io.neof;
+       return nbytes;
+
        return 0;
 }
 
-static int zoran_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+static int
+zoran_write_proc (struct file   *file,
+                 const char    *buffer,
+                 unsigned long  count,
+                 void          *data)
 {
-#ifdef CONFIG_PROC_FS
        char *string, *sp;
        char *line, *ldelim, *varname, *svar, *tdelim;
        struct zoran *zr;
 
        zr = (struct zoran *) data;
 
-       if(count > 32768)               /* Stupidity filter */
-               count = 32768;
-
        string = sp = vmalloc(count + 1);
        if (!string) {
-               printk(KERN_ERR "%s: write_proc: can not allocate memory\n", zr->name);
+               dprintk(1,
+                       KERN_ERR
+                       "%s: write_proc: can not allocate memory\n",
+                       ZR_DEVNAME(zr));
                return -ENOMEM;
        }
        if (copy_from_user(string, buffer, count)) {
-               vfree(string);
+               vfree (string);
                return -EFAULT;
        }
        string[count] = 0;
-       DEBUG2(printk(KERN_INFO "%s: write_proc: name=%s count=%lu data=%x\n", zr->name, file->f_dentry->d_name.name, count, (int) data));
+       dprintk(4, KERN_INFO "%s: write_proc: name=%s count=%lu data=%x\n",
+               ZR_DEVNAME(zr), file->f_dentry->d_name.name, count, (int) data);
        ldelim = " \t\n";
        tdelim = "=";
        line = strpbrk(sp, ldelim);
@@ -141,36 +238,44 @@ static int zoran_write_proc(struct file *file, const char *buffer, unsigned long
                line = strpbrk(sp, ldelim);
        }
        vfree(string);
-#endif
+
        return count;
 }
+#endif
 
-static int zoran_proc_init(int i)
+int
+zoran_proc_init (struct zoran *zr)
 {
 #ifdef CONFIG_PROC_FS
        char name[8];
-       sprintf(name, "zoran%d", i);
-       if ((zoran[i].zoran_proc = create_proc_entry(name, 0, 0))) {
-               zoran[i].zoran_proc->read_proc = zoran_read_proc;
-               zoran[i].zoran_proc->write_proc = zoran_write_proc;
-               zoran[i].zoran_proc->data = &zoran[i];
-               printk(KERN_INFO "%s: procfs entry /proc/%s allocated. data=%x\n", zoran[i].name, name, (int) zoran[i].zoran_proc->data);
+       snprintf(name, 7, "zoran%d", zr->id);
+       if ((zr->zoran_proc = create_proc_entry(name, 0, 0))) {
+               zr->zoran_proc->read_proc = zoran_read_proc;
+               zr->zoran_proc->write_proc = zoran_write_proc;
+               zr->zoran_proc->data = zr;
+               zr->zoran_proc->owner = THIS_MODULE;
+               dprintk(2,
+                       KERN_INFO
+                       "%s: procfs entry /proc/%s allocated. data=%p\n",
+                       ZR_DEVNAME(zr), name, zr->zoran_proc->data);
        } else {
-               printk(KERN_ERR "%s: Unable to initialise /proc/%s\n", zoran[i].name, name);
+               dprintk(1, KERN_ERR "%s: Unable to initialise /proc/%s\n",
+                       ZR_DEVNAME(zr), name);
                return 1;
        }
 #endif
        return 0;
 }
 
-static void zoran_proc_cleanup(int i)
+void
+zoran_proc_cleanup (struct zoran *zr)
 {
 #ifdef CONFIG_PROC_FS
        char name[8];
-       sprintf(name, "zoran%d", i);
-       if (zoran[i].zoran_proc) {
+       snprintf(name, 7, "zoran%d", zr->id);
+       if (zr->zoran_proc) {
                remove_proc_entry(name, 0);
        }
-       zoran[i].zoran_proc = NULL;
+       zr->zoran_proc = NULL;
 #endif
 }
diff --git a/drivers/media/video/zoran_procfs.h b/drivers/media/video/zoran_procfs.h
new file mode 100644 (file)
index 0000000..8904fc9
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles card-specific data and detection
+ * 
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.net>
+ *
+ * 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 __ZORAN_PROCFS_H__
+#define __ZORAN_PROCFS_H__
+
+extern int zoran_proc_init(struct zoran *zr);
+extern void zoran_proc_cleanup(struct zoran *zr);
+
+#endif                         /* __ZORAN_PROCFS_H__ */
diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c
new file mode 100644 (file)
index 0000000..f0fdbbc
--- /dev/null
@@ -0,0 +1,550 @@
+/*
+ * Zoran ZR36016 basic configuration functions
+ *
+ * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at>
+ *
+ * $Id: zr36016.c,v 1.1.2.14 2003/08/20 19:46:55 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * ------------------------------------------------------------------------
+ */
+
+#define ZR016_VERSION "v0.7"
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <linux/types.h>
+#include <linux/wait.h>
+
+/* includes for structures and defines regarding video 
+   #include<linux/videodev.h> */
+
+/* I/O commands, error codes */
+#include<asm/io.h>
+//#include<errno.h>
+
+/* v4l  API */
+#include<linux/videodev.h>
+
+/* headerfile of this module */
+#include"zr36016.h"
+
+/* codec io API */
+#include"videocodec.h"
+
+/* it doesn't make sense to have more than 20 or so,
+  just to prevent some unwanted loops */
+#define MAX_CODECS 20
+
+/* amount of chips attached via this driver */
+static int zr36016_codecs = 0;
+
+/* debugging is available via module parameter */
+
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-4)");
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
+
+/* =========================================================================
+   Local hardware I/O functions:
+
+   read/write via codec layer (registers are located in the master device)
+   ========================================================================= */
+
+/* read and write functions */
+static u8
+zr36016_read (struct zr36016 *ptr,
+             u16             reg)
+{
+       u8 value = 0;
+
+       // just in case something is wrong...
+       if (ptr->codec->master_data->readreg)
+               value =
+                   (ptr->codec->master_data->
+                    readreg(ptr->codec, reg)) & 0xFF;
+       else
+               dprintk(1,
+                       KERN_ERR "%s: invalid I/O setup, nothing read!\n",
+                       ptr->name);
+
+       dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg,
+               value);
+
+       return value;
+}
+
+static void
+zr36016_write (struct zr36016 *ptr,
+              u16             reg,
+              u8              value)
+{
+       dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value,
+               reg);
+
+       // just in case something is wrong...
+       if (ptr->codec->master_data->writereg) {
+               ptr->codec->master_data->writereg(ptr->codec, reg, value);
+       } else
+               dprintk(1,
+                       KERN_ERR
+                       "%s: invalid I/O setup, nothing written!\n",
+                       ptr->name);
+}
+
+/* indirect read and write functions */
+/* the 016 supports auto-addr-increment, but
+ * writing it all time cost not much and is safer... */
+static u8
+zr36016_readi (struct zr36016 *ptr,
+              u16             reg)
+{
+       u8 value = 0;
+
+       // just in case something is wrong...
+       if ((ptr->codec->master_data->writereg) &&
+           (ptr->codec->master_data->readreg)) {
+               ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR
+               value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF;     // DATA
+       } else
+               dprintk(1,
+                       KERN_ERR
+                       "%s: invalid I/O setup, nothing read (i)!\n",
+                       ptr->name);
+
+       dprintk(4, "%s: reading indirect from 0x%04x: %02x\n", ptr->name,
+               reg, value);
+       return value;
+}
+
+static void
+zr36016_writei (struct zr36016 *ptr,
+               u16             reg,
+               u8              value)
+{
+       dprintk(4, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name,
+               value, reg);
+
+       // just in case something is wrong...
+       if (ptr->codec->master_data->writereg) {
+               ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR
+               ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF);      // DATA
+       } else
+               dprintk(1,
+                       KERN_ERR
+                       "%s: invalid I/O setup, nothing written (i)!\n",
+                       ptr->name);
+}
+
+/* =========================================================================
+   Local helper function:
+
+   version read
+   ========================================================================= */
+
+/* version kept in datastructure */
+static u8
+zr36016_read_version (struct zr36016 *ptr)
+{
+       ptr->version = zr36016_read(ptr, 0) >> 4;
+       return ptr->version;
+}
+
+/* =========================================================================
+   Local helper function:
+
+   basic test of "connectivity", writes/reads to/from PAX-Lo register
+   ========================================================================= */
+
+static int
+zr36016_basic_test (struct zr36016 *ptr)
+{
+       if (debug) {
+               int i;
+               zr36016_writei(ptr, ZR016I_PAX_LO, 0x55);
+               dprintk(1, KERN_INFO "%s: registers: ", ptr->name);
+               for (i = 0; i <= 0x0b; i++)
+                       dprintk(1, "%02x ", zr36016_readi(ptr, i));
+               dprintk(1, "\n");
+       }
+       // for testing just write 0, then the default value to a register and read
+       // it back in both cases 
+       zr36016_writei(ptr, ZR016I_PAX_LO, 0x00);
+       if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: attach failed, can't connect to vfe processor!\n",
+                       ptr->name);
+               return -ENXIO;
+       }
+       zr36016_writei(ptr, ZR016I_PAX_LO, 0x0d0);
+       if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0d0) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: attach failed, can't connect to vfe processor!\n",
+                       ptr->name);
+               return -ENXIO;
+       }
+       // we allow version numbers from 0-3, should be enough, though
+       zr36016_read_version(ptr);
+       if (ptr->version & 0x0c) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: attach failed, suspicious version %d found...\n",
+                       ptr->name, ptr->version);
+               return -ENXIO;
+       }
+
+       return 0;               /* looks good! */
+}
+
+/* =========================================================================
+   Local helper function:
+
+   simple loop for pushing the init datasets - NO USE --
+   ========================================================================= */
+
+#if 0
+static int zr36016_pushit (struct zr36016 *ptr,
+                          u16             startreg,
+                          u16             len,
+                           const char     *data)
+{
+        int i=0;
+
+        dprintk(4, "%s: write data block to 0x%04x (len=%d)\n",
+               ptr->name, startreg,len);
+        while (i<len) {
+                zr36016_writei(ptr, startreg++,  data[i++]);
+        }
+
+        return i;
+}
+#endif
+
+/* =========================================================================
+   Basic datasets & init:
+
+   //TODO//
+   ========================================================================= */
+
+// needed offset values          PAL NTSC SECAM
+static const int zr016_xoff[] = { 20, 20, 20 };
+static const int zr016_yoff[] = { 8, 9, 7 };
+
+static void
+zr36016_init (struct zr36016 *ptr)
+{
+       // stop any processing
+       zr36016_write(ptr, ZR016_GOSTOP, 0);
+
+       // mode setup (yuv422 in and out, compression/expansuon due to mode)
+       zr36016_write(ptr, ZR016_MODE,
+                     ZR016_YUV422 | ZR016_YUV422_YUV422 |
+                     (ptr->mode == CODEC_DO_COMPRESSION ?
+                      ZR016_COMPRESSION : ZR016_EXPANSION));
+
+       // misc setup
+       zr36016_writei(ptr, ZR016I_SETUP1,
+                      (ptr->xdec ? (ZR016_HRFL | ZR016_HORZ) : 0) |
+                      (ptr->ydec ? ZR016_VERT : 0) | ZR016_CNTI);
+       zr36016_writei(ptr, ZR016I_SETUP2, ZR016_CCIR);
+
+       // Window setup
+       // (no extra offset for now, norm defines offset, default width height)
+       zr36016_writei(ptr, ZR016I_PAX_HI, ptr->width >> 8);
+       zr36016_writei(ptr, ZR016I_PAX_LO, ptr->width & 0xFF);
+       zr36016_writei(ptr, ZR016I_PAY_HI, ptr->height >> 8);
+       zr36016_writei(ptr, ZR016I_PAY_LO, ptr->height & 0xFF);
+       zr36016_writei(ptr, ZR016I_NAX_HI, ptr->xoff >> 8);
+       zr36016_writei(ptr, ZR016I_NAX_LO, ptr->xoff & 0xFF);
+       zr36016_writei(ptr, ZR016I_NAY_HI, ptr->yoff >> 8);
+       zr36016_writei(ptr, ZR016I_NAY_LO, ptr->yoff & 0xFF);
+
+       /* shall we continue now, please? */
+       zr36016_write(ptr, ZR016_GOSTOP, 1);
+}
+
+/* =========================================================================
+   CODEC API FUNCTIONS
+
+   this functions are accessed by the master via the API structure
+   ========================================================================= */
+
+/* set compression/expansion mode and launches codec -
+   this should be the last call from the master before starting processing */
+static int
+zr36016_set_mode (struct videocodec *codec,
+                 int                mode)
+{
+       struct zr36016 *ptr = (struct zr36016 *) codec->data;
+
+       dprintk(2, "%s: set_mode %d call\n", ptr->name, mode);
+
+       if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION))
+               return -EINVAL;
+
+       ptr->mode = mode;
+       zr36016_init(ptr);
+
+       return 0;
+}
+
+/* set picture size */
+static int
+zr36016_set_video (struct videocodec   *codec,
+                  struct tvnorm       *norm,
+                  struct vfe_settings *cap,
+                  struct vfe_polarity *pol)
+{
+       struct zr36016 *ptr = (struct zr36016 *) codec->data;
+
+       dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n",
+               ptr->name, norm->HStart, norm->VStart,
+               cap->x, cap->y, cap->width, cap->height,
+               cap->decimation);
+
+       /* if () return -EINVAL;
+        * trust the master driver that it knows what it does - so
+        * we allow invalid startx/y for now ... */
+       ptr->width = cap->width;
+       ptr->height = cap->height;
+       /* (Ronald) This is ugly. zoran_device.c, line 387
+        * already mentions what happens if HStart is even
+        * (blue faces, etc., cr/cb inversed). There's probably
+        * some good reason why HStart is 0 instead of 1, so I'm
+        * leaving it to this for now, but really... This can be
+        * done a lot simpler */
+       ptr->xoff = (norm->HStart ? norm->HStart : 1) + cap->x;
+       /* Something to note here (I don't understand it), setting
+        * VStart too high will cause the codec to 'not work'. I
+        * really don't get it. values of 16 (VStart) already break
+        * it here. Just '0' seems to work. More testing needed! */
+       ptr->yoff = norm->VStart + cap->y;
+       /* (Ronald) dzjeeh, can't this thing do hor_decimation = 4? */
+       ptr->xdec = ((cap->decimation & 0xff) == 1) ? 0 : 1;
+       ptr->ydec = (((cap->decimation >> 8) & 0xff) == 1) ? 0 : 1;
+
+       return 0;
+}
+
+/* additional control functions */
+static int
+zr36016_control (struct videocodec *codec,
+                int                type,
+                int                size,
+                void              *data)
+{
+       struct zr36016 *ptr = (struct zr36016 *) codec->data;
+       int *ival = (int *) data;
+
+       dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type,
+               size);
+
+       switch (type) {
+       case CODEC_G_STATUS:    /* get last status - we don't know it ... */
+               if (size != sizeof(int))
+                       return -EFAULT;
+               *ival = 0;
+               break;
+
+       case CODEC_G_CODEC_MODE:
+               if (size != sizeof(int))
+                       return -EFAULT;
+               *ival = 0;
+               break;
+
+       case CODEC_S_CODEC_MODE:
+               if (size != sizeof(int))
+                       return -EFAULT;
+               if (*ival != 0)
+                       return -EINVAL;
+               /* not needed, do nothing */
+               return 0;
+
+       case CODEC_G_VFE:
+       case CODEC_S_VFE:
+               return 0;
+
+       case CODEC_S_MMAP:
+               /* not available, give an error */
+               return -ENXIO;
+
+       default:
+               return -EINVAL;
+       }
+
+       return size;
+}
+
+/* =========================================================================
+   Exit and unregister function:
+
+   Deinitializes Zoran's JPEG processor
+   ========================================================================= */
+
+static int
+zr36016_unset (struct videocodec *codec)
+{
+       struct zr36016 *ptr = codec->data;
+
+       if (ptr) {
+               /* do wee need some codec deinit here, too ???? */
+
+               dprintk(1, "%s: finished codec #%d\n", ptr->name,
+                       ptr->num);
+               kfree(ptr);
+               codec->data = NULL;
+
+               zr36016_codecs--;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+               MOD_DEC_USE_COUNT;
+#else
+               module_put(THIS_MODULE);
+#endif
+
+               return 0;
+       }
+
+       return -EFAULT;
+}
+
+/* =========================================================================
+   Setup and registry function:
+
+   Initializes Zoran's JPEG processor
+
+   Also sets pixel size, average code size, mode (compr./decompr.)
+   (the given size is determined by the processor with the video interface)
+   ========================================================================= */
+
+static int
+zr36016_setup (struct videocodec *codec)
+{
+       struct zr36016 *ptr;
+       int res;
+
+       dprintk(2, "zr36016: initializing VFE subsystem #%d.\n",
+               zr36016_codecs);
+
+       if (zr36016_codecs == MAX_CODECS) {
+               dprintk(1,
+                       KERN_ERR "zr36016: Can't attach more codecs!\n");
+               return -ENOSPC;
+       }
+       //mem structure init
+       codec->data = ptr = kmalloc(sizeof(struct zr36016), GFP_KERNEL);
+       if (NULL == ptr) {
+               dprintk(1, KERN_ERR "zr36016: Can't get enough memory!\n");
+               return -ENOMEM;
+       }
+       memset(ptr, 0, sizeof(struct zr36016));
+
+       snprintf(ptr->name, sizeof(ptr->name), "zr36016[%d]",
+                zr36016_codecs);
+       ptr->num = zr36016_codecs++;
+       ptr->codec = codec;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+       MOD_INC_USE_COUNT;
+#else
+       if (!try_module_get(THIS_MODULE)) {
+               dprintk(1,
+                       KERN_ERR
+                       "zr36016: failed to increase module use count\n");
+               kfree(ptr);
+               zr36016_codecs--;
+               return -ENODEV;
+       }
+#endif
+
+       //testing
+       res = zr36016_basic_test(ptr);
+       if (res < 0) {
+               zr36016_unset(codec);
+               return res;
+       }
+       //final setup
+       ptr->mode = CODEC_DO_COMPRESSION;
+       ptr->width = 768;
+       ptr->height = 288;
+       ptr->xdec = 1;
+       ptr->ydec = 0;
+       zr36016_init(ptr);
+
+       dprintk(1, KERN_INFO "%s: codec v%d attached and running\n",
+               ptr->name, ptr->version);
+
+       return 0;
+}
+
+static const struct videocodec zr36016_codec = {
+       .name = "zr36016",
+       .magic = 0L,            // magic not used
+       .flags =
+           CODEC_FLAG_HARDWARE | CODEC_FLAG_VFE | CODEC_FLAG_ENCODER |
+           CODEC_FLAG_DECODER,
+       .type = CODEC_TYPE_ZR36016,
+       .setup = zr36016_setup, // functionality
+       .unset = zr36016_unset,
+       .set_mode = zr36016_set_mode,
+       .set_video = zr36016_set_video,
+       .control = zr36016_control,
+       // others are not used
+};
+
+/* =========================================================================
+   HOOK IN DRIVER AS KERNEL MODULE
+   ========================================================================= */
+
+static int __init
+zr36016_init_module (void)
+{
+       //dprintk(1, "ZR36016 driver %s\n",ZR016_VERSION);
+       zr36016_codecs = 0;
+       return videocodec_register(&zr36016_codec);
+}
+
+static void __exit
+zr36016_cleanup_module (void)
+{
+       if (zr36016_codecs) {
+               dprintk(1,
+                       "zr36016: something's wrong - %d codecs left somehow.\n",
+                       zr36016_codecs);
+       }
+       videocodec_unregister(&zr36016_codec);
+}
+
+module_init(zr36016_init_module);
+module_exit(zr36016_cleanup_module);
+
+MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>");
+MODULE_DESCRIPTION("Driver module for ZR36016 video frontends "
+                  ZR016_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/zr36016.h b/drivers/media/video/zr36016.h
new file mode 100644 (file)
index 0000000..8c79229
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Zoran ZR36016 basic configuration functions - header file
+ *
+ * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at>
+ *
+ * $Id: zr36016.h,v 1.1.2.3 2003/01/14 21:18:07 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * 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 ZR36016_H
+#define ZR36016_H
+
+/* data stored for each zoran jpeg codec chip */
+struct zr36016 {
+       char name[32];
+       int num;
+       /* io datastructure */
+       struct videocodec *codec;
+       // coder status
+       __u8 version;
+       // actual coder setup
+       int mode;
+
+       __u16 xoff;
+       __u16 yoff;
+       __u16 width;
+       __u16 height;
+       __u16 xdec;
+       __u16 ydec;
+};
+
+/* direct  register addresses */
+#define ZR016_GOSTOP      0x00
+#define ZR016_MODE        0x01
+#define ZR016_IADDR       0x02
+#define ZR016_IDATA       0x03
+
+/* indirect  register addresses */
+#define ZR016I_SETUP1     0x00
+#define ZR016I_SETUP2     0x01
+#define ZR016I_NAX_LO     0x02
+#define ZR016I_NAX_HI     0x03
+#define ZR016I_PAX_LO     0x04
+#define ZR016I_PAX_HI     0x05
+#define ZR016I_NAY_LO     0x06
+#define ZR016I_NAY_HI     0x07
+#define ZR016I_PAY_LO     0x08
+#define ZR016I_PAY_HI     0x09
+#define ZR016I_NOL_LO     0x0a
+#define ZR016I_NOL_HI     0x0b
+
+/* possible values for mode register */
+#define ZR016_RGB444_YUV444  0x00
+#define ZR016_RGB444_YUV422  0x01
+#define ZR016_RGB444_YUV411  0x02
+#define ZR016_RGB444_Y400    0x03
+#define ZR016_RGB444_RGB444  0x04
+#define ZR016_YUV444_YUV444  0x08
+#define ZR016_YUV444_YUV422  0x09
+#define ZR016_YUV444_YUV411  0x0a
+#define ZR016_YUV444_Y400    0x0b
+#define ZR016_YUV444_RGB444  0x0c
+#define ZR016_YUV422_YUV422  0x11
+#define ZR016_YUV422_YUV411  0x12
+#define ZR016_YUV422_Y400    0x13
+#define ZR016_YUV411_YUV411  0x16
+#define ZR016_YUV411_Y400    0x17
+#define ZR016_4444_4444      0x19
+#define ZR016_100_100        0x1b
+
+#define ZR016_RGB444         0x00
+#define ZR016_YUV444         0x20
+#define ZR016_YUV422         0x40
+
+#define ZR016_COMPRESSION    0x80
+#define ZR016_EXPANSION      0x80
+
+/* possible values for setup 1 register */
+#define ZR016_CKRT           0x80
+#define ZR016_VERT           0x40
+#define ZR016_HORZ           0x20
+#define ZR016_HRFL           0x10
+#define ZR016_DSFL           0x08
+#define ZR016_SBFL           0x04
+#define ZR016_RSTR           0x02
+#define ZR016_CNTI           0x01
+
+/* possible values for setup 2 register */
+#define ZR016_SYEN           0x40
+#define ZR016_CCIR           0x04
+#define ZR016_SIGN           0x02
+#define ZR016_YMCS           0x01
+
+#endif                         /*fndef ZR36016_H */
diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c
new file mode 100644 (file)
index 0000000..be09ffc
--- /dev/null
@@ -0,0 +1,872 @@
+/*
+ * Zoran ZR36050 basic configuration functions
+ *
+ * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at>
+ *
+ * $Id: zr36050.c,v 1.1.2.11 2003/08/03 14:54:53 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * ------------------------------------------------------------------------
+ */
+
+#define ZR050_VERSION "v0.7"
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <linux/types.h>
+#include <linux/wait.h>
+
+/* includes for structures and defines regarding video 
+   #include<linux/videodev.h> */
+
+/* I/O commands, error codes */
+#include<asm/io.h>
+//#include<errno.h>
+
+/* headerfile of this module */
+#include"zr36050.h"
+
+/* codec io API */
+#include"videocodec.h"
+
+/* it doesn't make sense to have more than 20 or so,
+  just to prevent some unwanted loops */
+#define MAX_CODECS 20
+
+/* amount of chips attached via this driver */
+static int zr36050_codecs = 0;
+
+/* debugging is available via module parameter */
+
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-4)");
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
+
+/* =========================================================================
+   Local hardware I/O functions:
+
+   read/write via codec layer (registers are located in the master device)
+   ========================================================================= */
+
+/* read and write functions */
+static u8
+zr36050_read (struct zr36050 *ptr,
+             u16             reg)
+{
+       u8 value = 0;
+
+       // just in case something is wrong...
+       if (ptr->codec->master_data->readreg)
+               value = (ptr->codec->master_data->readreg(ptr->codec,
+                                                         reg)) & 0xFF;
+       else
+               dprintk(1,
+                       KERN_ERR "%s: invalid I/O setup, nothing read!\n",
+                       ptr->name);
+
+       dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg,
+               value);
+
+       return value;
+}
+
+static void
+zr36050_write (struct zr36050 *ptr,
+              u16             reg,
+              u8              value)
+{
+       dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value,
+               reg);
+
+       // just in case something is wrong...
+       if (ptr->codec->master_data->writereg)
+               ptr->codec->master_data->writereg(ptr->codec, reg, value);
+       else
+               dprintk(1,
+                       KERN_ERR
+                       "%s: invalid I/O setup, nothing written!\n",
+                       ptr->name);
+}
+
+/* =========================================================================
+   Local helper function:
+
+   status read
+   ========================================================================= */
+
+/* status is kept in datastructure */
+static u8
+zr36050_read_status1 (struct zr36050 *ptr)
+{
+       ptr->status1 = zr36050_read(ptr, ZR050_STATUS_1);
+
+       zr36050_read(ptr, 0);
+       return ptr->status1;
+}
+
+/* =========================================================================
+   Local helper function:
+
+   scale factor read
+   ========================================================================= */
+
+/* scale factor is kept in datastructure */
+static u16
+zr36050_read_scalefactor (struct zr36050 *ptr)
+{
+       ptr->scalefact = (zr36050_read(ptr, ZR050_SF_HI) << 8) |
+                        (zr36050_read(ptr, ZR050_SF_LO) & 0xFF);
+
+       /* leave 0 selected for an eventually GO from master */
+       zr36050_read(ptr, 0);
+       return ptr->scalefact;
+}
+
+/* =========================================================================
+   Local helper function:
+
+   wait if codec is ready to proceed (end of processing) or time is over
+   ========================================================================= */
+
+static void
+zr36050_wait_end (struct zr36050 *ptr)
+{
+       int i = 0;
+
+       while (!(zr36050_read_status1(ptr) & 0x4)) {
+               udelay(1);
+               if (i++ > 200000) {     // 200ms, there is for shure something wrong!!!
+                       dprintk(1,
+                               "%s: timout at wait_end (last status: 0x%02x)\n",
+                               ptr->name, ptr->status1);
+                       break;
+               }
+       }
+}
+
+/* =========================================================================
+   Local helper function:
+
+   basic test of "connectivity", writes/reads to/from memory the SOF marker 
+   ========================================================================= */
+
+static int
+zr36050_basic_test (struct zr36050 *ptr)
+{
+       zr36050_write(ptr, ZR050_SOF_IDX, 0x00);
+       zr36050_write(ptr, ZR050_SOF_IDX + 1, 0x00);
+       if ((zr36050_read(ptr, ZR050_SOF_IDX) |
+            zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0x0000) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: attach failed, can't connect to jpeg processor!\n",
+                       ptr->name);
+               return -ENXIO;
+       }
+       zr36050_write(ptr, ZR050_SOF_IDX, 0xff);
+       zr36050_write(ptr, ZR050_SOF_IDX + 1, 0xc0);
+       if (((zr36050_read(ptr, ZR050_SOF_IDX) << 8) |
+            zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0xffc0) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: attach failed, can't connect to jpeg processor!\n",
+                       ptr->name);
+               return -ENXIO;
+       }
+
+       zr36050_wait_end(ptr);
+       if ((ptr->status1 & 0x4) == 0) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: attach failed, jpeg processor failed (end flag)!\n",
+                       ptr->name);
+               return -EBUSY;
+       }
+
+       return 0;               /* looks good! */
+}
+
+/* =========================================================================
+   Local helper function:
+
+   simple loop for pushing the init datasets
+   ========================================================================= */
+
+static int
+zr36050_pushit (struct zr36050 *ptr,
+               u16             startreg,
+               u16             len,
+               const char     *data)
+{
+       int i = 0;
+
+       dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", ptr->name,
+               startreg, len);
+       while (i < len) {
+               zr36050_write(ptr, startreg++, data[i++]);
+       }
+
+       return i;
+}
+
+/* =========================================================================
+   Basic datasets:
+
+   jpeg baseline setup data (you find it on lots places in internet, or just
+   extract it from any regular .jpg image...)
+
+   Could be variable, but until it's not needed it they are just fixed to save
+   memory. Otherwise expand zr36050 structure with arrays, push the values to
+   it and initalize from there, as e.g. the linux zr36057/60 driver does it.
+   ========================================================================= */
+
+static const char zr36050_dqt[0x86] = {
+       0xff, 0xdb,             //Marker: DQT
+       0x00, 0x84,             //Length: 2*65+2
+       0x00,                   //Pq,Tq first table
+       0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
+       0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
+       0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
+       0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
+       0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
+       0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
+       0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
+       0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
+       0x01,                   //Pq,Tq second table
+       0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
+       0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
+};
+
+static const char zr36050_dht[0x1a4] = {
+       0xff, 0xc4,             //Marker: DHT
+       0x01, 0xa2,             //Length: 2*AC, 2*DC
+       0x00,                   //DC first table
+       0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+       0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+       0x01,                   //DC second table
+       0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+       0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+       0x10,                   //AC first table
+       0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+       0x05, 0x05, 0x04, 0x04, 0x00, 0x00,
+       0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11,
+       0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
+       0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1,
+       0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24,
+       0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17,
+       0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34,
+       0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
+       0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56,
+       0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66,
+       0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+       0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
+       0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+       0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
+       0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9,
+       0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,
+       0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
+       0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+       0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+       0xF8, 0xF9, 0xFA,
+       0x11,                   //AC second table
+       0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+       0x07, 0x05, 0x04, 0x04, 0x00, 0x01,
+       0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
+       0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+       0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+       0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62,
+       0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25,
+       0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A,
+       0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
+       0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56,
+       0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66,
+       0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+       0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+       0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+       0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+       0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8,
+       0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+       0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8,
+       0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+       0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
+       0xF9, 0xFA
+};
+
+static const char zr36050_app[0x40] = {
+       0xff, 0xe0,             //Marker: APP0
+       0x00, 0x3e,             //Length: 60+2
+       ' ', 'A', 'V', 'I', '1', 0, 0, 0,       // 'AVI' field
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0
+};
+
+static const char zr36050_com[0x40] = {
+       0xff, 0xfe,             //Marker: COM
+       0x00, 0x3e,             //Length: 60+2
+       ' ', 'C', 'O', 'M', 0, 0, 0, 0, // 'COM' field
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0
+};
+
+/* jpeg baseline setup, this is just fixed in this driver (YUV pictures) */
+#define NO_OF_COMPONENTS          0x3  //Y,U,V
+#define BASELINE_PRECISION        0x8  //MCU size (?)
+static const char zr36050_tq[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };  //table idx's QT
+static const char zr36050_td[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };  //table idx's DC
+static const char zr36050_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };  //table idx's AC
+
+/* horizontal 422 decimation setup (maybe we support 411 or so later, too) */
+static const char zr36050_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 };
+static const char zr36050_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 };
+
+/* =========================================================================
+   Local helper functions:
+
+   calculation and setup of parameter-dependent JPEG baseline segments
+   (needed for compression only)
+   ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+
+/* SOF (start of frame) segment depends on width, height and sampling ratio
+                         of each color component */
+
+static int
+zr36050_set_sof (struct zr36050 *ptr)
+{
+       char sof_data[34];      // max. size of register set
+       int i;
+
+       dprintk(3, "%s: write SOF (%dx%d, %d components)\n", ptr->name,
+               ptr->width, ptr->height, NO_OF_COMPONENTS);
+       sof_data[0] = 0xff;
+       sof_data[1] = 0xc0;
+       sof_data[2] = 0x00;
+       sof_data[3] = (3 * NO_OF_COMPONENTS) + 8;
+       sof_data[4] = BASELINE_PRECISION;       // only '8' possible with zr36050
+       sof_data[5] = (ptr->height) >> 8;
+       sof_data[6] = (ptr->height) & 0xff;
+       sof_data[7] = (ptr->width) >> 8;
+       sof_data[8] = (ptr->width) & 0xff;
+       sof_data[9] = NO_OF_COMPONENTS;
+       for (i = 0; i < NO_OF_COMPONENTS; i++) {
+               sof_data[10 + (i * 3)] = i;     // index identifier
+               sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) | (ptr->v_samp_ratio[i]);  // sampling ratios
+               sof_data[12 + (i * 3)] = zr36050_tq[i]; // Q table selection
+       }
+       return zr36050_pushit(ptr, ZR050_SOF_IDX,
+                             (3 * NO_OF_COMPONENTS) + 10, sof_data);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* SOS (start of scan) segment depends on the used scan components 
+                        of each color component */
+
+static int
+zr36050_set_sos (struct zr36050 *ptr)
+{
+       char sos_data[16];      // max. size of register set
+       int i;
+
+       dprintk(3, "%s: write SOS\n", ptr->name);
+       sos_data[0] = 0xff;
+       sos_data[1] = 0xda;
+       sos_data[2] = 0x00;
+       sos_data[3] = 2 + 1 + (2 * NO_OF_COMPONENTS) + 3;
+       sos_data[4] = NO_OF_COMPONENTS;
+       for (i = 0; i < NO_OF_COMPONENTS; i++) {
+               sos_data[5 + (i * 2)] = i;      // index
+               sos_data[6 + (i * 2)] = (zr36050_td[i] << 4) | zr36050_ta[i];   // AC/DC tbl.sel.
+       }
+       sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 2] = 00;      // scan start
+       sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 3] = 0x3F;
+       sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 4] = 00;
+       return zr36050_pushit(ptr, ZR050_SOS1_IDX,
+                             4 + 1 + (2 * NO_OF_COMPONENTS) + 3,
+                             sos_data);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* DRI (define restart interval) */
+
+static int
+zr36050_set_dri (struct zr36050 *ptr)
+{
+       char dri_data[6];       // max. size of register set
+
+       dprintk(3, "%s: write DRI\n", ptr->name);
+       dri_data[0] = 0xff;
+       dri_data[1] = 0xdd;
+       dri_data[2] = 0x00;
+       dri_data[3] = 0x04;
+       dri_data[4] = ptr->dri >> 8;
+       dri_data[5] = ptr->dri * 0xff;
+       return zr36050_pushit(ptr, ZR050_DRI_IDX, 6, dri_data);
+}
+
+/* =========================================================================
+   Setup function:
+
+   Setup compression/decompression of Zoran's JPEG processor
+   ( see also zoran 36050 manual )
+
+   ... sorry for the spaghetti code ...
+   ========================================================================= */
+static void
+zr36050_init (struct zr36050 *ptr)
+{
+       int sum = 0;
+       long bitcnt, tmp;
+
+       if (ptr->mode == CODEC_DO_COMPRESSION) {
+               dprintk(2, "%s: COMPRESSION SETUP\n", ptr->name);
+
+               /* 050 communicates with 057 in master mode */
+               zr36050_write(ptr, ZR050_HARDWARE, ZR050_HW_MSTR);
+
+               /* encoding table preload for compression */
+               zr36050_write(ptr, ZR050_MODE,
+                             ZR050_MO_COMP | ZR050_MO_TLM);
+               zr36050_write(ptr, ZR050_OPTIONS, 0);
+
+               /* disable all IRQs */
+               zr36050_write(ptr, ZR050_INT_REQ_0, 0);
+               zr36050_write(ptr, ZR050_INT_REQ_1, 3); // low 2 bits always 1
+
+               /* volume control settings */
+               zr36050_write(ptr, ZR050_MBCV, ptr->max_block_vol >> 1);
+               zr36050_write(ptr, ZR050_SF_HI, ptr->scalefact >> 8);
+               zr36050_write(ptr, ZR050_SF_LO, ptr->scalefact & 0xff);
+
+               zr36050_write(ptr, ZR050_AF_HI, 0xff);
+               zr36050_write(ptr, ZR050_AF_M, 0xff);
+               zr36050_write(ptr, ZR050_AF_LO, 0xff);
+
+               /* setup the variable jpeg tables */
+               sum += zr36050_set_sof(ptr);
+               sum += zr36050_set_sos(ptr);
+               sum += zr36050_set_dri(ptr);
+
+               /* setup the fixed jpeg tables - maybe variable, though -
+                * (see table init section above) */
+               dprintk(3, "%s: write DQT, DHT, APP\n", ptr->name);
+               sum += zr36050_pushit(ptr, ZR050_DQT_IDX,
+                                     sizeof(zr36050_dqt), zr36050_dqt);
+               sum += zr36050_pushit(ptr, ZR050_DHT_IDX,
+                                     sizeof(zr36050_dht), zr36050_dht);
+               sum += zr36050_pushit(ptr, ZR050_APP_IDX,
+                                     sizeof(zr36050_app), zr36050_app);
+               sum += zr36050_pushit(ptr, ZR050_COM_IDX,
+                                     sizeof(zr36050_com), zr36050_com);
+
+               /* do the internal huffman table preload */
+               zr36050_write(ptr, ZR050_MARKERS_EN, ZR050_ME_DHTI);
+
+               zr36050_write(ptr, ZR050_GO, 1);        // launch codec
+               zr36050_wait_end(ptr);
+               dprintk(2, "%s: Status after table preload: 0x%02x\n",
+                       ptr->name, ptr->status1);
+
+               if ((ptr->status1 & 0x4) == 0) {
+                       dprintk(1, KERN_ERR "%s: init aborted!\n",
+                               ptr->name);
+                       return; // something is wrong, its timed out!!!!
+               }
+
+               /* setup misc. data for compression (target code sizes) */
+
+               /* size of compressed code to reach without header data */
+               sum = ptr->total_code_vol - sum;
+               bitcnt = sum << 3;      /* need the size in bits */
+
+               tmp = bitcnt >> 16;
+               dprintk(3,
+                       "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n",
+                       ptr->name, sum, ptr->total_code_vol, bitcnt, tmp);
+               zr36050_write(ptr, ZR050_TCV_NET_HI, tmp >> 8);
+               zr36050_write(ptr, ZR050_TCV_NET_MH, tmp & 0xff);
+               tmp = bitcnt & 0xffff;
+               zr36050_write(ptr, ZR050_TCV_NET_ML, tmp >> 8);
+               zr36050_write(ptr, ZR050_TCV_NET_LO, tmp & 0xff);
+
+               bitcnt -= bitcnt >> 7;  // bits without stuffing
+               bitcnt -= ((bitcnt * 5) >> 6);  // bits without eob
+
+               tmp = bitcnt >> 16;
+               dprintk(3, "%s: code: nettobit=%ld, highnettobits=%ld\n",
+                       ptr->name, bitcnt, tmp);
+               zr36050_write(ptr, ZR050_TCV_DATA_HI, tmp >> 8);
+               zr36050_write(ptr, ZR050_TCV_DATA_MH, tmp & 0xff);
+               tmp = bitcnt & 0xffff;
+               zr36050_write(ptr, ZR050_TCV_DATA_ML, tmp >> 8);
+               zr36050_write(ptr, ZR050_TCV_DATA_LO, tmp & 0xff);
+
+               /* compression setup with or without bitrate control */
+               zr36050_write(ptr, ZR050_MODE,
+                             ZR050_MO_COMP | ZR050_MO_PASS2 |
+                             (ptr->bitrate_ctrl ? ZR050_MO_BRC : 0));
+
+               /* this headers seem to deliver "valid AVI" jpeg frames */
+               zr36050_write(ptr, ZR050_MARKERS_EN,
+                             ZR050_ME_APP | ZR050_ME_DQT | ZR050_ME_DHT |
+                             ZR050_ME_COM);
+       } else {
+               dprintk(2, "%s: EXPANSION SETUP\n", ptr->name);
+
+               /* 050 communicates with 055 in master mode */
+               zr36050_write(ptr, ZR050_HARDWARE,
+                             ZR050_HW_MSTR | ZR050_HW_CFIS_2_CLK);
+
+               /* encoding table preload */
+               zr36050_write(ptr, ZR050_MODE, ZR050_MO_TLM);
+
+               /* disable all IRQs */
+               zr36050_write(ptr, ZR050_INT_REQ_0, 0);
+               zr36050_write(ptr, ZR050_INT_REQ_1, 3); // low 2 bits always 1
+
+               dprintk(3, "%s: write DHT\n", ptr->name);
+               zr36050_pushit(ptr, ZR050_DHT_IDX, sizeof(zr36050_dht),
+                              zr36050_dht);
+
+               /* do the internal huffman table preload */
+               zr36050_write(ptr, ZR050_MARKERS_EN, ZR050_ME_DHTI);
+
+               zr36050_write(ptr, ZR050_GO, 1);        // launch codec
+               zr36050_wait_end(ptr);
+               dprintk(2, "%s: Status after table preload: 0x%02x\n",
+                       ptr->name, ptr->status1);
+
+               if ((ptr->status1 & 0x4) == 0) {
+                       dprintk(1, KERN_ERR "%s: init aborted!\n",
+                               ptr->name);
+                       return; // something is wrong, its timed out!!!!
+               }
+
+               /* setup misc. data for expansion */
+               zr36050_write(ptr, ZR050_MODE, 0);
+               zr36050_write(ptr, ZR050_MARKERS_EN, 0);
+       }
+
+       /* adr on selected, to allow GO from master */
+       zr36050_read(ptr, 0);
+}
+
+/* =========================================================================
+   CODEC API FUNCTIONS
+
+   this functions are accessed by the master via the API structure
+   ========================================================================= */
+
+/* set compression/expansion mode and launches codec -
+   this should be the last call from the master before starting processing */
+static int
+zr36050_set_mode (struct videocodec *codec,
+                 int                mode)
+{
+       struct zr36050 *ptr = (struct zr36050 *) codec->data;
+
+       dprintk(2, "%s: set_mode %d call\n", ptr->name, mode);
+
+       if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION))
+               return -EINVAL;
+
+       ptr->mode = mode;
+       zr36050_init(ptr);
+
+       return 0;
+}
+
+/* set picture size (norm is ignored as the codec doesn't know about it) */
+static int
+zr36050_set_video (struct videocodec   *codec,
+                  struct tvnorm       *norm,
+                  struct vfe_settings *cap,
+                  struct vfe_polarity *pol)
+{
+       struct zr36050 *ptr = (struct zr36050 *) codec->data;
+
+       dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n",
+               ptr->name, norm->HStart, norm->VStart,
+               cap->x, cap->y, cap->width, cap->height,
+               cap->decimation);
+       /* if () return -EINVAL;
+        * trust the master driver that it knows what it does - so
+        * we allow invalid startx/y and norm for now ... */
+       ptr->width = cap->width / (cap->decimation & 0xff);
+       ptr->height = cap->height / ((cap->decimation >> 8) & 0xff);
+
+       return 0;
+}
+
+/* additional control functions */
+static int
+zr36050_control (struct videocodec *codec,
+                int                type,
+                int                size,
+                void              *data)
+{
+       struct zr36050 *ptr = (struct zr36050 *) codec->data;
+       int *ival = (int *) data;
+
+       dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type,
+               size);
+
+       switch (type) {
+       case CODEC_G_STATUS:    /* get last status */
+               if (size != sizeof(int))
+                       return -EFAULT;
+               zr36050_read_status1(ptr);
+               *ival = ptr->status1;
+               break;
+
+       case CODEC_G_CODEC_MODE:
+               if (size != sizeof(int))
+                       return -EFAULT;
+               *ival = CODEC_MODE_BJPG;
+               break;
+
+       case CODEC_S_CODEC_MODE:
+               if (size != sizeof(int))
+                       return -EFAULT;
+               if (*ival != CODEC_MODE_BJPG)
+                       return -EINVAL;
+               /* not needed, do nothing */
+               return 0;
+
+       case CODEC_G_VFE:
+       case CODEC_S_VFE:
+               /* not needed, do nothing */
+               return 0;
+
+       case CODEC_S_MMAP:
+               /* not available, give an error */
+               return -ENXIO;
+
+       case CODEC_G_JPEG_TDS_BYTE:     /* get target volume in byte */
+               if (size != sizeof(int))
+                       return -EFAULT;
+               *ival = ptr->total_code_vol;
+               break;
+
+       case CODEC_S_JPEG_TDS_BYTE:     /* get target volume in byte */
+               if (size != sizeof(int))
+                       return -EFAULT;
+               ptr->total_code_vol = *ival;
+               break;
+
+       case CODEC_G_JPEG_SCALE:        /* get scaling factor */
+               if (size != sizeof(int))
+                       return -EFAULT;
+               *ival = zr36050_read_scalefactor(ptr);
+               break;
+
+       case CODEC_S_JPEG_SCALE:        /* set scaling factor */
+               if (size != sizeof(int))
+                       return -EFAULT;
+               ptr->scalefact = *ival;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return size;
+}
+
+/* =========================================================================
+   Exit and unregister function:
+
+   Deinitializes Zoran's JPEG processor
+   ========================================================================= */
+
+static int
+zr36050_unset (struct videocodec *codec)
+{
+       struct zr36050 *ptr = codec->data;
+
+       if (ptr) {
+               /* do wee need some codec deinit here, too ???? */
+
+               dprintk(1, "%s: finished codec #%d\n", ptr->name,
+                       ptr->num);
+               kfree(ptr);
+               codec->data = NULL;
+
+               zr36050_codecs--;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+               MOD_DEC_USE_COUNT;
+#else
+               module_put(THIS_MODULE);
+#endif
+
+               return 0;
+       }
+
+       return -EFAULT;
+}
+
+/* =========================================================================
+   Setup and registry function:
+
+   Initializes Zoran's JPEG processor
+
+   Also sets pixel size, average code size, mode (compr./decompr.)
+   (the given size is determined by the processor with the video interface)
+   ========================================================================= */
+
+static int
+zr36050_setup (struct videocodec *codec)
+{
+       struct zr36050 *ptr;
+       int res;
+
+       dprintk(2, "zr36050: initializing MJPEG subsystem #%d.\n",
+               zr36050_codecs);
+
+       if (zr36050_codecs == MAX_CODECS) {
+               dprintk(1,
+                       KERN_ERR "zr36050: Can't attach more codecs!\n");
+               return -ENOSPC;
+       }
+       //mem structure init
+       codec->data = ptr = kmalloc(sizeof(struct zr36050), GFP_KERNEL);
+       if (NULL == ptr) {
+               dprintk(1, KERN_ERR "zr36050: Can't get enough memory!\n");
+               return -ENOMEM;
+       }
+       memset(ptr, 0, sizeof(struct zr36050));
+
+       snprintf(ptr->name, sizeof(ptr->name), "zr36050[%d]",
+                zr36050_codecs);
+       ptr->num = zr36050_codecs++;
+       ptr->codec = codec;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+       MOD_INC_USE_COUNT;
+#else
+       if (!try_module_get(THIS_MODULE)) {
+               dprintk(1,
+                       KERN_ERR
+                       "zr36050: failed to increase module use count\n");
+               kfree(ptr);
+               zr36050_codecs--;
+               return -ENODEV;
+       }
+#endif
+
+       //testing
+       res = zr36050_basic_test(ptr);
+       if (res < 0) {
+               zr36050_unset(codec);
+               return res;
+       }
+       //final setup
+       memcpy(ptr->h_samp_ratio, zr36050_decimation_h, 8);
+       memcpy(ptr->v_samp_ratio, zr36050_decimation_v, 8);
+
+       ptr->bitrate_ctrl = 0;  /* 0 or 1 - fixed file size flag
+                                * (what is the difference?) */
+       ptr->mode = CODEC_DO_COMPRESSION;
+       ptr->width = 384;
+       ptr->height = 288;
+       ptr->total_code_vol = 16000;
+       ptr->max_block_vol = 240;
+       ptr->scalefact = 0x100;
+       ptr->dri = 1;
+       zr36050_init(ptr);
+
+       dprintk(1, KERN_INFO "%s: codec attached and running\n",
+               ptr->name);
+
+       return 0;
+}
+
+static const struct videocodec zr36050_codec = {
+       .name = "zr36050",
+       .magic = 0L,            // magic not used
+       .flags =
+           CODEC_FLAG_JPEG | CODEC_FLAG_HARDWARE | CODEC_FLAG_ENCODER |
+           CODEC_FLAG_DECODER,
+       .type = CODEC_TYPE_ZR36050,
+       .setup = zr36050_setup, // functionality
+       .unset = zr36050_unset,
+       .set_mode = zr36050_set_mode,
+       .set_video = zr36050_set_video,
+       .control = zr36050_control,
+       // others are not used
+};
+
+/* =========================================================================
+   HOOK IN DRIVER AS KERNEL MODULE
+   ========================================================================= */
+
+static int __init
+zr36050_init_module (void)
+{
+       //dprintk(1, "ZR36050 driver %s\n",ZR050_VERSION);
+       zr36050_codecs = 0;
+       return videocodec_register(&zr36050_codec);
+}
+
+static void __exit
+zr36050_cleanup_module (void)
+{
+       if (zr36050_codecs) {
+               dprintk(1,
+                       "zr36050: something's wrong - %d codecs left somehow.\n",
+                       zr36050_codecs);
+       }
+       videocodec_unregister(&zr36050_codec);
+}
+
+module_init(zr36050_init_module);
+module_exit(zr36050_cleanup_module);
+
+MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>");
+MODULE_DESCRIPTION("Driver module for ZR36050 jpeg processors "
+                  ZR050_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/zr36050.h b/drivers/media/video/zr36050.h
new file mode 100644 (file)
index 0000000..ed494eb
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Zoran ZR36050 basic configuration functions - header file
+ *
+ * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at>
+ *
+ * $Id: zr36050.h,v 1.1.2.2 2003/01/14 21:18:22 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * 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 ZR36050_H
+#define ZR36050_H
+
+/* data stored for each zoran jpeg codec chip */
+struct zr36050 {
+       char name[32];
+       int num;
+       /* io datastructure */
+       struct videocodec *codec;
+       // last coder status
+       __u8 status1;
+       // actual coder setup
+       int mode;
+
+       __u16 width;
+       __u16 height;
+
+       __u16 bitrate_ctrl;
+
+       __u32 total_code_vol;
+       __u16 max_block_vol;
+
+       __u8 h_samp_ratio[8];
+       __u8 v_samp_ratio[8];
+       __u16 scalefact;
+       __u16 dri;
+};
+
+/* zr36050 register addresses */
+#define ZR050_GO                  0x000
+#define ZR050_HARDWARE            0x002
+#define ZR050_MODE                0x003
+#define ZR050_OPTIONS             0x004
+#define ZR050_MBCV                0x005
+#define ZR050_MARKERS_EN          0x006
+#define ZR050_INT_REQ_0           0x007
+#define ZR050_INT_REQ_1           0x008
+#define ZR050_TCV_NET_HI          0x009
+#define ZR050_TCV_NET_MH          0x00a
+#define ZR050_TCV_NET_ML          0x00b
+#define ZR050_TCV_NET_LO          0x00c
+#define ZR050_TCV_DATA_HI         0x00d
+#define ZR050_TCV_DATA_MH         0x00e
+#define ZR050_TCV_DATA_ML         0x00f
+#define ZR050_TCV_DATA_LO         0x010
+#define ZR050_SF_HI               0x011
+#define ZR050_SF_LO               0x012
+#define ZR050_AF_HI               0x013
+#define ZR050_AF_M                0x014
+#define ZR050_AF_LO               0x015
+#define ZR050_ACV_HI              0x016
+#define ZR050_ACV_MH              0x017
+#define ZR050_ACV_ML              0x018
+#define ZR050_ACV_LO              0x019
+#define ZR050_ACT_HI              0x01a
+#define ZR050_ACT_MH              0x01b
+#define ZR050_ACT_ML              0x01c
+#define ZR050_ACT_LO              0x01d
+#define ZR050_ACV_TRUN_HI         0x01e
+#define ZR050_ACV_TRUN_MH         0x01f
+#define ZR050_ACV_TRUN_ML         0x020
+#define ZR050_ACV_TRUN_LO         0x021
+#define ZR050_STATUS_0            0x02e
+#define ZR050_STATUS_1            0x02f
+
+#define ZR050_SOF_IDX             0x040
+#define ZR050_SOS1_IDX            0x07a
+#define ZR050_SOS2_IDX            0x08a
+#define ZR050_SOS3_IDX            0x09a
+#define ZR050_SOS4_IDX            0x0aa
+#define ZR050_DRI_IDX             0x0c0
+#define ZR050_DNL_IDX             0x0c6
+#define ZR050_DQT_IDX             0x0cc
+#define ZR050_DHT_IDX             0x1d4
+#define ZR050_APP_IDX             0x380
+#define ZR050_COM_IDX             0x3c0
+
+/* zr36050 hardware register bits */
+
+#define ZR050_HW_BSWD                0x80
+#define ZR050_HW_MSTR                0x40
+#define ZR050_HW_DMA                 0x20
+#define ZR050_HW_CFIS_1_CLK          0x00
+#define ZR050_HW_CFIS_2_CLK          0x04
+#define ZR050_HW_CFIS_3_CLK          0x08
+#define ZR050_HW_CFIS_4_CLK          0x0C
+#define ZR050_HW_CFIS_5_CLK          0x10
+#define ZR050_HW_CFIS_6_CLK          0x14
+#define ZR050_HW_CFIS_7_CLK          0x18
+#define ZR050_HW_CFIS_8_CLK          0x1C
+#define ZR050_HW_BELE                0x01
+
+/* zr36050 mode register bits */
+
+#define ZR050_MO_COMP                0x80
+#define ZR050_MO_COMP                0x80
+#define ZR050_MO_ATP                 0x40
+#define ZR050_MO_PASS2               0x20
+#define ZR050_MO_TLM                 0x10
+#define ZR050_MO_DCONLY              0x08
+#define ZR050_MO_BRC                 0x04
+
+#define ZR050_MO_ATP                 0x40
+#define ZR050_MO_PASS2               0x20
+#define ZR050_MO_TLM                 0x10
+#define ZR050_MO_DCONLY              0x08
+
+/* zr36050 option register bits */
+
+#define ZR050_OP_NSCN_1              0x00
+#define ZR050_OP_NSCN_2              0x20
+#define ZR050_OP_NSCN_3              0x40
+#define ZR050_OP_NSCN_4              0x60
+#define ZR050_OP_NSCN_5              0x80
+#define ZR050_OP_NSCN_6              0xA0
+#define ZR050_OP_NSCN_7              0xC0
+#define ZR050_OP_NSCN_8              0xE0
+#define ZR050_OP_OVF                 0x10
+
+
+/* zr36050 markers-enable register bits */
+
+#define ZR050_ME_APP                 0x80
+#define ZR050_ME_COM                 0x40
+#define ZR050_ME_DRI                 0x20
+#define ZR050_ME_DQT                 0x10
+#define ZR050_ME_DHT                 0x08
+#define ZR050_ME_DNL                 0x04
+#define ZR050_ME_DQTI                0x02
+#define ZR050_ME_DHTI                0x01
+
+/* zr36050 status0/1 register bit masks */
+
+#define ZR050_ST_RST_MASK            0x20
+#define ZR050_ST_SOF_MASK            0x02
+#define ZR050_ST_SOS_MASK            0x02
+#define ZR050_ST_DATRDY_MASK         0x80
+#define ZR050_ST_MRKDET_MASK         0x40
+#define ZR050_ST_RFM_MASK            0x10
+#define ZR050_ST_RFD_MASK            0x08
+#define ZR050_ST_END_MASK            0x04
+#define ZR050_ST_TCVOVF_MASK         0x02
+#define ZR050_ST_DATOVF_MASK         0x01
+
+/* pixel component idx */
+
+#define ZR050_Y_COMPONENT         0
+#define ZR050_U_COMPONENT         1
+#define ZR050_V_COMPONENT         2
+
+#endif                         /*fndef ZR36050_H */
index 9c6b50f175e3567813118e3bb04e617d784d56ba..159abfa034d96b4f3df3babd86136dc926a79711 100644 (file)
@@ -1,22 +1,22 @@
 /* 
   zr36057.h - zr36057 register offsets
-
   Copyright (C) 1998 Dave Perks <dperks@ibm.net>
-
   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.
-*/
* zr36057.h - zr36057 register offsets
+ *
* Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
* 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 _ZR36057_H_
 #define _ZR36057_H_
 
 /* Zoran ZR36057 registers */
 
-#define ZR36057_VFEHCR          0x000   /* Video Front End, Horizontal Configuration Register */
+#define ZR36057_VFEHCR          0x000  /* Video Front End, Horizontal Configuration Register */
 #define ZR36057_VFEHCR_HSPol            (1<<30)
 #define ZR36057_VFEHCR_HStart           10
 #define ZR36057_VFEHCR_HEnd            0
 #define ZR36057_VFEHCR_Hmask           0x3ff
 
-#define ZR36057_VFEVCR          0x004   /* Video Front End, Vertical Configuration Register */
+#define ZR36057_VFEVCR          0x004  /* Video Front End, Vertical Configuration Register */
 #define ZR36057_VFEVCR_VSPol            (1<<30)
 #define ZR36057_VFEVCR_VStart           10
 #define ZR36057_VFEVCR_VEnd            0
 #define ZR36057_VFEVCR_Vmask           0x3ff
 
-#define ZR36057_VFESPFR         0x008   /* Video Front End, Scaler and Pixel Format Register */
+#define ZR36057_VFESPFR         0x008  /* Video Front End, Scaler and Pixel Format Register */
 #define ZR36057_VFESPFR_ExtFl           (1<<26)
 #define ZR36057_VFESPFR_TopField        (1<<25)
 #define ZR36057_VFESPFR_VCLKPol         (1<<24)
 #define ZR36057_VFESPFR_Pack24          (1<<1)
 #define ZR36057_VFESPFR_LittleEndian    (1<<0)
 
-#define ZR36057_VDTR            0x00c   /* Video Display "Top" Register */
+#define ZR36057_VDTR            0x00c  /* Video Display "Top" Register */
 
-#define ZR36057_VDBR            0x010   /* Video Display "Bottom" Register */
+#define ZR36057_VDBR            0x010  /* Video Display "Bottom" Register */
 
-#define ZR36057_VSSFGR          0x014   /* Video Stride, Status, and Frame Grab Register */
+#define ZR36057_VSSFGR          0x014  /* Video Stride, Status, and Frame Grab Register */
 #define ZR36057_VSSFGR_DispStride       16
 #define ZR36057_VSSFGR_VidOvf           (1<<8)
 #define ZR36057_VSSFGR_SnapShot         (1<<1)
 #define ZR36057_VSSFGR_FrameGrab        (1<<0)
 
-#define ZR36057_VDCR            0x018   /* Video Display Configuration Register */
+#define ZR36057_VDCR            0x018  /* Video Display Configuration Register */
 #define ZR36057_VDCR_VidEn              (1<<31)
 #define ZR36057_VDCR_MinPix             24
 #define ZR36057_VDCR_Triton             (1<<24)
 #define ZR36057_VDCR_VidWinHt           12
 #define ZR36057_VDCR_VidWinWid          0
 
-#define ZR36057_MMTR            0x01c   /* Masking Map "Top" Register */
+#define ZR36057_MMTR            0x01c  /* Masking Map "Top" Register */
 
-#define ZR36057_MMBR            0x020   /* Masking Map "Bottom" Register */
+#define ZR36057_MMBR            0x020  /* Masking Map "Bottom" Register */
 
-#define ZR36057_OCR             0x024   /* Overlay Control Register */
+#define ZR36057_OCR             0x024  /* Overlay Control Register */
 #define ZR36057_OCR_OvlEnable           (1 << 15)
 #define ZR36057_OCR_MaskStride          0
 
-#define ZR36057_SPGPPCR         0x028   /* System, PCI, and General Purpose Pins Control Register */
+#define ZR36057_SPGPPCR         0x028  /* System, PCI, and General Purpose Pins Control Register */
 #define ZR36057_SPGPPCR_SoftReset      (1<<24)
 
-#define ZR36057_GPPGCR1         0x02c   /* General Purpose Pins and GuestBus Control Register (1) */
+#define ZR36057_GPPGCR1         0x02c  /* General Purpose Pins and GuestBus Control Register (1) */
 
-#define ZR36057_MCSAR           0x030   /* MPEG Code Source Address Register */
+#define ZR36057_MCSAR           0x030  /* MPEG Code Source Address Register */
 
-#define ZR36057_MCTCR           0x034   /* MPEG Code Transfer Control Register */
+#define ZR36057_MCTCR           0x034  /* MPEG Code Transfer Control Register */
 #define ZR36057_MCTCR_CodTime           (1 << 30)
 #define ZR36057_MCTCR_CEmpty            (1 << 29)
 #define ZR36057_MCTCR_CFlush            (1 << 28)
 #define ZR36057_MCTCR_CodGuestID       20
 #define ZR36057_MCTCR_CodGuestReg      16
 
-#define ZR36057_MCMPR           0x038   /* MPEG Code Memory Pointer Register */
+#define ZR36057_MCMPR           0x038  /* MPEG Code Memory Pointer Register */
 
-#define ZR36057_ISR             0x03c   /* Interrupt Status Register */
+#define ZR36057_ISR             0x03c  /* Interrupt Status Register */
 #define ZR36057_ISR_GIRQ1               (1<<30)
 #define ZR36057_ISR_GIRQ0               (1<<29)
 #define ZR36057_ISR_CodRepIRQ           (1<<28)
 #define ZR36057_ISR_JPEGRepIRQ          (1<<27)
 
-#define ZR36057_ICR             0x040   /* Interrupt Control Register */
+#define ZR36057_ICR             0x040  /* Interrupt Control Register */
 #define ZR36057_ICR_GIRQ1               (1<<30)
 #define ZR36057_ICR_GIRQ0               (1<<29)
 #define ZR36057_ICR_CodRepIRQ           (1<<28)
 #define ZR36057_ICR_JPEGRepIRQ          (1<<27)
 #define ZR36057_ICR_IntPinEn            (1<<24)
 
-#define ZR36057_I2CBR           0x044   /* I2C Bus Register */
+#define ZR36057_I2CBR           0x044  /* I2C Bus Register */
 #define ZR36057_I2CBR_SDA              (1<<1)
 #define ZR36057_I2CBR_SCL              (1<<0)
 
-#define ZR36057_JMC             0x100   /* JPEG Mode and Control */
+#define ZR36057_JMC             0x100  /* JPEG Mode and Control */
 #define ZR36057_JMC_JPG                 (1 << 31)
 #define ZR36057_JMC_JPGExpMode          (0 << 29)
 #define ZR36057_JMC_JPGCmpMode          (1 << 29)
 #define ZR36057_JMC_CFIFO_FB            (1 << 1)
 #define ZR36057_JMC_Stll_LitEndian      (1 << 0)
 
-#define ZR36057_JPC             0x104   /* JPEG Process Control */
+#define ZR36057_JPC             0x104  /* JPEG Process Control */
 #define ZR36057_JPC_P_Reset             (1 << 7)
 #define ZR36057_JPC_CodTrnsEn           (1 << 5)
 #define ZR36057_JPC_Active              (1 << 0)
 
-#define ZR36057_VSP             0x108   /* Vertical Sync Parameters */
+#define ZR36057_VSP             0x108  /* Vertical Sync Parameters */
 #define ZR36057_VSP_VsyncSize           16
 #define ZR36057_VSP_FrmTot              0
 
-#define ZR36057_HSP             0x10c   /* Horizontal Sync Parameters */
+#define ZR36057_HSP             0x10c  /* Horizontal Sync Parameters */
 #define ZR36057_HSP_HsyncStart          16
 #define ZR36057_HSP_LineTot             0
 
-#define ZR36057_FHAP            0x110   /* Field Horizontal Active Portion */
+#define ZR36057_FHAP            0x110  /* Field Horizontal Active Portion */
 #define ZR36057_FHAP_NAX                16
 #define ZR36057_FHAP_PAX                0
 
-#define ZR36057_FVAP            0x114   /* Field Vertical Active Portion */
+#define ZR36057_FVAP            0x114  /* Field Vertical Active Portion */
 #define ZR36057_FVAP_NAY                16
 #define ZR36057_FVAP_PAY                0
 
-#define ZR36057_FPP             0x118   /* Field Process Parameters */
+#define ZR36057_FPP             0x118  /* Field Process Parameters */
 #define ZR36057_FPP_Odd_Even            (1 << 0)
 
-#define ZR36057_JCBA            0x11c   /* JPEG Code Base Address */
+#define ZR36057_JCBA            0x11c  /* JPEG Code Base Address */
 
-#define ZR36057_JCFT            0x120   /* JPEG Code FIFO Threshold */
+#define ZR36057_JCFT            0x120  /* JPEG Code FIFO Threshold */
 
-#define ZR36057_JCGI            0x124   /* JPEG Codec Guest ID */
+#define ZR36057_JCGI            0x124  /* JPEG Codec Guest ID */
 #define ZR36057_JCGI_JPEGuestID         4
 #define ZR36057_JCGI_JPEGuestReg        0
 
-#define ZR36057_GCR2            0x12c   /* GuestBus Control Register (2) */
+#define ZR36057_GCR2            0x12c  /* GuestBus Control Register (2) */
 
-#define ZR36057_POR             0x200   /* Post Office Register */
+#define ZR36057_POR             0x200  /* Post Office Register */
 #define ZR36057_POR_POPen               (1<<25)
 #define ZR36057_POR_POTime              (1<<24)
 #define ZR36057_POR_PODir               (1<<23)
 
-#define ZR36057_STR             0x300   /* "Still" Transfer Register */
+#define ZR36057_STR             0x300  /* "Still" Transfer Register */
 
 #endif
diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zr36060.c
new file mode 100644 (file)
index 0000000..41ae711
--- /dev/null
@@ -0,0 +1,1006 @@
+/*
+ * Zoran ZR36060 basic configuration functions
+ *
+ * Copyright (C) 2002 Laurent Pinchart <laurent.pinchart@skynet.be>
+ *
+ * $Id: zr36060.c,v 1.1.2.22 2003/05/06 09:35:36 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * ------------------------------------------------------------------------
+ */
+
+#define ZR060_VERSION "v0.7"
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <linux/types.h>
+#include <linux/wait.h>
+
+/* includes for structures and defines regarding video 
+   #include<linux/videodev.h> */
+
+/* I/O commands, error codes */
+#include<asm/io.h>
+//#include<errno.h>
+
+/* headerfile of this module */
+#include"zr36060.h"
+
+/* codec io API */
+#include"videocodec.h"
+
+/* it doesn't make sense to have more than 20 or so,
+  just to prevent some unwanted loops */
+#define MAX_CODECS 20
+
+/* amount of chips attached via this driver */
+static int zr36060_codecs = 0;
+
+static int low_bitrate = 0;
+MODULE_PARM(low_bitrate, "i");
+MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate");
+
+/* debugging is available via module parameter */
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-4)");
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format, ##args); \
+       } while (0)
+
+/* =========================================================================
+   Local hardware I/O functions:
+
+   read/write via codec layer (registers are located in the master device)
+   ========================================================================= */
+
+/* read and write functions */
+static u8
+zr36060_read (struct zr36060 *ptr,
+             u16             reg)
+{
+       u8 value = 0;
+
+       // just in case something is wrong...
+       if (ptr->codec->master_data->readreg)
+               value = (ptr->codec->master_data->readreg(ptr->codec,
+                                                         reg)) & 0xff;
+       else
+               dprintk(1,
+                       KERN_ERR "%s: invalid I/O setup, nothing read!\n",
+                       ptr->name);
+
+       //dprintk(4, "%s: reading from 0x%04x: %02x\n",ptr->name,reg,value);
+
+       return value;
+}
+
+static void
+zr36060_write(struct zr36060 *ptr,
+             u16             reg,
+             u8              value)
+{
+       //dprintk(4, "%s: writing 0x%02x to 0x%04x\n",ptr->name,value,reg);
+       dprintk(4, "0x%02x @0x%04x\n", value, reg);
+
+       // just in case something is wrong...
+       if (ptr->codec->master_data->writereg)
+               ptr->codec->master_data->writereg(ptr->codec, reg, value);
+       else
+               dprintk(1,
+                       KERN_ERR
+                       "%s: invalid I/O setup, nothing written!\n",
+                       ptr->name);
+}
+
+/* =========================================================================
+   Local helper function:
+
+   status read
+   ========================================================================= */
+
+/* status is kept in datastructure */
+static u8
+zr36060_read_status (struct zr36060 *ptr)
+{
+       ptr->status = zr36060_read(ptr, ZR060_CFSR);
+
+       zr36060_read(ptr, 0);
+       return ptr->status;
+}
+
+/* =========================================================================
+   Local helper function:
+
+   scale factor read
+   ========================================================================= */
+
+/* scale factor is kept in datastructure */
+static u16
+zr36060_read_scalefactor (struct zr36060 *ptr)
+{
+       ptr->scalefact = (zr36060_read(ptr, ZR060_SF_HI) << 8) |
+                        (zr36060_read(ptr, ZR060_SF_LO) & 0xFF);
+
+       /* leave 0 selected for an eventually GO from master */
+       zr36060_read(ptr, 0);
+       return ptr->scalefact;
+}
+
+/* =========================================================================
+   Local helper function:
+
+   wait if codec is ready to proceed (end of processing) or time is over
+   ========================================================================= */
+
+static void
+zr36060_wait_end (struct zr36060 *ptr)
+{
+       int i = 0;
+
+       while (zr36060_read_status(ptr) & ZR060_CFSR_Busy) {
+               udelay(1);
+               if (i++ > 200000) {     // 200ms, there is for shure something wrong!!!
+                       dprintk(1,
+                               "%s: timout at wait_end (last status: 0x%02x)\n",
+                               ptr->name, ptr->status);
+                       break;
+               }
+       }
+}
+
+/* =========================================================================
+   Local helper function:
+
+   basic test of "connectivity", writes/reads to/from memory the SOF marker 
+   ========================================================================= */
+
+static int
+zr36060_basic_test (struct zr36060 *ptr)
+{
+       if ((zr36060_read(ptr, ZR060_IDR_DEV) != 0x33) &&
+           (zr36060_read(ptr, ZR060_IDR_REV) != 0x01)) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: attach failed, can't connect to jpeg processor!\n",
+                       ptr->name);
+               return -ENXIO;
+       }
+
+       zr36060_wait_end(ptr);
+       if (ptr->status & ZR060_CFSR_Busy) {
+               dprintk(1,
+                       KERN_ERR
+                       "%s: attach failed, jpeg processor failed (end flag)!\n",
+                       ptr->name);
+               return -EBUSY;
+       }
+
+       return 0;               /* looks good! */
+}
+
+/* =========================================================================
+   Local helper function:
+
+   simple loop for pushing the init datasets
+   ========================================================================= */
+
+static int
+zr36060_pushit (struct zr36060 *ptr,
+               u16             startreg,
+               u16             len,
+               const char     *data)
+{
+       int i = 0;
+
+       dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", ptr->name,
+               startreg, len);
+       while (i < len) {
+               zr36060_write(ptr, startreg++, data[i++]);
+       }
+
+       return i;
+}
+
+/* =========================================================================
+   Basic datasets:
+
+   jpeg baseline setup data (you find it on lots places in internet, or just
+   extract it from any regular .jpg image...)
+
+   Could be variable, but until it's not needed it they are just fixed to save
+   memory. Otherwise expand zr36060 structure with arrays, push the values to
+   it and initalize from there, as e.g. the linux zr36057/60 driver does it.
+   ========================================================================= */
+
+static const char zr36060_dqt[0x86] = {
+       0xff, 0xdb,             //Marker: DQT
+       0x00, 0x84,             //Length: 2*65+2
+       0x00,                   //Pq,Tq first table
+       0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
+       0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
+       0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
+       0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
+       0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
+       0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
+       0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
+       0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
+       0x01,                   //Pq,Tq second table
+       0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
+       0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
+};
+
+static const char zr36060_dht[0x1a4] = {
+       0xff, 0xc4,             //Marker: DHT
+       0x01, 0xa2,             //Length: 2*AC, 2*DC
+       0x00,                   //DC first table
+       0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+       0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+       0x01,                   //DC second table
+       0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+       0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+       0x10,                   //AC first table
+       0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+       0x05, 0x05, 0x04, 0x04, 0x00, 0x00,
+       0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11,
+       0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
+       0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1,
+       0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24,
+       0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17,
+       0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34,
+       0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
+       0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56,
+       0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66,
+       0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+       0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
+       0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+       0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
+       0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9,
+       0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,
+       0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
+       0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+       0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+       0xF8, 0xF9, 0xFA,
+       0x11,                   //AC second table
+       0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+       0x07, 0x05, 0x04, 0x04, 0x00, 0x01,
+       0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
+       0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+       0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+       0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62,
+       0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25,
+       0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A,
+       0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
+       0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56,
+       0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66,
+       0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+       0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+       0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+       0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+       0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8,
+       0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+       0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8,
+       0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+       0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
+       0xF9, 0xFA
+};
+
+static const char zr36060_app[0x40] = {
+       0xff, 0xe0,             //Marker: APP0
+       0x00, 0x07,             //Length: 7
+       ' ', 'A', 'V', 'I', '1', 0, 0, 0,       // 'AVI' field
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0
+};
+
+static const char zr36060_com[0x40] = {
+       0xff, 0xfe,             //Marker: COM
+       0x00, 0x06,             //Length: 6
+       ' ', 'C', 'O', 'M', 0, 0, 0, 0, // 'COM' field
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0
+};
+
+/* jpeg baseline setup, this is just fixed in this driver (YUV pictures) */
+#define NO_OF_COMPONENTS          0x3  //Y,U,V
+#define BASELINE_PRECISION        0x8  //MCU size (?)
+static const char zr36060_tq[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };  //table idx's QT
+static const char zr36060_td[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };  //table idx's DC
+static const char zr36060_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };  //table idx's AC
+
+/* horizontal 422 decimation setup (maybe we support 411 or so later, too) */
+static const char zr36060_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 };
+static const char zr36060_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 };
+
+/* =========================================================================
+   Local helper functions:
+
+   calculation and setup of parameter-dependent JPEG baseline segments
+   (needed for compression only)
+   ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+
+/* SOF (start of frame) segment depends on width, height and sampling ratio
+                         of each color component */
+
+static int
+zr36060_set_sof (struct zr36060 *ptr)
+{
+       char sof_data[34];      // max. size of register set
+       int i;
+
+       dprintk(3, "%s: write SOF (%dx%d, %d components)\n", ptr->name,
+               ptr->width, ptr->height, NO_OF_COMPONENTS);
+       sof_data[0] = 0xff;
+       sof_data[1] = 0xc0;
+       sof_data[2] = 0x00;
+       sof_data[3] = (3 * NO_OF_COMPONENTS) + 8;
+       sof_data[4] = BASELINE_PRECISION;       // only '8' possible with zr36060
+       sof_data[5] = (ptr->height) >> 8;
+       sof_data[6] = (ptr->height) & 0xff;
+       sof_data[7] = (ptr->width) >> 8;
+       sof_data[8] = (ptr->width) & 0xff;
+       sof_data[9] = NO_OF_COMPONENTS;
+       for (i = 0; i < NO_OF_COMPONENTS; i++) {
+               sof_data[10 + (i * 3)] = i;     // index identifier
+               sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) |
+                                        (ptr->v_samp_ratio[i]); // sampling ratios
+               sof_data[12 + (i * 3)] = zr36060_tq[i]; // Q table selection
+       }
+       return zr36060_pushit(ptr, ZR060_SOF_IDX,
+                             (3 * NO_OF_COMPONENTS) + 10, sof_data);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* SOS (start of scan) segment depends on the used scan components 
+                        of each color component */
+
+static int
+zr36060_set_sos (struct zr36060 *ptr)
+{
+       char sos_data[16];      // max. size of register set
+       int i;
+
+       dprintk(3, "%s: write SOS\n", ptr->name);
+       sos_data[0] = 0xff;
+       sos_data[1] = 0xda;
+       sos_data[2] = 0x00;
+       sos_data[3] = 2 + 1 + (2 * NO_OF_COMPONENTS) + 3;
+       sos_data[4] = NO_OF_COMPONENTS;
+       for (i = 0; i < NO_OF_COMPONENTS; i++) {
+               sos_data[5 + (i * 2)] = i;      // index
+               sos_data[6 + (i * 2)] = (zr36060_td[i] << 4) |
+                                       zr36060_ta[i]; // AC/DC tbl.sel.
+       }
+       sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 2] = 00;      // scan start
+       sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 3] = 0x3f;
+       sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 4] = 00;
+       return zr36060_pushit(ptr, ZR060_SOS_IDX,
+                             4 + 1 + (2 * NO_OF_COMPONENTS) + 3,
+                             sos_data);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* DRI (define restart interval) */
+
+static int
+zr36060_set_dri (struct zr36060 *ptr)
+{
+       char dri_data[6];       // max. size of register set
+
+       dprintk(3, "%s: write DRI\n", ptr->name);
+       dri_data[0] = 0xff;
+       dri_data[1] = 0xdd;
+       dri_data[2] = 0x00;
+       dri_data[3] = 0x04;
+       dri_data[4] = (ptr->dri) >> 8;
+       dri_data[5] = (ptr->dri) & 0xff;
+       return zr36060_pushit(ptr, ZR060_DRI_IDX, 6, dri_data);
+}
+
+/* =========================================================================
+   Setup function:
+
+   Setup compression/decompression of Zoran's JPEG processor
+   ( see also zoran 36060 manual )
+
+   ... sorry for the spaghetti code ...
+   ========================================================================= */
+static void
+zr36060_init (struct zr36060 *ptr)
+{
+       int sum = 0;
+       long bitcnt, tmp;
+
+       if (ptr->mode == CODEC_DO_COMPRESSION) {
+               dprintk(2, "%s: COMPRESSION SETUP\n", ptr->name);
+
+               zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SyncRst);
+
+               /* 060 communicates with 067 in master mode */
+               zr36060_write(ptr, ZR060_CIR, ZR060_CIR_CodeMstr);
+
+               /* Compression with or without variable scale factor */
+               /*FIXME: What about ptr->bitrate_ctrl? */
+               zr36060_write(ptr, ZR060_CMR,
+                             ZR060_CMR_Comp | ZR060_CMR_Pass2 |
+                             ZR060_CMR_BRB);
+
+               /* Must be zero */
+               zr36060_write(ptr, ZR060_MBZ, 0x00);
+               zr36060_write(ptr, ZR060_TCR_HI, 0x00);
+               zr36060_write(ptr, ZR060_TCR_LO, 0x00);
+
+               /* Disable all IRQs - no DataErr means autoreset */
+               zr36060_write(ptr, ZR060_IMR, 0);
+
+               /* volume control settings */
+               zr36060_write(ptr, ZR060_SF_HI, ptr->scalefact >> 8);
+               zr36060_write(ptr, ZR060_SF_LO, ptr->scalefact & 0xff);
+
+               zr36060_write(ptr, ZR060_AF_HI, 0xff);
+               zr36060_write(ptr, ZR060_AF_M, 0xff);
+               zr36060_write(ptr, ZR060_AF_LO, 0xff);
+
+               /* setup the variable jpeg tables */
+               sum += zr36060_set_sof(ptr);
+               sum += zr36060_set_sos(ptr);
+               sum += zr36060_set_dri(ptr);
+
+               /* setup the fixed jpeg tables - maybe variable, though -
+                * (see table init section above) */
+               sum +=
+                   zr36060_pushit(ptr, ZR060_DQT_IDX, sizeof(zr36060_dqt),
+                                  zr36060_dqt);
+               sum +=
+                   zr36060_pushit(ptr, ZR060_DHT_IDX, sizeof(zr36060_dht),
+                                  zr36060_dht);
+               sum +=
+                   zr36060_pushit(ptr, ZR060_APP_IDX, sizeof(zr36060_app),
+                                  zr36060_app);
+               sum +=
+                   zr36060_pushit(ptr, ZR060_COM_IDX, sizeof(zr36060_com),
+                                  zr36060_com);
+
+               /* setup misc. data for compression (target code sizes) */
+
+               /* size of compressed code to reach without header data */
+               sum = ptr->real_code_vol - sum;
+               bitcnt = sum << 3;      /* need the size in bits */
+
+               tmp = bitcnt >> 16;
+               dprintk(3,
+                       "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n",
+                       ptr->name, sum, ptr->real_code_vol, bitcnt, tmp);
+               zr36060_write(ptr, ZR060_TCV_NET_HI, tmp >> 8);
+               zr36060_write(ptr, ZR060_TCV_NET_MH, tmp & 0xff);
+               tmp = bitcnt & 0xffff;
+               zr36060_write(ptr, ZR060_TCV_NET_ML, tmp >> 8);
+               zr36060_write(ptr, ZR060_TCV_NET_LO, tmp & 0xff);
+
+               bitcnt -= bitcnt >> 7;  // bits without stuffing
+               bitcnt -= ((bitcnt * 5) >> 6);  // bits without eob
+
+               tmp = bitcnt >> 16;
+               dprintk(3, "%s: code: nettobit=%ld, highnettobits=%ld\n",
+                       ptr->name, bitcnt, tmp);
+               zr36060_write(ptr, ZR060_TCV_DATA_HI, tmp >> 8);
+               zr36060_write(ptr, ZR060_TCV_DATA_MH, tmp & 0xff);
+               tmp = bitcnt & 0xffff;
+               zr36060_write(ptr, ZR060_TCV_DATA_ML, tmp >> 8);
+               zr36060_write(ptr, ZR060_TCV_DATA_LO, tmp & 0xff);
+
+               /* JPEG markers to be included in the compressed stream */
+               zr36060_write(ptr, ZR060_MER,
+                             ZR060_MER_App | ZR060_MER_Com | ZR060_MER_DQT
+                             | ZR060_MER_DHT);
+
+               /* Setup the Video Frontend */
+               /* Limit pixel range to 16..235 as per CCIR-601 */
+               zr36060_write(ptr, ZR060_VCR, ZR060_VCR_Range);
+
+       } else {
+               dprintk(2, "%s: EXPANSION SETUP\n", ptr->name);
+
+               zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SyncRst);
+
+               /* 060 communicates with 067 in master mode */
+               zr36060_write(ptr, ZR060_CIR, ZR060_CIR_CodeMstr);
+
+               /* Decompression */
+               zr36060_write(ptr, ZR060_CMR, 0);
+
+               /* Must be zero */
+               zr36060_write(ptr, ZR060_MBZ, 0x00);
+               zr36060_write(ptr, ZR060_TCR_HI, 0x00);
+               zr36060_write(ptr, ZR060_TCR_LO, 0x00);
+
+               /* Disable all IRQs - no DataErr means autoreset */
+               zr36060_write(ptr, ZR060_IMR, 0);
+
+               /* setup misc. data for expansion */
+               zr36060_write(ptr, ZR060_MER, 0);
+
+               /* setup the fixed jpeg tables - maybe variable, though -
+                * (see table init section above) */
+               zr36060_pushit(ptr, ZR060_DHT_IDX, sizeof(zr36060_dht),
+                              zr36060_dht);
+
+               /* Setup the Video Frontend */
+               //zr36060_write(ptr, ZR060_VCR, ZR060_VCR_FIExt);
+               //this doesn't seem right and doesn't work...
+               zr36060_write(ptr, ZR060_VCR, ZR060_VCR_Range);
+       }
+
+       /* Load the tables */
+       zr36060_write(ptr, ZR060_LOAD,
+                     ZR060_LOAD_SyncRst | ZR060_LOAD_Load);
+       zr36060_wait_end(ptr);
+       dprintk(2, "%s: Status after table preload: 0x%02x\n", ptr->name,
+               ptr->status);
+
+       if (ptr->status & ZR060_CFSR_Busy) {
+               dprintk(1, KERN_ERR "%s: init aborted!\n", ptr->name);
+               return;         // something is wrong, its timed out!!!!
+       }
+}
+
+/* =========================================================================
+   CODEC API FUNCTIONS
+
+   this functions are accessed by the master via the API structure
+   ========================================================================= */
+
+/* set compression/expansion mode and launches codec -
+   this should be the last call from the master before starting processing */
+static int
+zr36060_set_mode (struct videocodec *codec,
+                 int                mode)
+{
+       struct zr36060 *ptr = (struct zr36060 *) codec->data;
+
+       dprintk(2, "%s: set_mode %d call\n", ptr->name, mode);
+
+       if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION))
+               return -EINVAL;
+
+       ptr->mode = mode;
+       zr36060_init(ptr);
+
+       return 0;
+}
+
+/* set picture size (norm is ignored as the codec doesn't know about it) */
+static int
+zr36060_set_video (struct videocodec   *codec,
+                  struct tvnorm       *norm,
+                  struct vfe_settings *cap,
+                  struct vfe_polarity *pol)
+{
+       struct zr36060 *ptr = (struct zr36060 *) codec->data;
+       u32 reg;
+       int size;
+
+       dprintk(2, "%s: set_video %d/%d-%dx%d (%%%d) call\n", ptr->name,
+               cap->x, cap->y, cap->width, cap->height, cap->decimation);
+
+       /* if () return -EINVAL;
+        * trust the master driver that it knows what it does - so
+        * we allow invalid startx/y and norm for now ... */
+       ptr->width = cap->width / (cap->decimation & 0xff);
+       ptr->height = cap->height / (cap->decimation >> 8);
+
+       zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SyncRst);
+
+       /* Note that VSPol/HSPol bits in zr36060 have the opposite
+        * meaning of their zr360x7 counterparts with the same names
+        * N.b. for VSPol this is only true if FIVEdge = 0 (default,
+        * left unchanged here - in accordance with datasheet).
+       */
+       reg = (!pol->vsync_pol ? ZR060_VPR_VSPol : 0)
+           | (!pol->hsync_pol ? ZR060_VPR_HSPol : 0)
+           | (pol->field_pol ? ZR060_VPR_FIPol : 0)
+           | (pol->blank_pol ? ZR060_VPR_BLPol : 0)
+           | (pol->subimg_pol ? ZR060_VPR_SImgPol : 0)
+           | (pol->poe_pol ? ZR060_VPR_PoePol : 0)
+           | (pol->pvalid_pol ? ZR060_VPR_PValPol : 0)
+           | (pol->vclk_pol ? ZR060_VPR_VCLKPol : 0);
+       zr36060_write(ptr, ZR060_VPR, reg);
+
+       reg = 0;
+       switch (cap->decimation & 0xff) {
+       default:
+       case 1:
+               break;
+
+       case 2:
+               reg |= ZR060_SR_HScale2;
+               break;
+
+       case 4:
+               reg |= ZR060_SR_HScale4;
+               break;
+       }
+
+       switch (cap->decimation >> 8) {
+       default:
+       case 1:
+               break;
+
+       case 2:
+               reg |= ZR060_SR_VScale;
+               break;
+       }
+       zr36060_write(ptr, ZR060_SR, reg);
+
+       zr36060_write(ptr, ZR060_BCR_Y, 0x00);
+       zr36060_write(ptr, ZR060_BCR_U, 0x80);
+       zr36060_write(ptr, ZR060_BCR_V, 0x80);
+
+       /* sync generator */
+
+       reg = norm->Ht - 1;     /* Vtotal */
+       zr36060_write(ptr, ZR060_SGR_VTOTAL_HI, (reg >> 8) & 0xff);
+       zr36060_write(ptr, ZR060_SGR_VTOTAL_LO, (reg >> 0) & 0xff);
+
+       reg = norm->Wt - 1;     /* Htotal */
+       zr36060_write(ptr, ZR060_SGR_HTOTAL_HI, (reg >> 8) & 0xff);
+       zr36060_write(ptr, ZR060_SGR_HTOTAL_LO, (reg >> 0) & 0xff);
+
+       reg = 6 - 1;            /* VsyncSize */
+       zr36060_write(ptr, ZR060_SGR_VSYNC, reg);
+
+       //reg   = 30 - 1;               /* HsyncSize */
+///*CP*/        reg = (zr->params.norm == 1 ? 57 : 68);
+       reg = 68;
+       zr36060_write(ptr, ZR060_SGR_HSYNC, reg);
+
+       reg = norm->VStart - 1; /* BVstart */
+       zr36060_write(ptr, ZR060_SGR_BVSTART, reg);
+
+       reg += norm->Ha / 2;    /* BVend */
+       zr36060_write(ptr, ZR060_SGR_BVEND_HI, (reg >> 8) & 0xff);
+       zr36060_write(ptr, ZR060_SGR_BVEND_LO, (reg >> 0) & 0xff);
+
+       reg = norm->HStart - 1; /* BHstart */
+       zr36060_write(ptr, ZR060_SGR_BHSTART, reg);
+
+       reg += norm->Wa;        /* BHend */
+       zr36060_write(ptr, ZR060_SGR_BHEND_HI, (reg >> 8) & 0xff);
+       zr36060_write(ptr, ZR060_SGR_BHEND_LO, (reg >> 0) & 0xff);
+
+       /* active area */
+       reg = cap->y + norm->VStart;    /* Vstart */
+       zr36060_write(ptr, ZR060_AAR_VSTART_HI, (reg >> 8) & 0xff);
+       zr36060_write(ptr, ZR060_AAR_VSTART_LO, (reg >> 0) & 0xff);
+
+       reg += cap->height;     /* Vend */
+       zr36060_write(ptr, ZR060_AAR_VEND_HI, (reg >> 8) & 0xff);
+       zr36060_write(ptr, ZR060_AAR_VEND_LO, (reg >> 0) & 0xff);
+
+       reg = cap->x + norm->HStart;    /* Hstart */
+       zr36060_write(ptr, ZR060_AAR_HSTART_HI, (reg >> 8) & 0xff);
+       zr36060_write(ptr, ZR060_AAR_HSTART_LO, (reg >> 0) & 0xff);
+
+       reg += cap->width;      /* Hend */
+       zr36060_write(ptr, ZR060_AAR_HEND_HI, (reg >> 8) & 0xff);
+       zr36060_write(ptr, ZR060_AAR_HEND_LO, (reg >> 0) & 0xff);
+
+       /* subimage area */
+       reg = norm->VStart - 4; /* SVstart */
+       zr36060_write(ptr, ZR060_SWR_VSTART_HI, (reg >> 8) & 0xff);
+       zr36060_write(ptr, ZR060_SWR_VSTART_LO, (reg >> 0) & 0xff);
+
+       reg += norm->Ha / 2 + 8;        /* SVend */
+       zr36060_write(ptr, ZR060_SWR_VEND_HI, (reg >> 8) & 0xff);
+       zr36060_write(ptr, ZR060_SWR_VEND_LO, (reg >> 0) & 0xff);
+
+       reg = norm->HStart /*+ 64 */  - 4;      /* SHstart */
+       zr36060_write(ptr, ZR060_SWR_HSTART_HI, (reg >> 8) & 0xff);
+       zr36060_write(ptr, ZR060_SWR_HSTART_LO, (reg >> 0) & 0xff);
+
+       reg += norm->Wa + 8;    /* SHend */
+       zr36060_write(ptr, ZR060_SWR_HEND_HI, (reg >> 8) & 0xff);
+       zr36060_write(ptr, ZR060_SWR_HEND_LO, (reg >> 0) & 0xff);
+
+       size = ptr->width * ptr->height;
+       /* Target compressed field size in bits: */
+       size = size * 16;       /* uncompressed size in bits */
+       /* (Ronald) by default, quality = 100 is a compression
+        * ratio 1:2. Setting low_bitrate (insmod option) sets
+        * it to 1:4 (instead of 1:2, zr36060 max) as limit because the
+        * buz can't handle more at decimation=1... Use low_bitrate if
+        * you have a Buz, unless you know what you're doing */
+       size = size * cap->quality / (low_bitrate ? 400 : 200);
+       /* Lower limit (arbitrary, 1 KB) */
+       if (size < 8192)
+               size = 8192;
+       /* Upper limit: 7/8 of the code buffers */
+       if (size > ptr->total_code_vol * 7)
+               size = ptr->total_code_vol * 7;
+
+       ptr->real_code_vol = size >> 3; /* in bytes */
+
+       /* the MBCVR is the *maximum* block volume, according to the
+        * JPEG ISO specs, this shouldn't be used, since that allows
+        * for the best encoding quality. So set it to it's max value */
+       reg = ptr->max_block_vol;
+       zr36060_write(ptr, ZR060_MBCVR, reg);
+
+       return 0;
+}
+
+/* additional control functions */
+static int
+zr36060_control (struct videocodec *codec,
+                int                type,
+                int                size,
+                void              *data)
+{
+       struct zr36060 *ptr = (struct zr36060 *) codec->data;
+       int *ival = (int *) data;
+
+       dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type,
+               size);
+
+       switch (type) {
+       case CODEC_G_STATUS:    /* get last status */
+               if (size != sizeof(int))
+                       return -EFAULT;
+               zr36060_read_status(ptr);
+               *ival = ptr->status;
+               break;
+
+       case CODEC_G_CODEC_MODE:
+               if (size != sizeof(int))
+                       return -EFAULT;
+               *ival = CODEC_MODE_BJPG;
+               break;
+
+       case CODEC_S_CODEC_MODE:
+               if (size != sizeof(int))
+                       return -EFAULT;
+               if (*ival != CODEC_MODE_BJPG)
+                       return -EINVAL;
+               /* not needed, do nothing */
+               return 0;
+
+       case CODEC_G_VFE:
+       case CODEC_S_VFE:
+               /* not needed, do nothing */
+               return 0;
+
+       case CODEC_S_MMAP:
+               /* not available, give an error */
+               return -ENXIO;
+
+       case CODEC_G_JPEG_TDS_BYTE:     /* get target volume in byte */
+               if (size != sizeof(int))
+                       return -EFAULT;
+               *ival = ptr->total_code_vol;
+               break;
+
+       case CODEC_S_JPEG_TDS_BYTE:     /* get target volume in byte */
+               if (size != sizeof(int))
+                       return -EFAULT;
+               ptr->total_code_vol = *ival;
+               ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3;
+               break;
+
+       case CODEC_G_JPEG_SCALE:        /* get scaling factor */
+               if (size != sizeof(int))
+                       return -EFAULT;
+               *ival = zr36060_read_scalefactor(ptr);
+               break;
+
+       case CODEC_S_JPEG_SCALE:        /* set scaling factor */
+               if (size != sizeof(int))
+                       return -EFAULT;
+               ptr->scalefact = *ival;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return size;
+}
+
+/* =========================================================================
+   Exit and unregister function:
+
+   Deinitializes Zoran's JPEG processor
+   ========================================================================= */
+
+static int
+zr36060_unset (struct videocodec *codec)
+{
+       struct zr36060 *ptr = codec->data;
+
+       if (ptr) {
+               /* do wee need some codec deinit here, too ???? */
+
+               dprintk(1, "%s: finished codec #%d\n", ptr->name,
+                       ptr->num);
+               kfree(ptr);
+               codec->data = NULL;
+
+               zr36060_codecs--;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+               MOD_DEC_USE_COUNT;
+#else
+               module_put(THIS_MODULE);
+#endif
+
+               return 0;
+       }
+
+       return -EFAULT;
+}
+
+/* =========================================================================
+   Setup and registry function:
+
+   Initializes Zoran's JPEG processor
+
+   Also sets pixel size, average code size, mode (compr./decompr.)
+   (the given size is determined by the processor with the video interface)
+   ========================================================================= */
+
+static int
+zr36060_setup (struct videocodec *codec)
+{
+       struct zr36060 *ptr;
+       int res;
+
+       dprintk(2, "zr36060: initializing MJPEG subsystem #%d.\n",
+               zr36060_codecs);
+
+       if (zr36060_codecs == MAX_CODECS) {
+               dprintk(1,
+                       KERN_ERR "zr36060: Can't attach more codecs!\n");
+               return -ENOSPC;
+       }
+       //mem structure init
+       codec->data = ptr = kmalloc(sizeof(struct zr36060), GFP_KERNEL);
+       if (NULL == ptr) {
+               dprintk(1, KERN_ERR "zr36060: Can't get enough memory!\n");
+               return -ENOMEM;
+       }
+       memset(ptr, 0, sizeof(struct zr36060));
+
+       snprintf(ptr->name, sizeof(ptr->name), "zr36060[%d]",
+                zr36060_codecs);
+       ptr->num = zr36060_codecs++;
+       ptr->codec = codec;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+       MOD_INC_USE_COUNT;
+#else
+       if (!try_module_get(THIS_MODULE)) {
+               dprintk(1,
+                       KERN_ERR
+                       "zr36060: failed to increase module use count\n");
+               kfree(ptr);
+               zr36060_codecs--;
+               return -ENODEV;
+       }
+#endif
+
+       //testing
+       res = zr36060_basic_test(ptr);
+       if (res < 0) {
+               zr36060_unset(codec);
+               return res;
+       }
+       //final setup
+       memcpy(ptr->h_samp_ratio, zr36060_decimation_h, 8);
+       memcpy(ptr->v_samp_ratio, zr36060_decimation_v, 8);
+
+       ptr->bitrate_ctrl = 0;  /* 0 or 1 - fixed file size flag
+                                * (what is the difference?) */
+       ptr->mode = CODEC_DO_COMPRESSION;
+       ptr->width = 384;
+       ptr->height = 288;
+       ptr->total_code_vol = 16000;    /* CHECKME */
+       ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3;
+       ptr->max_block_vol = 240;       /* CHECKME, was 120 is 240 */
+       ptr->scalefact = 0x100;
+       ptr->dri = 1;           /* CHECKME, was 8 is 1 */
+       zr36060_init(ptr);
+
+       dprintk(1, KERN_INFO "%s: codec attached and running\n",
+               ptr->name);
+
+       return 0;
+}
+
+static const struct videocodec zr36060_codec = {
+       .name = "zr36060",
+       .magic = 0L,            // magic not used
+       .flags =
+           CODEC_FLAG_JPEG | CODEC_FLAG_HARDWARE | CODEC_FLAG_ENCODER |
+           CODEC_FLAG_DECODER | CODEC_FLAG_VFE,
+       .type = CODEC_TYPE_ZR36060,
+       .setup = zr36060_setup, // functionality
+       .unset = zr36060_unset,
+       .set_mode = zr36060_set_mode,
+       .set_video = zr36060_set_video,
+       .control = zr36060_control,
+       // others are not used
+};
+
+/* =========================================================================
+   HOOK IN DRIVER AS KERNEL MODULE
+   ========================================================================= */
+
+static int __init
+zr36060_init_module (void)
+{
+       //dprintk(1, "zr36060 driver %s\n",ZR060_VERSION);
+       zr36060_codecs = 0;
+       return videocodec_register(&zr36060_codec);
+}
+
+static void __exit
+zr36060_cleanup_module (void)
+{
+       if (zr36060_codecs) {
+               dprintk(1,
+                       "zr36060: something's wrong - %d codecs left somehow.\n",
+                       zr36060_codecs);
+       } 
+
+       /* however, we can't just stay alive */
+       videocodec_unregister(&zr36060_codec);
+}
+
+module_init(zr36060_init_module);
+module_exit(zr36060_cleanup_module);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@skynet.be>");
+MODULE_DESCRIPTION("Driver module for ZR36060 jpeg processors "
+                  ZR060_VERSION);
+MODULE_LICENSE("GPL");
index 4938c36dec8700b6b04357994ce8e56b336eb86b..e64540ba20ddb5c358763ab587a434384a3fb68d 100644 (file)
-/* 
-    zr36060.h - zr36060 register offsets
+/*
+ * Zoran ZR36060 basic configuration functions - header file
+ *
+ * Copyright (C) 2002 Laurent Pinchart <laurent.pinchart@skynet.be>
+ *
+ * $Id: zr36060.h,v 1.1.1.1.2.3 2003/01/14 21:18:47 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * ------------------------------------------------------------------------
+ */
 
-    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+#ifndef ZR36060_H
+#define ZR36060_H
 
-    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.
+/* data stored for each zoran jpeg codec chip */
+struct zr36060 {
+       char name[32];
+       int num;
+       /* io datastructure */
+       struct videocodec *codec;
+       // last coder status
+       __u8 status;
+       // actual coder setup
+       int mode;
 
-    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.
+       __u16 width;
+       __u16 height;
 
-    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.
-*/
+       __u16 bitrate_ctrl;
 
-#ifndef _ZR36060_H_
-#define _ZR36060_H_
+       __u32 total_code_vol;
+       __u32 real_code_vol;
+       __u16 max_block_vol;
 
+       __u8 h_samp_ratio[8];
+       __u8 v_samp_ratio[8];
+       __u16 scalefact;
+       __u16 dri;
+};
 
-/* Zoran ZR36060 registers */
+/* ZR36060 register addresses */
+#define ZR060_LOAD                     0x000
+#define ZR060_CFSR                     0x001
+#define ZR060_CIR                      0x002
+#define ZR060_CMR                      0x003
+#define ZR060_MBZ                      0x004
+#define ZR060_MBCVR                    0x005
+#define ZR060_MER                      0x006
+#define ZR060_IMR                      0x007
+#define ZR060_ISR                      0x008
+#define ZR060_TCV_NET_HI               0x009
+#define ZR060_TCV_NET_MH               0x00a
+#define ZR060_TCV_NET_ML               0x00b
+#define ZR060_TCV_NET_LO               0x00c
+#define ZR060_TCV_DATA_HI              0x00d
+#define ZR060_TCV_DATA_MH              0x00e
+#define ZR060_TCV_DATA_ML              0x00f
+#define ZR060_TCV_DATA_LO              0x010
+#define ZR060_SF_HI                    0x011
+#define ZR060_SF_LO                    0x012
+#define ZR060_AF_HI                    0x013
+#define ZR060_AF_M                     0x014
+#define ZR060_AF_LO                    0x015
+#define ZR060_ACV_HI                   0x016
+#define ZR060_ACV_MH                   0x017
+#define ZR060_ACV_ML                   0x018
+#define ZR060_ACV_LO                   0x019
+#define ZR060_ACT_HI                   0x01a
+#define ZR060_ACT_MH                   0x01b
+#define ZR060_ACT_ML                   0x01c
+#define ZR060_ACT_LO                   0x01d
+#define ZR060_ACV_TRUN_HI              0x01e
+#define ZR060_ACV_TRUN_MH              0x01f
+#define ZR060_ACV_TRUN_ML              0x020
+#define ZR060_ACV_TRUN_LO              0x021
+#define ZR060_IDR_DEV                  0x022
+#define ZR060_IDR_REV                  0x023
+#define ZR060_TCR_HI                   0x024
+#define ZR060_TCR_LO                   0x025
+#define ZR060_VCR                      0x030
+#define ZR060_VPR                      0x031
+#define ZR060_SR                       0x032
+#define ZR060_BCR_Y                    0x033
+#define ZR060_BCR_U                    0x034
+#define ZR060_BCR_V                    0x035
+#define ZR060_SGR_VTOTAL_HI            0x036
+#define ZR060_SGR_VTOTAL_LO            0x037
+#define ZR060_SGR_HTOTAL_HI            0x038
+#define ZR060_SGR_HTOTAL_LO            0x039
+#define ZR060_SGR_VSYNC                        0x03a
+#define ZR060_SGR_HSYNC                        0x03b
+#define ZR060_SGR_BVSTART              0x03c
+#define ZR060_SGR_BHSTART              0x03d
+#define ZR060_SGR_BVEND_HI             0x03e
+#define ZR060_SGR_BVEND_LO             0x03f
+#define ZR060_SGR_BHEND_HI             0x040
+#define ZR060_SGR_BHEND_LO             0x041
+#define ZR060_AAR_VSTART_HI            0x042
+#define ZR060_AAR_VSTART_LO            0x043
+#define ZR060_AAR_VEND_HI              0x044
+#define ZR060_AAR_VEND_LO              0x045
+#define ZR060_AAR_HSTART_HI            0x046
+#define ZR060_AAR_HSTART_LO            0x047
+#define ZR060_AAR_HEND_HI              0x048
+#define ZR060_AAR_HEND_LO              0x049
+#define ZR060_SWR_VSTART_HI            0x04a
+#define ZR060_SWR_VSTART_LO            0x04b
+#define ZR060_SWR_VEND_HI              0x04c
+#define ZR060_SWR_VEND_LO              0x04d
+#define ZR060_SWR_HSTART_HI            0x04e
+#define ZR060_SWR_HSTART_LO            0x04f
+#define ZR060_SWR_HEND_HI              0x050
+#define ZR060_SWR_HEND_LO              0x051
 
-#define ZR36060_LoadParameters         0x000
-#define ZR36060_Load                    (1<<7)
-#define ZR36060_SyncRst                 (1<<0)
+#define ZR060_SOF_IDX                  0x060
+#define ZR060_SOS_IDX                  0x07a
+#define ZR060_DRI_IDX                  0x0c0
+#define ZR060_DQT_IDX                  0x0cc
+#define ZR060_DHT_IDX                  0x1d4
+#define ZR060_APP_IDX                  0x380
+#define ZR060_COM_IDX                  0x3c0
 
-#define ZR36060_CodeFifoStatus         0x001
-#define ZR36060_Load                    (1<<7)
-#define ZR36060_SyncRst                 (1<<0)
+/* ZR36060 LOAD register bits */
 
-#endif
+#define ZR060_LOAD_Load                        (1 << 7)
+#define ZR060_LOAD_SyncRst             (1 << 0)
+
+/* ZR36060 Code FIFO Status register bits */
+
+#define ZR060_CFSR_Busy                        (1 << 7)
+#define ZR060_CFSR_CBusy               (1 << 2)
+#define ZR060_CFSR_CFIFO               (3 << 0)
+
+/* ZR36060 Code Interface register */
+
+#define ZR060_CIR_Code16               (1 << 7)
+#define ZR060_CIR_Endian               (1 << 6)
+#define ZR060_CIR_CFIS                 (1 << 2)
+#define ZR060_CIR_CodeMstr             (1 << 0)
+
+/* ZR36060 Codec Mode register */
+
+#define ZR060_CMR_Comp                 (1 << 7)
+#define ZR060_CMR_ATP                  (1 << 6)
+#define ZR060_CMR_Pass2                        (1 << 5)
+#define ZR060_CMR_TLM                  (1 << 4)
+#define ZR060_CMR_BRB                  (1 << 2)
+#define ZR060_CMR_FSF                  (1 << 1)
+
+/* ZR36060 Markers Enable register */
+
+#define ZR060_MER_App                  (1 << 7)
+#define ZR060_MER_Com                  (1 << 6)
+#define ZR060_MER_DRI                  (1 << 5)
+#define ZR060_MER_DQT                  (1 << 4)
+#define ZR060_MER_DHT                  (1 << 3)
+
+/* ZR36060 Interrupt Mask register */
+
+#define ZR060_IMR_EOAV                 (1 << 3)
+#define ZR060_IMR_EOI                  (1 << 2)
+#define ZR060_IMR_End                  (1 << 1)
+#define ZR060_IMR_DataErr              (1 << 0)
+
+/* ZR36060 Interrupt Status register */
+
+#define ZR060_ISR_ProCnt               (3 << 6)
+#define ZR060_ISR_EOAV                 (1 << 3)
+#define ZR060_ISR_EOI                  (1 << 2)
+#define ZR060_ISR_End                  (1 << 1)
+#define ZR060_ISR_DataErr              (1 << 0)
+
+/* ZR36060 Video Control register */
+
+#define ZR060_VCR_Video8               (1 << 7)
+#define ZR060_VCR_Range                        (1 << 6)
+#define ZR060_VCR_FIDet                        (1 << 3)
+#define ZR060_VCR_FIVedge              (1 << 2)
+#define ZR060_VCR_FIExt                        (1 << 1)
+#define ZR060_VCR_SyncMstr             (1 << 0)
+
+/* ZR36060 Video Polarity register */
+
+#define ZR060_VPR_VCLKPol              (1 << 7)
+#define ZR060_VPR_PValPol              (1 << 6)
+#define ZR060_VPR_PoePol               (1 << 5)
+#define ZR060_VPR_SImgPol              (1 << 4)
+#define ZR060_VPR_BLPol                        (1 << 3)
+#define ZR060_VPR_FIPol                        (1 << 2)
+#define ZR060_VPR_HSPol                        (1 << 1)
+#define ZR060_VPR_VSPol                        (1 << 0)
+
+/* ZR36060 Scaling register */
+
+#define ZR060_SR_VScale                        (1 << 2)
+#define ZR060_SR_HScale2               (1 << 0)
+#define ZR060_SR_HScale4               (2 << 0)
+
+#endif                         /*fndef ZR36060_H */
diff --git a/drivers/media/video/zr36067.c b/drivers/media/video/zr36067.c
deleted file mode 100644 (file)
index 775a792..0000000
+++ /dev/null
@@ -1,4905 +0,0 @@
-#define DEBUGLEVEL 0
-#define MAX_KMALLOC_MEM (128*1024)
-
-/*
-   Miro/Pinnacle Systems Inc. DC10/DC10plus and
-   Linux Media Labs LML33 video capture boards driver
-   now with IOMega BUZ support!
-   
-   Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
-
-   Changes for BUZ by Wolfgang Scherr <scherr@net4you.net>
-   
-   Based on
-   
-    Miro DC10 driver
-    Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
-   
-    Iomega Buz driver version 1.0
-    Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
-
-    buz.0.0.3
-    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
-
-    bttv - Bt848 frame grabber driver
-    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                           & Marcus Metzler (mocm@thp.uni-koeln.de)
-
-    
-    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/config.h>
-#include <linux/version.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/signal.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-
-#include <linux/spinlock.h>
-#include <linux/vmalloc.h>
-#include <linux/i2c-old.h>
-#define     ZORAN_HARDWARE  VID_HARDWARE_ZR36067
-
-#include <linux/videodev.h>
-
-#include <asm/uaccess.h>
-#include <linux/proc_fs.h>
-
-#include "zoran.h"
-#include <linux/video_decoder.h>
-#include <linux/video_encoder.h>
-
-// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
-#if !defined(CONFIG_BIGPHYS_AREA)
-//#undef CONFIG_BIGPHYS_AREA
-#define BUZ_USE_HIMEM
-#endif
-
-#if defined(CONFIG_BIGPHYS_AREA)
-#   include <linux/bigphysarea.h>
-#endif
-
-#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | ZR36057_ISR_GIRQ1 | /* ZR36057_ISR_CodRepIRQ | */  ZR36057_ISR_JPEGRepIRQ )     // SW
-//#define GPIO_MASK 0xcd
-//#define GPIO_MASK 0x8d
-
-/*
-DC10:
-GPIO0 = /RESET ZR 36060
-GPIO1 = VIDEO BUS DIRECTION (0: CAPTURE, 1: DISPLAY)
-GPIO2 = VIDEO BUS ENABLE    (0: ON, 1: OFF)
-GPIO3 = /SLEEP ZR 36060
-GPIO4 = ADC7175 (video out) FREQUENCY (0: LCC/SAA7110, 1: 27 MHz (quarz))
-GPIO5 = ZORAN FREQUENCY  (0: LCC and LCC2 from SAA7110,
-                          1: 27 and 13.5 MHz (quarz))
-GPIO6 = /FRAME ZR 36060
-GPIO7 = /RESET ADV7175 (video out)
-(I think they lost the SAA7110 reset.....)
-
-GIRQ0 signals that ZR36060's DATERR# line is asserted.
-GIRQ1 signals a vertical sync of the video signal (VS SAA7110)
-
-  SAA7110A:
-   mode 0 - Composite
-   mode 1 - 
-   mode 2 - 
-   mode 3 - 
-   mode 4 - 
-   mode 5 - internal Composite (from PCTV)
-   mode 6 - 
-   mode 7 - S-Video
-
-BUZ:
-GPIO0 = 1, take board out of reset
-GPIO1 = 1, take JPEG codec out of sleep mode
-GPIO3 = 1, deassert FRAME# to 36060
-
-GIRQ0 signals a vertical sync of the video signal
-GIRQ1 signals that ZR36060's DATERR# line is asserted.
-
-SAA7111A
-
-   In their infinite wisdom, the Iomega engineers decided to
-   use the same input line for composite and S-Video Color,
-   although there are two entries not connected at all!
-   Through this ingenious strike, it is not possible to
-   keep two running video sources connected at the same time
-   to Composite and S-VHS input!
-
-   mode 0 - N/C
-   mode 1 - S-Video Y
-   mode 2 - noise or something I don't know
-   mode 3 - Composite and S-Video C
-   mode 4 - N/C
-   mode 5 - S-Video (gain C independently selectable of gain Y)
-   mode 6 - N/C
-   mode 7 - S-Video (gain C adapted to gain Y)
-*/
-
-#define MAJOR_VERSION 0                /* driver major version */
-#define MINOR_VERSION 7                /* driver minor version */
-
-#define ZORAN_NAME    "zr36067"        /* name of the device */
-
-#define BUZ_ERR       KERN_ERR     ZORAN_NAME
-#define BUZ_DEBUG     KERN_INFO    ZORAN_NAME
-#define BUZ_INFO      KERN_INFO    ZORAN_NAME
-#define BUZ_WARNING   KERN_WARNING ZORAN_NAME
-
-#if(DEBUGLEVEL>0)
-#define DEBUG1(x...)    x
-#else
-#define DEBUG1(x...)
-#endif
-
-#if(DEBUGLEVEL>1)
-#define DEBUG2(x...)    x
-#else
-#define DEBUG2(x...)
-#endif
-
-#if(DEBUGLEVEL>2)
-#define DEBUG3(x...)    x
-#else
-#define DEBUG3(x...)
-#endif
-
-#if(DEBUGLEVEL>3)
-#define DEBUG4(x...)    x
-#else
-#define DEBUG4(x...)
-#endif
-
-/* The parameters for this driver */
-
-/*
-   The video mem address of the video card.
-   The driver has a little database for some videocards
-   to determine it from there. If your video card is not in there
-   you have either to give it to the driver as a parameter
-   or set in in a VIDIOCSFBUF ioctl
- */
-
-static unsigned long vidmem = 0;       /* Video memory base address */
-
-/* Special purposes only: */
-
-static int triton = 0;         /* 0=no, 1=yes */
-static int natoma = 0;         /* 0=no, 1=yes */
-
-/*
-   Number and size of grab buffers for Video 4 Linux
-   The vast majority of applications should not need more than 2,
-   the very popular BTTV driver actually does ONLY have 2.
-   Time sensitive applications might need more, the maximum
-   is VIDEO_MAX_FRAME (defined in <linux/videodev.h>).
-
-   The size is set so that the maximum possible request
-   can be satisfied. Decrease  it, if bigphys_area alloc'd
-   memory is low. If you don't have the bigphys_area patch,
-   set it to 128 KB. Will you allow only to grab small
-   images with V4L, but that's better than nothing.
-
-   v4l_bufsize has to be given in KB !
-
-*/
-
-static int v4l_nbufs = 2;
-static int v4l_bufsize = 128;  /* Everybody should be able to work with this setting */
-
-/*
-   Default input and video norm at startup of the driver.
-*/
-
-static int default_input = 0;  /* 0=Composite, 1=S-VHS */
-static int default_norm = 0;   /* 0=PAL, 1=NTSC 2=SECAM */
-static int lock_norm = 0;      /* 1=Don't change TV standard (norm) */
-
-static int pass_through = 0;   /* 1=Pass through TV signal when device is not used */
-                               /* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */
-
-static int lml33dpath = 0;     /* 1 will use digital path in capture mode instead of analog.
-                                  It can be used for picture adjustments using tool like xawtv
-                                  while watching image on TV monitor connected to the output.
-                                  However, due to absence of 75 Ohm load on Bt819 input, there
-                                  will be some image imperfections */
-static int video_nr = -1;
-
-MODULE_PARM(vidmem, "i");
-MODULE_PARM(triton, "i");
-MODULE_PARM(natoma, "i");
-MODULE_PARM(v4l_nbufs, "i");
-MODULE_PARM(v4l_bufsize, "i");
-MODULE_PARM(default_input, "i");
-MODULE_PARM(default_norm, "i");
-MODULE_PARM(lock_norm, "i");
-MODULE_PARM(pass_through, "i");
-MODULE_PARM(lml33dpath, "i");
-MODULE_PARM(video_nr, "i");
-
-static struct pci_device_id zr36067_pci_tbl[] = {
-       { PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, 
-         PCI_ANY_ID, PCI_ANY_ID,  0, 0, 0 },
-       { 0 }
-};
-MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl);
-
-/* Anybody who uses more than four? */
-#define BUZ_MAX 4
-
-static int zoran_num;          /* number of Buzs in use */
-static struct zoran zoran[BUZ_MAX];
-
-/* forward references */
-
-static void v4l_fbuffer_free(struct zoran *zr);
-static void jpg_fbuffer_free(struct zoran *zr);
-static void zoran_feed_stat_com(struct zoran *zr);
-
-/*
- *   Allocate the V4L grab buffers
- *
- *   These have to be physically contiguous.
- *   If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc
- *   else we try to allocate them with bigphysarea_alloc_pages
- *   if the bigphysarea patch is present in the kernel,
- *   else we try to use high memory (if the user has booted
- *   Linux with the necessary memory left over).
- */
-
-static int v4l_fbuffer_alloc(struct zoran *zr)
-{
-       int i, off;
-       unsigned char *mem;
-
-       for (i = 0; i < v4l_nbufs; i++) {
-               if (zr->v4l_gbuf[i].fbuffer)
-                       printk(KERN_WARNING
-                              "%s: v4l_fbuffer_alloc: buffer %d already allocated ???\n",
-                              zr->name, i);
-
-               //udelay(20);
-               if (v4l_bufsize <= MAX_KMALLOC_MEM) {
-                       /* Use kmalloc */
-
-                       mem =
-                           (unsigned char *) kmalloc(v4l_bufsize,
-                                                     GFP_KERNEL);
-                       if (mem == 0) {
-                               printk(KERN_ERR
-                                      "%s: kmalloc for V4L bufs failed\n",
-                                      zr->name);
-                               v4l_fbuffer_free(zr);
-                               return -ENOBUFS;
-                       }
-                       zr->v4l_gbuf[i].fbuffer = mem;
-                       zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem);
-                       zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem);
-                       for (off = 0; off < v4l_bufsize; off += PAGE_SIZE)
-                               SetPageReserved(virt_to_page(mem + off));
-                       DEBUG1(printk
-                              (KERN_INFO
-                               "%s: V4L frame %d mem 0x%lx (bus: 0x%lx)\n",
-                               zr->name, i, (unsigned long) mem,
-                               virt_to_bus(mem)));
-               } else {
-#if defined(CONFIG_BIGPHYS_AREA)
-                       /* Use bigphysarea_alloc_pages */
-
-                       int n = (v4l_bufsize + PAGE_SIZE - 1) / PAGE_SIZE;
-                       mem =
-                           (unsigned char *) bigphysarea_alloc_pages(n, 0,
-                                                                     GFP_KERNEL);
-                       if (mem == 0) {
-                               printk(KERN_ERR
-                                      "%s: bigphysarea_alloc_pages for V4L bufs failed\n",
-                                      zr->name);
-                               v4l_fbuffer_free(zr);
-                               return -ENOBUFS;
-                       }
-                       zr->v4l_gbuf[i].fbuffer = mem;
-                       zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem);
-                       zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem);
-                       DEBUG1(printk
-                              (KERN_INFO
-                               "%s: Bigphysarea frame %d mem 0x%x (bus: 0x%x)\n",
-                               zr->name, i, (unsigned) mem,
-                               (unsigned) virt_to_bus(mem)));
-
-                       /* Zero out the allocated memory */
-                       memset(zr->v4l_gbuf[i].fbuffer, 0, v4l_bufsize);
-#else
-                       /* No bigphysarea present, usage of high memory disabled,
-                          but user wants buffers of more than MAX_KMALLOC_MEM */
-                       printk(KERN_ERR
-                              "%s: No bigphysarea_patch present, usage of high memory disabled,\n",
-                              zr->name);
-                       printk(KERN_ERR
-                              "%s: sorry, could not allocate V4L buffers of size %d KB.\n",
-                              zr->name, v4l_bufsize >> 10);
-                       return -ENOBUFS;
-#endif
-               }
-       }
-
-       return 0;
-}
-
-/* free the V4L grab buffers */
-
-static void v4l_fbuffer_free(struct zoran *zr)
-{
-       int i, off;
-       unsigned char *mem;
-
-       for (i = 0; i < v4l_nbufs; i++) {
-               if (!zr->v4l_gbuf[i].fbuffer)
-                       continue;
-
-               if (v4l_bufsize <= MAX_KMALLOC_MEM) {
-                       mem = zr->v4l_gbuf[i].fbuffer;
-                       for (off = 0; off < v4l_bufsize; off += PAGE_SIZE)
-                               ClearPageReserved(virt_to_page(mem + off));
-                       kfree((void *) zr->v4l_gbuf[i].fbuffer);
-               }
-#if defined(CONFIG_BIGPHYS_AREA)
-               else
-                       bigphysarea_free_pages((void *) zr->v4l_gbuf[i].
-                                              fbuffer);
-#endif
-               zr->v4l_gbuf[i].fbuffer = NULL;
-       }
-}
-
-/*
- *   Allocate the MJPEG grab buffers.
- *
- *   If the requested buffer size is smaller than MAX_KMALLOC_MEM,
- *   kmalloc is used to request a physically contiguous area,
- *   else we allocate the memory in framgents with get_zeroed_page.
- *
- *   If a Natoma chipset is present and this is a revision 1 zr36057,
- *   each MJPEG buffer needs to be physically contiguous.
- *   (RJ: This statement is from Dave Perks' original driver,
- *   I could never check it because I have a zr36067)
- *   The driver cares about this because it reduces the buffer
- *   size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation).
- *
- *   RJ: The contents grab buffers needs never be accessed in the driver.
- *       Therefore there is no need to allocate them with vmalloc in order
- *       to get a contiguous virtual memory space.
- *       I don't understand why many other drivers first allocate them with
- *       vmalloc (which uses internally also get_zeroed_page, but delivers you
- *       virtual addresses) and then again have to make a lot of efforts
- *       to get the physical address.
- *
- */
-
-static int jpg_fbuffer_alloc(struct zoran *zr)
-{
-       int i, j, off;          //alloc_contig;
-       unsigned long mem;
-
-       /* Decide if we should alloc contiguous or fragmented memory */
-       /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */
-
-       //alloc_contig = (zr->jpg_bufsize <= MAX_KMALLOC_MEM);
-
-       for (i = 0; i < zr->jpg_nbufs; i++) {
-               if (zr->jpg_gbuf[i].frag_tab)
-                       printk(KERN_WARNING
-                              "%s: jpg_fbuffer_alloc: buffer %d already allocated ???\n",
-                              zr->name, i);
-
-               /* Allocate fragment table for this buffer */
-
-               mem = get_zeroed_page(GFP_KERNEL);
-               if (mem == 0) {
-                       printk(KERN_ERR
-                              "%s: jpg_fbuffer_alloc: get_zeroed_page (frag_tab) failed for buffer %d\n",
-                              zr->name, i);
-                       jpg_fbuffer_free(zr);
-                       return -ENOBUFS;
-               }
-               memset((void *) mem, 0, PAGE_SIZE);
-               zr->jpg_gbuf[i].frag_tab = (u32 *) mem;
-               zr->jpg_gbuf[i].frag_tab_bus = virt_to_bus((void *) mem);
-
-               //if (alloc_contig) {
-               if (zr->need_contiguous) {
-                       mem = (unsigned long) kmalloc(zr->jpg_bufsize, GFP_KERNEL);
-                       if (mem == 0) {
-                               printk(KERN_ERR "%s: jpg_fbuffer_alloc: kmalloc failed for buffer %d\n",
-                                      zr->name, i);
-                               jpg_fbuffer_free(zr);
-                               return -ENOBUFS;
-                       }
-                       zr->jpg_gbuf[i].frag_tab[0] = virt_to_bus((void *) mem);
-                       zr->jpg_gbuf[i].frag_tab[1] =
-                           ((zr->jpg_bufsize / 4) << 1) | 1;
-                       for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE)
-                               SetPageReserved(virt_to_page(mem + off));
-               } else {
-                       /* jpg_bufsize is already page aligned */
-                       for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) 
-                       {
-                               mem = get_zeroed_page(GFP_KERNEL);
-                               if (mem == 0) {
-                                       printk(KERN_ERR
-                                              "%s: jpg_fbuffer_alloc: get_zeroed_page failed for buffer %d\n",
-                                              zr->name, i);
-                                       jpg_fbuffer_free(zr);
-                                       return -ENOBUFS;
-                               }
-
-                               zr->jpg_gbuf[i].frag_tab[2 * j] =
-                                   virt_to_bus((void *) mem);
-                               zr->jpg_gbuf[i].frag_tab[2 * j + 1] =
-                                   (PAGE_SIZE / 4) << 1;
-                               SetPageReserved(virt_to_page(mem));
-                       }
-
-                       zr->jpg_gbuf[i].frag_tab[2 * j - 1] |= 1;
-               }
-       }
-
-       DEBUG1(printk
-              ("%s: jpg_fbuffer_alloc: %ld KB allocated\n", zr->name,
-               (zr->jpg_nbufs * zr->jpg_bufsize) >> 10));
-       zr->jpg_buffers_allocated = 1;
-       return 0;
-}
-
-/* free the MJPEG grab buffers */
-static void jpg_fbuffer_free(struct zoran *zr)
-{
-       int i, j, off;          // alloc_contig;
-       unsigned char *mem;
-
-       /* Decide if we should alloc contiguous or fragmented memory */
-       /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */
-
-       //alloc_contig = (zr->jpg_bufsize <= MAX_KMALLOC_MEM);
-
-       for (i = 0; i < zr->jpg_nbufs; i++) {
-               if (!zr->jpg_gbuf[i].frag_tab)
-                       continue;
-
-               //if (alloc_contig) {
-               if (zr->need_contiguous) {
-                       if (zr->jpg_gbuf[i].frag_tab[0]) {
-                               mem =
-                                   (unsigned char *) bus_to_virt(zr->
-                                                                 jpg_gbuf
-                                                                 [i].
-                                                                 frag_tab
-                                                                 [0]);
-                               for (off = 0; off < zr->jpg_bufsize;
-                                    off += PAGE_SIZE)
-                                       ClearPageReserved(virt_to_page
-                                                         (mem + off));
-                               kfree((void *) mem);
-                               zr->jpg_gbuf[i].frag_tab[0] = 0;
-                               zr->jpg_gbuf[i].frag_tab[1] = 0;
-                       }
-               } else {
-                       for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) {
-                               if (!zr->jpg_gbuf[i].frag_tab[2 * j])
-                                       break;
-                               ClearPageReserved(virt_to_page
-                                                 (bus_to_virt
-                                                  (zr->jpg_gbuf[i].
-                                                   frag_tab[2 * j])));
-                               free_page((unsigned long)
-                                         bus_to_virt(zr->jpg_gbuf[i].
-                                                     frag_tab[2 * j]));
-                               zr->jpg_gbuf[i].frag_tab[2 * j] = 0;
-                               zr->jpg_gbuf[i].frag_tab[2 * j + 1] = 0;
-                       }
-               }
-
-               free_page((unsigned long) zr->jpg_gbuf[i].frag_tab);
-               zr->jpg_gbuf[i].frag_tab = NULL;
-       }
-       zr->jpg_buffers_allocated = 0;
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-/* I2C functions                                                           */
-
-#define I2C_DELAY   10
-
-
-/* software I2C functions */
-
-static void i2c_setlines(struct i2c_bus *bus, int ctrl, int data)
-{
-       struct zoran *zr = (struct zoran *) bus->data;
-       btwrite((data << 1) | ctrl, ZR36057_I2CBR);
-       udelay(I2C_DELAY);
-}
-
-static int i2c_getdataline(struct i2c_bus *bus)
-{
-       struct zoran *zr = (struct zoran *) bus->data;
-       return (btread(ZR36057_I2CBR) >> 1) & 1;
-}
-
-static void attach_inform(struct i2c_bus *bus, int id)
-{
-       int i;
-       struct zoran *zr = (struct zoran *) bus->data;
-
-       DEBUG1(printk(KERN_DEBUG "%s: i2c attach %02x\n", zr->name, id));
-       for (i = 0; i < bus->devcount; i++) {
-               if (strcmp(bus->devices[i]->name, "saa7110") == 0) {
-                       if (zr->revision < 2) {
-                               zr->card = DC10;
-                               sprintf(zr->name, "DC10[%u]", zr->id);
-                       } else {
-                               zr->card = DC10plus;
-                               sprintf(zr->name, "DC10plus[%u]", zr->id);
-                       }
-                       break;
-               }
-               if (strcmp(bus->devices[i]->name, "bt819") == 0) {
-                       zr->card = LML33;
-                       sprintf(zr->name, "LML33[%u]", zr->id);
-                       break;
-               }
-               if (strcmp(bus->devices[i]->name, "saa7111") == 0) {
-                       zr->card = BUZ;
-                       sprintf(zr->name, "Buz[%u]", zr->id);
-                       break;
-               }
-       }
-}
-
-static void detach_inform(struct i2c_bus *bus, int id)
-{
-       DEBUG1(struct zoran *zr = (struct zoran *) bus->data);
-       DEBUG1(printk(KERN_DEBUG "%s: i2c detach %02x\n", zr->name, id));
-}
-
-static struct i2c_bus zoran_i2c_bus_template = {
-       "zr36057",
-       I2C_BUSID_BT848,
-       NULL,
-
-       SPIN_LOCK_UNLOCKED,
-
-       attach_inform,
-       detach_inform,
-
-       i2c_setlines,
-       i2c_getdataline,
-       NULL,
-       NULL,
-};
-
-/*
- *   Set the registers for the size we have specified. Don't bother
- *   trying to understand this without the ZR36057 manual in front of
- *   you [AC].
- *
- *   PS: The manual is free for download in .pdf format from
- *   www.zoran.com - nicely done those folks.
- */
-
-static struct tvnorm f50sqpixel = { 944, 768, 83, 880, 625, 576, 16 };
-static struct tvnorm f60sqpixel = { 780, 640, 51, 716, 525, 480, 12 };
-
-static struct tvnorm f50ccir601 = { 864, 720, 75, 804, 625, 576, 18 };
-static struct tvnorm f60ccir601 = { 858, 720, 57, 788, 525, 480, 16 };
-
-static struct tvnorm *dc10norms[] = {
-       &f50sqpixel,            /* PAL-BDGHI */
-       &f60sqpixel,            /* NTSC */
-       &f50sqpixel,            /* SECAM */
-};
-
-static struct tvnorm *lml33norms[] = {
-       &f50ccir601,            /* PAL-BDGHI */
-       &f60ccir601,            /* NTSC      */
-       NULL,                   /* SECAM (not supported in LML33) */
-};
-
-static struct tvnorm *buznorms[] = {
-       &f50ccir601,            /* PAL-BDGHI */
-       &f60ccir601,            /* NTSC      */
-       NULL,                   /* SECAM     */
-};
-
-static struct tvnorm *unsupported[] = {
-       NULL,                   /* PAL-BDGHI */
-       NULL,                   /* NTSC      */
-       NULL,                   /* SECAM     */
-};
-
-static struct tvnorm **cardnorms[] = {
-       unsupported,            /* UNKNOWN  */
-       dc10norms,              /* DC10     */
-       dc10norms,              /* DC10plus */
-       lml33norms,             /* LML33    */
-       buznorms,               /* Buz      */
-};
-
-static u32 cardvsync[] = {
-       0,                      /* UNKNOWN  */
-       ZR36057_ISR_GIRQ1,      /* DC10     */
-       ZR36057_ISR_GIRQ1,      /* DC10plus */
-       ZR36057_ISR_GIRQ0,      /* LML33    */
-       ZR36057_ISR_GIRQ0,      /* Buz      */
-};
-
-static u32 cardjpegint[] = {
-       0,                      /* UNKNOWN  */
-       ZR36057_ISR_GIRQ0,      /* DC10     */
-       ZR36057_ISR_GIRQ0,      /* DC10plus */
-       ZR36057_ISR_GIRQ1,      /* LML33    */
-       ZR36057_ISR_GIRQ1,      /* Buz      */
-};
-
-static int format2bpp(int format)
-{
-       int bpp;
-
-       /* Determine the number of bytes per pixel for the video format requested */
-
-       switch (format) {
-
-       case VIDEO_PALETTE_YUV422:
-               bpp = 2;
-               break;
-
-       case VIDEO_PALETTE_RGB555:
-               bpp = 2;
-               break;
-
-       case VIDEO_PALETTE_RGB565:
-               bpp = 2;
-               break;
-
-       case VIDEO_PALETTE_RGB24:
-               bpp = 3;
-               break;
-
-       case VIDEO_PALETTE_RGB32:
-               bpp = 4;
-               break;
-
-       default:
-               bpp = 0;
-       }
-
-       return bpp;
-}
-
-static void zr36057_adjust_vfe(struct zoran *zr,
-                              enum zoran_codec_mode mode)
-{
-       u32 reg;
-       switch (mode) {
-       case BUZ_MODE_MOTION_DECOMPRESS:
-               btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
-               reg = btread(ZR36057_VFEHCR);
-               if (reg & (1 << 10)) {
-                       reg += ((1 << 10) | 1);
-               }
-               btwrite(reg, ZR36057_VFEHCR);
-               break;
-       case BUZ_MODE_MOTION_COMPRESS:
-       case BUZ_MODE_IDLE:
-       default:
-               if (zr->params.norm == VIDEO_MODE_NTSC)
-                       btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
-               else
-                       btor(ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
-               reg = btread(ZR36057_VFEHCR);
-               if (!(reg & (1 << 10))) {
-                       reg -= ((1 << 10) | 1);
-               }
-               btwrite(reg, ZR36057_VFEHCR);
-               break;
-       }
-}
-
-/*
- * set geometry
- */
-static void zr36057_set_vfe(struct zoran *zr, int video_width,
-                           int video_height, unsigned int video_format)
-{
-       struct tvnorm *tvn;
-       unsigned HStart, HEnd, VStart, VEnd;
-       unsigned DispMode;
-       unsigned VidWinWid, VidWinHt;
-       unsigned hcrop1, hcrop2, vcrop1, vcrop2;
-       unsigned Wa, We, Ha, He;
-       unsigned X, Y, HorDcm, VerDcm;
-       u32 reg;
-       unsigned mask_line_size;
-
-       tvn = zr->timing;
-
-       Wa = tvn->Wa;
-       Ha = tvn->Ha;
-
-       DEBUG1(printk (BUZ_INFO ": width = %d, height = %d\n", video_width, video_height));
-
-       if (zr->params.norm != VIDEO_MODE_PAL
-           && zr->params.norm != VIDEO_MODE_NTSC
-           && zr->params.norm != VIDEO_MODE_SECAM) {
-               printk(KERN_ERR "%s: set_vfe: video_norm = %d not valid\n",
-                      zr->name, zr->params.norm);
-               return;
-       }
-       if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT
-           || video_width > Wa || video_height > Ha) {
-               printk(KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n",
-                      zr->name, video_width, video_height);
-               return;
-       }
-
-       /* if window has more than half of active height,
-          switch on interlacing - we want the full information */
-
-       zr->video_interlace = (video_height > Ha / 2);
-
-       /**** zr36057 ****/
-
-       /* horizontal */
-       VidWinWid = video_width;
-       X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa;
-       We = (VidWinWid * 64) / X;
-       HorDcm = 64 - X;
-       hcrop1 = 2 * ((tvn->Wa - We) / 4);
-       hcrop2 = tvn->Wa - We - hcrop1;
-       HStart = tvn->HStart | 1;
-       if (zr->card == LML33)
-               HStart += 62;
-       if (zr->card == BUZ) {  //HStart += 67;
-               HStart += 44;
-       }
-       HEnd = HStart + tvn->Wa - 1;
-       HStart += hcrop1;
-       HEnd -= hcrop2;
-       reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart)
-           | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd);
-       if (zr->card != BUZ)
-               reg |= ZR36057_VFEHCR_HSPol;
-       btwrite(reg, ZR36057_VFEHCR);
-
-       /* Vertical */
-       DispMode = !zr->video_interlace;
-       VidWinHt = DispMode ? video_height : video_height / 2;
-       Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha;
-       He = (VidWinHt * 64) / Y;
-       VerDcm = 64 - Y;
-       vcrop1 = (tvn->Ha / 2 - He) / 2;
-       vcrop2 = tvn->Ha / 2 - He - vcrop1;
-       VStart = tvn->VStart;
-       VEnd = VStart + tvn->Ha / 2 - 1;
-       VStart += vcrop1;
-       VEnd -= vcrop2;
-       reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart)
-           | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd);
-       reg |= ZR36057_VFEVCR_VSPol;
-       btwrite(reg, ZR36057_VFEVCR);
-
-       /* scaler and pixel format */
-       reg = 0;
-       reg |= (HorDcm << ZR36057_VFESPFR_HorDcm);
-       reg |= (VerDcm << ZR36057_VFESPFR_VerDcm);
-       reg |= (DispMode << ZR36057_VFESPFR_DispMode);
-       reg |= ZR36057_VFESPFR_LittleEndian;
-       /* RJ: I don't know, why the following has to be the opposite
-          of the corresponding ZR36060 setting, but only this way
-          we get the correct colors when uncompressing to the screen  */
-       //reg |= ZR36057_VFESPFR_VCLKPol; /**/
-       /* RJ: Don't know if that is needed for NTSC also */
-       if (zr->params.norm != VIDEO_MODE_NTSC)
-               reg |= ZR36057_VFESPFR_ExtFl;   // NEEDED!!!!!!! Wolfgang
-       reg |= ZR36057_VFESPFR_TopField;
-       switch (video_format) {
-
-       case VIDEO_PALETTE_YUV422:
-               reg |= ZR36057_VFESPFR_YUV422;
-               break;
-
-       case VIDEO_PALETTE_RGB555:
-               reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif;
-               break;
-
-       case VIDEO_PALETTE_RGB565:
-               reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif;
-               break;
-
-       case VIDEO_PALETTE_RGB24:
-               reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24;
-               break;
-
-       case VIDEO_PALETTE_RGB32:
-               reg |= ZR36057_VFESPFR_RGB888;
-               break;
-
-       default:
-               printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name,
-                      video_format);
-               return;
-
-       }
-       if (HorDcm >= 48) {
-               reg |= 3 << ZR36057_VFESPFR_HFilter;    /* 5 tap filter */
-       } else if (HorDcm >= 32) {
-               reg |= 2 << ZR36057_VFESPFR_HFilter;    /* 4 tap filter */
-       } else if (HorDcm >= 16) {
-               reg |= 1 << ZR36057_VFESPFR_HFilter;    /* 3 tap filter */
-       }
-       btwrite(reg, ZR36057_VFESPFR);
-
-       /* display configuration */
-
-       reg = (16 << ZR36057_VDCR_MinPix)
-           | (VidWinHt << ZR36057_VDCR_VidWinHt)
-           | (VidWinWid << ZR36057_VDCR_VidWinWid);
-       if (triton || zr->revision <= 1)
-               reg &= ~ZR36057_VDCR_Triton;
-       else
-               reg |= ZR36057_VDCR_Triton;
-       btwrite(reg, ZR36057_VDCR);
-
-       /* Write overlay clipping mask data, but don't enable overlay clipping */
-       /* RJ: since this makes only sense on the screen, we use 
-          zr->window.width instead of video_width */
-
-       mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
-       reg = virt_to_bus(zr->overlay_mask);
-       btwrite(reg, ZR36057_MMTR);
-       reg = virt_to_bus(zr->overlay_mask + mask_line_size);
-       btwrite(reg, ZR36057_MMBR);
-       reg = mask_line_size - (zr->window.width + 31) / 32;
-       if (DispMode == 0)
-               reg += mask_line_size;
-       reg <<= ZR36057_OCR_MaskStride;
-       btwrite(reg, ZR36057_OCR);
-
-       zr36057_adjust_vfe(zr, zr->codec_mode);
-
-}
-
-/*
- * Switch overlay on or off
- */
-
-static void zr36057_overlay(struct zoran *zr, int on)
-{
-       int fmt, bpp;
-       u32 reg;
-
-       if (on) {
-               /* do the necessary settings ... */
-
-               btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);       /* switch it off first */
-
-               switch (zr->buffer.depth) {
-               case 15:
-                       fmt = VIDEO_PALETTE_RGB555;
-                       bpp = 2;
-                       break;
-               case 16:
-                       fmt = VIDEO_PALETTE_RGB565;
-                       bpp = 2;
-                       break;
-               case 24:
-                       fmt = VIDEO_PALETTE_RGB24;
-                       bpp = 3;
-                       break;
-               case 32:
-                       fmt = VIDEO_PALETTE_RGB32;
-                       bpp = 4;
-                       break;
-               default:
-                       fmt = 0;
-                       bpp = 0;
-               }
-
-               zr36057_set_vfe(zr, zr->window.width, zr->window.height,
-                               fmt);
-
-               /* Start and length of each line MUST be 4-byte aligned.
-                  This should be already checked before the call to this routine.
-                  All error messages are internal driver checking only! */
-
-               /* video display top and bottom registers */
-
-               reg =
-                   (u32) zr->buffer.base + zr->window.x * bpp +
-                   zr->window.y * zr->buffer.bytesperline;
-               btwrite(reg, ZR36057_VDTR);
-               if (reg & 3)
-                       printk(KERN_ERR
-                              "%s: zr36057_overlay: video_address not aligned\n",
-                              zr->name);
-               if (zr->video_interlace)
-                       reg += zr->buffer.bytesperline;
-               btwrite(reg, ZR36057_VDBR);
-
-               /* video stride, status, and frame grab register */
-
-               reg = zr->buffer.bytesperline - zr->window.width * bpp;
-               if (zr->video_interlace)
-                       reg += zr->buffer.bytesperline;
-               if (reg & 3)
-                       printk(KERN_ERR
-                              "%s: zr36057_overlay: video_stride not aligned\n",
-                              zr->name);
-               reg = (reg << ZR36057_VSSFGR_DispStride);
-               reg |= ZR36057_VSSFGR_VidOvf;   /* clear overflow status */
-               btwrite(reg, ZR36057_VSSFGR);
-
-               /* Set overlay clipping */
-
-               if (zr->window.clipcount)
-                       btor(ZR36057_OCR_OvlEnable, ZR36057_OCR);
-
-               /* ... and switch it on */
-
-               btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);
-       } else {
-               /* Switch it off */
-
-               btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
-       }
-}
-
-/*
- * The overlay mask has one bit for each pixel on a scan line,
- *  and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels.
- */
-static void write_overlay_mask(struct zoran *zr, struct video_clip *vp,
-                              int count)
-{
-       unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
-       u32 *mask;
-       int x, y, width, height;
-       unsigned i, j, k;
-       u32 reg;
-
-       /* fill mask with one bits */
-       memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT);
-       reg = 0;
-
-       for (i = 0; i < count; ++i) {
-               /* pick up local copy of clip */
-               x = vp[i].x;
-               y = vp[i].y;
-               width = vp[i].width;
-               height = vp[i].height;
-
-               /* trim clips that extend beyond the window */
-               if (x < 0) {
-                       width += x;
-                       x = 0;
-               }
-               if (y < 0) {
-                       height += y;
-                       y = 0;
-               }
-               if (x + width > zr->window.width) {
-                       width = zr->window.width - x;
-               }
-               if (y + height > zr->window.height) {
-                       height = zr->window.height - y;
-               }
-
-               /* ignore degenerate clips */
-               if (height <= 0) {
-                       continue;
-               }
-               if (width <= 0) {
-                       continue;
-               }
-
-               /* apply clip for each scan line */
-               for (j = 0; j < height; ++j) {
-                       /* reset bit for each pixel */
-                       /* this can be optimized later if need be */
-                       mask = zr->overlay_mask + (y + j) * mask_line_size;
-                       for (k = 0; k < width; ++k) {
-                               mask[(x + k) / 32] &=
-                                   ~((u32) 1 << (x + k) % 32);
-                       }
-               }
-       }
-}
-
-/* Enable/Disable uncompressed memory grabbing of the 36057 */
-
-static void zr36057_set_memgrab(struct zoran *zr, int mode)
-{
-       if (mode) {
-               if (btread(ZR36057_VSSFGR) &
-                   (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab))
-                       printk(KERN_WARNING
-                              "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n",
-                              zr->name);
-
-               /* switch on VSync interrupts */
-
-               btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts
-               btor(cardvsync[zr->card], ZR36057_ICR); // SW
-
-               /* enable SnapShot */
-
-               btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
-
-               /* Set zr36057 video front end  and enable video */
-
-               zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat);
-
-               zr->v4l_memgrab_active = 1;
-       } else {
-               zr->v4l_memgrab_active = 0;
-
-               /* switch off VSync interrupts */
-
-               //btand(~ZR36057_ICR_GIRQ1, ZR36057_ICR); // SW
-
-               /* reenable grabbing to screen if it was running */
-
-               if (zr->v4l_overlay_active) {
-                       zr36057_overlay(zr, 1);
-               } else {
-                       btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
-                       btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
-               }
-       }
-}
-
-static int wait_grab_pending(struct zoran *zr)
-{
-       unsigned long flags;
-
-       /* wait until all pending grabs are finished */
-
-       if (!zr->v4l_memgrab_active)
-               return 0;
-
-       while (zr->v4l_pend_tail != zr->v4l_pend_head) {
-               interruptible_sleep_on(&zr->v4l_capq);
-               if (signal_pending(current))
-                       return -ERESTARTSYS;
-       }
-
-       spin_lock_irqsave(&zr->lock, flags);
-       zr36057_set_memgrab(zr, 0);
-       spin_unlock_irqrestore(&zr->lock, flags);
-
-       return 0;
-}
-
-/*
- *   V4L Buffer grabbing
- */
-
-static int v4l_grab(struct zoran *zr, struct video_mmap *mp)
-{
-       unsigned long flags;
-       int res, bpp;
-
-       /*
-        * There is a long list of limitations to what is allowed to be grabbed
-        * We don't output error messages here, since some programs (e.g. xawtv)
-        * just try several settings to find out what is valid or not.
-        */
-
-       /* No grabbing outside the buffer range! */
-
-       if (mp->frame >= v4l_nbufs || mp->frame < 0) {
-               DEBUG2(printk
-                      (KERN_ERR "%s: Can not grab frame %d\n", zr->name,
-                       mp->frame));
-               return -EINVAL;
-       }
-
-       /* Check size and format of the grab wanted */
-
-       if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH
-           || mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH) {
-               DEBUG2(printk
-                      (KERN_ERR "%s: Wrong frame size.\n", zr->name));
-               return -EINVAL;
-       }
-
-       bpp = format2bpp(mp->format);
-       if (bpp == 0) {
-               DEBUG2(printk
-                      (KERN_ERR "%s: Wrong bytes-per-pixel format\n",
-                       zr->name));
-               return -EINVAL;
-       }
-
-       /* Check against available buffer size */
-
-       if (mp->height * mp->width * bpp > v4l_bufsize) {
-               DEBUG2(printk
-                      (KERN_ERR "%s: Video buffer size is too small\n",
-                       zr->name));
-               return -EINVAL;
-       }
-
-       /* The video front end needs 4-byte alinged line sizes */
-
-       if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3))) {
-               DEBUG2(printk
-                      (KERN_ERR "%s: Wrong frame alingment\n", zr->name));
-               return -EINVAL;
-       }
-
-       /*
-        * To minimize the time spent in the IRQ routine, we avoid setting up
-        * the video front end there.
-        * If this grab has different parameters from a running streaming capture
-        * we stop the streaming capture and start it over again.
-        */
-
-       if (zr->v4l_memgrab_active
-           && (zr->gwidth != mp->width || zr->gheight != mp->height
-               || zr->gformat != mp->format)) {
-               res = wait_grab_pending(zr);
-               if (res)
-                       return res;
-       }
-       zr->gwidth = mp->width;
-       zr->gheight = mp->height;
-       zr->gformat = mp->format;
-       zr->gbpl = bpp * zr->gwidth;
-
-
-       spin_lock_irqsave(&zr->lock, flags);
-
-       /* make sure a grab isn't going on currently with this buffer */
-
-       switch (zr->v4l_gbuf[mp->frame].state) {
-
-       default:
-       case BUZ_STATE_PEND:
-               res = -EBUSY;   /* what are you doing? */
-               break;
-
-       case BUZ_STATE_USER:
-       case BUZ_STATE_DONE:
-               /* since there is at least one unused buffer there's room for at least one more pend[] entry */
-               zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] =
-                   mp->frame;
-               zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND;
-               res = 0;
-               break;
-
-       }
-
-       /* put the 36057 into frame grabbing mode */
-
-       if (!res && !zr->v4l_memgrab_active)
-               zr36057_set_memgrab(zr, 1);
-
-       spin_unlock_irqrestore(&zr->lock, flags);
-       //DEBUG2(printk(KERN_INFO "%s: Frame grab 3...\n", zr->name));
-
-       return res;
-}
-
-/*
- * Sync on a V4L buffer
- */
-
-static int v4l_sync(struct zoran *zr, int frame)
-{
-       unsigned long flags;
-
-       /* check passed-in frame number */
-
-       if (frame >= v4l_nbufs || frame < 0) {
-               DEBUG1(printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n",
-                      zr->name, frame));
-               return -EINVAL;
-       }
-
-       /* Check if is buffer was queued at all */
-
-       if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) {
-               DEBUG1(printk(KERN_ERR
-                      "%s: v4l_sync: Attempt to sync on a buffer which was not queued?\n",
-                      zr->name));
-               return -EPROTO;
-       }
-
-       /* wait on this buffer to get ready */
-
-       while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) {
-               interruptible_sleep_on(&zr->v4l_capq);
-               if (signal_pending(current))
-                       return -ERESTARTSYS;
-       }
-
-       /* buffer should now be in BUZ_STATE_DONE */
-
-       if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE)
-               printk(KERN_ERR "%s: v4l_sync - internal error\n",
-                      zr->name);
-
-       /* Check if streaming capture has finished */
-
-       spin_lock_irqsave(&zr->lock, flags);
-
-       if (zr->v4l_pend_tail == zr->v4l_pend_head)
-               zr36057_set_memgrab(zr, 0);
-
-       spin_unlock_irqrestore(&zr->lock, flags);
-
-       return 0;
-}
-
-/*****************************************************************************
- *                                                                           *
- *  Set up the Buz-specific MJPEG part                                       *
- *                                                                           *
- *****************************************************************************/
-
-/*
-Wait til post office is no longer busy */
-static int post_office_wait(struct zoran *zr)
-{
-       u32 por;
-
-//      while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) {
-       while ((por = btread(ZR36057_POR)) & ZR36057_POR_POPen) {
-               /* wait for something to happen */
-       }
-       if ((por & ZR36057_POR_POTime) && zr->card != LML33
-           && zr->card != BUZ) {
-               /* In LML33/BUZ \GWS line is not connected, so it has always timeout set */
-               printk(KERN_WARNING "%s: pop timeout %08x\n", zr->name, por);
-               return -1;
-       }
-       return 0;
-}
-
-static int post_office_write(struct zoran *zr, unsigned guest,
-                            unsigned reg, unsigned value)
-{
-       u32 por;
-
-       por =
-           ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) |
-           ((reg & 7) << 16) | (value & 0xFF);
-       btwrite(por, ZR36057_POR);
-       return post_office_wait(zr);
-}
-
-static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg)
-{
-       u32 por;
-
-       por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16);
-       btwrite(por, ZR36057_POR);
-       if (post_office_wait(zr) < 0) {
-               return -1;
-       }
-       return btread(ZR36057_POR) & 0xFF;
-}
-
-static int zr36060_write_8(struct zoran *zr, unsigned reg, unsigned val)
-{
-       if (post_office_wait(zr)
-           || post_office_write(zr, 0, 1, reg >> 8)
-           || post_office_write(zr, 0, 2, reg)) {
-               return -1;
-       }
-       return post_office_write(zr, 0, 3, val);
-}
-
-static int zr36060_write_16(struct zoran *zr, unsigned reg, unsigned val)
-{
-       if (zr36060_write_8(zr, reg + 0, val >> 8)) {
-               return -1;
-       }
-       return zr36060_write_8(zr, reg + 1, val >> 0);
-}
-
-static int zr36060_write_24(struct zoran *zr, unsigned reg, unsigned val)
-{
-       if (zr36060_write_8(zr, reg + 0, val >> 16)) {
-               return -1;
-       }
-       return zr36060_write_16(zr, reg + 1, val >> 0);
-}
-
-static int zr36060_write_32(struct zoran *zr, unsigned reg, unsigned val)
-{
-       if (zr36060_write_16(zr, reg + 0, val >> 16)) {
-               return -1;
-       }
-       return zr36060_write_16(zr, reg + 2, val >> 0);
-}
-
-static u32 zr36060_read_8(struct zoran *zr, unsigned reg)
-{
-       if (post_office_wait(zr)
-           || post_office_write(zr, 0, 1, reg >> 8)
-           || post_office_write(zr, 0, 2, reg)) {
-               return -1;
-       }
-       return post_office_read(zr, 0, 3) & 0xFF;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void GPIO(struct zoran *zr, unsigned bit, unsigned value)
-{
-       u32 reg;
-       u32 mask;
-
-       mask = 1 << (24 + bit);
-       reg = btread(ZR36057_GPPGCR1) & ~mask;
-       if (value) {
-               reg |= mask;
-       }
-       btwrite(reg, ZR36057_GPPGCR1);
-       udelay(1);
-}
-
-
-static void zr36060_sleep(struct zoran *zr, int sleep)
-{
-       switch (zr->card) {
-       case DC10:
-       case DC10plus:
-               GPIO(zr, 3, !sleep);
-               break;
-       case BUZ:
-       case LML33:
-               GPIO(zr, 1, !sleep);
-               break;
-       default:
-               break;
-       }
-       if (!sleep)
-               udelay(500);
-       else
-               udelay(2);
-}
-
-static int zr36060_reset(struct zoran *zr)
-{
-       switch (zr->card) {
-       case DC10:
-       case DC10plus:
-               zr36060_sleep(zr, 0);
-               GPIO(zr, 0, 0);
-               udelay(2);
-               GPIO(zr, 0, 1);
-               udelay(2);
-               break;
-       case LML33:
-       case BUZ:
-               zr36060_sleep(zr, 0);
-               post_office_write(zr, 3, 0, 0);
-               udelay(2);
-       default:;
-       }
-       return 0;
-}
-
-static void set_frame(struct zoran *zr, int val)
-{
-       switch (zr->card) {
-       case DC10:
-       case DC10plus:
-               GPIO(zr, 6, val);
-               break;
-       case LML33:
-       case BUZ:
-               GPIO(zr, 3, val);
-               break;
-       default:
-               break;
-       }
-}
-
-static void set_videobus_dir(struct zoran *zr, int val)
-{
-       switch (zr->card) {
-       case DC10:
-       case DC10plus:
-               GPIO(zr, 1, val);
-               break;
-       case LML33:
-               if (lml33dpath == 0)
-                       GPIO(zr, 5, val);
-               else
-                       GPIO(zr, 5, 1);
-               break;
-       case BUZ:
-       default:
-               break;
-       }
-}
-
-static void set_videobus_enable(struct zoran *zr, int val)
-{
-       switch (zr->card) {
-       case LML33:
-               GPIO(zr, 7, val);
-               break;
-       case DC10:
-       case DC10plus:
-       case BUZ:
-       default:
-               break;
-       }
-}
-
-static void zr36060_set_jpg(struct zoran *zr, enum zoran_codec_mode mode)
-{
-       struct tvnorm *tvn;
-       u32 reg;
-       int size, blocks;
-
-       reg = (1 << 0)          /* CodeMstr */
-           |(0 << 2)           /* CFIS=0 */
-           |(0 << 6)           /* Endian=0 */
-           |(0 << 7);          /* Code16=0 */
-       zr36060_write_8(zr, 0x002, reg);
-
-       switch (mode) {
-
-       case BUZ_MODE_MOTION_DECOMPRESS:
-       case BUZ_MODE_STILL_DECOMPRESS:
-               reg = 0x00;     /* Codec mode = decompression */
-               break;
-
-       case BUZ_MODE_MOTION_COMPRESS:
-       case BUZ_MODE_STILL_COMPRESS:
-       default:
-               reg = 0xa4;     /* Codec mode = compression with variable scale factor */
-               break;
-
-       }
-       zr36060_write_8(zr, 0x003, reg);
-
-       reg = 0x00;             /* reserved, mbz */
-       zr36060_write_8(zr, 0x004, reg);
-
-       /* code volume */
-
-       /* Target field size in pixels: */
-       tvn = zr->timing;
-       size =
-           (tvn->Ha / 2) * (tvn->Wa) / (zr->params.HorDcm) /
-           (zr->params.VerDcm);
-       blocks = size / 64;
-
-       /* Target compressed field size in bits: */
-       size = size * 16;       /* uncompressed size in bits */
-       size = size * zr->params.quality / 400; /* quality = 100 is a compression ratio 1:4 */
-
-       /* Lower limit (arbitrary, 1 KB) */
-       if (size < 8192)
-               size = 8192;
-
-       /* Upper limit: 6/8 of the code buffers */
-       if (size * zr->params.field_per_buff > zr->jpg_bufsize * 6)
-               size = zr->jpg_bufsize * 6 / zr->params.field_per_buff;
-
-       reg = size * 4 / blocks;
-       if (reg > 0xf0)
-               reg = 0xf0;     /* 480 bits/block, does 0xff represents unlimited? */
-       zr36060_write_8(zr, 0x005, reg);
-
-       /* JPEG markers */
-       reg = (zr->params.jpeg_markers) & 0x38; /* DRI, DQT, DHT */
-       if (zr->params.COM_len)
-               reg |= JPEG_MARKER_COM;
-       if (zr->params.APP_len)
-               reg |= JPEG_MARKER_APP;
-       zr36060_write_8(zr, 0x006, reg);
-
-       if (zr->card != LML33 && zr->card != BUZ) {
-               reg = (0 << 3)  /* EOAV=0 */
-                   |(0 << 2)   /* EOI=0 */
-                   |(0 << 1)   /* END=0 */
-                   |(1 << 0);  /* DATERR=1 */
-       } else {
-               reg = (0 << 3)  /* EOAV=0 */
-                   |(0 << 2)   /* EOI=0 */
-                   |(0 << 1)   /* END=0 */
-                   |(0 << 0);  /* DATERR=0 */
-       }
-       zr36060_write_8(zr, 0x007, reg);
-
-       reg = size;
-       zr36060_write_32(zr, 0x009, reg);
-
-       reg = (size * 10) / 11;
-       zr36060_write_32(zr, 0x00d, reg);       // Not needed for compr. with variable scale factor, just in case ...
-
-       /* how do we set initial SF as a function of quality parameter? */
-       reg = 0x0100;           /* SF=1.0 */
-       zr36060_write_16(zr, 0x011, reg);
-
-       reg = 0x00ffffff;       /* AF=max */
-       zr36060_write_24(zr, 0x013, reg);
-
-       reg = 0x0000;           /* test */
-       zr36060_write_16(zr, 0x024, reg);
-
-       //post_office_read(zr,1,0);
-}
-
-static void zr36060_set_video(struct zoran *zr, enum zoran_codec_mode mode)
-{
-       struct tvnorm *tvn;
-       u32 reg;
-       unsigned HStart;
-
-       tvn = zr->timing;
-
-       reg = (0 << 7)          /* Video8     */
-           |(0 << 6)           /* Range      */
-           |(0 << 3)           /* FlDet      */
-           |(1 << 2)           /* FlVedge    */
-           |(0 << 1)           /* FlExt      */
-           |(0 << 0);          /* SyncMstr   */
-
-       if (mode != BUZ_MODE_STILL_DECOMPRESS) {
-               /* limit pixels to range 16..235 as per CCIR-601 */
-               reg |= (1 << 6);        /* Range=1 */
-       }
-       zr36060_write_8(zr, 0x030, reg);
-
-       switch (zr->card) {
-       case DC10:
-       case DC10plus:
-               reg = (0 << 7)  /* VCLKPol   */
-                   |(0 << 6)   /* PValPol   */
-                   |(0 << 5)   /* PoePol    */
-                   |(0 << 4)   /* SImgPol   */
-                   |(1 << 3)   /* BLPol     */
-                   |(1 << 2)   /* FlPol     */
-                   |(1 << 1)   /* HSPol     */
-                   |(1 << 0);  /* VSPol     */
-               break;
-       case LML33:
-               reg = (0 << 7)  /* VCLKPol=0 */
-                   |(0 << 6)   /* PValPol=0 */
-                   |(1 << 5)   /* PoePol=1 */
-                   |(0 << 4)   /* SImgPol=0 */
-                   |(0 << 3)   /* BLPol=0 */
-                   |(0 << 2)   /* FlPol=0 */
-                   |(0 << 1)   /* HSPol=0, sync on falling edge */
-                   |(1 << 0);  /* VSPol=1 */
-               break;
-       case BUZ:
-       default:
-               reg = (0 << 7)  /* VCLKPol=0 */
-                   |(0 << 6)   /* PValPol=0 */
-                   |(1 << 5)   /* PoePol=1 */
-                   |(0 << 4)   /* SImgPol=0 */
-                   |(0 << 3)   /* BLPol=0 */
-                   |(0 << 2)   /* FlPol=0 */
-                   |(1 << 1)   /* HSPol=0, sync on falling edge */
-                   |(1 << 0);  /* VSPol=1 */
-               break;
-       }
-       zr36060_write_8(zr, 0x031, reg);
-
-       switch (zr->params.HorDcm) {
-       default:
-       case 1:
-               reg = (0 << 0);
-               break;          /* HScale = 0 */
-
-       case 2:
-               reg = (1 << 0);
-               break;          /* HScale = 1 */
-
-       case 4:
-               reg = (2 << 0);
-               break;          /* HScale = 2 */
-       }
-       if (zr->params.VerDcm == 2)
-               reg |= (1 << 2);
-       zr36060_write_8(zr, 0x032, reg);
-
-       reg = 0x00;             /* BackY */
-       zr36060_write_8(zr, 0x033, reg);
-
-       reg = 0x80;             /* BackU */
-       zr36060_write_8(zr, 0x034, reg);
-
-       reg = 0x80;             /* BackV */
-       zr36060_write_8(zr, 0x035, reg);
-
-       /* sync generator */
-
-       reg = tvn->Ht - 1;      /* Vtotal */
-       zr36060_write_16(zr, 0x036, reg);
-
-       reg = tvn->Wt - 1;      /* Htotal */
-       zr36060_write_16(zr, 0x038, reg);
-
-       reg = 6 - 1;            /* VsyncSize */
-       zr36060_write_8(zr, 0x03a, reg);
-
-       //reg   = 30 - 1;               /* HsyncSize */
-       reg = (zr->params.norm == 1 ? 57 : 68);
-       zr36060_write_8(zr, 0x03b, reg);
-
-       reg = tvn->VStart - 1;  /* BVstart */
-       zr36060_write_8(zr, 0x03c, reg);
-
-       reg += tvn->Ha / 2;     /* BVend */
-       zr36060_write_16(zr, 0x03e, reg);
-
-       reg = tvn->HStart + 64 - 1;     /* BHstart */
-       zr36060_write_8(zr, 0x03d, reg);
-
-       reg += tvn->Wa;         /* BHend */
-       zr36060_write_16(zr, 0x040, reg);
-
-       /* active area */
-       reg = zr->params.img_y + tvn->VStart;   /* Vstart */
-       zr36060_write_16(zr, 0x042, reg);
-
-       reg += zr->params.img_height;   /* Vend */
-       zr36060_write_16(zr, 0x044, reg);
-
-       HStart = tvn->HStart;
-       if (zr->card == BUZ) {
-               HStart += 44;
-       } else {
-               HStart += 64;
-       }
-       reg = zr->params.img_x + HStart;        /* Hstart */
-       zr36060_write_16(zr, 0x046, reg);
-
-       reg += zr->params.img_width;    /* Hend */
-       zr36060_write_16(zr, 0x048, reg);
-
-       /* subimage area */
-       reg = tvn->VStart - 4;  /* SVstart */
-       zr36060_write_16(zr, 0x04a, reg);
-
-       reg += tvn->Ha / 2 + 8; /* SVend */
-       zr36060_write_16(zr, 0x04c, reg);
-
-       reg = tvn->HStart + 64 - 4;     /* SHstart */
-       zr36060_write_16(zr, 0x04e, reg);
-
-       reg += tvn->Wa + 8;     /* SHend */
-       zr36060_write_16(zr, 0x050, reg);
-}
-
-static void zr36060_set_jpg_SOF(struct zoran *zr)
-{
-       u32 reg;
-
-
-       reg = 0xffc0;           /* SOF marker */
-       zr36060_write_16(zr, 0x060, reg);
-
-       reg = 17;               /* SOF length */
-       zr36060_write_16(zr, 0x062, reg);
-
-       reg = 8;                /* precision 8 bits */
-       zr36060_write_8(zr, 0x064, reg);
-
-       reg = zr->params.img_height / zr->params.VerDcm;        /* image height */
-       zr36060_write_16(zr, 0x065, reg);
-
-       reg = zr->params.img_width / zr->params.HorDcm; /* image width */
-       zr36060_write_16(zr, 0x067, reg);
-
-       reg = 3;                /* 3 color components */
-       zr36060_write_8(zr, 0x069, reg);
-
-       reg = 0x002100;         /* Y component */
-       zr36060_write_24(zr, 0x06a, reg);
-
-       reg = 0x011101;         /* U component */
-       zr36060_write_24(zr, 0x06d, reg);
-
-       reg = 0x021101;         /* V component */
-       zr36060_write_24(zr, 0x070, reg);
-}
-
-static void zr36060_set_jpg_SOS(struct zoran *zr)
-{
-       u32 reg;
-
-
-       reg = 0xffda;           /* SOS marker */
-       zr36060_write_16(zr, 0x07a, reg);
-
-       reg = 12;               /* SOS length */
-       zr36060_write_16(zr, 0x07c, reg);
-
-       reg = 3;                /* 3 color components */
-       zr36060_write_8(zr, 0x07e, reg);
-
-       reg = 0x0000;           /* Y component */
-       zr36060_write_16(zr, 0x07f, reg);
-
-       reg = 0x0111;           /* U component */
-       zr36060_write_16(zr, 0x081, reg);
-
-       reg = 0x0211;           /* V component */
-       zr36060_write_16(zr, 0x083, reg);
-
-       reg = 0x003f00;         /* Start, end spectral scans */
-       zr36060_write_24(zr, 0x085, reg);
-}
-
-static void zr36060_set_jpg_DRI(struct zoran *zr)
-{
-       u32 reg;
-
-
-       reg = 0xffdd;           /* DRI marker */
-       zr36060_write_16(zr, 0x0c0, reg);
-
-       reg = 4;                /* DRI length */
-       zr36060_write_16(zr, 0x0c2, reg);
-
-       reg = 8;                /* length in MCUs */
-       zr36060_write_16(zr, 0x0c4, reg);
-}
-
-static void zr36060_set_jpg_DQT(struct zoran *zr)
-{
-       unsigned i;
-       unsigned adr;
-       static const u8 dqt[] = {
-               0xff, 0xdb,     /* DHT marker */
-               0x00, 0x84,     /* DHT length */
-               0x00,           /* table ID 0 */
-               0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
-               0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
-               0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
-               0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
-               0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
-               0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
-               0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
-               0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
-               0x01,           /* table ID 1 */
-               0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
-               0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
-               0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-               0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-               0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-               0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-               0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-               0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
-       };
-
-       /* write fixed quantitization tables */
-       adr = 0x0cc;
-       for (i = 0; i < sizeof(dqt); ++i) {
-               zr36060_write_8(zr, adr++, dqt[i]);
-       }
-}
-
-static void zr36060_set_jpg_DHT(struct zoran *zr)
-{
-       unsigned i;
-       unsigned adr;
-       static const u8 dht[] = {
-               0xff, 0xc4,     /* DHT marker */
-               0x01, 0xa2,     /* DHT length */
-               0x00,           /* table class 0, ID 0 */
-               0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */
-               0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 8..16 */
-               0x00,           /* values for codes of length 2 */
-               0x01, 0x02, 0x03, 0x04, 0x05,   /* values for codes of length 3 */
-               0x06,           /* values for codes of length 4 */
-               0x07,           /* values for codes of length 5 */
-               0x08,           /* values for codes of length 6 */
-               0x09,           /* values for codes of length 7 */
-               0x0a,           /* values for codes of length 8 */
-               0x0b,           /* values for codes of length 9 */
-               0x01,           /* table class 0, ID 1 */
-               0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */
-               0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 9..16 */
-               0x00, 0x01, 0x02,       /* values for codes of length 2 */
-               0x03,           /* values for codes of length 3 */
-               0x04,           /* values for codes of length 4 */
-               0x05,           /* values for codes of length 5 */
-               0x06,           /* values for codes of length 6 */
-               0x07,           /* values for codes of length 7 */
-               0x08,           /* values for codes of length 8 */
-               0x09,           /* values for codes of length 9 */
-               0x0a,           /* values for codes of length 10 */
-               0x0b,           /* values for codes of length 11 */
-               0x10,
-               0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
-               0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
-               0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
-               0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
-               0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
-               0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
-               0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
-               0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
-               0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
-               0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
-               0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
-               0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
-               0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
-               0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
-               0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
-               0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
-               0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
-               0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
-               0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
-               0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
-               0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
-               0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
-               0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
-               0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00,
-               0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11,
-               0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
-               0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08,
-               0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23,
-               0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a,
-               0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18,
-               0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35,
-               0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
-               0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55,
-               0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
-               0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75,
-               0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84,
-               0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
-               0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2,
-               0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
-               0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
-               0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
-               0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
-               0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
-               0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5,
-               0xf6, 0xf7, 0xf8, 0xf9, 0xfa
-       };
-
-       /* write fixed Huffman tables */
-       adr = 0x1d4;
-       for (i = 0; i < sizeof(dht); ++i) {
-               zr36060_write_8(zr, adr++, dht[i]);
-       }
-}
-
-static void zr36060_set_jpg_APP(struct zoran *zr)
-{
-       unsigned adr;
-       int len, i;
-       u32 reg;
-
-
-       len = zr->params.APP_len;
-       if (len < 0)
-               len = 0;
-       if (len > 60)
-               len = 60;
-
-       i = zr->params.APPn;
-       if (i < 0)
-               i = 0;
-       if (i > 15)
-               i = 15;
-
-       reg = 0xffe0 + i;       /* APPn marker */
-       zr36060_write_16(zr, 0x380, reg);
-
-       reg = len + 2;          /* APPn len */
-       zr36060_write_16(zr, 0x382, reg);
-
-       /* write APPn data */
-       adr = 0x384;
-       for (i = 0; i < 60; i++) {
-               zr36060_write_8(zr, adr++,
-                               (i < len ? zr->params.APP_data[i] : 0));
-       }
-}
-
-static void zr36060_set_jpg_COM(struct zoran *zr)
-{
-       unsigned adr;
-       int len, i;
-       u32 reg;
-
-
-       len = zr->params.COM_len;
-       if (len < 0)
-               len = 0;
-       if (len > 60)
-               len = 60;
-
-       reg = 0xfffe;           /* COM marker */
-       zr36060_write_16(zr, 0x3c0, reg);
-
-       reg = len + 2;          /* COM len */
-       zr36060_write_16(zr, 0x3c2, reg);
-
-       /* write COM data */
-       adr = 0x3c4;
-       for (i = 0; i < 60; i++) {
-               zr36060_write_8(zr, adr++,
-                               (i < len ? zr->params.COM_data[i] : 0));
-       }
-}
-
-static void zr36060_set_cap(struct zoran *zr, enum zoran_codec_mode mode)
-{
-       unsigned i;
-       u32 reg;
-
-       zr36060_reset(zr);
-       mdelay(10);
-
-       reg = (0 << 7)          /* Load=0 */
-           |(1 << 0);          /* SynRst=1 */
-       zr36060_write_8(zr, 0x000, reg);
-
-       zr36060_set_jpg(zr, mode);
-       zr36060_set_video(zr, mode);
-       zr36060_set_jpg_SOF(zr);
-       zr36060_set_jpg_SOS(zr);
-       zr36060_set_jpg_DRI(zr);
-       zr36060_set_jpg_DQT(zr);
-       zr36060_set_jpg_DHT(zr);
-       zr36060_set_jpg_APP(zr);
-       zr36060_set_jpg_COM(zr);
-
-       reg = (1 << 7)          /* Load=1 */
-           |(1 << 0);          /* SynRst=0 */
-       zr36060_write_8(zr, 0x000, reg);
-
-       /* wait for codec to unbusy */
-       for (i = 0; i < 100000; ++i) {
-               reg = zr36060_read_8(zr, 0x001);
-               if ((reg & (1 << 7)) == 0) {
-                       return;
-               }
-               //udelay(100);
-       }
-       printk(KERN_ERR "%sZR36060: stuck busy, statux=%02x\n", zr->name,
-              reg);
-}
-
-static void init_jpeg_queue(struct zoran *zr)
-{
-       int i;
-       /* re-initialize DMA ring stuff */
-       zr->jpg_que_head = 0;
-       zr->jpg_dma_head = 0;
-       zr->jpg_dma_tail = 0;
-       zr->jpg_que_tail = 0;
-       zr->jpg_seq_num = 0;
-       zr->JPEG_error = 0;
-       zr->num_errors = 0;
-       zr->jpg_err_seq = 0;
-       zr->jpg_err_shift = 0;
-       zr->jpg_queued_num = 0;
-       for (i = 0; i < zr->jpg_nbufs; i++) {
-               zr->jpg_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */
-       }
-       for (i = 0; i < BUZ_NUM_STAT_COM; i++) {
-               zr->stat_com[i] = 1;    /* mark as unavailable to zr36057 */
-       }
-}
-
-static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode)
-{
-       struct tvnorm *tvn;
-       u32 reg;
-
-       tvn = zr->timing;
-
-       /* assert P_Reset */
-       btwrite(0, ZR36057_JPC);
-
-       /* MJPEG compression mode */
-       switch (mode) {
-
-       case BUZ_MODE_MOTION_COMPRESS:
-       default:
-               reg = ZR36057_JMC_MJPGCmpMode;
-               break;
-
-       case BUZ_MODE_MOTION_DECOMPRESS:
-               reg = ZR36057_JMC_MJPGExpMode;
-               reg |= ZR36057_JMC_SyncMstr;
-               /* RJ: The following is experimental - improves the output to screen */
-               //if(zr->params.VFIFO_FB) reg |= ZR36057_JMC_VFIFO_FB; // No, it doesn't. SM
-               break;
-
-       case BUZ_MODE_STILL_COMPRESS:
-               reg = ZR36057_JMC_JPGCmpMode;
-               break;
-
-       case BUZ_MODE_STILL_DECOMPRESS:
-               reg = ZR36057_JMC_JPGExpMode;
-               break;
-
-       }
-       reg |= ZR36057_JMC_JPG;
-       if (zr->params.field_per_buff == 1)
-               reg |= ZR36057_JMC_Fld_per_buff;
-       btwrite(reg, ZR36057_JMC);
-
-       /* vertical */
-       btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR);
-       reg =
-           (6 << ZR36057_VSP_VsyncSize) | (tvn->Ht << ZR36057_VSP_FrmTot);
-       btwrite(reg, ZR36057_VSP);
-       reg = ((zr->params.img_y + tvn->VStart) << ZR36057_FVAP_NAY)
-           | (zr->params.img_height << ZR36057_FVAP_PAY);
-       btwrite(reg, ZR36057_FVAP);
-
-       /* horizontal */
-       btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
-       reg =
-           ((tvn->HSyncStart) << ZR36057_HSP_HsyncStart) | (tvn->
-                                                            Wt <<
-                                                            ZR36057_HSP_LineTot);
-       btwrite(reg, ZR36057_HSP);
-       reg = ((zr->params.img_x + tvn->HStart + 4) << ZR36057_FHAP_NAX)
-           | (zr->params.img_width << ZR36057_FHAP_PAX);
-       btwrite(reg, ZR36057_FHAP);
-
-       /* field process parameters */
-       if (zr->params.odd_even)
-               reg = ZR36057_FPP_Odd_Even;
-       else
-               reg = 0;
-       if (mode == BUZ_MODE_MOTION_DECOMPRESS && zr->card != LML33
-           && zr->card != BUZ)
-               reg ^= ZR36057_FPP_Odd_Even;
-
-       btwrite(reg, ZR36057_FPP);
-
-       /* Set proper VCLK Polarity, else colors will be wrong during playback */
-       //btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR);
-
-       /* code base address */
-       reg = virt_to_bus(zr->stat_com);
-       btwrite(reg, ZR36057_JCBA);
-
-       /* FIFO threshold (FIFO is 160. double words) */
-       /* NOTE: decimal values here */
-       switch (mode) {
-
-       case BUZ_MODE_STILL_COMPRESS:
-       case BUZ_MODE_MOTION_COMPRESS:
-               reg = 140;
-               break;
-
-       case BUZ_MODE_STILL_DECOMPRESS:
-       case BUZ_MODE_MOTION_DECOMPRESS:
-               reg = 20;
-               break;
-
-       default:
-               reg = 80;
-               break;
-
-       }
-       btwrite(reg, ZR36057_JCFT);
-       zr36057_adjust_vfe(zr, mode);
-
-}
-
-#if (DEBUGLEVEL > 2)
-static void dump_guests(struct zoran *zr)
-{
-       int i, guest[8];
-
-       for (i = 1; i < 8; i++) {       // Don't read zr36060 here
-               guest[i] = post_office_read(zr, i, 0);
-       }
-
-       printk(KERN_INFO "%s: Guests:", zr->name);
-
-       for (i = 1; i < 8; i++) {
-               printk(" 0x%02x", guest[i]);
-       }
-       printk("\n");
-}
-
-static unsigned long get_time(void)
-{
-       struct timeval tv;
-       do_gettimeofday(&tv);
-       return (1000000 * tv.tv_sec + tv.tv_usec);
-}
-
-static void detect_guest_activity(struct zoran *zr)
-{
-       int timeout, i, j, res, guest[8], guest0[8], change[8][3];
-       unsigned long t0, t1;
-
-       dump_guests(zr);
-       printk(KERN_INFO "%s: Detecting guests activity, please wait...\n",
-              zr->name);
-       for (i = 1; i < 8; i++) {       // Don't read zr36060 here
-               guest0[i] = guest[i] = post_office_read(zr, i, 0);
-       }
-
-       timeout = 0;
-       j = 0;
-       t0 = get_time();
-       while (timeout < 10000) {
-               udelay(10);
-               timeout++;
-               for (i = 1; (i < 8) && (j < 8); i++) {
-                       res = post_office_read(zr, i, 0);
-                       if (res != guest[i]) {
-                               t1 = get_time();
-                               change[j][0] = (t1 - t0);
-                               t0 = t1;
-                               change[j][1] = i;
-                               change[j][2] = res;
-                               j++;
-                               guest[i] = res;
-                       }
-               }
-               if (j >= 8)
-                       break;
-       }
-       printk(KERN_INFO "%s: Guests:", zr->name);
-
-       for (i = 1; i < 8; i++) {
-               printk(" 0x%02x", guest0[i]);
-       }
-       printk("\n");
-       if (j == 0) {
-               printk(KERN_INFO "%s: No activity detected.\n", zr->name);
-               return;
-       }
-       for (i = 0; i < j; i++) {
-               printk(KERN_INFO "%s: %6d: %d => 0x%02x\n", zr->name,
-                      change[i][0], change[i][1], change[i][2]);
-       }
-}
-#endif
-
-static void print_interrupts(struct zoran *zr)
-{
-       int res, noerr;
-       noerr = 0;
-       printk(KERN_INFO "%s: interrupts received:", zr->name);
-       if ((res = zr->field_counter) < -1 || res > 1) {
-               printk(" FD:%d", res);
-       }
-       if ((res = zr->intr_counter_GIRQ1) != 0) {
-               printk(" GIRQ1:%d", res);
-               noerr++;
-       }
-       if ((res = zr->intr_counter_GIRQ0) != 0) {
-               printk(" GIRQ0:%d", res);
-               noerr++;
-       }
-       if ((res = zr->intr_counter_CodRepIRQ) != 0) {
-               printk(" CodRepIRQ:%d", res);
-               noerr++;
-       }
-       if ((res = zr->intr_counter_JPEGRepIRQ) != 0) {
-               printk(" JPEGRepIRQ:%d", res);
-               noerr++;
-       }
-       if (zr->JPEG_max_missed) {
-               printk(" JPEG delays: max=%d min=%d", zr->JPEG_max_missed,
-                      zr->JPEG_min_missed);
-       }
-       if (zr->END_event_missed) {
-               printk(" ENDs missed: %d", zr->END_event_missed);
-       }
-       //if (zr->jpg_queued_num) {
-       printk(" queue_state=%ld/%ld/%ld/%ld", zr->jpg_que_tail,
-              zr->jpg_dma_tail, zr->jpg_dma_head, zr->jpg_que_head);
-       //}
-       if (!noerr) {
-               printk(": no interrupts detected.");
-       }
-       printk("\n");
-}
-
-static void clear_interrupt_counters(struct zoran *zr)
-{
-       zr->intr_counter_GIRQ1 = 0;
-       zr->intr_counter_GIRQ0 = 0;
-       zr->intr_counter_CodRepIRQ = 0;
-       zr->intr_counter_JPEGRepIRQ = 0;
-       zr->field_counter = 0;
-       zr->IRQ1_in = 0;
-       zr->IRQ1_out = 0;
-       zr->JPEG_in = 0;
-       zr->JPEG_out = 0;
-       zr->JPEG_0 = 0;
-       zr->JPEG_1 = 0;
-       zr->END_event_missed = 0;
-       zr->JPEG_missed = 0;
-       zr->JPEG_max_missed = 0;
-       zr->JPEG_min_missed = 0x7fffffff;
-}
-
-static u32 count_reset_interrupt(struct zoran *zr)
-{
-       u32 isr;
-       if ((isr = btread(ZR36057_ISR) & 0x78000000)) {
-               if (isr & ZR36057_ISR_GIRQ1) {
-                       btwrite(ZR36057_ISR_GIRQ1, ZR36057_ISR);
-                       zr->intr_counter_GIRQ1++;
-               }
-               if (isr & ZR36057_ISR_GIRQ0) {
-                       btwrite(ZR36057_ISR_GIRQ0, ZR36057_ISR);
-                       zr->intr_counter_GIRQ0++;
-               }
-               if (isr & ZR36057_ISR_CodRepIRQ) {
-                       btwrite(ZR36057_ISR_CodRepIRQ, ZR36057_ISR);
-                       zr->intr_counter_CodRepIRQ++;
-               }
-               if (isr & ZR36057_ISR_JPEGRepIRQ) {
-                       btwrite(ZR36057_ISR_JPEGRepIRQ, ZR36057_ISR);
-                       zr->intr_counter_JPEGRepIRQ++;
-               }
-       }
-       return isr;
-}
-
-static void jpeg_start(struct zoran *zr)
-{
-       int reg;
-       zr->frame_num = 0;
-
-       btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC);      // /P_Reset
-       btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR);    // \CFlush
-       btor(ZR36057_JPC_CodTrnsEn, ZR36057_JPC);       // /CodTrnsEn
-       btwrite(IRQ_MASK, ZR36057_ISR); // Clear IRQs
-       btwrite(IRQ_MASK | ZR36057_ICR_IntPinEn, ZR36057_ICR);  // Enable IRQs
-
-       set_frame(zr, 0);       // \FRAME
-
-       /* JPEG codec guest ID */
-       reg =
-           (1 << ZR36057_JCGI_JPEGuestID) | (0 <<
-                                             ZR36057_JCGI_JPEGuestReg);
-       btwrite(reg, ZR36057_JCGI);
-
-       btor(ZR36057_JPC_Active, ZR36057_JPC);  // /Active
-       btor(ZR36057_JMC_Go_en, ZR36057_JMC);   // /Go_en
-       udelay(30);
-       set_frame(zr, 1);       // /FRAME
-}
-
-static void zr36057_enable_jpg(struct zoran *zr,
-                              enum zoran_codec_mode mode)
-{
-       static int zero = 0;
-       static int one = 1;
-
-       zr->codec_mode = mode;
-       switch (mode) {
-
-       case BUZ_MODE_MOTION_COMPRESS:
-               set_videobus_enable(zr, 0);
-               set_videobus_dir(zr, 0);        // GPIO(zr, 1, 0);
-               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER,
-                                  DECODER_ENABLE_OUTPUT, &one);
-               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER,
-                                  ENCODER_SET_INPUT, &zero);
-               set_videobus_enable(zr, 1);
-               zr36060_sleep(zr, 0);
-               zr36060_set_cap(zr, mode);      // Load ZR36060
-               init_jpeg_queue(zr);
-               zr36057_set_jpg(zr, mode);      // \P_Reset, ... Video param, FIFO
-
-               clear_interrupt_counters(zr);
-               DEBUG1(printk
-                      (KERN_INFO "%s: enable_jpg MOTION_COMPRESS\n",
-                       zr->name));
-               break;
-
-       case BUZ_MODE_MOTION_DECOMPRESS:
-               set_videobus_enable(zr, 0);
-               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER,
-                                  DECODER_ENABLE_OUTPUT, &zero);
-               set_videobus_dir(zr, 1);        // GPIO(zr, 1, 1);
-               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER,
-                                  ENCODER_SET_INPUT, &one);
-               set_videobus_enable(zr, 1);
-               zr36060_sleep(zr, 0);
-               zr36060_set_cap(zr, mode);      // Load ZR36060
-               init_jpeg_queue(zr);
-               zr36057_set_jpg(zr, mode);      // \P_Reset, ... Video param, FIFO
-
-               clear_interrupt_counters(zr);
-               DEBUG1(printk
-                      (KERN_INFO "%s: enable_jpg MOTION_DECOMPRESS\n",
-                       zr->name));
-               break;
-
-       case BUZ_MODE_IDLE:
-       default:
-               /* shut down processing */
-               btand(~(cardjpegint[zr->card] | ZR36057_ICR_JPEGRepIRQ),
-                     ZR36057_ICR);
-               btwrite(cardjpegint[zr->card] | ZR36057_ICR_JPEGRepIRQ,
-                       ZR36057_ISR);
-               btand(~ZR36057_JMC_Go_en, ZR36057_JMC); // \Go_en
-
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(HZ/20);
-
-               set_videobus_dir(zr, 0);        // GPIO(zr, 1, 0);
-               set_frame(zr, 1);       //GPIO(zr, 6, 1);     // /FRAME
-               btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);      // /CFlush
-               btwrite(0, ZR36057_JPC);        // \P_Reset,\CodTrnsEn,\Active
-               btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC);
-               btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC);
-               zr36060_reset(zr);
-               zr36060_sleep(zr, 1);
-               zr36057_adjust_vfe(zr, mode);
-               set_videobus_enable(zr, 0);
-               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER,
-                                  DECODER_ENABLE_OUTPUT, &one);
-               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER,
-                                  ENCODER_SET_INPUT, &zero);
-               set_videobus_enable(zr, 1);
-               DEBUG1(printk
-                      (KERN_INFO "%s: enable_jpg IDLE\n", zr->name));
-               break;
-
-       }
-}
-
-/*
- *   Queue a MJPEG buffer for capture/playback
- */
-
-static int jpg_qbuf(struct zoran *zr, int frame,
-                   enum zoran_codec_mode mode)
-{
-       unsigned long flags;
-       int res;
-
-       /* Check if buffers are allocated */
-
-       if (!zr->jpg_buffers_allocated) {
-               printk(KERN_ERR
-                      "%s: jpg_qbuf: buffers not yet allocated\n",
-                      zr->name);
-               return -ENOMEM;
-       }
-
-       /* Does the user want to stop streaming? */
-
-       if (frame < 0) {
-               if (zr->codec_mode == mode) {
-                       zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
-                       return 0;
-               } else {
-                       printk(KERN_ERR
-                              "%s: jpg_qbuf - stop streaming but not in streaming mode\n",
-                              zr->name);
-                       return -EINVAL;
-               }
-       }
-
-       /* No grabbing outside the buffer range! */
-
-       if (frame >= zr->jpg_nbufs) {
-               printk(KERN_ERR "%s: jpg_qbuf: buffer %d out of range\n",
-                      zr->name, frame);
-               return -EINVAL;
-       }
-
-       /* what is the codec mode right now? */
-
-       if (zr->codec_mode == BUZ_MODE_IDLE) {
-               /* Ok load up the zr36060 */
-               zr36057_enable_jpg(zr, mode);
-       } else if (zr->codec_mode != mode) {
-               /* wrong codec mode active - invalid */
-               printk(KERN_ERR "%s: jpg_qbuf - codec in wrong mode\n",
-                      zr->name);
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&zr->lock, flags);
-
-       /* make sure a grab isn't going on currently with this buffer */
-
-       switch (zr->jpg_gbuf[frame].state) {
-
-       case BUZ_STATE_DONE:
-               DEBUG1(printk
-                      (KERN_WARNING
-                       "%s: Warning: queing frame in BUZ_STATE_DONE state\n",
-                       zr->name));
-       case BUZ_STATE_USER:
-               /* since there is at least one unused buffer there's room for at least one more pend[] entry */
-               zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = frame;
-               zr->jpg_gbuf[frame].state = BUZ_STATE_PEND;
-               zoran_feed_stat_com(zr);
-               res = 0;
-               break;
-
-       default:
-       case BUZ_STATE_DMA:
-       case BUZ_STATE_PEND:
-               res = -EBUSY;   /* what are you doing? */
-               break;
-
-       }
-
-       spin_unlock_irqrestore(&zr->lock, flags);
-
-       /* Start the zr36060 when the first frame is queued  */
-       if (zr->jpg_que_head == 1)
-               jpeg_start(zr);
-
-       return res;
-}
-
-/*
- *   Sync on a MJPEG buffer
- */
-
-static int jpg_sync(struct zoran *zr, struct zoran_sync *bs)
-{
-       unsigned long flags;
-       int frame, timeout;
-
-       if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS
-           && zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) {
-               DEBUG1(printk(KERN_ERR
-                      "%s: BUZIOCSYNC: - codec not in streaming mode\n",
-                      zr->name));
-               return -EINVAL;
-       }
-       while (zr->jpg_que_tail == zr->jpg_dma_tail) {
-               if (zr->jpg_dma_tail == zr->jpg_dma_head)
-                       break;
-               timeout =
-                   interruptible_sleep_on_timeout(&zr->jpg_capq, 10 * HZ);
-               if (!timeout) {
-                       btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
-                       udelay(1);
-                       printk(KERN_ERR
-                              "%s: timeout: codec isr=0x%02x, csr=0x%02x\n",
-                              zr->name, zr36060_read_8(zr, 0x008),
-                              zr36060_read_8(zr, 0x001));
-                       return -ETIME;
-               } else if (signal_pending(current))
-                       return -ERESTARTSYS;
-       }
-
-       spin_lock_irqsave(&zr->lock, flags);
-
-       if (zr->jpg_dma_tail != zr->jpg_dma_head)
-               frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME];
-       else
-               frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
-       /* buffer should now be in BUZ_STATE_DONE */
-
-#if(DEBUGLEVEL > 0)
-       if (zr->jpg_gbuf[frame].state != BUZ_STATE_DONE)
-               printk(KERN_ERR "%s: jpg_sync - internal error\n",
-                      zr->name);
-#endif
-
-       *bs = zr->jpg_gbuf[frame].bs;
-       zr->jpg_gbuf[frame].state = BUZ_STATE_USER;
-
-       spin_unlock_irqrestore(&zr->lock, flags);
-
-       return 0;
-}
-
-/* when this is called the spinlock must be held */
-static void zoran_feed_stat_com(struct zoran *zr)
-{
-       /* move frames from pending queue to DMA */
-
-       int frame, i, max_stat_com;
-
-       max_stat_com =
-           (zr->params.TmpDcm ==
-            1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1);
-
-       while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com
-              && zr->jpg_dma_head < zr->jpg_que_head) {
-
-               frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME];
-               if (zr->params.TmpDcm == 1) {
-                       /* fill 1 stat_com entry */
-                       i = (zr->jpg_dma_head -
-                            zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
-                       if (!(zr->stat_com[i] & 1))
-                               break;
-                       zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus;
-               } else {
-                       /* fill 2 stat_com entries */
-                       i = ((zr->jpg_dma_head -
-                             zr->jpg_err_shift) & 1) * 2;
-                       if (!(zr->stat_com[i] & 1))
-                               break;
-                       zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus;
-                       zr->stat_com[i + 1] =
-                           zr->jpg_gbuf[frame].frag_tab_bus;
-               }
-               zr->jpg_gbuf[frame].state = BUZ_STATE_DMA;
-               zr->jpg_dma_head++;
-
-       }
-       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS)
-               zr->jpg_queued_num++;
-}
-
-/* when this is called the spinlock must be held */
-static void zoran_reap_stat_com(struct zoran *zr)
-{
-       /* move frames from DMA queue to done queue */
-
-       int i;
-       u32 stat_com;
-       unsigned int seq;
-       unsigned int dif;
-       int frame;
-       struct zoran_gbuffer *gbuf;
-
-       /* In motion decompress we don't have a hardware frame counter,
-          we just count the interrupts here */
-
-       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
-               zr->jpg_seq_num++;
-       }
-       while (zr->jpg_dma_tail < zr->jpg_dma_head) {
-               if (zr->params.TmpDcm == 1)
-                       i = (zr->jpg_dma_tail -
-                            zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
-               else
-                       i = ((zr->jpg_dma_tail -
-                             zr->jpg_err_shift) & 1) * 2 + 1;
-
-               stat_com = zr->stat_com[i];
-
-               if ((stat_com & 1) == 0) {
-                       return;
-               }
-               frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
-               gbuf = &zr->jpg_gbuf[frame];
-               do_gettimeofday(&gbuf->bs.timestamp);
-
-               if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
-                       gbuf->bs.length = (stat_com & 0x7fffff) >> 1;
-
-                       /* update sequence number with the help of the counter in stat_com */
-
-                       seq = ((stat_com >> 24) + zr->jpg_err_seq) & 0xff;
-                       dif = (seq - zr->jpg_seq_num) & 0xff;
-                       zr->jpg_seq_num += dif;
-               } else {
-                       gbuf->bs.length = 0;
-               }
-               gbuf->bs.seq =
-                   zr->params.TmpDcm ==
-                   2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num;
-               gbuf->state = BUZ_STATE_DONE;
-
-               zr->jpg_dma_tail++;
-       }
-}
-
-static void error_handler(struct zoran *zr, u32 astat, u32 stat)
-{
-       /* This is JPEG error handling part */
-       if ((zr->codec_mode != BUZ_MODE_MOTION_COMPRESS)
-           && (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS)) {
-               //printk(KERN_ERR "%s: Internal error: error handling request in mode %d\n", zr->name, zr->codec_mode);
-               return;
-       }
-       if ((stat & 1) == 0
-           && zr->codec_mode == BUZ_MODE_MOTION_COMPRESS
-           && zr->jpg_dma_tail - zr->jpg_que_tail >= zr->jpg_nbufs) {
-               /* No free buffers... */
-               zoran_reap_stat_com(zr);
-               zoran_feed_stat_com(zr);
-               wake_up_interruptible(&zr->jpg_capq);
-               zr->JPEG_missed = 0;
-               return;
-       }
-       if (zr->JPEG_error != 1) {
-               /*
-                * First entry: error just happened during normal operation
-                * 
-                * In BUZ_MODE_MOTION_COMPRESS:
-                * 
-                * Possible glitch in TV signal. In this case we should
-                * stop the codec and wait for good quality signal before
-                * restarting it to avoid further problems
-                * 
-                * In BUZ_MODE_MOTION_DECOMPRESS:
-                * 
-                * Bad JPEG frame: we have to mark it as processed (codec crashed
-                * and was not able to do it itself), and to remove it from queue.
-                */
-               btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
-               udelay(1);
-               stat =
-                   stat | (post_office_read(zr, 7, 0) & 3) << 8 |
-                   zr36060_read_8(zr, 0x008);
-               btwrite(0, ZR36057_JPC);
-               btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
-               zr36060_reset(zr);
-               zr36060_sleep(zr, 1);
-               zr->JPEG_error = 1;
-               zr->num_errors++;
-               /* Report error */
-#if(DEBUGLEVEL > 1)
-               if (zr->num_errors <= 8) {
-                       long frame;
-                       frame =
-                           zr->jpg_pend[zr->
-                                        jpg_dma_tail & BUZ_MASK_FRAME];
-                       printk(KERN_ERR
-                              "%s: JPEG error stat=0x%08x(0x%08x) queue_state=%ld/%ld/%ld/%ld seq=%ld frame=%ld. Codec stopped. ",
-                              zr->name, stat, zr->last_isr,
-                              zr->jpg_que_tail, zr->jpg_dma_tail,
-                              zr->jpg_dma_head, zr->jpg_que_head,
-                              zr->jpg_seq_num, frame);
-                       printk("stat_com frames:");
-                       {
-                               int i, j;
-                               for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
-                                       for (i = 0; i < zr->jpg_nbufs; i++) {
-                                               if (zr->stat_com[j] ==
-                                                   zr->jpg_gbuf[i].
-                                                   frag_tab_bus) {
-                                                       printk("% d->%d",
-                                                              j, i);
-                                               }
-                                       }
-                               }
-                               printk("\n");
-                       }
-               }
-#endif
-               /* Find an entry in stat_com and rotate contents */
-               {
-                       int i;
-
-                       if (zr->params.TmpDcm == 1)
-                               i = (zr->jpg_dma_tail -
-                                    zr->
-                                    jpg_err_shift) & BUZ_MASK_STAT_COM;
-                       else
-                               i = ((zr->jpg_dma_tail -
-                                     zr->jpg_err_shift) & 1) * 2;
-                       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
-                               /* Mimic zr36067 operation */
-                               zr->stat_com[i] |= 1;
-                               if (zr->params.TmpDcm != 1)
-                                       zr->stat_com[i + 1] |= 1;
-                               /* Refill */
-                               zoran_reap_stat_com(zr);
-                               zoran_feed_stat_com(zr);
-                               wake_up_interruptible(&zr->jpg_capq);
-                               /* Find an entry in stat_com again after refill */
-                               if (zr->params.TmpDcm == 1)
-                                       i = (zr->jpg_dma_tail -
-                                            zr->
-                                            jpg_err_shift) &
-                                           BUZ_MASK_STAT_COM;
-                               else
-                                       i = ((zr->jpg_dma_tail -
-                                             zr->jpg_err_shift) & 1) * 2;
-                       }
-                       if (i) {
-                               /* Rotate stat_comm entries to make current entry first */
-                               int j;
-                               u32 bus_addr[BUZ_NUM_STAT_COM];
-
-                               memcpy(bus_addr, zr->stat_com,
-                                      sizeof(bus_addr));
-                               for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
-                                       zr->stat_com[j] =
-                                           bus_addr[(i +
-                                                     j) &
-                                                    BUZ_MASK_STAT_COM];
-                               }
-                               zr->jpg_err_shift += i;
-                               zr->jpg_err_shift &= BUZ_MASK_STAT_COM;
-                       }
-                       if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)
-                               zr->jpg_err_seq = zr->jpg_seq_num;      /* + 1; */
-               }
-       }
-       /* Now the stat_comm buffer is ready for restart */
-       {
-               int status;
-
-               status = 0;
-               if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)
-                       i2c_control_device(&zr->i2c,
-                                          I2C_DRIVERID_VIDEODECODER,
-                                          DECODER_GET_STATUS, &status);
-               if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS
-                   || (status & DECODER_STATUS_GOOD)) {
-           /********** RESTART code *************/
-                       zr36060_reset(zr);
-                       zr36060_set_cap(zr, zr->codec_mode);
-                       zr36057_set_jpg(zr, zr->codec_mode);
-                       jpeg_start(zr);
-#if(DEBUGLEVEL > 1)
-                       if (zr->num_errors <= 8)
-                               printk(KERN_INFO "%s: Restart\n",
-                                      zr->name);
-#endif
-                       zr->JPEG_missed = 0;
-                       zr->JPEG_error = 2;
-           /********** End RESTART code ***********/
-               }
-       }
-}
-
-static irqreturn_t zoran_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-       u32 stat, astat;
-       int count;
-       struct zoran *zr;
-       unsigned long flags;
-       int handled = 0;
-
-       zr = (struct zoran *) dev_id;
-       count = 0;
-
-       if (zr->testing) {
-               /* Testing interrupts */
-               spin_lock_irqsave(&zr->lock, flags);
-               while ((stat = count_reset_interrupt(zr))) {
-                       if (count++ > 100) {
-                               btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
-                               printk(KERN_ERR
-                                      "%s: IRQ lockup while testing, isr=0x%08x, cleared int mask\n",
-                                      zr->name, stat);
-                               wake_up_interruptible(&zr->test_q);
-                       }
-               }
-               zr->last_isr = stat;
-               spin_unlock_irqrestore(&zr->lock, flags);
-               return IRQ_HANDLED;
-       }
-
-       spin_lock_irqsave(&zr->lock, flags);
-       while (1) {
-               /* get/clear interrupt status bits */
-               stat = count_reset_interrupt(zr);
-               astat = stat & IRQ_MASK;
-               if (!astat) {
-                       break;
-               }
-               handled = 1;
-               if (astat & cardvsync[zr->card]) {      // SW
-
-                       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS
-                           || zr->codec_mode ==
-                           BUZ_MODE_MOTION_COMPRESS) {
-                               /* count missed interrupts */
-                               zr->JPEG_missed++;
-                       }
-                       //post_office_read(zr,1,0);
-                       /* Interrupts may still happen when zr->v4l_memgrab_active is switched off.
-                          We simply ignore them */
-
-                       if (zr->v4l_memgrab_active) {
-
-                               /* A lot more checks should be here ... */
-                               if ((btread(ZR36057_VSSFGR) &
-                                    ZR36057_VSSFGR_SnapShot) == 0)
-                                       printk(KERN_WARNING
-                                              "%s: BuzIRQ with SnapShot off ???\n",
-                                              zr->name);
-
-                               if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) {
-                                       /* There is a grab on a frame going on, check if it has finished */
-
-                                       if ((btread(ZR36057_VSSFGR) &
-                                            ZR36057_VSSFGR_FrameGrab) ==
-                                           0) {
-                                               /* it is finished, notify the user */
-
-                                               zr->v4l_gbuf[zr->
-                                                            v4l_grab_frame].
-                                                   state = BUZ_STATE_DONE;
-                                               zr->v4l_grab_frame =
-                                                   NO_GRAB_ACTIVE;
-                                               zr->v4l_grab_seq++;
-                                               zr->v4l_pend_tail++;
-                                       }
-                               }
-
-                               if (zr->v4l_grab_frame == NO_GRAB_ACTIVE)
-                                       wake_up_interruptible(&zr->
-                                                             v4l_capq);
-
-                               /* Check if there is another grab queued */
-
-                               if (zr->v4l_grab_frame == NO_GRAB_ACTIVE
-                                   && zr->v4l_pend_tail !=
-                                   zr->v4l_pend_head) {
-
-                                       int frame =
-                                           zr->v4l_pend[zr->
-                                                        v4l_pend_tail &
-                                                        V4L_MASK_FRAME];
-                                       u32 reg;
-
-                                       zr->v4l_grab_frame = frame;
-
-                                       /* Set zr36057 video front end and enable video */
-
-                                       /* Buffer address */
-
-                                       reg =
-                                           zr->v4l_gbuf[frame].
-                                           fbuffer_bus;
-                                       btwrite(reg, ZR36057_VDTR);
-                                       if (zr->video_interlace)
-                                               reg += zr->gbpl;
-                                       btwrite(reg, ZR36057_VDBR);
-
-                                       /* video stride, status, and frame grab register */
-
-                                       reg = 0;
-                                       if (zr->video_interlace)
-                                               reg += zr->gbpl;
-                                       reg =
-                                           (reg <<
-                                            ZR36057_VSSFGR_DispStride);
-                                       reg |= ZR36057_VSSFGR_VidOvf;
-                                       reg |= ZR36057_VSSFGR_SnapShot;
-                                       reg |= ZR36057_VSSFGR_FrameGrab;
-                                       btwrite(reg, ZR36057_VSSFGR);
-
-                                       btor(ZR36057_VDCR_VidEn,
-                                            ZR36057_VDCR);
-                               }
-                       }
-               }
-#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ)
-               if (astat & ZR36057_ISR_CodRepIRQ) {
-                       zr->intr_counter_CodRepIRQ++;
-                       IDEBUG(printk
-                              (KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n",
-                               zr->name));
-                       btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR);
-               }
-#endif                         /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */
-
-#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ)
-               if (astat & ZR36057_ISR_JPEGRepIRQ) {
-
-                       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS
-                           || zr->codec_mode ==
-                           BUZ_MODE_MOTION_COMPRESS) {
-#if(DEBUGLEVEL > 1)
-                               if (!zr->frame_num || zr->JPEG_error) {
-                                       printk(KERN_INFO
-                                              "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n",
-                                              zr->name, stat,
-                                              zr->params.odd_even,
-                                              zr->params.field_per_buff,
-                                              zr->JPEG_missed);
-                                       {
-                                               char sc[] = "0000";
-                                               char sv[5];
-                                               int i;
-                                               strcpy(sv, sc);
-                                               for (i = 0; i < 4; i++) {
-                                                       if (zr->
-                                                           stat_com[i] &
-                                                           1)
-                                                               sv[i] =
-                                                                   '1';
-                                               }
-                                               sv[4] = 0;
-                                               printk(KERN_INFO
-                                                      "%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n",
-                                                      zr->name, sv,
-                                                      zr->jpg_que_tail,
-                                                      zr->jpg_dma_tail,
-                                                      zr->jpg_dma_head,
-                                                      zr->jpg_que_head);
-                                       }
-                               } else {
-                                       if (zr->JPEG_missed > zr->JPEG_max_missed)      // Get statistics
-                                               zr->JPEG_max_missed =
-                                                   zr->JPEG_missed;
-                                       if (zr->JPEG_missed <
-                                           zr->JPEG_min_missed)
-                                               zr->JPEG_min_missed =
-                                                   zr->JPEG_missed;
-                               }
-#endif
-#if(DEBUGLEVEL > 2)
-                               if (zr->frame_num < 6) {
-                                       int i;
-                                       printk("%s: seq=%ld stat_com:",
-                                              zr->name, zr->jpg_seq_num);
-                                       for (i = 0; i < 4; i++) {
-                                               printk(" %08x",
-                                                      zr->stat_com[i]);
-                                       }
-                                       printk("\n");
-                               }
-#endif
-                               zr->frame_num++;
-                               zr->JPEG_missed = 0;
-                               zr->JPEG_error = 0;
-                               zoran_reap_stat_com(zr);
-                               zoran_feed_stat_com(zr);
-                               wake_up_interruptible(&zr->jpg_capq);
-                       }       //else {
-                       //      printk(KERN_ERR "%s: JPEG interrupt while not in motion (de)compress mode!\n", zr->name);
-                       //}
-               }
-#endif                         /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */
-
-               if ((astat & cardjpegint[zr->card])     /* DATERR interrupt received                 */
-                   ||zr->JPEG_missed > 25      /* Too many fields missed without processing */
-                   || zr->JPEG_error == 1      /* We are already in error processing        */
-                   || ((zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS)
-                       && (zr->
-                           frame_num & (zr->JPEG_missed >
-                                        zr->params.field_per_buff)))
-                   /* fields missed during decompression */
-                   ) {
-                       error_handler(zr, astat, stat);
-               }
-
-               count++;
-               if (count > 10) {
-                       printk(KERN_WARNING "%s: irq loop %d\n", zr->name,
-                              count);
-                       if (count > 20) {
-                               btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
-                               printk(KERN_ERR
-                                      "%s: IRQ lockup, cleared int mask\n",
-                                      zr->name);
-                               break;
-                       }
-               }
-               zr->last_isr = stat;
-       }
-       spin_unlock_irqrestore(&zr->lock, flags);
-       return IRQ_RETVAL(handled);
-}
-
-/* Check a zoran_params struct for correctness, insert default params */
-
-static int zoran_check_params(struct zoran *zr,
-                             struct zoran_params *params)
-{
-       int err = 0, err0 = 0;
-
-       /* insert constant params */
-
-       params->major_version = MAJOR_VERSION;
-       params->minor_version = MINOR_VERSION;
-
-       /* Check input and norm: must be set by calling VIDIOCSCHAN only! */
-
-       params->norm = zr->params.norm;
-       params->input = zr->params.input;
-
-       /* Check decimation, set default values for decimation = 1, 2, 4 */
-
-       switch (params->decimation) {
-       case 1:
-
-               params->HorDcm = 1;
-               params->VerDcm = 1;
-               params->TmpDcm = 1;
-               params->field_per_buff = 2;
-
-               params->img_x = 0;
-               params->img_y = 0;
-               params->img_width = zr->timing->Wa;
-               params->img_height = zr->timing->Ha / 2;
-               break;
-
-       case 2:
-
-               params->HorDcm = 2;
-               params->VerDcm = 1;
-               params->TmpDcm = 2;
-               params->field_per_buff = 1;
-
-               params->img_x = 8;
-               params->img_y = 0;
-               params->img_width = zr->timing->Wa;
-               params->img_height = zr->timing->Ha / 2;
-               break;
-
-       case 4:
-
-               params->HorDcm = 4;
-               params->VerDcm = 2;
-               params->TmpDcm = 2;
-               params->field_per_buff = 1;
-
-               params->img_x = 8;
-               params->img_y = 0;
-               params->img_width = zr->timing->Wa;
-               params->img_height = zr->timing->Ha / 2;
-               break;
-
-       case 0:
-
-               /* We have to check the data the user has set */
-
-               if (params->HorDcm != 1 && params->HorDcm != 2
-                   && params->HorDcm != 4)
-                       err0++;
-               if (params->VerDcm != 1 && params->VerDcm != 2)
-                       err0++;
-               if (params->TmpDcm != 1 && params->TmpDcm != 2)
-                       err0++;
-               if (params->field_per_buff != 1
-                   && params->field_per_buff != 2)
-                       err0++;
-
-               if (params->img_x < 0)
-                       err0++;
-               if (params->img_y < 0)
-                       err0++;
-               if (params->img_width < 0)
-                       err0++;
-               if (params->img_height < 0)
-                       err0++;
-               if (params->img_x + params->img_width > zr->timing->Wa)
-                       err0++;
-               if (params->img_y + params->img_height >
-                   zr->timing->Ha / 2)
-                       err0++;
-               if (params->HorDcm) {
-                       if (params->img_width % (16 * params->HorDcm) != 0)
-                               err0++;
-                       if (params->img_height % (8 * params->VerDcm) != 0)
-                               err0++;
-               }
-
-               if (err0) {
-                       DEBUG1(printk(KERN_ERR
-                              "%s: SET PARAMS: error in params for decimation = 0\n",
-                              zr->name));
-                       err++;
-               }
-               break;
-
-       default:
-               DEBUG1(printk(KERN_ERR
-                      "%s: SET PARAMS: decimation = %d, must be 0, 1, 2 or 4\n",
-                      zr->name, params->decimation));
-               err++;
-               break;
-       }
-
-       if (params->quality > 100)
-               params->quality = 100;
-       if (params->quality < 5)
-               params->quality = 5;
-
-       if (params->APPn < 0)
-               params->APPn = 0;
-       if (params->APPn > 15)
-               params->APPn = 15;
-       if (params->APP_len < 0)
-               params->APP_len = 0;
-       if (params->APP_len > 60)
-               params->APP_len = 60;
-       if (params->COM_len < 0)
-               params->COM_len = 0;
-       if (params->COM_len > 60)
-               params->COM_len = 60;
-
-       if (err)
-               return -EINVAL;
-
-       return 0;
-
-}
-static void zoran_open_init_params(struct zoran *zr)
-{
-       int i;
-
-       /* Per default, map the V4L Buffers */
-
-       zr->map_mjpeg_buffers = 0;
-
-       /* User must explicitly set a window */
-
-       zr->window_set = 0;
-
-       zr->window.x = 0;
-       zr->window.y = 0;
-       zr->window.width = 0;
-       zr->window.height = 0;
-       zr->window.chromakey = 0;
-       zr->window.flags = 0;
-       zr->window.clips = NULL;
-       zr->window.clipcount = 0;
-
-       zr->video_interlace = 0;
-
-       zr->v4l_memgrab_active = 0;
-       zr->v4l_overlay_active = 0;
-
-       zr->v4l_grab_frame = NO_GRAB_ACTIVE;
-       zr->v4l_grab_seq = 0;
-
-       zr->gwidth = 0;
-       zr->gheight = 0;
-       zr->gformat = 0;
-       zr->gbpl = 0;
-
-       /* DMA ring stuff for V4L */
-
-       zr->v4l_pend_tail = 0;
-       zr->v4l_pend_head = 0;
-       for (i = 0; i < v4l_nbufs; i++) {
-               zr->v4l_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */
-       }
-
-       /* Set necessary params and call zoran_check_params to set the defaults */
-
-       zr->params.decimation = 1;
-
-       zr->params.quality = 50;        /* default compression factor 8 */
-       if (zr->card != BUZ)
-               zr->params.odd_even = 1;
-       else
-               zr->params.odd_even = 0;
-
-       zr->params.APPn = 0;
-       zr->params.APP_len = 0; /* No APPn marker */
-       for (i = 0; i < 60; i++)
-               zr->params.APP_data[i] = 0;
-
-       zr->params.COM_len = 0; /* No COM marker */
-       for (i = 0; i < 60; i++)
-               zr->params.COM_data[i] = 0;
-
-       zr->params.VFIFO_FB = 0;
-
-       memset(zr->params.reserved, 0, sizeof(zr->params.reserved));
-
-       zr->params.jpeg_markers = JPEG_MARKER_DHT | JPEG_MARKER_DQT;
-
-       i = zoran_check_params(zr, &zr->params);
-       if (i)
-               printk(KERN_ERR
-                      "%s: zoran_open_init_params internal error\n",
-                      zr->name);
-
-       clear_interrupt_counters(zr);
-       zr->testing = 0;
-}
-
-/*
- *   Open a zoran card. Right now the flags stuff is just playing
- */
-
-static int zoran_open(struct video_device *dev, int flags)
-{
-       struct zoran *zr = (struct zoran *) dev;
-       //int one = 1;
-
-       DEBUG1(printk
-              (KERN_INFO "%s: zoran_open, %s pid=[%d]\n", zr->name,
-               current->comm, current->pid));
-
-       switch (flags) {
-
-       case 0:
-               if (zr->user > 1) {
-                       DEBUG1(printk(KERN_WARNING
-                              "%s: zoran_open: Buz is already in use\n",
-                              zr->name));
-                       return -EBUSY;
-               }
-               zr->user++;
-
-               if (zr->user == 1 && v4l_fbuffer_alloc(zr) < 0) {
-                       zr->user--;
-                       printk(KERN_ERR
-                              "%s: zoran_open: v4l_fbuffer_alloc failed\n",
-                              zr->name);
-                       return -ENOMEM;
-               }
-
-               /* default setup */
-
-               if (zr->user == 1) {    /* First device open */
-                       zoran_open_init_params(zr);
-
-                       zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
-
-                       btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts
-                       btor(ZR36057_ICR_IntPinEn, ZR36057_ICR);
-                       dev->busy = 0;  /* Allow second open */
-               }
-
-               break;
-
-       default:
-               DEBUG1(printk(KERN_WARNING
-                      "%s: zoran_open: flags = 0x%x not yet supported\n",
-                      zr->name, flags));
-               return -EBUSY;
-               break;
-
-       }
-       MOD_INC_USE_COUNT;
-       return 0;
-}
-
-static void zoran_close(struct video_device *dev)
-{
-       struct zoran *zr = (struct zoran *) dev;
-       int zero = 0, two = 2;
-
-       DEBUG1(printk
-              (KERN_INFO "%s: zoran_close, %s pid=[%d]\n", zr->name,
-               current->comm, current->pid));
-       /* Clean up JPEG process */
-
-       wake_up_interruptible(&zr->jpg_capq);
-       zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
-       jpg_fbuffer_free(zr);
-       zr->jpg_nbufs = 0;
-
-       if (zr->user == 1) {    /* Last process */
-               /* disable interrupts */
-               btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
-
-#if(DEBUGLEVEL > 1)
-               print_interrupts(zr);
-#endif
-               /* Overlay off */
-               wake_up_interruptible(&zr->v4l_capq);
-               zr36057_set_memgrab(zr, 0);
-               if (zr->v4l_overlay_active)
-                       zr36057_overlay(zr, 0);
-               v4l_fbuffer_free(zr);
-
-               if (!pass_through) {    /* Switch to color bar */
-                       set_videobus_enable(zr, 0);
-                       i2c_control_device(&zr->i2c,
-                                          I2C_DRIVERID_VIDEODECODER,
-                                          DECODER_ENABLE_OUTPUT, &zero);
-                       i2c_control_device(&zr->i2c,
-                                          I2C_DRIVERID_VIDEOENCODER,
-                                          ENCODER_SET_INPUT, &two);
-                       set_videobus_enable(zr, 1);
-               }
-       }
-
-       zr->user--;
-
-       MOD_DEC_USE_COUNT;
-       DEBUG2(printk(KERN_INFO "%s: zoran_close done\n", zr->name));
-}
-
-
-static long zoran_read(struct video_device *dev, char *buf,
-                      unsigned long count, int nonblock)
-{
-       return -EINVAL;
-}
-
-static long zoran_write(struct video_device *dev, const char *buf,
-                       unsigned long count, int nonblock)
-{
-       return -EINVAL;
-}
-
-/*
- *   ioctl routine
- */
-
-static int do_zoran_ioctl(struct zoran *zr, unsigned int cmd,
-                      void *arg)
-{
-       switch (cmd) {
-
-       case VIDIOCGCAP:
-               {
-                       struct video_capability b;
-                       DEBUG2(printk("%s: ioctl VIDIOCGCAP\n", zr->name));
-
-                       strlcpy(b.name, zr->video_dev.name,
-                               sizeof(b.name));
-                       b.type =
-                           VID_TYPE_CAPTURE | VID_TYPE_OVERLAY |
-                           VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
-                           VID_TYPE_SCALES;
-                       /* theoretically we could also flag VID_TYPE_SUBCAPTURE
-                          but this is not even implemented in the BTTV driver */
-
-                       if (zr->card == DC10 || zr->card == DC10plus) {
-                               b.channels = 3; /* composite, svhs, internal */
-                       } else {
-                               b.channels = 2; /* composite, svhs */
-                       }
-                       b.audios = 0;
-                       b.maxwidth = BUZ_MAX_WIDTH;
-                       b.maxheight = BUZ_MAX_HEIGHT;
-                       b.minwidth = BUZ_MIN_WIDTH;
-                       b.minheight = BUZ_MIN_HEIGHT;
-                       if (copy_to_user(arg, &b, sizeof(b))) {
-                               return -EFAULT;
-                       }
-                       return 0;
-               }
-               break;
-
-       case VIDIOCGCHAN:
-               {
-                       struct video_channel v;
-
-                       if (copy_from_user(&v, arg, sizeof(v))) {
-                               return -EFAULT;
-                       }
-                       DEBUG2(printk
-                              ("%s: ioctl VIDIOCGCHAN for channel %d\n",
-                               zr->name, v.channel));
-                       switch (v.channel) {
-                       case 0:
-                               strcpy(v.name, "Composite");
-                               break;
-                       case 1:
-                               strcpy(v.name, "SVHS");
-                               break;
-                       case 2:
-                               if (zr->card == DC10
-                                   || zr->card == DC10plus) {
-                                       strcpy(v.name, "Internal/comp");
-                                       break;
-                               }
-                       default:
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: VIDIOCGCHAN on not existing channel %d\n",
-                                      zr->name, v.channel));
-                               return -EINVAL;
-                       }
-                       v.tuners = 0;
-                       v.flags = 0;
-                       v.type = VIDEO_TYPE_CAMERA;
-                       v.norm = zr->params.norm;
-                       if (copy_to_user(arg, &v, sizeof(v))) {
-                               return -EFAULT;
-                       }
-                       return 0;
-               }
-               break;
-
-               /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says:
-
-                * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input."
-                *                                 ^^^^^^^
-                * The famos BTTV driver has it implemented with a struct video_channel argument
-                * and we follow it for compatibility reasons
-                *
-                * BTW: this is the only way the user can set the norm!
-                */
-
-       case VIDIOCSCHAN:
-               {
-                       struct video_channel v;
-                       int input;
-                       int on, res;
-                       int encoder_norm;
-
-                       if (copy_from_user(&v, arg, sizeof(v))) {
-                               return -EFAULT;
-                       }
-
-                       if (zr->codec_mode != BUZ_MODE_IDLE) {
-                               if (v.norm != zr->params.norm
-                                   || v.channel != zr->params.input) {
-                                       DEBUG1(printk(KERN_ERR
-                                              "%s: VIDIOCSCHAN called while the card in capture/playback mode\n",
-                                              zr->name));
-                                       return -EINVAL;
-                               } else {
-                                       DEBUG1(printk(BUZ_WARNING
-                                              "%s: Warning: VIDIOCSCHAN called while the card in capture/playback mode\n",
-                                              zr->name));
-                               }
-                       }
-
-                       DEBUG2(printk
-                              ("%s: ioctl VIDIOCSCHAN: channel=%d, norm=%d\n",
-                               zr->name, v.channel, v.norm));
-                       switch (v.channel) {
-                       case 0:
-                               if (zr->card == BUZ)
-                                       input = 3;
-                               else
-                                       input = 0;
-                               break;
-                       case 1:
-                               input = 7;
-                               break;
-                       case 2:
-                               if (zr->card == DC10
-                                   || zr->card == DC10plus) {
-                                       input = 5;
-                                       break;
-                               }
-                       default:
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: VIDIOCSCHAN on not existing channel %d\n",
-                                      zr->name, v.channel));
-                               return -EINVAL;
-                               break;
-                       }
-
-                       if (lock_norm && v.norm != zr->params.norm) {
-                               if (lock_norm > 1) {
-                                       DEBUG1(printk(KERN_WARNING
-                                              "%s: VIDIOCSCHAN: TV standard is locked, can not switch norm.\n",
-                                              zr->name));
-                                       return -EINVAL;
-                               } else {
-                                       DEBUG1(printk(KERN_WARNING
-                                              "%s: VIDIOCSCHAN: TV standard is locked, norm was not changed.\n",
-                                              zr->name));
-                                       v.norm = zr->params.norm;
-                               }
-                       }
-                       
-                       if(v.norm >= 2)
-                               return -EINVAL;
-
-                       if (!cardnorms[zr->card][v.norm]) {
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: VIDIOCSCHAN with not supported norm %d\n",
-                                      zr->name, v.norm));
-                               return -EOPNOTSUPP;
-                               break;
-                       }
-                       encoder_norm = v.norm;
-
-                       zr->params.norm = v.norm;
-                       zr->params.input = v.channel;
-                       zr->timing = cardnorms[zr->card][zr->params.norm];
-
-                       /* We switch overlay off and on since a change in the norm
-                          needs different VFE settings */
-
-                       on = zr->v4l_overlay_active
-                           && !zr->v4l_memgrab_active;
-                       if (on)
-                               zr36057_overlay(zr, 0);
-
-                       set_videobus_enable(zr, 0);
-                       i2c_control_device(&zr->i2c,
-                                          I2C_DRIVERID_VIDEODECODER,
-                                          DECODER_SET_INPUT, &input);
-                       i2c_control_device(&zr->i2c,
-                                          I2C_DRIVERID_VIDEODECODER,
-                                          DECODER_SET_NORM,
-                                          &zr->params.norm);
-                       i2c_control_device(&zr->i2c,
-                                          I2C_DRIVERID_VIDEOENCODER,
-                                          ENCODER_SET_NORM,
-                                          &encoder_norm);
-                       set_videobus_enable(zr, 1);
-
-                       if (on)
-                               zr36057_overlay(zr, 1);
-
-                       /* Make sure the changes come into effect */
-                       res = wait_grab_pending(zr);
-                       if (res)
-                               return res;
-
-                       return 0;
-               }
-               break;
-
-       case VIDIOCGTUNER:
-               {
-                       DEBUG1(printk(KERN_ERR
-                              "%s: ioctl VIDIOCGTUNER not supported\n",
-                              zr->name));
-                       return -EINVAL;
-               }
-               break;
-
-       case VIDIOCSTUNER:
-               {
-                       DEBUG1(printk(KERN_ERR
-                              "%s: ioctl VIDIOCSTUNER not supported\n",
-                              zr->name));
-                       return -EINVAL;
-               }
-               break;
-
-       case VIDIOCGPICT:
-               {
-                       struct video_picture p = zr->picture;
-
-                       DEBUG2(printk
-                              ("%s: ioctl VIDIOCGPICT\n", zr->name));
-                       p.depth = zr->buffer.depth;
-                       switch (zr->buffer.depth) {
-                       case 15:
-                               p.palette = VIDEO_PALETTE_RGB555;
-                               break;
-
-                       case 16:
-                               p.palette = VIDEO_PALETTE_RGB565;
-                               break;
-
-                       case 24:
-                               p.palette = VIDEO_PALETTE_RGB24;
-                               break;
-
-                       case 32:
-                               p.palette = VIDEO_PALETTE_RGB32;
-                               break;
-                       }
-
-                       if (copy_to_user(arg, &p, sizeof(p))) {
-                               return -EFAULT;
-                       }
-                       return 0;
-               }
-               break;
-
-       case VIDIOCSPICT:
-               {
-                       struct video_picture p;
-
-                       if (copy_from_user(&p, arg, sizeof(p))) {
-                               return -EFAULT;
-                       }
-                       i2c_control_device(&zr->i2c,
-                                          I2C_DRIVERID_VIDEODECODER,
-                                          DECODER_SET_PICTURE, &p);
-                       DEBUG2(printk
-                              ("%s: ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n",
-                               zr->name, p.brightness, p.hue, p.colour,
-                               p.contrast, p.depth, p.palette));
-                       /* The depth and palette values have no meaning to us,
-                          should we return  -EINVAL if they don't fit ? */
-                       zr->picture = p;
-                       return 0;
-               }
-               break;
-
-       case VIDIOCCAPTURE:
-               {
-                       int v, res;
-
-                       if (copy_from_user(&v, arg, sizeof(v))) {
-                               return -EFAULT;
-                       }
-                       DEBUG2(printk
-                              ("%s: ioctl VIDIOCCAPTURE: %d\n", zr->name,
-                               v));
-
-                       /* If there is nothing to do, return immediately */
-
-                       if ((v && zr->v4l_overlay_active)
-                           || (!v && !zr->v4l_overlay_active))
-                               return 0;
-
-                       if (v == 0) {
-                               zr->v4l_overlay_active = 0;
-                               if (!zr->v4l_memgrab_active)
-                                       zr36057_overlay(zr, 0);
-                               /* When a grab is running, the video simply won't be switched on any more */
-                       } else {
-                               if (!zr->buffer_set || !zr->window_set) {
-                                       DEBUG1(printk(KERN_ERR
-                                              "%s: VIDIOCCAPTURE: buffer or window not set\n",
-                                              zr->name));
-                                       return -EINVAL;
-                               }
-                               zr->v4l_overlay_active = 1;
-                               if (!zr->v4l_memgrab_active)
-                                       zr36057_overlay(zr, 1);
-                               /* When a grab is running, the video will be switched on when grab is finished */
-                       }
-                       /* Make sure the changes come into effect */
-                       res = wait_grab_pending(zr);
-                       if (res)
-                               return res;
-                       return 0;
-               }
-               break;
-
-       case VIDIOCGWIN:
-               {
-                       DEBUG2(printk("%s: ioctl VIDIOCGWIN\n", zr->name));
-                       if (copy_to_user
-                           (arg, &zr->window, sizeof(zr->window))) {
-                               return -EFAULT;
-                       }
-                       return 0;
-               }
-               break;
-
-       case VIDIOCSWIN:
-               {
-                       struct video_clip *vcp;
-                       struct video_window vw;
-                       struct tvnorm *tvn;
-                       int on, end, res, Wa, Ha;
-
-                       tvn = zr->timing;
-
-                       Wa = tvn->Wa;
-                       Ha = tvn->Ha;
-
-                       if (copy_from_user(&vw, arg, sizeof(vw))) {
-                               return -EFAULT;
-                       }
-
-                       DEBUG2(printk
-                              ("%s: ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n",
-                               zr->name, vw.x, vw.y, vw.width, vw.height,
-                               vw.clipcount));
-
-                       if (!zr->buffer_set) {
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: VIDIOCSWIN: frame buffer has to be set first\n",
-                                      zr->name));
-                               return -EINVAL;
-                       }
-
-                       /*
-                        * The video front end needs 4-byte alinged line sizes, we correct that
-                        * silently here if necessary
-                        */
-
-                       if (zr->buffer.depth == 15
-                           || zr->buffer.depth == 16) {
-                               end = (vw.x + vw.width) & ~1;   /* round down */
-                               vw.x = (vw.x + 1) & ~1; /* round up */
-                               vw.width = end - vw.x;
-                       }
-
-                       if (zr->buffer.depth == 24) {
-                               end = (vw.x + vw.width) & ~3;   /* round down */
-                               vw.x = (vw.x + 3) & ~3; /* round up */
-                               vw.width = end - vw.x;
-                       }
-
-                       if (vw.width > Wa)
-                               vw.width = Wa;
-                       if (vw.height > Ha)
-                               vw.height = Ha;
-
-                       /* Check for vaild parameters */
-                       if (vw.width < BUZ_MIN_WIDTH
-                           || vw.height < BUZ_MIN_HEIGHT
-                           || vw.width > BUZ_MAX_WIDTH
-                           || vw.height > BUZ_MAX_HEIGHT) {
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: VIDIOCSWIN: width = %d or height = %d invalid\n",
-                                      zr->name, vw.width, vw.height));
-                               return -EINVAL;
-                       }
-
-                       zr->window.x = vw.x;
-                       zr->window.y = vw.y;
-                       zr->window.width = vw.width;
-                       zr->window.height = vw.height;
-                       zr->window.chromakey = 0;
-                       zr->window.flags = 0;   // RJ: Is this intended for interlace on/off ?
-                       zr->window.clips = NULL;
-
-                       /*
-                        * If an overlay is running, we have to switch it off
-                        * and switch it on again in order to get the new settings in effect.
-                        *
-                        * We also want to avoid that the overlay mask is written
-                        * when an overlay is running.
-                        */
-
-                       on = zr->v4l_overlay_active
-                           && !zr->v4l_memgrab_active;
-                       if (on)
-                               zr36057_overlay(zr, 0);
-
-                       /*
-                        *   Write the overlay mask if clips are wanted.
-                        */
-                        
-                       if (vw.clipcount < 0 || vw.clipcount > 2048)
-                               return -EINVAL;
-                       if (vw.clipcount) {
-                               vcp =
-                                   vmalloc(sizeof(struct video_clip) *
-                                           (vw.clipcount + 4));
-                               if (vcp == NULL) {
-                                       printk(KERN_ERR
-                                              "%s: zoran_ioctl: Alloc of clip mask failed\n",
-                                              zr->name);
-                                       return -ENOMEM;
-                               }
-                               if (copy_from_user
-                                   (vcp, vw.clips,
-                                    sizeof(struct video_clip) *
-                                    vw.clipcount)) {
-                                       vfree(vcp);
-                                       return -EFAULT;
-                               }
-                               write_overlay_mask(zr, vcp, vw.clipcount);
-                               vfree(vcp);
-                       }
-                       zr->window.clipcount = vw.clipcount;
-       
-                       if (on)
-                               zr36057_overlay(zr, 1);
-                       zr->window_set = 1;
-
-                       /* Make sure the changes come into effect */
-                       res = wait_grab_pending(zr);
-                       if (res)
-                               return res;
-
-                       return 0;
-               }
-               break;
-
-       case VIDIOCGFBUF:
-               {
-                       DEBUG2(printk
-                              ("%s: ioctl VIDIOCGFBUF\n", zr->name));
-                       if (copy_to_user
-                           (arg, &zr->buffer, sizeof(zr->buffer))) {
-                               return -EFAULT;
-                       }
-                       return 0;
-               }
-               break;
-
-       case VIDIOCSFBUF:
-               {
-                       struct video_buffer v;
-
-                       /* RJ: Isn't this too restrictive? As long as the user doesn't set
-                          the base address it shouldn't be too dangerous */
-
-                       if (!capable(CAP_SYS_ADMIN)) {
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: Only the superuser may issue VIDIOCSFBUF ioctl\n",
-                                      zr->name));
-                               return -EPERM;
-                       }
-                       if (copy_from_user(&v, arg, sizeof(v))) {
-                               return -EFAULT;
-                       }
-                       DEBUG2(printk
-                              ("%s: ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n",
-                               zr->name, (u32) v.base, v.width, v.height,
-                               v.depth, v.bytesperline));
-                       if (zr->v4l_overlay_active) {
-                               /* Has the user gotten crazy ... ? */
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: VIDIOCSFBUF not allowed when overlay active\n",
-                                      zr->name));
-                               return -EINVAL;
-                       }
-                       if (v.depth != 15 && v.depth != 16 && v.depth != 24
-                           && v.depth != 32) {
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: VIDIOCSFBUF: depth=%d not supported\n",
-                                      zr->name, v.depth));
-                               return -EINVAL;
-                       }
-                       if (v.height <= 0 || v.width <= 0
-                           || v.bytesperline <= 0) {
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: VIDIOCSFBUF: invalid height/width/bpl value\n",
-                                      zr->name));
-                               return -EINVAL;
-                       }
-                       if (v.bytesperline & 3) {
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: VIDIOCSFBUF: bytesperline must be 4-byte aligned\n",
-                                      zr->name));
-                               return -EINVAL;
-                       }
-                       if (v.base) {
-                               zr->buffer.base =
-                                   (void *) ((unsigned long) v.base & ~3);
-                       }
-                       zr->buffer.height = v.height;
-                       zr->buffer.width = v.width;
-                       zr->buffer.depth = v.depth;
-                       zr->buffer.bytesperline = v.bytesperline;
-
-                       if (zr->buffer.base)
-                               zr->buffer_set = 1;
-                       zr->window_set = 0;     /* The user should set new window parameters */
-                       return 0;
-               }
-               break;
-
-               /* RJ: what is VIDIOCKEY intended to do ??? */
-
-       case VIDIOCKEY:
-               {
-                       /* Will be handled higher up .. */
-                       DEBUG2(printk("%s: ioctl VIDIOCKEY\n", zr->name));
-                       return 0;
-               }
-               break;
-
-       case VIDIOCGFREQ:
-               {
-                       DEBUG1(printk(KERN_ERR
-                              "%s: ioctl VIDIOCGFREQ not supported\n",
-                              zr->name));
-                       return -EINVAL;
-               }
-               break;
-
-       case VIDIOCSFREQ:
-               {
-                       DEBUG1(printk(KERN_ERR
-                              "%s: ioctl VIDIOCSFREQ not supported\n",
-                              zr->name));
-                       return -EINVAL;
-               }
-               break;
-
-       case VIDIOCGAUDIO:
-               {
-                       DEBUG1(printk(KERN_ERR
-                              "%s: ioctl VIDIOCGAUDIO not supported\n",
-                              zr->name));
-                       return -EINVAL;
-               }
-               break;
-
-       case VIDIOCSAUDIO:
-               {
-                       DEBUG1(printk(KERN_ERR
-                              "%s: ioctl VIDIOCSAUDIO not supported\n",
-                              zr->name));
-                       return -EINVAL;
-               }
-               break;
-
-       case VIDIOCSYNC:
-               {
-                       int v;
-
-                       if (copy_from_user(&v, arg, sizeof(v))) {
-                               return -EFAULT;
-                       }
-                       DEBUG3(printk
-                              ("%s: ioctl VIDIOCSYNC %d\n", zr->name, v));
-                       return v4l_sync(zr, v);
-               }
-               break;
-
-       case VIDIOCMCAPTURE:
-               {
-                       struct video_mmap vm;
-
-                       if (copy_from_user
-                           ((void *) &vm, (void *) arg, sizeof(vm))) {
-                               return -EFAULT;
-                       }
-                       DEBUG2(printk
-                              ("%s: ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n",
-                               zr->name, vm.frame, vm.width, vm.height,
-                               vm.format));
-                       return v4l_grab(zr, &vm);
-               }
-               break;
-
-       case VIDIOCGMBUF:
-               {
-                       struct video_mbuf vm;
-                       int i;
-
-                       DEBUG2(printk
-                              ("%s: ioctl VIDIOCGMBUF\n", zr->name));
-                       vm.size = v4l_nbufs * v4l_bufsize;
-                       vm.frames = v4l_nbufs;
-                       for (i = 0; i < v4l_nbufs; i++) {
-                               vm.offsets[i] = i * v4l_bufsize;
-                       }
-
-                       /* The next mmap will map the V4L buffers */
-                       zr->map_mjpeg_buffers = 0;
-
-                       if (copy_to_user(arg, &vm, sizeof(vm))) {
-                               return -EFAULT;
-                       }
-                       return 0;
-               }
-               break;
-
-       case VIDIOCGUNIT:
-               {
-                       struct video_unit vu;
-
-                       DEBUG2(printk
-                              ("%s: ioctl VIDIOCGUNIT\n", zr->name));
-                       vu.video = zr->video_dev.minor;
-                       vu.vbi = VIDEO_NO_UNIT;
-                       vu.radio = VIDEO_NO_UNIT;
-                       vu.audio = VIDEO_NO_UNIT;
-                       vu.teletext = VIDEO_NO_UNIT;
-                       if (copy_to_user(arg, &vu, sizeof(vu))) {
-                               return -EFAULT;
-                       }
-                       return 0;
-               }
-               break;
-
-               /*
-                * RJ: In principal we could support subcaptures for V4L grabbing.
-                *     Not even the famous BTTV driver has them, however.
-                *     If there should be a strong demand, one could consider
-                *     to implement them.
-                */
-       case VIDIOCGCAPTURE:
-               {
-                       DEBUG1(printk(KERN_ERR
-                              "%s: ioctl VIDIOCGCAPTURE not supported\n",
-                              zr->name));
-                       return -EINVAL;
-               }
-               break;
-
-       case VIDIOCSCAPTURE:
-               {
-                       DEBUG1(printk(KERN_ERR
-                              "%s: ioctl VIDIOCSCAPTURE not supported\n",
-                              zr->name));
-                       return -EINVAL;
-               }
-               break;
-
-       case BUZIOC_G_PARAMS:
-               {
-                       DEBUG2(printk
-                              ("%s: ioctl BUZIOC_G_PARAMS\n", zr->name));
-
-                       if (copy_to_user
-                           (arg, &(zr->params), sizeof(zr->params))) {
-                               return -EFAULT;
-                       }
-                       return 0;
-               }
-               break;
-
-       case BUZIOC_S_PARAMS:
-               {
-                       struct zoran_params bp;
-                       /* int input, on; */
-
-                       if (zr->codec_mode != BUZ_MODE_IDLE) {
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: BUZIOC_S_PARAMS called but Buz in capture/playback mode\n",
-                                      zr->name));
-                               return -EINVAL;
-                       }
-
-                       if (copy_from_user(&bp, arg, sizeof(bp))) {
-                               return -EFAULT;
-                       }
-                       DEBUG2(printk
-                              ("%s: ioctl BUZIOC_S_PARAMS\n", zr->name));
-
-                       /* Check the params first before overwriting our internal values */
-
-                       if (zoran_check_params(zr, &bp))
-                               return -EINVAL;
-
-                       zr->params = bp;
-
-                       /* Make changes of input and norm go into effect immediately */
-
-                       /* We switch overlay off and on since a change in the norm
-                          needs different VFE settings */
-
-                       if (copy_to_user(arg, &bp, sizeof(bp))) {
-                               return -EFAULT;
-                       }
-                       return 0;
-               }
-               break;
-
-       case BUZIOC_REQBUFS:
-               {
-                       struct zoran_requestbuffers br;
-
-                       if (zr->jpg_buffers_allocated) {
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: BUZIOC_REQBUFS: buffers already allocated\n",
-                                      zr->name));
-                               return -EINVAL;
-                       }
-                       if (copy_from_user(&br, arg, sizeof(br))) {
-                               return -EFAULT;
-                       }
-                       DEBUG2(printk
-                              ("%s: ioctl BUZIOC_REQBUFS count = %lu size=%lu\n",
-                               zr->name, br.count, br.size));
-
-                       /* Enforce reasonable lower and upper limits */
-                       if (br.count < 4)
-                               br.count = 4;   /* Could be choosen smaller */
-                       if (br.count > BUZ_MAX_FRAME)
-                               br.count = BUZ_MAX_FRAME;
-                       br.size = PAGE_ALIGN(br.size);
-                       if (br.size < 8192)
-                               br.size = 8192; /* Arbitrary */
-                       /* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */
-                       if (br.size > (512 * 1024))
-                               br.size = (512 * 1024); /* 512 K should be enough */
-                       if (zr->need_contiguous
-                           && br.size > MAX_KMALLOC_MEM)
-                               br.size = MAX_KMALLOC_MEM;
-
-                       zr->jpg_nbufs = br.count;
-                       zr->jpg_bufsize = br.size;
-
-                       if (jpg_fbuffer_alloc(zr))
-                               return -ENOMEM;
-
-                       /* The next mmap will map the MJPEG buffers */
-                       zr->map_mjpeg_buffers = 1;
-
-                       if (copy_to_user(arg, &br, sizeof(br))) {
-                               return -EFAULT;
-                       }
-                       return 0;
-               }
-               break;
-
-       case BUZIOC_QBUF_CAPT:
-               {
-                       int nb;
-
-                       if (copy_from_user
-                           ((void *) &nb, (void *) arg, sizeof(int))) {
-                               return -EFAULT;
-                       }
-                       DEBUG4(printk
-                              ("%s: ioctl BUZIOC_QBUF_CAPT %d\n",
-                               zr->name, nb));
-                       return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS);
-               }
-               break;
-
-       case BUZIOC_QBUF_PLAY:
-               {
-                       int nb;
-
-                       if (copy_from_user
-                           ((void *) &nb, (void *) arg, sizeof(int))) {
-                               return -EFAULT;
-                       }
-                       DEBUG4(printk
-                              ("%s: ioctl BUZIOC_QBUF_PLAY %d\n",
-                               zr->name, nb));
-                       return jpg_qbuf(zr, nb,
-                                       BUZ_MODE_MOTION_DECOMPRESS);
-               }
-               break;
-
-       case BUZIOC_SYNC:
-               {
-                       struct zoran_sync bs;
-                       int res;
-
-                       DEBUG4(printk
-                              ("%s: ioctl BUZIOC_SYNC\n", zr->name));
-                       res = jpg_sync(zr, &bs);
-                       if (copy_to_user(arg, &bs, sizeof(bs))) {
-                               return -EFAULT;
-                       }
-                       return res;
-               }
-               break;
-
-       case BUZIOC_G_STATUS:
-               {
-                       struct zoran_status bs;
-                       int norm, input, status;
-
-                       if (zr->codec_mode != BUZ_MODE_IDLE) {
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: BUZIOC_G_STATUS called but Buz in capture/playback mode\n",
-                                      zr->name));
-                               return -EINVAL;
-                       }
-
-                       if (copy_from_user(&bs, arg, sizeof(bs))) {
-                               return -EFAULT;
-                       }
-                       DEBUG2(printk
-                              ("%s: ioctl BUZIOC_G_STATUS\n", zr->name));
-
-                       switch (bs.input) {
-                       case 0:
-                               if (zr->card == BUZ)
-                                       input = 3;
-                               else
-                                       input = 0;
-                               break;
-                       case 1:
-                               input = 7;
-                               break;
-                       default:
-                               DEBUG1(printk(KERN_ERR
-                                      "%s: BUZIOC_G_STATUS on not existing input %d\n",
-                                      zr->name, bs.input));
-                               return -EINVAL;
-                       }
-
-                       /* Set video norm to VIDEO_MODE_AUTO */
-
-                       norm = VIDEO_MODE_AUTO;
-                       set_videobus_enable(zr, 0);
-                       i2c_control_device(&zr->i2c,
-                                          I2C_DRIVERID_VIDEODECODER,
-                                          DECODER_SET_INPUT, &input);
-                       i2c_control_device(&zr->i2c,
-                                          I2C_DRIVERID_VIDEODECODER,
-                                          DECODER_SET_NORM, &norm);
-                       set_videobus_enable(zr, 1);
-
-                       /* sleep 1 second */
-
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(HZ);
-
-                       /* Get status of video decoder */
-
-                       i2c_control_device(&zr->i2c,
-                                          I2C_DRIVERID_VIDEODECODER,
-                                          DECODER_GET_STATUS, &status);
-                       bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0;
-
-                       if (status & DECODER_STATUS_NTSC)
-                               bs.norm = VIDEO_MODE_NTSC;
-                       else if (status & DECODER_STATUS_SECAM)
-                               bs.norm = VIDEO_MODE_SECAM;
-                       else
-                               bs.norm = VIDEO_MODE_PAL;
-
-                       bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0;
-
-                       /* restore previous input and norm */
-                       if (zr->card == BUZ)
-                               input = zr->params.input == 0 ? 3 : 7;
-                       else
-                               input = zr->params.input == 0 ? 0 : 7;
-                       set_videobus_enable(zr, 0);
-                       i2c_control_device(&zr->i2c,
-                                          I2C_DRIVERID_VIDEODECODER,
-                                          DECODER_SET_INPUT, &input);
-                       i2c_control_device(&zr->i2c,
-                                          I2C_DRIVERID_VIDEODECODER,
-                                          DECODER_SET_NORM,
-                                          &zr->params.norm);
-                       set_videobus_enable(zr, 1);
-
-                       if (copy_to_user(arg, &bs, sizeof(bs))) {
-                               return -EFAULT;
-                       }
-                       return 0;
-               }
-               break;
-
-       default:
-               DEBUG1(printk
-                      ("%s: UNKNOWN ioctl cmd: 0x%x\n", zr->name, cmd));
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
-{
-       struct zoran *zr = (struct zoran *) dev;
-       int err;
-       
-       down(&zr->sem);
-       err = do_zoran_ioctl(zr, cmd, arg);
-       up(&zr->sem);
-       
-       return err;
-}
-
-/*
- *   This maps the buffers to user space.
- *
- *   Depending on the state of zr->map_mjpeg_buffers
- *   the V4L or the MJPEG buffers are mapped
- *
- */
-
-static int do_zoran_mmap(struct vm_area_struct *vma, struct zoran *zr, const char *adr,
-                     unsigned long size)
-{
-       unsigned long start = (unsigned long) adr;
-       unsigned long page, pos, todo, fraglen;
-       int i, j;
-
-       DEBUG2(printk
-              (KERN_INFO "%s: mmap at 0x%08lx, size %lu\n", zr->name,
-               start, size));
-       if (zr->map_mjpeg_buffers) {
-               /* Map the MJPEG buffers */
-
-               if (!zr->jpg_buffers_allocated) {
-                       DEBUG1(printk(KERN_ERR
-                              "%s: zoran_mmap(MJPEG): buffers not yet allocated\n",
-                              zr->name));
-                       return -ENOMEM;
-               }
-
-               if (size > zr->jpg_nbufs * zr->jpg_bufsize) {
-                       DEBUG1(printk(KERN_ERR
-                              "%s: zoran_mmap(MJPEG): Max size is %lu - you wanted %lu\n",
-                              zr->name, zr->jpg_nbufs * zr->jpg_bufsize,
-                              size));
-                       return -EINVAL;
-               }
-
-               if (size != zr->jpg_nbufs * zr->jpg_bufsize)
-                       DEBUG1(printk(KERN_WARNING
-                              "%s: zoran_mmap(MJPEG): Expected %lu - you wanted %lu\n",
-                              zr->name, zr->jpg_nbufs * zr->jpg_bufsize,
-                              size));
-
-               for (i = 0; i < zr->jpg_nbufs; i++) {
-                       for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) {
-                               fraglen =
-                                   (zr->jpg_gbuf[i].
-                                    frag_tab[2 * j + 1] & ~1) << 1;
-                               todo = size;
-                               if (todo > fraglen)
-                                       todo = fraglen;
-                               pos =
-                                   (unsigned long) zr->jpg_gbuf[i].
-                                   frag_tab[2 * j];
-                               page = virt_to_phys(bus_to_virt(pos));  /* should just be pos on i386 */
-                               if (remap_page_range
-                                   (vma, start, page, todo, PAGE_SHARED)) {
-                                       printk(KERN_ERR
-                                              "%s: zoran_mmap(V4L): remap_page_range failed\n",
-                                              zr->name);
-                                       return -EAGAIN;
-                               }
-                               size -= todo;
-                               start += todo;
-                               if (size == 0)
-                                       break;
-                               if (zr->jpg_gbuf[i].
-                                   frag_tab[2 * j + 1] & 1)
-                                       break;  /* was last fragment */
-                       }
-                       if (size == 0)
-                               break;
-               }
-       } else {
-               /* Map the V4L buffers */
-
-               if (size > v4l_nbufs * v4l_bufsize) {
-                       DEBUG1(printk(KERN_ERR
-                              "%s: zoran_mmap(V4L): Max size is %d - you wanted %ld\n",
-                              zr->name, v4l_nbufs * v4l_bufsize, size));
-                       return -EINVAL;
-               }
-
-               if (size != v4l_nbufs * v4l_bufsize)
-                       DEBUG1(printk(KERN_WARNING
-                              "%s: zoran_mmap(V4L): Expected %d - you wanted %ld\n",
-                              zr->name, v4l_nbufs * v4l_bufsize, size));
-
-               for (i = 0; i < v4l_nbufs; i++) {
-                       todo = size;
-                       if (todo > v4l_bufsize)
-                               todo = v4l_bufsize;
-                       page = zr->v4l_gbuf[i].fbuffer_phys;
-                       DEBUG2(printk
-                              ("V4L remap page range %d 0x%lx %ld to 0x%lx\n",
-                               i, page, todo, start));
-                       if (remap_page_range
-                           (vma, start, page, todo, PAGE_SHARED)) {
-                               printk(KERN_ERR
-                                      "%s: zoran_mmap(V4L): remap_page_range failed\n",
-                                      zr->name);
-                               return -EAGAIN;
-                       }
-                       size -= todo;
-                       start += todo;
-                       if (size == 0)
-                               break;
-               }
-       }
-       return 0;
-}
-
-static int zoran_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr,
-                     unsigned long size)
-{
-       int err;
-       struct zoran *zr = (struct zoran *) dev;
-       
-       down(&zr->sem);
-       err = do_zoran_mmap(vma, zr, adr, size);
-       up(&zr->sem);
-               
-       return err;
-}
-
-static int zoran_init_done(struct video_device *dev)
-{
-       return 0;
-}
-
-static struct video_device zoran_template = {
-       .owner          = THIS_MODULE,
-       .name           = ZORAN_NAME,
-       .type           = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING |
-           VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE,
-       .hardware       = ZORAN_HARDWARE,
-       .open           = zoran_open,
-       .close          = zoran_close,
-       .read           = zoran_read,
-       .write          = zoran_write,
-       .ioctl          = zoran_ioctl,
-       .mmap           = zoran_mmap,
-       .initialize     = zoran_init_done,
-};
-
-/*
- * initialize video front end
- */
-static void zr36057_init_vfe(struct zoran *zr)
-{
-       u32 reg;
-       reg = btread(ZR36057_VFESPFR);
-       reg |= ZR36057_VFESPFR_LittleEndian;
-       reg &= ~ZR36057_VFESPFR_VCLKPol;
-       reg |= ZR36057_VFESPFR_ExtFl;
-       reg |= ZR36057_VFESPFR_TopField;
-       btwrite(reg, ZR36057_VFESPFR);
-       reg = btread(ZR36057_VDCR);
-       if (triton || zr->revision <= 1)
-               reg &= ~ZR36057_VDCR_Triton;
-       else
-               reg |= ZR36057_VDCR_Triton;
-       btwrite(reg, ZR36057_VDCR);
-}
-
-static void test_interrupts(struct zoran *zr)
-{
-       int timeout, icr;
-
-       clear_interrupt_counters(zr);
-       zr->testing = 1;
-       icr = btread(ZR36057_ICR);
-       btwrite(0x78000000 | ZR36057_ICR_IntPinEn, ZR36057_ICR);
-       timeout = interruptible_sleep_on_timeout(&zr->test_q, 1 * HZ);
-       btwrite(0, ZR36057_ICR);
-       btwrite(0x78000000, ZR36057_ISR);
-       zr->testing = 0;
-       printk(KERN_INFO "%s: Testing interrupts...\n", zr->name);
-       if (timeout) {
-               printk(": time spent: %d\n", 1 * HZ - timeout);
-       }
-       print_interrupts(zr);
-       btwrite(icr, ZR36057_ICR);
-}
-
-static int zr36057_init(int i)
-{
-       struct zoran *zr = &zoran[i];
-       unsigned long mem;
-       unsigned mem_needed;
-       int j;
-       int two = 2;
-       int zero = 0;
-
-       printk(KERN_INFO "%s: Initializing card[%d], zr=%x\n", zr->name, i, (int) zr);
-
-       /* default setup of all parameters which will persist beetween opens */
-
-       zr->user = 0;
-
-       init_waitqueue_head(&zr->v4l_capq);
-       init_waitqueue_head(&zr->jpg_capq);
-       init_waitqueue_head(&zr->test_q);
-
-       zr->map_mjpeg_buffers = 0;      /* Map V4L buffers by default */
-
-       zr->jpg_nbufs = 0;
-       zr->jpg_bufsize = 0;
-       zr->jpg_buffers_allocated = 0;
-
-       zr->buffer_set = 0;     /* Flag if frame buffer has been set */
-       zr->buffer.base = (void *) vidmem;
-       zr->buffer.width = 0;
-       zr->buffer.height = 0;
-       zr->buffer.depth = 0;
-       zr->buffer.bytesperline = 0;
-
-       zr->params.norm = default_norm = (default_norm < 3 ? default_norm : VIDEO_MODE_PAL);    /* Avoid nonsense settings from user */
-       if (!(zr->timing = cardnorms[zr->card][zr->params.norm])) {
-               printk(KERN_WARNING
-                      "%s: default TV statdard not supported by hardware. PAL will be used.\n",
-                      zr->name);
-               zr->params.norm = VIDEO_MODE_PAL;
-               zr->timing = cardnorms[zr->card][zr->params.norm];
-       }
-       zr->params.input = default_input = (default_input ? 1 : 0);     /* Avoid nonsense settings from user */
-       zr->video_interlace = 0;
-
-       /* Should the following be reset at every open ? */
-
-       zr->picture.colour = 32768;
-       zr->picture.brightness = 32768;
-       zr->picture.hue = 32768;
-       zr->picture.contrast = 32768;
-       zr->picture.whiteness = 0;
-       zr->picture.depth = 0;
-       zr->picture.palette = 0;
-
-       for (j = 0; j < VIDEO_MAX_FRAME; j++) {
-               zr->v4l_gbuf[i].fbuffer = 0;
-               zr->v4l_gbuf[i].fbuffer_phys = 0;
-               zr->v4l_gbuf[i].fbuffer_bus = 0;
-       }
-
-       zr->stat_com = 0;
-
-       /* default setup (will be repeated at every open) */
-
-       zoran_open_init_params(zr);
-
-       /* allocate memory *before* doing anything to the hardware in case allocation fails */
-
-       /* STAT_COM table and overlay mask */
-
-       mem_needed = (BUZ_NUM_STAT_COM + ((BUZ_MAX_WIDTH + 31) / 32) * BUZ_MAX_HEIGHT) * 4;
-       mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL);
-       if (!mem) {
-               printk(KERN_ERR "%s: zr36057_init: kmalloc (STAT_COM + ovl.mask) failed\n", zr->name);
-               return -ENOMEM;
-       }
-       memset((void *) mem, 0, mem_needed);
-
-       zr->stat_com = (u32 *) mem;
-       for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
-               zr->stat_com[j] = 1;    /* mark as unavailable to zr36057 */
-       }
-       zr->overlay_mask = (u32 *) (mem + BUZ_NUM_STAT_COM * 4);
-
-       /* Initialize zr->jpg_gbuf */
-
-       for (j = 0; j < BUZ_MAX_FRAME; j++) {
-               zr->jpg_gbuf[j].frag_tab = 0;
-               zr->jpg_gbuf[j].frag_tab_bus = 0;
-               zr->jpg_gbuf[j].state = BUZ_STATE_USER;
-               zr->jpg_gbuf[j].bs.frame = j;
-       }
-
-       /*
-        *   Now add the template and register the device unit.
-        */
-       memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template));
-       strcpy(zr->video_dev.name, zr->name);
-       if (video_register_device(&zr->video_dev, VFL_TYPE_GRABBER, video_nr) < 0) {
-               i2c_unregister_bus(&zr->i2c);
-               kfree((void *) zr->stat_com);
-               return -1;
-       }
-
-       /* Enable bus-mastering */
-       pci_set_master(zr->pci_dev);
-
-       if (zr->card == BUZ)
-               j = zr->params.input == 0 ? 3 : 7;
-       else
-               j = zr->params.input == 0 ? 0 : 7;
-       set_videobus_enable(zr, 0);
-       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER,
-                          DECODER_SET_INPUT, &j);
-       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER,
-                          DECODER_SET_NORM, &zr->params.norm);
-       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER,
-                          ENCODER_SET_NORM, &zr->params.norm);
-       set_videobus_enable(zr, 1);
-
-       /* toggle JPEG codec sleep to sync PLL */
-       zr36060_sleep(zr, 1);
-       zr36060_sleep(zr, 0);
-
-       /* set individual interrupt enables (without GIRQ1)
-          but don't global enable until zoran_open() */
-
-       //btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ1, ZR36057_ICR);  // SW
-       // It looks like using only JPEGRepIRQEn is not always reliable,
-       // may be when JPEG codec crashes it won't generate IRQ? So,
-       btwrite(IRQ_MASK, ZR36057_ICR); // Enable Vsync interrupts too. SM
-
-       zr36057_init_vfe(zr);
-
-       zr->zoran_proc = NULL;
-       zr->initialized = 1;
-
-       zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
-#if (DEBUGLEVEL > 2)
-       detect_guest_activity(zr);
-#endif
-       test_interrupts(zr);
-       btwrite(IRQ_MASK, ZR36057_ICR); // Enable Vsync interrupts too. SM
-       if (!pass_through) {
-               set_videobus_enable(zr, 0);
-               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER,
-                                  DECODER_ENABLE_OUTPUT, &zero);
-               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER,
-                                  ENCODER_SET_INPUT, &two);
-               set_videobus_enable(zr, 1);
-       }
-       return 0;
-}
-
-#include "zoran_procfs.c"
-
-static void release_dc10(void)
-{
-       u8 command;
-       int i;
-       struct zoran *zr;
-
-       for (i = 0; i < zoran_num; i++) {
-               zr = &zoran[i];
-
-               if (!zr->initialized)
-                       continue;
-
-               /* unregister i2c_bus */
-               i2c_unregister_bus((&zr->i2c));
-
-               /* disable PCI bus-mastering */
-               pci_read_config_byte(zr->pci_dev, PCI_COMMAND, &command);
-               command &= ~PCI_COMMAND_MASTER;
-               pci_write_config_byte(zr->pci_dev, PCI_COMMAND, command);
-
-               /* put chip into reset */
-               btwrite(0, ZR36057_SPGPPCR);
-
-               free_irq(zr->pci_dev->irq, zr);
-
-               /* unmap and free memory */
-
-               kfree((void *) zr->stat_com);
-
-               zoran_proc_cleanup(i);
-               iounmap(zr->zr36057_mem);
-
-               video_unregister_device(&zr->video_dev);
-       }
-}
-
-/*
- *   Scan for a Buz card (actually for the PCI contoler ZR36057),
- *   request the irq and map the io memory
- */
-
-static int find_zr36057(void)
-{
-       unsigned char latency, need_latency;
-       struct zoran *zr;
-       struct pci_dev *dev = NULL;
-       int result;
-
-       zoran_num = 0;
-
-       while (zoran_num < BUZ_MAX
-              && (dev =
-                  pci_find_device(PCI_VENDOR_ID_ZORAN,
-                                  PCI_DEVICE_ID_ZORAN_36057,
-                                  dev)) != NULL) {
-               zr = &zoran[zoran_num];
-               zr->pci_dev = dev;
-               zr->zr36057_mem = NULL;
-               zr->id = zoran_num;
-               sprintf(zr->name, "MJPEG[%u]", zr->id);
-
-               spin_lock_init(&zr->lock);
-               init_MUTEX(&zr->sem);
-
-               if (pci_enable_device(dev))
-                       continue;
-
-               zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0);
-               pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION,
-                                    &zr->revision);
-               if (zr->revision < 2) {
-                       printk(KERN_INFO
-                              "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n",
-                              zr->name, zr->revision, zr->pci_dev->irq,
-                              zr->zr36057_adr);
-               } else {
-                       unsigned short ss_vendor_id, ss_id;
-                       ss_vendor_id = zr->pci_dev->subsystem_vendor;
-                       ss_id = zr->pci_dev->subsystem_device;
-                       printk(KERN_INFO
-                              "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n",
-                              zr->name, zr->revision, zr->pci_dev->irq,
-                              zr->zr36057_adr);
-                       printk(KERN_INFO
-                              "%s: subsystem vendor=0x%04x id=0x%04x\n",
-                              zr->name, ss_vendor_id, ss_id);
-               }
-
-               zr->zr36057_mem = ioremap_nocache(zr->zr36057_adr, 0x1000);
-               if (!zr->zr36057_mem) {
-                       printk(KERN_ERR "%s: ioremap failed\n", zr->name);
-                       /* XXX handle error */
-               }
-
-               result = request_irq(zr->pci_dev->irq, zoran_irq, SA_SHIRQ | SA_INTERRUPT, zr->name, (void *) zr);
-               if (result < 0) {
-                       if (result == -EINVAL) {
-                               printk(KERN_ERR
-                                      "%s: Bad irq number or handler\n",
-                                      zr->name);
-                       } else if (result == -EBUSY) {
-                               printk(KERN_ERR
-                                      "%s: IRQ %d busy, change your PnP config in BIOS\n",
-                                      zr->name, zr->pci_dev->irq);
-                       } else {
-                               printk(KERN_ERR
-                                      "%s: Can't assign irq, error code %d\n",
-                                      zr->name, result);
-                       }
-                       iounmap(zr->zr36057_mem);
-                       continue;
-               }
-
-               /* set PCI latency timer */
-               pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency);
-               need_latency = zr->revision > 1 ? 32 : 48;
-               if (latency != need_latency) {
-                       printk(KERN_INFO "%s: Changing PCI latency from %d to %d.\n",  zr->name, latency, need_latency);
-                       pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER,  need_latency);
-               }
-
-               btwrite(0, ZR36057_SPGPPCR);
-               mdelay(1);
-               btwrite(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR);
-               mdelay(1);
-
-               /* assert P_Reset */
-               btwrite(0, ZR36057_JPC);
-
-               /* set up GPIO direction - all output */
-               btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR);
-               btwrite((0x81 << 24) | 0x8888, ZR36057_GPPGCR1);
-
-               /* i2c */
-               memcpy(&zr->i2c, &zoran_i2c_bus_template,
-                      sizeof(struct i2c_bus));
-               strcpy(zr->i2c.name, zr->name);
-               zr->i2c.data = zr;
-               printk(KERN_INFO "%s: Initializing i2c bus...\n", zr->name);
-               if (i2c_register_bus(&zr->i2c) < 0) {
-                       /* put chip into reset */
-                       btwrite(0, ZR36057_SPGPPCR);
-                       free_irq(zr->pci_dev->irq, zr);
-                       iounmap(zr->zr36057_mem);
-                       printk(KERN_ERR "%s: Can't initialize i2c bus\n", zr->name);
-                       continue;
-               }
-
-               if (zr->card != DC10 && zr->card != DC10plus
-                   && zr->card != LML33 && zr->card != BUZ) {
-                       /* unregister i2c_bus */
-                       i2c_unregister_bus((&zr->i2c));
-                       /* put chip into reset */
-                       btwrite(0, ZR36057_SPGPPCR);
-                       free_irq(zr->pci_dev->irq, zr);
-                       iounmap(zr->zr36057_mem);
-                       printk(KERN_ERR "%s: Card not supported\n",
-                              zr->name);
-                       continue;
-               }
-               printk(KERN_INFO "%s card detected\n", zr->name);
-               if (zr->card == LML33) {
-                       GPIO(zr, 2, 1); // Set Composite input/output
-               }
-
-               /* reset JPEG codec */
-               zr36060_sleep(zr, 1);
-               zr36060_reset(zr);
-
-               /* video bus enabled */
-
-               /* display codec revision */
-               if (zr36060_read_8(zr, 0x022) == 0x33) {
-                       printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n",
-                              zr->name, zr36060_read_8(zr, 0x023));
-               } else {
-                       /* unregister i2c_bus */
-                       i2c_unregister_bus((&zr->i2c));
-                       /* put chip into reset */
-                       btwrite(0, ZR36057_SPGPPCR);
-                       free_irq(zr->pci_dev->irq, zr);
-                       iounmap(zr->zr36057_mem);
-                       printk(KERN_ERR "%s: Zoran ZR36060 not found\n",
-                              zr->name);
-                       continue;
-               }
-
-               zoran_num++;
-       }
-       if (zoran_num == 0) {
-               printk(KERN_INFO "No known MJPEG cards found.\n");
-       }
-       return zoran_num;
-}
-
-static void handle_chipset(void)
-{
-       if(pci_pci_problems & PCIPCI_FAIL)
-               printk(KERN_WARNING "Chipset may not support reliable PCI-PCI DMA.\n");
-
-       if(pci_pci_problems & PCIPCI_TRITON)
-       {
-               printk(KERN_WARNING "Enabling Triton support.\n");
-               triton = 1;
-       }
-       
-       if(pci_pci_problems & PCIPCI_NATOMA)
-       {
-               printk(KERN_WARNING "Enabling Natoma workaround.\n");
-               natoma = 1;
-       }
-}
-
-static int init_dc10_cards(void)
-{
-       int i;
-
-       memset(zoran, 0, sizeof(zoran));
-       printk(KERN_INFO
-              "Zoran ZR36060 + ZR36057/67 MJPEG board driver version %d.%d\n",
-              MAJOR_VERSION, MINOR_VERSION);
-
-       /* Look for cards */
-
-       if (find_zr36057() < 0) {
-               return -EIO;
-       }
-       if (zoran_num == 0)
-               return 0;       //-ENXIO;
-
-       printk(KERN_INFO "MJPEG: %d card(s) found\n", zoran_num);
-
-       /* check the parameters we have been given, adjust if necessary */
-
-       if (v4l_nbufs < 0)
-               v4l_nbufs = 0;
-       if (v4l_nbufs > VIDEO_MAX_FRAME)
-               v4l_nbufs = VIDEO_MAX_FRAME;
-       /* The user specfies the in KB, we want them in byte (and page aligned) */
-       v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024);
-       if (v4l_bufsize < 32768)
-               v4l_bufsize = 32768;
-       /* 2 MB is arbitrary but sufficient for the maximum possible images */
-       if (v4l_bufsize > 2048 * 1024)
-               v4l_bufsize = 2048 * 1024;
-
-       printk(KERN_INFO "MJPEG: using %d V4L buffers of size %d KB\n",
-              v4l_nbufs, v4l_bufsize >> 10);
-
-       /* Use parameter for vidmem or try to find a video card */
-
-       if (vidmem) {
-               printk(KERN_INFO
-                      "MJPEG: Using supplied video memory base address @ 0x%lx\n",
-                      vidmem);
-       }
-       /* check if we have a Triton or Natome chipset */
-
-       handle_chipset();
-
-       /* take care of Natoma chipset and a revision 1 zr36057 */
-
-       for (i = 0; i < zoran_num; i++) {
-               if (natoma && zoran[i].revision <= 1) {
-                       zoran[i].need_contiguous = 1;
-                       printk(KERN_INFO
-                              "%s: ZR36057/Natoma bug, max. buffer size is 128K\n",
-                              zoran[i].name);
-               } else {
-                       zoran[i].need_contiguous = 0;
-               }
-       }
-
-       /* initialize the Buzs */
-
-       /* We have to know which ones must be released if an error occurs */
-       for (i = 0; i < zoran_num; i++)
-               zoran[i].initialized = 0;
-
-       for (i = 0; i < zoran_num; i++) {
-               if (zr36057_init(i) < 0) {
-                       release_dc10();
-                       return -EIO;
-               }
-               zoran_proc_init(i);
-       }
-
-       return 0;
-}
-
-static void unload_dc10_cards(void)
-{
-       release_dc10();
-}
-
-
-module_init(init_dc10_cards);
-module_exit(unload_dc10_cards);
-MODULE_LICENSE("GPL");
index 66899d4974fd6ab00bc4362e83b70f8164f2fc58..6f12340e8e24333c29c34f696513b29b9a392cab 100644 (file)
 #define I2C_DRIVERID_TDA8444   39     /* octuple 6-bit DAC             */
 #define I2C_DRIVERID_BT819     40     /* video decoder                 */
 #define I2C_DRIVERID_BT856     41     /* video encoder                 */
-#define I2C_DRIVERID_VPX32XX   42     /* video decoder+vbi/vtxt        */
+#define I2C_DRIVERID_VPX3220   42     /* video decoder+vbi/vtxt        */
 #define I2C_DRIVERID_DRP3510   43     /* ADR decoder (Astra Radio)     */
 #define I2C_DRIVERID_SP5055    44     /* Satellite tuner               */
 #define I2C_DRIVERID_STV0030   45     /* Multipurpose switch           */
 #define I2C_DRIVERID_SAA7108   46     /* video decoder, image scaler   */
 #define I2C_DRIVERID_DS1307    47     /* DS1307 real time clock        */
-#define I2C_DRIVERID_ADV717x   48     /* ADV 7175/7176 video encoder   */
-#define I2C_DRIVERID_ZR36067   49     /* Zoran 36067 video encoder     */
+#define I2C_DRIVERID_ADV7175   48     /* ADV 7175/7176 video encoder   */
+#define I2C_DRIVERID_SAA7114   49      /* video decoder                */
 #define I2C_DRIVERID_ZR36120   50     /* Zoran 36120 video encoder     */
 #define I2C_DRIVERID_24LC32A   51      /* Microchip 24LC32A 32k EEPROM */
 #define I2C_DRIVERID_STM41T00  52      /* real time clock              */
 #define I2C_DRIVERID_UDA1342   53      /* UDA1342 audio codec          */
+#define I2C_DRIVERID_ADV7170   54      /* video encoder                */
 
 
 
 #define I2C_HW_B_IXP2000 0x16  /* GPIO on IXP2000 systems              */
 #define I2C_HW_B_IXP425 0x17   /* GPIO on IXP425 systems               */
 #define I2C_HW_B_S3VIA 0x18    /* S3Via ProSavage adapter              */
+#define I2C_HW_B_ZR36067 0x19  /* Zoran-36057/36067 based boards       */
 
 /* --- PCF 8584 based algorithms                                       */
 #define I2C_HW_P_LP    0x00    /* Parallel port interface              */
index 27e515912d29362923c2b96b62851357013767fd..14306cc8e65b039629a8deb530e200f28a9802af 100644 (file)
 
 #define PCI_VENDOR_ID_MIRO             0x1031
 #define PCI_DEVICE_ID_MIRO_36050       0x5601
+#define PCI_DEVICE_ID_MIRO_DC10PLUS    0x7efe
+#define PCI_DEVICE_ID_MIRO_DC30PLUS    0xd801
 
 #define PCI_VENDOR_ID_NEC              0x1033
 #define PCI_DEVICE_ID_NEC_CBUS_1       0x0001 /* PCI-Cbus Bridge */
 #define PCI_DEVICE_ID_AUREAL_VORTEX_1  0x0001
 #define PCI_DEVICE_ID_AUREAL_VORTEX_2  0x0002
 
+#define PCI_VENDOR_ID_ELECTRONICDESIGNGMBH 0x12f8
+#define PCI_DEVICE_ID_LML_33R10                0x8a02
+
 #define PCI_VENDOR_ID_CBOARDS          0x1307
 #define PCI_DEVICE_ID_CBOARDS_DAS1602_16 0x0001
 
 #define PCI_VENDOR_ID_3WARE            0x13C1
 #define PCI_DEVICE_ID_3WARE_1000       0x1000
 
+#define PCI_VENDOR_ID_IOMEGA           0x13ca
+#define PCI_DEVICE_ID_IOMEGA_BUZ       0x4231
+
 #define PCI_VENDOR_ID_ABOCOM           0x13D1
 #define PCI_DEVICE_ID_ABOCOM_2BD1       0x2BD1