-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
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/)
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.
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
<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"
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
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
--- /dev/null
+/*
+ * 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);
-#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
0x0f, 0x00, /* */
0x10, 0x00, /* */
0x11, 0x00, /* */
- 0x12, 0x00, /* MR3 */
- 0x24, 0x00, /* */
};
static const unsigned char init_pal[] = {
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);
/*
- 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;
int contrast;
int hue;
int sat;
- struct semaphore lock;
};
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 */
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
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:
/* ----------------------------------------------------------------------- */
-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");
/*
- 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;
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:
/* ----------------------------------------------------------------------- */
+/*
+ * 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");
/*
- 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;
/* ----------------------------------------------------------------------- */
-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");
/*
- 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;
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:
/* ----------------------------------------------------------------------- */
-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");
--- /dev/null
+/*
+ * 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);
/*
- 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;
#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 */
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 */
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 */
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 */
};
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 */
};
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 */
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:
/* ----------------------------------------------------------------------- */
-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");
--- /dev/null
+/*
+ * 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");
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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");
/*
- 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 */
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 ??? */
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 */
#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 */
#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
#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 {
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 */
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;
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.*/
#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
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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
+};
+/*
+ * 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;
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},
{"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);
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;
}
}
}
-/* 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);
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
}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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");
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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");
--- /dev/null
+/*
+ * 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 */
/*
- 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
--- /dev/null
+/*
+ * 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");
-/*
- 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 */
+++ /dev/null
-#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");
#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 */
#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